Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/trusty/trusty/kernel/lib/dtb_boot_params/src/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 12 kB image not shown  

Quelle  lib.rs

  Sprache: Rust
 

/*
 * Copyright (c) 2025 Google Inc. All rights reserved
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files
 * (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */


#![no_std]

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};

const PAGE_MASK: usize = PAGE_SIZE as usize - 1;

extern "C" {
    static lk_boot_args: [c_ulong; 4];
}

#[derive(Error, Debug)]
pub enum MappingError {
    #[error("failed to convert address: {0}")]
    ConversionError(#[from] core::num::TryFromIntError),

    #[error("mapping error {0}")]
    MappingError(status_t),
}

struct Mapped<T: ?Sized + FromBytes> {
    size: usize,
    ptr: *mut c_void,
    aligned_ptr: *mut c_void,

    _phantom: core::marker::PhantomData<T>,
}

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
    unsafe fn 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;

        assert!(offset < aligned_size);
        assert_ne!(size, 0);

        let mut aligned_ptr: *mut c_void = core::ptr::null_mut();

        // 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) };

        Ok(Self { size, ptr, aligned_ptr, _phantom: Default::default() })
    }
}

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
    pub unsafe fn map(paddr: u64) -> Result<Self, MappingError> {
        // SAFETY:Delegated to caller
        Self::map_nbytes(paddr, core::mem::size_of::<T>())
    }
}

impl<T: FromBytes> AsRef<T> for Mapped<T> {
    fn as_ref(&self) -> &T {
        debug_assert!(self.size == 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.
    pub unsafe fn 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(&mut self) {
        // 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) }
    }
}

const BOOT_PARAMS_BOOT_FLAG_OFFSET: usize = 0x1fe;
const BOOT_PARAMS_BOOT_FLAG_MAGIC: u16 = 0xaa55;

const BOOT_PARAMS_HEADER_OFFSET: usize = 0x202;
const BOOT_PARAMS_HEADER_MAGIC: u32 = 0x53726448;

const BOOT_PARAMS_SETUP_DATA_OFFSET: usize = 0x250;

/// Based on crosvm's SETUP_DTB (x86_64/src/lib.rs)
pub const 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)]
pub enum 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`]
pub struct SetupData {
    type_: u32,
    data: Mapped<[u8]>,
}

/// Iterator over `setup_data` chain rooted in `boot_params` structure
pub struct SetupDataIter {
    next: u64,
}

impl SetupDataIter {
    /// Searches for boot_params using second boot argument and then creates a iterator over
    /// setup_data chain.
    pub fn 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(&mut self) -> Result<Option<SetupData>, FindSetupDataError> {
        // Check if the end of chain has been reached
        if self.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(&mut self) -> Option<Self::Item> {
        // Repack the Option and Result
        match self.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
pub fn 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
C=93 H=96 G=94

¤ Dauer der Verarbeitung: 0.18 Sekunden  (vorverarbeitet am  2026-06-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

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.