mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 18:09:56 +00:00
Pull Char/Misc/IIO/Binder updates from Greg KH:
"Here is the big set of char/misc/iio and other driver subsystem
changes for 6.18-rc1.
Loads of different stuff in here, it was a busy development cycle in
lots of different subsystems, with over 27k new lines added to the
tree.
Included in here are:
- IIO updates including new drivers, reworking of existing apis, and
other goodness in the sensor subsystems
- MEI driver updates and additions
- NVMEM driver updates
- slimbus removal for an unused driver and some other minor updates
- coresight driver updates and additions
- MHI driver updates
- comedi driver updates and fixes
- extcon driver updates
- interconnect driver additions
- eeprom driver updates and fixes
- minor UIO driver updates
- tiny W1 driver updates
But the majority of new code is in the rust bindings and additions,
which includes:
- misc driver rust binding updates for read/write support, we can now
write "normal" misc drivers in rust fully, and the sample driver
shows how this can be done.
- Initial framework for USB driver rust bindings, which are disabled
for now in the build, due to limited support, but coming in through
this tree due to dependencies on other rust binding changes that
were in here. I'll be enabling these back on in the build in the
usb.git tree after -rc1 is out so that developers can continue to
work on these in linux-next over the next development cycle.
- Android Binder driver implemented in Rust.
This is the big one, and was driving a huge majority of the rust
binding work over the past years. Right now there are two binder
drivers in the kernel, selected only at build time as to which one
to use as binder wants to be included in the system at boot time.
The binder C maintainers all agreed on this, as eventually, they
want the C code to be removed from the tree, but it will take a few
releases to get there while both are maintained to ensure that the
rust implementation is fully stable and compliant with the existing
userspace apis.
All of these have been in linux-next for a while"
* tag 'char-misc-6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (320 commits)
rust: usb: keep usb::Device private for now
rust: usb: don't retain device context for the interface parent
USB: disable rust bindings from the build for now
samples: rust: add a USB driver sample
rust: usb: add basic USB abstractions
coresight: Add label sysfs node support
dt-bindings: arm: Add label in the coresight components
coresight: tnoc: add new AMBA ID to support Trace Noc V2
coresight: Fix incorrect handling for return value of devm_kzalloc
coresight: tpda: fix the logic to setup the element size
coresight: trbe: Return NULL pointer for allocation failures
coresight: Refactor runtime PM
coresight: Make clock sequence consistent
coresight: Refactor driver data allocation
coresight: Consolidate clock enabling
coresight: Avoid enable programming clock duplicately
coresight: Appropriately disable trace bus clocks
coresight: Appropriately disable programming clocks
coresight: etm4x: Support atclk
coresight: catu: Support atclk
...
352 lines
14 KiB
Rust
352 lines
14 KiB
Rust
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
//! Kernel page allocation and management.
|
|
|
|
use crate::{
|
|
alloc::{AllocError, Flags},
|
|
bindings,
|
|
error::code::*,
|
|
error::Result,
|
|
uaccess::UserSliceReader,
|
|
};
|
|
use core::{
|
|
marker::PhantomData,
|
|
mem::ManuallyDrop,
|
|
ops::Deref,
|
|
ptr::{self, NonNull},
|
|
};
|
|
|
|
/// A bitwise shift for the page size.
|
|
pub const PAGE_SHIFT: usize = bindings::PAGE_SHIFT as usize;
|
|
|
|
/// The number of bytes in a page.
|
|
pub const PAGE_SIZE: usize = bindings::PAGE_SIZE;
|
|
|
|
/// A bitmask that gives the page containing a given address.
|
|
pub const PAGE_MASK: usize = !(PAGE_SIZE - 1);
|
|
|
|
/// Round up the given number to the next multiple of [`PAGE_SIZE`].
|
|
///
|
|
/// It is incorrect to pass an address where the next multiple of [`PAGE_SIZE`] doesn't fit in a
|
|
/// [`usize`].
|
|
pub const fn page_align(addr: usize) -> usize {
|
|
// Parentheses around `PAGE_SIZE - 1` to avoid triggering overflow sanitizers in the wrong
|
|
// cases.
|
|
(addr + (PAGE_SIZE - 1)) & PAGE_MASK
|
|
}
|
|
|
|
/// Representation of a non-owning reference to a [`Page`].
|
|
///
|
|
/// This type provides a borrowed version of a [`Page`] that is owned by some other entity, e.g. a
|
|
/// [`Vmalloc`] allocation such as [`VBox`].
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```
|
|
/// # use kernel::{bindings, prelude::*};
|
|
/// use kernel::page::{BorrowedPage, Page, PAGE_SIZE};
|
|
/// # use core::{mem::MaybeUninit, ptr, ptr::NonNull };
|
|
///
|
|
/// fn borrow_page<'a>(vbox: &'a mut VBox<MaybeUninit<[u8; PAGE_SIZE]>>) -> BorrowedPage<'a> {
|
|
/// let ptr = ptr::from_ref(&**vbox);
|
|
///
|
|
/// // SAFETY: `ptr` is a valid pointer to `Vmalloc` memory.
|
|
/// let page = unsafe { bindings::vmalloc_to_page(ptr.cast()) };
|
|
///
|
|
/// // SAFETY: `vmalloc_to_page` returns a valid pointer to a `struct page` for a valid
|
|
/// // pointer to `Vmalloc` memory.
|
|
/// let page = unsafe { NonNull::new_unchecked(page) };
|
|
///
|
|
/// // SAFETY:
|
|
/// // - `self.0` is a valid pointer to a `struct page`.
|
|
/// // - `self.0` is valid for the entire lifetime of `self`.
|
|
/// unsafe { BorrowedPage::from_raw(page) }
|
|
/// }
|
|
///
|
|
/// let mut vbox = VBox::<[u8; PAGE_SIZE]>::new_uninit(GFP_KERNEL)?;
|
|
/// let page = borrow_page(&mut vbox);
|
|
///
|
|
/// // SAFETY: There is no concurrent read or write to this page.
|
|
/// unsafe { page.fill_zero_raw(0, PAGE_SIZE)? };
|
|
/// # Ok::<(), Error>(())
|
|
/// ```
|
|
///
|
|
/// # Invariants
|
|
///
|
|
/// The borrowed underlying pointer to a `struct page` is valid for the entire lifetime `'a`.
|
|
///
|
|
/// [`VBox`]: kernel::alloc::VBox
|
|
/// [`Vmalloc`]: kernel::alloc::allocator::Vmalloc
|
|
pub struct BorrowedPage<'a>(ManuallyDrop<Page>, PhantomData<&'a Page>);
|
|
|
|
impl<'a> BorrowedPage<'a> {
|
|
/// Constructs a [`BorrowedPage`] from a raw pointer to a `struct page`.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// - `ptr` must point to a valid `bindings::page`.
|
|
/// - `ptr` must remain valid for the entire lifetime `'a`.
|
|
pub unsafe fn from_raw(ptr: NonNull<bindings::page>) -> Self {
|
|
let page = Page { page: ptr };
|
|
|
|
// INVARIANT: The safety requirements guarantee that `ptr` is valid for the entire lifetime
|
|
// `'a`.
|
|
Self(ManuallyDrop::new(page), PhantomData)
|
|
}
|
|
}
|
|
|
|
impl<'a> Deref for BorrowedPage<'a> {
|
|
type Target = Page;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
/// Trait to be implemented by types which provide an [`Iterator`] implementation of
|
|
/// [`BorrowedPage`] items, such as [`VmallocPageIter`](kernel::alloc::allocator::VmallocPageIter).
|
|
pub trait AsPageIter {
|
|
/// The [`Iterator`] type, e.g. [`VmallocPageIter`](kernel::alloc::allocator::VmallocPageIter).
|
|
type Iter<'a>: Iterator<Item = BorrowedPage<'a>>
|
|
where
|
|
Self: 'a;
|
|
|
|
/// Returns an [`Iterator`] of [`BorrowedPage`] items over all pages owned by `self`.
|
|
fn page_iter(&mut self) -> Self::Iter<'_>;
|
|
}
|
|
|
|
/// A pointer to a page that owns the page allocation.
|
|
///
|
|
/// # Invariants
|
|
///
|
|
/// The pointer is valid, and has ownership over the page.
|
|
pub struct Page {
|
|
page: NonNull<bindings::page>,
|
|
}
|
|
|
|
// SAFETY: Pages have no logic that relies on them staying on a given thread, so moving them across
|
|
// threads is safe.
|
|
unsafe impl Send for Page {}
|
|
|
|
// SAFETY: Pages have no logic that relies on them not being accessed concurrently, so accessing
|
|
// them concurrently is safe.
|
|
unsafe impl Sync for Page {}
|
|
|
|
impl Page {
|
|
/// Allocates a new page.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// Allocate memory for a page.
|
|
///
|
|
/// ```
|
|
/// use kernel::page::Page;
|
|
///
|
|
/// let page = Page::alloc_page(GFP_KERNEL)?;
|
|
/// # Ok::<(), kernel::alloc::AllocError>(())
|
|
/// ```
|
|
///
|
|
/// Allocate memory for a page and zero its contents.
|
|
///
|
|
/// ```
|
|
/// use kernel::page::Page;
|
|
///
|
|
/// let page = Page::alloc_page(GFP_KERNEL | __GFP_ZERO)?;
|
|
/// # Ok::<(), kernel::alloc::AllocError>(())
|
|
/// ```
|
|
#[inline]
|
|
pub fn alloc_page(flags: Flags) -> Result<Self, AllocError> {
|
|
// SAFETY: Depending on the value of `gfp_flags`, this call may sleep. Other than that, it
|
|
// is always safe to call this method.
|
|
let page = unsafe { bindings::alloc_pages(flags.as_raw(), 0) };
|
|
let page = NonNull::new(page).ok_or(AllocError)?;
|
|
// INVARIANT: We just successfully allocated a page, so we now have ownership of the newly
|
|
// allocated page. We transfer that ownership to the new `Page` object.
|
|
Ok(Self { page })
|
|
}
|
|
|
|
/// Returns a raw pointer to the page.
|
|
pub fn as_ptr(&self) -> *mut bindings::page {
|
|
self.page.as_ptr()
|
|
}
|
|
|
|
/// Get the node id containing this page.
|
|
pub fn nid(&self) -> i32 {
|
|
// SAFETY: Always safe to call with a valid page.
|
|
unsafe { bindings::page_to_nid(self.as_ptr()) }
|
|
}
|
|
|
|
/// Runs a piece of code with this page mapped to an address.
|
|
///
|
|
/// The page is unmapped when this call returns.
|
|
///
|
|
/// # Using the raw pointer
|
|
///
|
|
/// It is up to the caller to use the provided raw pointer correctly. The pointer is valid for
|
|
/// `PAGE_SIZE` bytes and for the duration in which the closure is called. The pointer might
|
|
/// only be mapped on the current thread, and when that is the case, dereferencing it on other
|
|
/// threads is UB. Other than that, the usual rules for dereferencing a raw pointer apply: don't
|
|
/// cause data races, the memory may be uninitialized, and so on.
|
|
///
|
|
/// If multiple threads map the same page at the same time, then they may reference with
|
|
/// different addresses. However, even if the addresses are different, the underlying memory is
|
|
/// still the same for these purposes (e.g., it's still a data race if they both write to the
|
|
/// same underlying byte at the same time).
|
|
fn with_page_mapped<T>(&self, f: impl FnOnce(*mut u8) -> T) -> T {
|
|
// SAFETY: `page` is valid due to the type invariants on `Page`.
|
|
let mapped_addr = unsafe { bindings::kmap_local_page(self.as_ptr()) };
|
|
|
|
let res = f(mapped_addr.cast());
|
|
|
|
// This unmaps the page mapped above.
|
|
//
|
|
// SAFETY: Since this API takes the user code as a closure, it can only be used in a manner
|
|
// where the pages are unmapped in reverse order. This is as required by `kunmap_local`.
|
|
//
|
|
// In other words, if this call to `kunmap_local` happens when a different page should be
|
|
// unmapped first, then there must necessarily be a call to `kmap_local_page` other than the
|
|
// call just above in `with_page_mapped` that made that possible. In this case, it is the
|
|
// unsafe block that wraps that other call that is incorrect.
|
|
unsafe { bindings::kunmap_local(mapped_addr) };
|
|
|
|
res
|
|
}
|
|
|
|
/// Runs a piece of code with a raw pointer to a slice of this page, with bounds checking.
|
|
///
|
|
/// If `f` is called, then it will be called with a pointer that points at `off` bytes into the
|
|
/// page, and the pointer will be valid for at least `len` bytes. The pointer is only valid on
|
|
/// this task, as this method uses a local mapping.
|
|
///
|
|
/// If `off` and `len` refers to a region outside of this page, then this method returns
|
|
/// [`EINVAL`] and does not call `f`.
|
|
///
|
|
/// # Using the raw pointer
|
|
///
|
|
/// It is up to the caller to use the provided raw pointer correctly. The pointer is valid for
|
|
/// `len` bytes and for the duration in which the closure is called. The pointer might only be
|
|
/// mapped on the current thread, and when that is the case, dereferencing it on other threads
|
|
/// is UB. Other than that, the usual rules for dereferencing a raw pointer apply: don't cause
|
|
/// data races, the memory may be uninitialized, and so on.
|
|
///
|
|
/// If multiple threads map the same page at the same time, then they may reference with
|
|
/// different addresses. However, even if the addresses are different, the underlying memory is
|
|
/// still the same for these purposes (e.g., it's still a data race if they both write to the
|
|
/// same underlying byte at the same time).
|
|
fn with_pointer_into_page<T>(
|
|
&self,
|
|
off: usize,
|
|
len: usize,
|
|
f: impl FnOnce(*mut u8) -> Result<T>,
|
|
) -> Result<T> {
|
|
let bounds_ok = off <= PAGE_SIZE && len <= PAGE_SIZE && (off + len) <= PAGE_SIZE;
|
|
|
|
if bounds_ok {
|
|
self.with_page_mapped(move |page_addr| {
|
|
// SAFETY: The `off` integer is at most `PAGE_SIZE`, so this pointer offset will
|
|
// result in a pointer that is in bounds or one off the end of the page.
|
|
f(unsafe { page_addr.add(off) })
|
|
})
|
|
} else {
|
|
Err(EINVAL)
|
|
}
|
|
}
|
|
|
|
/// Maps the page and reads from it into the given buffer.
|
|
///
|
|
/// This method will perform bounds checks on the page offset. If `offset .. offset+len` goes
|
|
/// outside of the page, then this call returns [`EINVAL`].
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// * Callers must ensure that `dst` is valid for writing `len` bytes.
|
|
/// * Callers must ensure that this call does not race with a write to the same page that
|
|
/// overlaps with this read.
|
|
pub unsafe fn read_raw(&self, dst: *mut u8, offset: usize, len: usize) -> Result {
|
|
self.with_pointer_into_page(offset, len, move |src| {
|
|
// SAFETY: If `with_pointer_into_page` calls into this closure, then
|
|
// it has performed a bounds check and guarantees that `src` is
|
|
// valid for `len` bytes.
|
|
//
|
|
// There caller guarantees that there is no data race.
|
|
unsafe { ptr::copy_nonoverlapping(src, dst, len) };
|
|
Ok(())
|
|
})
|
|
}
|
|
|
|
/// Maps the page and writes into it from the given buffer.
|
|
///
|
|
/// This method will perform bounds checks on the page offset. If `offset .. offset+len` goes
|
|
/// outside of the page, then this call returns [`EINVAL`].
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// * Callers must ensure that `src` is valid for reading `len` bytes.
|
|
/// * Callers must ensure that this call does not race with a read or write to the same page
|
|
/// that overlaps with this write.
|
|
pub unsafe fn write_raw(&self, src: *const u8, offset: usize, len: usize) -> Result {
|
|
self.with_pointer_into_page(offset, len, move |dst| {
|
|
// SAFETY: If `with_pointer_into_page` calls into this closure, then it has performed a
|
|
// bounds check and guarantees that `dst` is valid for `len` bytes.
|
|
//
|
|
// There caller guarantees that there is no data race.
|
|
unsafe { ptr::copy_nonoverlapping(src, dst, len) };
|
|
Ok(())
|
|
})
|
|
}
|
|
|
|
/// Maps the page and zeroes the given slice.
|
|
///
|
|
/// This method will perform bounds checks on the page offset. If `offset .. offset+len` goes
|
|
/// outside of the page, then this call returns [`EINVAL`].
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// Callers must ensure that this call does not race with a read or write to the same page that
|
|
/// overlaps with this write.
|
|
pub unsafe fn fill_zero_raw(&self, offset: usize, len: usize) -> Result {
|
|
self.with_pointer_into_page(offset, len, move |dst| {
|
|
// SAFETY: If `with_pointer_into_page` calls into this closure, then it has performed a
|
|
// bounds check and guarantees that `dst` is valid for `len` bytes.
|
|
//
|
|
// There caller guarantees that there is no data race.
|
|
unsafe { ptr::write_bytes(dst, 0u8, len) };
|
|
Ok(())
|
|
})
|
|
}
|
|
|
|
/// Copies data from userspace into this page.
|
|
///
|
|
/// This method will perform bounds checks on the page offset. If `offset .. offset+len` goes
|
|
/// outside of the page, then this call returns [`EINVAL`].
|
|
///
|
|
/// Like the other `UserSliceReader` methods, data races are allowed on the userspace address.
|
|
/// However, they are not allowed on the page you are copying into.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// Callers must ensure that this call does not race with a read or write to the same page that
|
|
/// overlaps with this write.
|
|
pub unsafe fn copy_from_user_slice_raw(
|
|
&self,
|
|
reader: &mut UserSliceReader,
|
|
offset: usize,
|
|
len: usize,
|
|
) -> Result {
|
|
self.with_pointer_into_page(offset, len, move |dst| {
|
|
// SAFETY: If `with_pointer_into_page` calls into this closure, then it has performed a
|
|
// bounds check and guarantees that `dst` is valid for `len` bytes. Furthermore, we have
|
|
// exclusive access to the slice since the caller guarantees that there are no races.
|
|
reader.read_raw(unsafe { core::slice::from_raw_parts_mut(dst.cast(), len) })
|
|
})
|
|
}
|
|
}
|
|
|
|
impl Drop for Page {
|
|
#[inline]
|
|
fn drop(&mut self) {
|
|
// SAFETY: By the type invariants, we have ownership of the page and can free it.
|
|
unsafe { bindings::__free_pages(self.page.as_ptr(), 0) };
|
|
}
|
|
}
|