diff --git a/alioth/src/hv/kvm/vcpu/vmexit.rs b/alioth/src/hv/kvm/vcpu/vmexit.rs index 9ccc11b2..b84ab968 100644 --- a/alioth/src/hv/kvm/vcpu/vmexit.rs +++ b/alioth/src/hv/kvm/vcpu/vmexit.rs @@ -22,10 +22,11 @@ impl KvmVcpu { #[cfg(target_endian = "little")] pub(super) fn handle_mmio(&mut self) -> Result { let kvm_mmio = unsafe { &self.kvm_run.exit.mmio }; + let data = u64::from_ne_bytes(kvm_mmio.data) & u64::MAX >> (64 - (kvm_mmio.len << 3)); let exit = VmExit::Mmio { addr: kvm_mmio.phys_addr, write: if kvm_mmio.is_write > 0 { - Some(u64::from_ne_bytes(kvm_mmio.data)) + Some(data) } else { None }, diff --git a/alioth/src/mem/emulated.rs b/alioth/src/mem/emulated.rs index d03dc5c0..24e4d23c 100644 --- a/alioth/src/mem/emulated.rs +++ b/alioth/src/mem/emulated.rs @@ -12,13 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::cmp::min; use std::fmt::Debug; use std::sync::Arc; use crate::mem::addressable::{Addressable, SlotBackend}; use crate::mem::{Memory, Result}; -use crate::utils::truncate_u64; #[cfg(not(test))] pub trait ChangeLayout: Debug + Send + Sync + 'static { @@ -158,63 +156,17 @@ where } pub fn read(&self, addr: u64, size: u8) -> Result { - let mut count = 0; - let mut val = 0; - let size = size as u64; - while count < size { - let base_addr = addr + count; - let Some((start, dev)) = self.inner.search_next(base_addr) else { - break; - }; - count += start.saturating_sub(base_addr); - let offset = base_addr.saturating_sub(start); - let mut read_size = min(Mmio::size(dev) - offset, size.saturating_sub(count)); - if read_size == 0 { - break; - } - read_size = min(read_size, 1 << read_size.trailing_zeros()); - if offset > 0 { - read_size = min(read_size, 1 << offset.trailing_zeros()); - } - val |= truncate_u64(dev.read(offset, read_size as u8)?, read_size) << (count << 3); - count += read_size; + match self.inner.search(addr) { + Some((start, dev)) => dev.read(addr - start, size), + None => Ok(u64::MAX), } - Ok(val) } pub fn write(&self, addr: u64, size: u8, val: u64) -> Result { - let mut count = 0; - let size = size as u64; - let mut action = Action::None; - while count < size { - let base_addr = addr + count; - let Some((start, dev)) = self.inner.search_next(base_addr) else { - break; - }; - count += start.saturating_sub(base_addr); - let offset = base_addr.saturating_sub(start); - let mut write_size = min(Mmio::size(dev) - offset, size.saturating_sub(count)); - if write_size == 0 { - break; - } - write_size = min(write_size, 1 << write_size.trailing_zeros()); - if offset > 0 { - write_size = min(write_size, 1 << offset.trailing_zeros()); - } - let write_val = truncate_u64(val >> (count << 3), write_size); - let r = dev.write(offset, write_size as u8, write_val)?; - if matches!(action, Action::None) { - action = r - } else { - // TODO: handle multiple side effects caused by a single write - log::error!( - "Write {write_val:#x} to {:#x}: dropped: {action:#x?}", - start + offset - ); - } - count += write_size; + match self.inner.search(addr) { + Some((start, dev)) => dev.write(addr - start, size, val), + None => Ok(Action::None), } - Ok(action) } } diff --git a/alioth/src/mem/emulated_test.rs b/alioth/src/mem/emulated_test.rs index 805c7f3e..5c10c0e7 100644 --- a/alioth/src/mem/emulated_test.rs +++ b/alioth/src/mem/emulated_test.rs @@ -31,18 +31,19 @@ impl Mmio for TestRange { self.size } - fn read(&self, offset: u64, _size: u8) -> Result { + fn read(&self, offset: u64, size: u8) -> Result { let val = *self.val.lock() >> (offset << 3); - Ok(val) + let mask = u64::MAX >> (64 - (size << 3)); + Ok(val & mask) } fn write(&self, offset: u64, size: u8, val: u64) -> Result { assert_eq!(size.count_ones(), 1); - assert!(offset.trailing_zeros() >= size.trailing_zeros()); let v = &mut *self.val.lock(); let shift = offset << 3; - *v &= !(((1 << (size << 3)) - 1) << shift); - *v |= val << shift; + let mask = u64::MAX >> (64 - (size << 3)); + *v &= !(mask << shift); + *v |= (val & mask) << shift; Ok(Action::None) } } @@ -74,53 +75,49 @@ fn fixture_mmio_bus() -> MmioBus { #[rstest] #[case(0x0, 1, 0x01)] -#[case(0x0, 2, 0x2301)] -#[case(0x0, 3, 0x672301)] -#[case(0x0, 4, 0x45672301)] -#[case(0x0, 8, 0x89ab_cdef_4567_2301)] +#[case(0x0, 2, 0xff01)] +#[case(0x0, 3, 0xff_ff01)] +#[case(0x0, 4, 0xffff_ff01)] +#[case(0x0, 8, 0xffff_ffff_ffff_ff01)] #[case(0x1, 1, 0x23)] -#[case(0x1, 2, 0x6723)] -#[case(0x1, 3, 0x45_6723)] -#[case(0x1, 4, 0xef45_6723)] -#[case(0x1, 8, 0x89_abcd_ef45_6723)] -#[case(0x4, 8, 0x89ab_cdef)] +#[case(0x1, 2, 0xff23)] +#[case(0x1, 3, 0xff_ff23)] +#[case(0x1, 4, 0xffff_ff23)] +#[case(0x1, 8, 0xffff_ffff_ffff_ff23)] +#[case(0x4, 8, 0xffff_ffff_89ab_cdef)] #[case(0x6, 1, 0xab)] #[case(0x6, 2, 0x89ab)] -#[case(0x6, 4, 0x89ab)] -#[case(0x8, 1, 0x0)] -#[case(0x8, 4, 0x0)] -#[case(0x8, 5, 0x34_0000_0000)] -#[case(0x8, 8, 0xabcd_1234_0000_0000)] -#[case(0xa, 8, 0x0000_abcd_1234_0000)] +#[case(0x6, 4, 0xffff_89ab)] +#[case(0x8, 1, u64::MAX)] +#[case(0xa, 8, u64::MAX)] +#[case(0xe, 2, 0xabcd)] fn test_mmio_bus_read( fixture_mmio_bus: MmioBus, #[case] addr: u64, #[case] size: u8, #[case] val: u64, ) { - assert_eq!(fixture_mmio_bus.read(addr, size).unwrap(), val) + assert_eq!( + fixture_mmio_bus.read(addr, size).unwrap(), + val, + "Read from addr {addr:#x} with size {size} failed" + ) } #[rstest] -#[case(0x0, 1, 0x3210, 0x89ab_cdef_4567_2310)] -#[case(0x0, 2, 0x3210, 0x89ab_cdef_4567_3210)] -#[case(0x0, 3, 0x763201, 0x89ab_cdef_4576_3201)] -#[case(0x0, 4, 0x10, 0x89ab_cdef_0000_0010)] +#[case(0x0, 1, 0x3210, 0xffff_ffff_ffff_ff10)] +#[case(0x0, 2, 0x3210, 0xffff_ffff_ffff_3210)] +#[case(0x0, 4, 0x10, 0xffff_ffff_0000_0010)] #[case(0x0, 8, 0x10, 0x10)] -#[case(0x1, 1, 0x32, 0x89_abcd_ef45_6732)] -#[case(0x1, 2, 0x7632, 0x89_abcd_ef45_7632)] -#[case(0x1, 3, 0x1254_7632, 0x89_abcd_ef54_7632)] -#[case(0x1, 4, 0xfe54_7632, 0x89_abcd_fe54_7632)] +#[case(0x1, 1, 0x32, 0xffff_ffff_ffff_ff32)] +#[case(0x1, 2, 0x7632, 0xffff_ffff_ffff_7632)] +#[case(0x1, 4, 0xfe54_7632, 0xffff_ffff_fe54_7632)] #[case(0x1, 8, 0x0, 0x0)] -#[case(0x4, 8, 0x1234_89ab_cdef, 0x89ab_cdef)] -#[case(0x6, 1, 0xba, 0x1234_0000_0000_89ba)] -#[case(0x6, 2, 0x98ba, 0x1234_0000_0000_98ba)] -#[case(0x6, 4, 0xff_ab98, 0x1234_0000_0000_ab98)] -#[case(0x8, 1, 0xff, 0xabcd_1234_0000_0000)] -#[case(0x8, 4, 0xffff, 0xabcd_1234_0000_0000)] -#[case(0x8, 5, 0xfe_1234_0000, 0xabcd_12fe_0000_0000)] -#[case(0x8, 8, 0x5678_cdfe_1234_0000, 0x5678_cdfe_0000_0000)] -#[case(0xa, 8, 0xcdfe_1234_abcd, 0xcdfe_1234_0000)] +#[case(0x4, 8, 0x1234_89ab_cdef, 0x1234_89ab_cdef)] +#[case(0x6, 1, 0xba, 0xffff_ffff_89ba)] +#[case(0x6, 2, 0x98ba, 0xffff_ffff_98ba)] +#[case(0x6, 4, 0xcd_ab98, 0xffff_00cd_ab98)] +#[case(0x8, 1, 0xff, u64::MAX)] fn test_mmio_bus_write( fixture_mmio_bus: MmioBus, #[case] addr: u64,