diff --git a/sys_util/src/guest_memory.rs b/sys_util/src/guest_memory.rs index 1246a9cace..d40b5bece5 100644 --- a/sys_util/src/guest_memory.rs +++ b/sys_util/src/guest_memory.rs @@ -224,13 +224,20 @@ impl GuestMemory { /// Returns true if the given address is within the memory range available to the guest. pub fn address_in_range(&self, addr: GuestAddress) -> bool { - addr < self.end_addr() + self.regions + .iter() + .any(|region| region.guest_base <= addr && addr < region_end(region)) } /// Returns the address plus the offset if it is in range. pub fn checked_offset(&self, addr: GuestAddress, offset: u64) -> Option { - addr.checked_add(offset) - .and_then(|a| if a < self.end_addr() { Some(a) } else { None }) + addr.checked_add(offset).and_then(|a| { + if self.address_in_range(a) { + Some(a) + } else { + None + } + }) } /// Returns the size of the memory region in bytes. @@ -598,6 +605,20 @@ mod tests { assert!(GuestMemory::new(&vec![(start_addr1, 0x2000), (start_addr2, 0x2000)]).is_err()); } + #[test] + fn region_hole() { + let start_addr1 = GuestAddress(0x0); + let start_addr2 = GuestAddress(0x4000); + let gm = GuestMemory::new(&vec![(start_addr1, 0x2000), (start_addr2, 0x2000)]).unwrap(); + assert_eq!(gm.address_in_range(GuestAddress(0x1000)), true); + assert_eq!(gm.address_in_range(GuestAddress(0x3000)), false); + assert_eq!(gm.address_in_range(GuestAddress(0x5000)), true); + assert_eq!(gm.address_in_range(GuestAddress(0x6000)), false); + assert!(gm.checked_offset(GuestAddress(0x1000), 0x1000).is_none()); + assert!(gm.checked_offset(GuestAddress(0x5000), 0x800).is_some()); + assert!(gm.checked_offset(GuestAddress(0x5000), 0x1000).is_none()); + } + #[test] fn test_read_u64() { let start_addr1 = GuestAddress(0x0); diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs index 88c91f98dd..9c960d70c6 100644 --- a/x86_64/src/lib.rs +++ b/x86_64/src/lib.rs @@ -282,16 +282,13 @@ fn arch_memory_regions(size: u64, has_bios: bool) -> Vec<(GuestAddress, u64)> { } } else { regions.push((GuestAddress(0), end_32bit_gap_start.offset())); - if mem_end > first_addr_past_32bits { - let region_start = if has_bios { - GuestAddress(BIOS_START) - } else { - first_addr_past_32bits - }; - regions.push((region_start, mem_end.offset_from(first_addr_past_32bits))); - } else if has_bios { + if has_bios { regions.push((GuestAddress(BIOS_START), BIOS_LEN as u64)); } + regions.push(( + first_addr_past_32bits, + mem_end.offset_from(end_32bit_gap_start), + )); } regions @@ -810,8 +807,10 @@ mod tests { #[test] fn regions_gt_4gb_bios() { let regions = arch_memory_regions((1u64 << 32) + 0x8000, /* has_bios */ true); - assert_eq!(2, regions.len()); + assert_eq!(3, regions.len()); assert_eq!(GuestAddress(0), regions[0].0); assert_eq!(GuestAddress(BIOS_START), regions[1].0); + assert_eq!(BIOS_LEN as u64, regions[1].1); + assert_eq!(GuestAddress(1u64 << 32), regions[2].0); } }