Alioth Code Coverage

emulated.rs90.67%

1// Copyright 2024 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt::Debug;
16use std::sync::Arc;
17
18use crate::mem::addressable::{Addressable, SlotBackend};
19use crate::mem::{Memory, Result};
20
21#[cfg(not(test))]
22pub trait ChangeLayout: Debug + Send + Sync + 'static {
23 fn change(&self, memory: &Memory) -> Result<()>;
24}
25#[cfg(test)]
26pub trait ChangeLayout: Debug + Send + Sync + std::any::Any + 'static {
27 fn change(&self, memory: &Memory) -> Result<()>;
28}
29
30#[derive(Debug)]
31pub enum Action {
32 None,
33 Shutdown,
34 Reset,
35 ChangeLayout { callback: Box<dyn ChangeLayout> },
36}
37
38pub trait Mmio: Debug + Send + Sync + 'static {
39 fn read(&self, offset: u64, size: u8) -> Result<u64>;
40 fn write(&self, offset: u64, size: u8, val: u64) -> Result<Action>;
41 fn size(&self) -> u64;
42}
43
44impl Mmio for Arc<dyn Mmio> {
45 fn read(&self, offset: u64, size: u8) -> Result<u64> {81x
46 Mmio::read(self.as_ref(), offset, size)81x
47 }81x
48
49 fn write(&self, offset: u64, size: u8, val: u64) -> Result<Action> {36x
50 Mmio::write(self.as_ref(), offset, size, val)36x
51 }36x
52
53 fn size(&self) -> u64 {231x
54 Mmio::size(self.as_ref())231x
55 }231x
56}
57
58impl SlotBackend for Arc<dyn Mmio> {
59 fn size(&self) -> u64 {1347x
60 Mmio::size(self.as_ref())1347x
61 }1347x
62}
63
64#[macro_export]
65macro_rules! impl_mmio_for_zerocopy {
66 ($ty:ident) => {
67 impl $crate::mem::emulated::Mmio for $ty {
68 fn size(&self) -> u64 {3x
69 ::core::mem::size_of::<Self>() as u643x
70 }3x
71
72 fn read(&self, offset: u64, size: u8) -> $crate::mem::Result<u64> {205x
73 fn read_from_prefix<T: ::zerocopy::FromBytes + Into<u64>>(159x
74 bytes: &[u8],159x
75 ) -> ::core::option::Option<u64> {159x
76 let (n, _) = T::read_from_prefix(bytes).ok()?;159x
77 Some(n.into())159x
78 }159x
79
80 let bytes = ::zerocopy::IntoBytes::as_bytes(self);205x
81 let offset = offset as usize;205x
82 let val = match size {205x
83 1 => bytes.get(offset).map(|b| *b as u64),46x
84 2 => bytes.get(offset..).and_then(read_from_prefix::<u16>),75x
85 4 => bytes.get(offset..).and_then(read_from_prefix::<u32>),81x
86 8 => bytes.get(offset..).and_then(read_from_prefix::<u64>),3x
87 _ => ::core::option::Option::None,
88 };
89
90 if let ::core::option::Option::Some(val) = val {205x
91 ::core::result::Result::Ok(val)205x
92 } else {
93 ::log::error!(
94 "{}: invalid read access, offset = {offset:#x}, size = {size}.",
95 ::core::any::type_name::<Self>()
96 );
97 ::core::result::Result::Ok(0)
98 }
99 }205x
100
101 fn write(3x
102 &self,3x
103 offset: u64,3x
104 size: u8,3x
105 val: u64,3x
106 ) -> $crate::mem::Result<$crate::mem::emulated::Action> {3x
107 ::log::error!(3x
108 "{}: write 0x{val:0width$x} to readonly offset 0x{offset:x}.",
109 ::core::any::type_name::<Self>(),3x
110 width = 2 * size as usize3x
111 );
112 Ok($crate::mem::emulated::Action::None)3x
113 }3x
114 }
115 };
116}
117
118#[derive(Debug)]
119pub struct MmioBus<R = Arc<dyn Mmio>>
120where
121 R: Debug + SlotBackend,
122{
123 pub(crate) inner: Addressable<R>,
124}
125
126impl<R> Default for MmioBus<R>
127where
128 R: Debug + SlotBackend + Mmio,
129{
130 fn default() -> Self {
131 Self::new()
132 }
133}
134
135impl<R> MmioBus<R>
136where
137 R: Debug + SlotBackend + Mmio,
138{
139 pub fn new() -> MmioBus<R> {187x
140 Self {187x
141 inner: Addressable::new(),187x
142 }187x
143 }187x
144
145 pub fn is_empty(&self) -> bool {89x
146 self.inner.is_empty()89x
147 }89x
148
149 pub fn add(&mut self, addr: u64, range: R) -> Result<()> {480x
150 self.inner.add(addr, range)?;480x
151 Ok(())480x
152 }480x
153
154 pub(super) fn remove(&mut self, addr: u64) -> Result<R> {18x
155 self.inner.remove(addr)18x
156 }18x
157
158 pub fn read(&self, addr: u64, size: u8) -> Result<u64> {126x
159 match self.inner.search(addr) {126x
160 Some((start, dev)) => dev.read(addr - start, size),117x
161 None => Ok(u64::MAX),9x
162 }
163 }126x
164
165 pub fn write(&self, addr: u64, size: u8, val: u64) -> Result<Action> {45x
166 match self.inner.search(addr) {45x
167 Some((start, dev)) => dev.write(addr - start, size, val),42x
168 None => Ok(Action::None),3x
169 }
170 }45x
171}
172
173#[cfg(test)]
174#[path = "emulated_test.rs"]
175mod tests;
176