use core::ffi::{c_ulong, c_void}; use rust_support::{
mmu::{ARCH_MMU_FLAG_CACHED, ARCH_MMU_FLAG_PERM_NO_EXECUTE, ARCH_MMU_FLAG_PERM_RO, PAGE_SIZE},
status_t,
vmm::{vmm_alloc_physical, vmm_free_region, vmm_get_kernel_aspace},
}; use thiserror::Error; use zerocopy::{FromBytes, Immutable, KnownLayout};
impl<T: ?Sized + FromBytes> Mapped<T> { /// Maps [`size`] bytes at at the [`paddr`] physical address into virtual memory. /// If the [`paddr`] is not page aligned, the function will also map the preceding space /// to a closest page aligned address. Similarly the function will align up the size of /// the mapped region to page alignment. /// /// # Safety /// - The caller must be sure that [`paddr`] is mappable of at least [`size`] bytes /// and readable /// - The caller must be sure that [`paddr`] is properly aligned for T /// - The caller must be sure that [`paddr`]..[`paddr`] + [`size`] contains the correct data /// for T unsafefn map_nbytes(paddr: u64, size: usize) -> Result<Self, MappingError> { let paddr = usize::try_from(paddr).map_err(MappingError::ConversionError)?;
// Page align address and size let aligned_paddr = paddr & !PAGE_MASK; let aligned_size = (size + PAGE_MASK) & !PAGE_MASK; let offset = paddr - aligned_paddr;
// Map the physical address to virtual memory // SAFETY:Delegated to caller let ret = unsafe { // vmm_alloc_physical function accepts a constant reference for outputting a pointer to // mapped region. Pass mutable reference and silence the clippy warning. #[allow(clippy::unnecessary_mut_passed)]
vmm_alloc_physical(
vmm_get_kernel_aspace(),
c"rust-setup_data".as_ptr() as _,
aligned_size,
&mut aligned_ptr, 0,
aligned_paddr, 0,
ARCH_MMU_FLAG_CACHED | ARCH_MMU_FLAG_PERM_RO | ARCH_MMU_FLAG_PERM_NO_EXECUTE,
)
};
// Make sure that the region was mapped correctly if ret != 0 || aligned_ptr.is_null() { return Err(MappingError::MappingError(ret));
}
// Adjust the pointer to virtual memory back from aligned address to desired offset // SAFETY: The pointer is within mapped range let ptr = unsafe { aligned_ptr.add(paddr - aligned_paddr) };
impl<T: FromBytes> Mapped<T> { /// Maps T at at the [`paddr`] physical address into virtual memory. If the [`paddr`] is not /// page aligned, the function will also map the preceding space to a closest page aligned /// address. Similarly the function will align up the size of [`T`] to page alignment. /// /// # Safety /// /// - The caller must be sure that [`paddr`] is mappable of at least sizeof(T) bytes /// and readable. /// - The caller must be sure that [`paddr`] is properly aligned for T /// - The caller must be sure that [`paddr`]..[`paddr`] + sizeof(T) contains the correct /// data for T pubunsafefn map(paddr: u64) -> Result<Self, MappingError> { // SAFETY:Delegated to caller Self::map_nbytes(paddr, core::mem::size_of::<T>())
}
}
// SAFETY:[`Self`] created with [`Self::map`] is at least the T size and the alignment // for T is asserted during the construction of [`Self`]. The bit pattern property is // asserted by requiring T to be [`FromBytes`]. unsafe { self.ptr.cast::<T>().as_ref().unwrap() }
}
}
impl<T: FromBytes> Mapped<[T]> { /// Maps `[T; size]` as a slice at at the [`paddr`] physical address into virtual memory /// If the [`paddr`] is not page aligned, the function will also map the preceding space /// to a closest page aligned address. Similarly the function will align up the size of /// `[T; size]` to page alignment. /// /// # Safety /// - The caller must be sure that [`paddr`] is mappable of at least [`size`] * sizeof(T) /// bytes and readable. /// - The caller must be sure that [`paddr`] is properly aligned for T /// - The caller must be sure that [`paddr`]..[`paddr`] + [`size`] * sizeof(T) contains /// the correct data for [T; size] /// - The [`size`] must not be zero. pubunsafefn map_slice(paddr: u64, size: usize) -> Result<Self, MappingError> { // SAFETY:Delegated to caller Self::map_nbytes(paddr, size * core::mem::size_of::<T>())
}
}
impl<T: ?Sized + FromBytes> Drop for Mapped<T> { fn drop(&mutself) { // Unmap the no longer needed memory region from virtual memory // SAFETY:: ptr came from vmm_alloc_physical unsafe { vmm_free_region(vmm_get_kernel_aspace(), self.aligned_ptr as _) };
}
}
impl<T: FromBytes> AsRef<[T]> for Mapped<[T]> { fn as_ref(&self) -> &[T] { let n = self.size / core::mem::size_of::<T>();
assert_ne!(n, 0);
// SAFETY: The pointer compes from a successful vmm_alloc_physical call, so it's not null // and valid. It is mapped as RO making it immutable. The caller of constructor is // required to be sure that the data under the pointer is correct for [T; n] and properly // aligned. unsafe { core::slice::from_raw_parts::<'_, T>(self.ptr.cast::<T>(), n) }
}
}
/// Based on crosvm's SETUP_DTB (x86_64/src/lib.rs) pubconst SETUP_DTB: u32 = 2;
/// Based on crosvm's setup_data_hdr (x86_64/src/lib.rs) which is /// based on https://www.kernel.org/doc/html/latest/arch/x86/boot.html #[repr(C)] #[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)] struct setup_data_hdr {
next: u64,
type_: u32,
len: u32,
}
/// Error type returned by [`SetupDataIter`] functions #[derive(Error, Debug)] pubenum FindSetupDataError { #[error("failed to map a memory region: {0}")]
MappingError(#[from] MappingError), #[error("invalid magic in boot params structure")]
InvalidMagic, #[error("failed to convert a value: {0}")]
ConversionError(#[from] core::num::TryFromIntError),
}
/// Unpacked type and data from [`setup_data_hdr`] pubstruct SetupData {
type_: u32,
data: Mapped<[u8]>,
}
/// Iterator over `setup_data` chain rooted in `boot_params` structure pubstruct SetupDataIter {
next: u64,
}
impl SetupDataIter { /// Searches for boot_params using second boot argument and then creates a iterator over /// setup_data chain. pubfn find() -> Result<Self, FindSetupDataError> { // SAFETY: lk_boot_args are set in early init and not modified afterwards let boot_params_addr = unsafe { lk_boot_args[1] };
// Map the boot_params structure // SAFETY: boot_params struct should be passed by boot loader in second register let mapped_boot_params = unsafe {
Mapped::<[u8]>::map_slice(
boot_params_addr,
BOOT_PARAMS_SETUP_DATA_OFFSET + core::mem::size_of::<u64>(),
)?
};
let boot_params: &[u8] = mapped_boot_params.as_ref();
// Verify that constant value of boot_flag in boot_params matches let boot_flag = u16::from_le_bytes(
boot_params[BOOT_PARAMS_BOOT_FLAG_OFFSET..][..2].try_into().unwrap(),
);
if boot_flag != BOOT_PARAMS_BOOT_FLAG_MAGIC { return Err(FindSetupDataError::InvalidMagic);
}
// Verify that constant value of header in boot_params matches let header =
u32::from_le_bytes(boot_params[BOOT_PARAMS_HEADER_OFFSET..][..4].try_into().unwrap());
if header != BOOT_PARAMS_HEADER_MAGIC { return Err(FindSetupDataError::InvalidMagic);
}
// Get the first setup_data_hdr node address in the chain let next = u64::from_le_bytes(
boot_params[BOOT_PARAMS_SETUP_DATA_OFFSET..][..8].try_into().unwrap(),
);
Ok(Self { next })
}
fn find_next(&mutself) -> Result<Option<SetupData>, FindSetupDataError> { // Check if the end of chain has been reached ifself.next == 0u64 { return Ok(None);
}
// Briefly map setup_data_hdr into memory and copy into variable. // SAFETY:Each setup_data/next address passed using boot_params struct from bootloader // is expected to be valid. let mapped_hdr = unsafe { Mapped::<setup_data_hdr>::map(self.next)? }; let hdr: setup_data_hdr = *mapped_hdr.as_ref();
drop(mapped_hdr);
// Calculate data start address let payload = self.next + u64::try_from(core::mem::size_of::<setup_data_hdr>())?;
// Set the next setup_data_hdr address in the chain self.next = hdr.next;
// Map the data into virtual memory and return it // SAFETY: The setup_data pointee is expected to be a valid mappable address and // size. let data = unsafe { Mapped::<[u8]>::map_slice(payload, usize::try_from(hdr.len)?)? };
Ok(Some(SetupData { type_: hdr.type_, data }))
}
}
impl Iterator for SetupDataIter { type Item = Result<SetupData, FindSetupDataError>;
fn next(&mutself) -> Option<Self::Item> { // Repack the Option and Result matchself.find_next() {
Ok(Some(next)) => Some(Ok(next)),
Ok(None) => None,
Err(err) => { // Prevent next iterations to avoid dead lock self.next = 0u64;
Some(Err(err))
}
}
}
}
/// Searches for boot_params structure and returns iterator that yields setup_datas with DTBs pubfn find_dtbs(
) -> Result<impl Iterator<Item = Result<impl AsRef<[u8]>, FindSetupDataError>>, FindSetupDataError>
{
Ok(SetupDataIter::find()?.filter_map(|setup| match setup { // Filter out setup_data_hdr that are not DTBs
Ok(setup) if setup.type_ == SETUP_DTB => Some(Ok(setup.data)),
Ok(_) => None,
Err(err) => Some(Err(err)),
}))
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.19 Sekunden
(vorverarbeitet am 2026-06-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.