dbs-boot 0.3.0

Traits and structs for booting sandbox
Documentation
// Copyright 2021 Alibaba Cloud. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

//! VM boot related constants and utilities for `aarch64` architecture.

use vm_fdt::Error as VmFdtError;
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryError};
/// Magic addresses externally used to lay out aarch64 VMs.
pub mod layout;

/// FDT is used to inform the guest kernel of device tree information.
pub mod fdt;

/// Default (smallest) memory page size for the supported architectures.
pub const PAGE_SIZE: usize = 4096;

/// Errors thrown while configuring the Flattened Device Tree for aarch64.
#[derive(Debug, thiserror::Error)]
pub enum Error {
    /// Failure in creating FDT
    #[error("create fdt fail: {0}")]
    CreateFdt(#[from] VmFdtError),
    /// Failure in writing FDT in memory.
    #[error("write fdt to memory fail: {0}")]
    WriteFDTToMemory(#[from] GuestMemoryError),
    /// Failed to compute the initrd address.
    #[error("Failed to compute the initrd address.")]
    InitrdAddress,
    /// Invalid arguments
    #[error("invalid arguments")]
    InvalidArguments,
}

/// Returns the memory address where the kernel could be loaded.
pub fn get_kernel_start() -> u64 {
    layout::DRAM_MEM_START
}

/// Auxiliary function to get the address where the device tree blob is loaded.
pub fn get_fdt_addr<M: GuestMemory>(mem: &M) -> u64 {
    // If the memory allocated is smaller than the size allocated for the FDT,
    // we return the start of the DRAM so that
    // we allow the code to try and load the FDT.
    if let Some(offset) = mem.last_addr().checked_sub(layout::FDT_MAX_SIZE as u64 - 1) {
        if mem.address_in_range(offset) {
            return offset.raw_value();
        }
    }
    layout::DRAM_MEM_START
}

/// Returns the memory address where the initrd could be loaded.
pub fn initrd_load_addr<M: GuestMemory>(guest_mem: &M, initrd_size: u64) -> super::Result<u64> {
    let round_to_pagesize = |size| (size + (PAGE_SIZE as u64 - 1)) & !(PAGE_SIZE as u64 - 1);
    match GuestAddress(get_fdt_addr(guest_mem)).checked_sub(round_to_pagesize(initrd_size) as u64) {
        Some(offset) => {
            if guest_mem.address_in_range(offset) {
                Ok(offset.raw_value())
            } else {
                Err(Error::InitrdAddress)
            }
        }
        None => Err(Error::InitrdAddress),
    }
}