Lines Matching +full:page +full:- +full:offset
1 // SPDX-License-Identifier: GPL-2.0
3 //! Kernel page allocation and management.
14 /// A bitwise shift for the page size.
17 /// The number of bytes in a page.
20 /// A bitmask that gives the page containing a given address.
21 pub const PAGE_MASK: usize = !(PAGE_SIZE - 1);
27 pub const fn page_align(addr: usize) -> usize {
28 // Parentheses around `PAGE_SIZE - 1` to avoid triggering overflow sanitizers in the wrong
30 (addr + (PAGE_SIZE - 1)) & PAGE_MASK
33 /// A pointer to a page that owns the page allocation.
37 /// The pointer is valid, and has ownership over the page.
38 pub struct Page {
39 page: NonNull<bindings::page>,
44 unsafe impl Send for Page {}
48 unsafe impl Sync for Page {}
50 impl Page {
51 /// Allocates a new page.
55 /// Allocate memory for a page.
58 /// use kernel::page::Page;
60 /// # fn dox() -> Result<(), kernel::alloc::AllocError> {
61 /// let page = Page::alloc_page(GFP_KERNEL)?;
65 /// Allocate memory for a page and zero its contents.
68 /// use kernel::page::Page;
70 /// # fn dox() -> Result<(), kernel::alloc::AllocError> {
71 /// let page = Page::alloc_page(GFP_KERNEL | __GFP_ZERO)?;
74 pub fn alloc_page(flags: Flags) -> Result<Self, AllocError> {
77 let page = unsafe { bindings::alloc_pages(flags.as_raw(), 0) };
78 let page = NonNull::new(page).ok_or(AllocError)?;
79 // INVARIANT: We just successfully allocated a page, so we now have ownership of the newly
80 // allocated page. We transfer that ownership to the new `Page` object.
81 Ok(Self { page })
84 /// Returns a raw pointer to the page.
85 pub fn as_ptr(&self) -> *mut bindings::page {
86 self.page.as_ptr()
89 /// Runs a piece of code with this page mapped to an address.
91 /// The page is unmapped when this call returns.
101 /// If multiple threads map the same page at the same time, then they may reference with
105 fn with_page_mapped<T>(&self, f: impl FnOnce(*mut u8) -> T) -> T {
106 // SAFETY: `page` is valid due to the type invariants on `Page`.
111 // This unmaps the page mapped above.
116 // In other words, if this call to `kunmap_local` happens when a different page should be
125 /// Runs a piece of code with a raw pointer to a slice of this page, with bounds checking.
128 /// page, and the pointer will be valid for at least `len` bytes. The pointer is only valid on
131 /// If `off` and `len` refers to a region outside of this page, then this method returns
142 /// If multiple threads map the same page at the same time, then they may reference with
150 f: impl FnOnce(*mut u8) -> Result<T>,
151 ) -> Result<T> {
156 // SAFETY: The `off` integer is at most `PAGE_SIZE`, so this pointer offset will
157 // result in a pointer that is in bounds or one off the end of the page.
165 /// Maps the page and reads from it into the given buffer.
167 /// This method will perform bounds checks on the page offset. If `offset .. offset+len` goes
168 /// outside of the page, then this call returns [`EINVAL`].
173 /// * Callers must ensure that this call does not race with a write to the same page that
175 pub unsafe fn read_raw(&self, dst: *mut u8, offset: usize, len: usize) -> Result {
176 self.with_pointer_into_page(offset, len, move |src| {
187 /// Maps the page and writes into it from the given buffer.
189 /// This method will perform bounds checks on the page offset. If `offset .. offset+len` goes
190 /// outside of the page, then this call returns [`EINVAL`].
195 /// * Callers must ensure that this call does not race with a read or write to the same page
197 pub unsafe fn write_raw(&self, src: *const u8, offset: usize, len: usize) -> Result {
198 self.with_pointer_into_page(offset, len, move |dst| {
208 /// Maps the page and zeroes the given slice.
210 /// This method will perform bounds checks on the page offset. If `offset .. offset+len` goes
211 /// outside of the page, then this call returns [`EINVAL`].
215 /// Callers must ensure that this call does not race with a read or write to the same page that
217 pub unsafe fn fill_zero_raw(&self, offset: usize, len: usize) -> Result {
218 self.with_pointer_into_page(offset, len, move |dst| {
228 /// Copies data from userspace into this page.
230 /// This method will perform bounds checks on the page offset. If `offset .. offset+len` goes
231 /// outside of the page, then this call returns [`EINVAL`].
234 /// However, they are not allowed on the page you are copying into.
238 /// Callers must ensure that this call does not race with a read or write to the same page that
243 offset: usize,
245 ) -> Result {
246 self.with_pointer_into_page(offset, len, move |dst| {
255 impl Drop for Page {
257 // SAFETY: By the type invariants, we have ownership of the page and can free it.
258 unsafe { bindings::__free_pages(self.page.as_ptr(), 0) };