microsoft/openvmm
Publicmirrored fromhttps://github.com/microsoft/openvmmAvailable
openhcl/hcl/src/mapped_page.rs
68lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | use std::cell::UnsafeCell; |
| 5 | use std::fs::File; |
| 6 | use std::io; |
| 7 | use std::os::fd::AsRawFd; |
| 8 | use std::ptr::NonNull; |
| 9 | |
| 10 | pub(crate) struct MappedPage<T>(NonNull<UnsafeCell<T>>); |
| 11 | |
| 12 | impl<T> MappedPage<T> { |
| 13 | pub fn new(fd: &File, pg_off: i64) -> io::Result<Self> { |
| 14 | // Make sure any T we're using can fit in any size page. |
| 15 | assert!(size_of::<T>() <= 4096); |
| 16 | |
| 17 | // SAFETY: calling mmap as documented to create a new mapping. |
| 18 | let ptr = unsafe { |
| 19 | let page_size = libc::sysconf(libc::_SC_PAGESIZE); |
| 20 | libc::mmap( |
| 21 | std::ptr::null_mut(), |
| 22 | page_size as usize, |
| 23 | libc::PROT_READ | libc::PROT_WRITE, |
| 24 | libc::MAP_SHARED, |
| 25 | fd.as_raw_fd(), |
| 26 | pg_off * page_size, |
| 27 | ) |
| 28 | }; |
| 29 | if ptr == libc::MAP_FAILED { |
| 30 | return Err(io::Error::last_os_error()); |
| 31 | } |
| 32 | |
| 33 | Ok(Self(NonNull::new(ptr).unwrap().cast())) |
| 34 | } |
| 35 | |
| 36 | pub fn as_ptr(&self) -> *mut T { |
| 37 | UnsafeCell::raw_get(self.0.as_ptr()) |
| 38 | } |
| 39 | |
| 40 | pub fn as_ref(&self) -> &UnsafeCell<T> { |
| 41 | // SAFETY: The pointer is valid and mapped for the lifetime of the struct, |
| 42 | // it will only every point to a T, and UnsafeCell allows interior mutability. |
| 43 | unsafe { self.0.as_ref() } |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | impl<T> std::fmt::Debug for MappedPage<T> { |
| 48 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 49 | f.debug_tuple("MappedPage").field(&self.0).finish() |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | impl<T> Drop for MappedPage<T> { |
| 54 | fn drop(&mut self) { |
| 55 | // SAFETY: unmapping memory mapped at construction. |
| 56 | unsafe { |
| 57 | libc::munmap( |
| 58 | self.0.as_ptr().cast(), |
| 59 | libc::sysconf(libc::_SC_PAGESIZE) as usize, |
| 60 | ); |
| 61 | } |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | // SAFETY: this is just a pointer value. |
| 66 | unsafe impl<T> Send for MappedPage<T> {} |
| 67 | // SAFETY: see above comment |
| 68 | unsafe impl<T> Sync for MappedPage<T> {} |
| 69 | |