emulated.rs90.67%
1
// Copyright 2024 Google LLC2
//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 at6
//7
// https://www.apache.org/licenses/LICENSE-2.08
//9
// Unless required by applicable law or agreed to in writing, software10
// 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 and13
// limitations under the License.14
15
use std::fmt::Debug;16
use std::sync::Arc;17
18
use crate::mem::addressable::{Addressable, SlotBackend};19
use crate::mem::{Memory, Result};20
21
#[cfg(not(test))]22
pub trait ChangeLayout: Debug + Send + Sync + 'static {23
fn change(&self, memory: &Memory) -> Result<()>;24
}25
#[cfg(test)]26
pub trait ChangeLayout: Debug + Send + Sync + std::any::Any + 'static {27
fn change(&self, memory: &Memory) -> Result<()>;28
}29
30
#[derive(Debug)]31
pub enum Action {32
None,33
Shutdown,34
Reset,35
ChangeLayout { callback: Box<dyn ChangeLayout> },36
}37
38
pub 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
44
impl Mmio for Arc<dyn Mmio> {45
fn read(&self, offset: u64, size: u8) -> Result<u64> {81x46
Mmio::read(self.as_ref(), offset, size)81x47
}81x48
49
fn write(&self, offset: u64, size: u8, val: u64) -> Result<Action> {36x50
Mmio::write(self.as_ref(), offset, size, val)36x51
}36x52
53
fn size(&self) -> u64 {231x54
Mmio::size(self.as_ref())231x55
}231x56
}57
58
impl SlotBackend for Arc<dyn Mmio> {59
fn size(&self) -> u64 {1347x60
Mmio::size(self.as_ref())1347x61
}1347x62
}63
64
#[macro_export]65
macro_rules! impl_mmio_for_zerocopy {66
($ty:ident) => {67
impl $crate::mem::emulated::Mmio for $ty {68
fn size(&self) -> u64 {3x69
::core::mem::size_of::<Self>() as u643x70
}3x71
72
fn read(&self, offset: u64, size: u8) -> $crate::mem::Result<u64> {205x73
fn read_from_prefix<T: ::zerocopy::FromBytes + Into<u64>>(159x74
bytes: &[u8],159x75
) -> ::core::option::Option<u64> {159x76
let (n, _) = T::read_from_prefix(bytes).ok()?;159x77
Some(n.into())159x78
}159x79
80
let bytes = ::zerocopy::IntoBytes::as_bytes(self);205x81
let offset = offset as usize;205x82
let val = match size {205x83
1 => bytes.get(offset).map(|b| *b as u64),46x84
2 => bytes.get(offset..).and_then(read_from_prefix::<u16>),75x85
4 => bytes.get(offset..).and_then(read_from_prefix::<u32>),81x86
8 => bytes.get(offset..).and_then(read_from_prefix::<u64>),3x87
_ => ::core::option::Option::None,88
};89
90
if let ::core::option::Option::Some(val) = val {205x91
::core::result::Result::Ok(val)205x92
} 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
}205x100
101
fn write(3x102
&self,3x103
offset: u64,3x104
size: u8,3x105
val: u64,3x106
) -> $crate::mem::Result<$crate::mem::emulated::Action> {3x107
::log::error!(3x108
"{}: write 0x{val:0width$x} to readonly offset 0x{offset:x}.",109
::core::any::type_name::<Self>(),3x110
width = 2 * size as usize3x111
);112
Ok($crate::mem::emulated::Action::None)3x113
}3x114
}115
};116
}117
118
#[derive(Debug)]119
pub struct MmioBus<R = Arc<dyn Mmio>>120
where121
R: Debug + SlotBackend,122
{123
pub(crate) inner: Addressable<R>,124
}125
126
impl<R> Default for MmioBus<R>127
where128
R: Debug + SlotBackend + Mmio,129
{130
fn default() -> Self {131
Self::new()132
}133
}134
135
impl<R> MmioBus<R>136
where137
R: Debug + SlotBackend + Mmio,138
{139
pub fn new() -> MmioBus<R> {187x140
Self {187x141
inner: Addressable::new(),187x142
}187x143
}187x144
145
pub fn is_empty(&self) -> bool {89x146
self.inner.is_empty()89x147
}89x148
149
pub fn add(&mut self, addr: u64, range: R) -> Result<()> {480x150
self.inner.add(addr, range)?;480x151
Ok(())480x152
}480x153
154
pub(super) fn remove(&mut self, addr: u64) -> Result<R> {18x155
self.inner.remove(addr)18x156
}18x157
158
pub fn read(&self, addr: u64, size: u8) -> Result<u64> {126x159
match self.inner.search(addr) {126x160
Some((start, dev)) => dev.read(addr - start, size),117x161
None => Ok(u64::MAX),9x162
}163
}126x164
165
pub fn write(&self, addr: u64, size: u8, val: u64) -> Result<Action> {45x166
match self.inner.search(addr) {45x167
Some((start, dev)) => dev.write(addr - start, size, val),42x168
None => Ok(Action::None),3x169
}170
}45x171
}172
173
#[cfg(test)]174
#[path = "emulated_test.rs"]175
mod tests;176