Locate the user region address for a guest address within all mmio regions
(&self, guest_addr: u64, size: u64)
| 322 | |
| 323 | // Locate the user region address for a guest address within all mmio regions |
| 324 | fn find_user_address(&self, guest_addr: u64, size: u64) -> Result<*mut u8, io::Error> { |
| 325 | for region in self.iter() { |
| 326 | for user_region in region.user_memory_regions.iter() { |
| 327 | let mapping: &MmapRegion = &user_region.mapping; |
| 328 | let start: u64 = user_region.start; |
| 329 | let len: u64 = mapping.len().try_into().unwrap(); |
| 330 | // See if the guest address is inside the region. |
| 331 | let Some(offset_from_start) = guest_addr.checked_sub(start) else { |
| 332 | continue; |
| 333 | }; |
| 334 | if offset_from_start >= len { |
| 335 | continue; |
| 336 | } |
| 337 | // Check that the size is in bounds. |
| 338 | // This enforces the invariant promised by implementing MmioRegionRange. |
| 339 | assert!( |
| 340 | size <= len - offset_from_start, |
| 341 | "Attempt to read {size} bytes at offset {offset_from_start} into \ |
| 342 | a region of size {len}" |
| 343 | ); |
| 344 | // SAFETY: MmapRegion guarantees that mapping.addr points to at least |
| 345 | // mapping.len() bytes of valid memory. offset_from_start is equal |
| 346 | // to guest_addr - start, which was checked to be less than mapping.len(). |
| 347 | // Therefore, the returned pointer is still in the range of valid memory. |
| 348 | // Also, since mapping.len() fit in usize, offset_from_start must as well, |
| 349 | // so the cast is safe. |
| 350 | return Ok(unsafe { mapping.addr().add(offset_from_start as usize) }); |
| 351 | } |
| 352 | } |
| 353 | |
| 354 | Err(io::Error::other(format!( |
| 355 | "unable to find user address: 0x{guest_addr:x}" |
| 356 | ))) |
| 357 | } |
| 358 | } |
| 359 | |
| 360 | #[derive(Debug, Error)] |