|
3 | 3 | //! Kernel page allocation and management. |
4 | 4 |
|
5 | 5 | use crate::{ |
| 6 | + addr::*, |
6 | 7 | alloc::{AllocError, Flags}, |
7 | 8 | bindings, |
8 | 9 | error::code::*, |
9 | 10 | error::Result, |
10 | 11 | types::{Opaque, Ownable, Owned}, |
11 | 12 | uaccess::UserSliceReader, |
12 | 13 | }; |
| 14 | +use core::mem::ManuallyDrop; |
13 | 15 | use core::ptr::{self, NonNull}; |
14 | 16 |
|
15 | 17 | /// A bitwise shift for the page size. |
@@ -248,6 +250,69 @@ impl Page { |
248 | 250 | reader.read_raw(unsafe { core::slice::from_raw_parts_mut(dst.cast(), len) }) |
249 | 251 | }) |
250 | 252 | } |
| 253 | + |
| 254 | + /// Returns the physical address of this page. |
| 255 | + pub fn phys(&self) -> PhysicalAddr { |
| 256 | + // SAFETY: `page` is valid due to the type invariants on `Page`. |
| 257 | + unsafe { bindings::page_to_phys(self.as_ptr()) } |
| 258 | + } |
| 259 | + |
| 260 | + /// Converts a Rust-owned Page into its physical address. |
| 261 | + /// The caller is responsible for calling `from_phys()` to avoid |
| 262 | + /// leaking memory. |
| 263 | + pub fn into_phys(this: Owned<Self>) -> PhysicalAddr { |
| 264 | + ManuallyDrop::new(this).phys() |
| 265 | + } |
| 266 | + |
| 267 | + /// Converts a physical address to a Rust-owned Page. |
| 268 | + /// |
| 269 | + /// SAFETY: |
| 270 | + /// The caller must ensure that the physical address was previously returned |
| 271 | + /// by a call to `Page::into_phys()`, and that the physical address is no |
| 272 | + /// longer used after this call, nor is `from_phys()` called again on it. |
| 273 | + pub unsafe fn from_phys(phys: PhysicalAddr) -> Owned<Self> { |
| 274 | + // SAFETY: By the safety requirements, the physical address must be valid and |
| 275 | + // have come from `into_phys()`, so phys_to_page() cannot fail and |
| 276 | + // must return the original struct page pointer. |
| 277 | + unsafe { Owned::from_raw(NonNull::new_unchecked(bindings::phys_to_page(phys)).cast()) } |
| 278 | + } |
| 279 | + |
| 280 | + /// Borrows a Page from a physical address, without taking over ownership. |
| 281 | + /// |
| 282 | + /// If the physical address does not have a `struct page` entry or is not |
| 283 | + /// part of the System RAM region, returns None. |
| 284 | + /// |
| 285 | + /// SAFETY: |
| 286 | + /// The caller must ensure that the physical address, if it is backed by a |
| 287 | + /// `struct page`, remains available for the duration of the borrowed |
| 288 | + /// lifetime. |
| 289 | + pub unsafe fn borrow_phys(phys: &PhysicalAddr) -> Option<&Self> { |
| 290 | + // SAFETY: This is always safe, as it is just arithmetic |
| 291 | + let pfn = unsafe { bindings::phys_to_pfn(*phys) }; |
| 292 | + // SAFETY: This function is safe to call with any pfn |
| 293 | + if !unsafe { bindings::pfn_valid(pfn) && bindings::page_is_ram(pfn) != 0 } { |
| 294 | + None |
| 295 | + } else { |
| 296 | + // SAFETY: We have just checked that the pfn is valid above, so it must |
| 297 | + // have a corresponding struct page. By the safety requirements, we can |
| 298 | + // return a borrowed reference to it. |
| 299 | + Some(unsafe { &*(bindings::pfn_to_page(pfn) as *mut Self as *const Self) }) |
| 300 | + } |
| 301 | + } |
| 302 | + |
| 303 | + /// Borrows a Page from a physical address, without taking over ownership |
| 304 | + /// nor checking for validity. |
| 305 | + /// |
| 306 | + /// SAFETY: |
| 307 | + /// The caller must ensure that the physical address is backed by a |
| 308 | + /// `struct page` and corresponds to System RAM. |
| 309 | + pub unsafe fn borrow_phys_unchecked(phys: &PhysicalAddr) -> &Self { |
| 310 | + // SAFETY: This is always safe, as it is just arithmetic |
| 311 | + let pfn = unsafe { bindings::phys_to_pfn(*phys) }; |
| 312 | + // SAFETY: The caller guarantees that the pfn is valid. By the safety |
| 313 | + // requirements, we can return a borrowed reference to it. |
| 314 | + unsafe { &*(bindings::pfn_to_page(pfn) as *mut Self as *const Self) } |
| 315 | + } |
251 | 316 | } |
252 | 317 |
|
253 | 318 | // SAFETY: See below. |
|
0 commit comments