Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/arch/src/aarch64/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,14 @@
//
// Taken from (http://infocenter.arm.com/help/topic/com.arm.doc.den0001c/DEN0001C_principles_of_arm_memory_maps.pdf).

/// Start of RAM on 64 bit ARM.
pub const DRAM_MEM_START: u64 = 0x4000_0000; // 1 GB.
/// Start of RAM on 64 bit ARM when loading an EFI firmware.
pub const DRAM_MEM_START_EFI: u64 = 0x4000_0000; // 1 GB.
/// Start of RAM on 64 bit ARM when loading a kernel.
pub const DRAM_MEM_START_KERNEL: u64 = 0x8000_0000; // 2 GB.
/// The maximum addressable RAM address.
pub const DRAM_MEM_END: u64 = 0x00FF_8000_0000; // 1024 - 2 = 1022 GB.
/// The maximum RAM size.
pub const DRAM_MEM_MAX_SIZE: u64 = DRAM_MEM_END - DRAM_MEM_START;
pub const DRAM_MEM_MAX_SIZE: u64 = DRAM_MEM_END - DRAM_MEM_START_KERNEL;

/// Kernel command line maximum size.
/// As per `arch/arm64/include/uapi/asm/setup.h`.
Expand Down
14 changes: 9 additions & 5 deletions src/arch/src/aarch64/linux/regs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

use std::{mem, mem::offset_of, num::TryFromIntError, result};

use super::super::get_fdt_addr;
use crate::ArchMemoryInfo;

use kvm_bindings::{
kvm_regs, user_pt_regs, KVM_REG_ARM64, KVM_REG_ARM64_SYSREG, KVM_REG_ARM64_SYSREG_CRM_MASK,
KVM_REG_ARM64_SYSREG_CRM_SHIFT, KVM_REG_ARM64_SYSREG_CRN_MASK, KVM_REG_ARM64_SYSREG_CRN_SHIFT,
Expand All @@ -17,8 +18,6 @@ use kvm_bindings::{
};
use kvm_ioctls::VcpuFd;

use vm_memory::GuestMemoryMmap;

/// Errors thrown while setting aarch64 registers.
#[derive(Debug)]
pub enum Error {
Expand Down Expand Up @@ -109,7 +108,12 @@ arm64_sys_reg!(MPIDR_EL1, 3, 0, 0, 0, 5);
/// * `cpu_id` - Index of current vcpu.
/// * `boot_ip` - Starting instruction pointer.
/// * `mem` - Reserved DRAM for current VM.
pub fn setup_regs(vcpu: &VcpuFd, cpu_id: u8, boot_ip: u64, mem: &GuestMemoryMmap) -> Result<()> {
pub fn setup_regs(
vcpu: &VcpuFd,
cpu_id: u8,
boot_ip: u64,
mem_info: &ArchMemoryInfo,
) -> Result<()> {
// Get the register index of the PSTATE (Processor State) register.
vcpu.set_one_reg(arm64_core_reg!(pstate), &PSTATE_FAULT_BITS_64.to_le_bytes())
.map_err(Error::SetCoreRegister)?;
Expand All @@ -124,7 +128,7 @@ pub fn setup_regs(vcpu: &VcpuFd, cpu_id: u8, boot_ip: u64, mem: &GuestMemoryMmap
// "The device tree blob (dtb) must be placed on an 8-byte boundary and must
// not exceed 2 megabytes in size." -> https://www.kernel.org/doc/Documentation/arm64/booting.txt.
// We are choosing to place it the end of DRAM. See `get_fdt_addr`.
vcpu.set_one_reg(arm64_core_reg!(regs), &get_fdt_addr(mem).to_le_bytes())
vcpu.set_one_reg(arm64_core_reg!(regs), &mem_info.fdt_addr.to_le_bytes())
.map_err(Error::SetCoreRegister)?;
}
Ok(())
Expand Down
103 changes: 39 additions & 64 deletions src/arch/src/aarch64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ pub use self::macos::*;

use std::fmt::Debug;

use crate::{aarch64::layout::FIRMWARE_START, ArchMemoryInfo};
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryMmap};
use crate::{
aarch64::layout::{DRAM_MEM_START_EFI, DRAM_MEM_START_KERNEL, FIRMWARE_START},
ArchMemoryInfo,
};
use vm_memory::{GuestAddress, GuestMemoryMmap};
use vmm_sys_util::align_upwards;

use smbios;
Expand All @@ -43,78 +46,59 @@ pub fn arch_memory_regions(
initrd_size: u64,
firmware_size: Option<usize>,
) -> (ArchMemoryInfo, Vec<(GuestAddress, usize)>) {
let ram_start_addr = if firmware_size.is_some() {
DRAM_MEM_START_EFI
} else {
DRAM_MEM_START_KERNEL
};
let page_size: usize = unsafe { libc::sysconf(libc::_SC_PAGESIZE).try_into().unwrap() };
let dram_size = align_upwards!(size, page_size);
let ram_last_addr = layout::DRAM_MEM_START + (dram_size as u64);
let ram_last_addr = ram_start_addr + (dram_size as u64);
let shm_start_addr = ((ram_last_addr / 0x4000_0000) + 1) * 0x4000_0000;
let fdt_addr = if firmware_size.is_some() {
DRAM_MEM_START_EFI
} else {
ram_last_addr - layout::FDT_MAX_SIZE as u64
};

let info = ArchMemoryInfo {
ram_start_addr,
ram_last_addr,
shm_start_addr,
page_size,
initrd_addr: ram_last_addr - layout::FDT_MAX_SIZE as u64 - initrd_size,
fdt_addr,
initrd_addr: fdt_addr - initrd_size,
firmware_addr: FIRMWARE_START,
};
let regions = if let Some(firmware_size) = firmware_size {
vec![
// Space for loading the firmware
(GuestAddress(0u64), align_upwards!(firmware_size, page_size)),
(GuestAddress(layout::DRAM_MEM_START), dram_size),
(GuestAddress(ram_start_addr), dram_size),
]
} else {
vec![(GuestAddress(layout::DRAM_MEM_START), dram_size)]
vec![(GuestAddress(ram_start_addr), dram_size)]
};

(info, regions)
}

/// Configures the system and should be called once per vm before starting vcpu threads.
/// For aarch64, we only setup the FDT.
///
/// # Arguments
///
/// * `guest_mem` - The memory to be used by the guest.
/// * `cmdline_cstring` - The kernel commandline.
/// * `vcpu_mpidr` - Array of MPIDR register values per vcpu.
/// * `device_info` - A hashmap containing the attached devices for building FDT device nodes.
/// * `gic_device` - The GIC device.
/// * `initrd` - Information about an optional initrd.
/// For aarch64, we only setup SMBIOS.
#[allow(clippy::too_many_arguments)]
pub fn configure_system(
_guest_mem: &GuestMemoryMmap,
_smbios_oem_strings: &Option<Vec<String>>,
guest_mem: &GuestMemoryMmap,
mem_info: &ArchMemoryInfo,
smbios_oem_strings: &Option<Vec<String>>,
) -> super::Result<()> {
smbios::setup_smbios(_guest_mem, layout::SMBIOS_START, _smbios_oem_strings)
.map_err(Error::Smbios)?;

Ok(())
}

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

/// Returns the memory address where the initrd could be loaded.
pub fn initrd_load_addr(guest_mem: &GuestMemoryMmap, initrd_size: usize) -> super::Result<u64> {
match GuestAddress(get_fdt_addr(guest_mem))
.checked_sub(align_upwards!(initrd_size, super::PAGE_SIZE) as u64)
{
Some(offset) => {
if guest_mem.address_in_range(offset) {
Ok(offset.raw_value())
} else {
Err(Error::InitrdAddress)
}
}
None => Err(Error::InitrdAddress),
// When booting EFI, RAM starts at 0x4000_0000, while when doing a direct kernel
// boot RAM starts at 0x8000_0000. Only write SMBIOS in the former case.
if mem_info.ram_start_addr < layout::SMBIOS_START {
smbios::setup_smbios(guest_mem, layout::SMBIOS_START, smbios_oem_strings)
.map_err(Error::Smbios)?;
}
}

// Auxiliary function to get the address where the device tree blob is loaded.
pub fn get_fdt_addr(_mem: &GuestMemoryMmap) -> u64 {
// Put FDT at the beginning of the DRAM
layout::DRAM_MEM_START
Ok(())
}

#[cfg(test)]
Expand All @@ -125,30 +109,21 @@ mod tests {
fn test_regions_lt_1024gb() {
let (_mem_info, regions) = arch_memory_regions(1usize << 29, 0);
assert_eq!(1, regions.len());
assert_eq!(GuestAddress(super::layout::DRAM_MEM_START), regions[0].0);
assert_eq!(
GuestAddress(super::layout::DRAM_MEM_START_KERNEL),
regions[0].0
);
assert_eq!(1usize << 29, regions[0].1);
}

#[test]
fn test_regions_gt_1024gb() {
let (_mem_info, regions) = arch_memory_regions(1usize << 41, 0);
assert_eq!(1, regions.len());
assert_eq!(GuestAddress(super::layout::DRAM_MEM_START), regions[0].0);
assert_eq!(
GuestAddress(super::layout::DRAM_MEM_START_KERNEL),
regions[0].0
);
assert_eq!(super::layout::DRAM_MEM_MAX_SIZE, regions[0].1 as u64);
}

#[test]
fn test_get_fdt_addr() {
let (_mem_info, regions) = arch_memory_regions(layout::FDT_MAX_SIZE - 0x1000, 0);
let mem = GuestMemoryMmap::from_ranges(&regions).expect("Cannot initialize memory");
assert_eq!(get_fdt_addr(&mem), layout::DRAM_MEM_START);

let (_mem_info, regions) = arch_memory_regions(layout::FDT_MAX_SIZE, 0);
let mem = GuestMemoryMmap::from_ranges(&regions).expect("Cannot initialize memory");
assert_eq!(get_fdt_addr(&mem), layout::DRAM_MEM_START);

let (_mem_info, regions) = arch_memory_regions(layout::FDT_MAX_SIZE + 0x1000, 0);
let mem = GuestMemoryMmap::from_ranges(&regions).expect("Cannot initialize memory");
assert_eq!(get_fdt_addr(&mem), 0x1000 + layout::DRAM_MEM_START);
}
}
20 changes: 11 additions & 9 deletions src/arch/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@ pub struct ArchMemoryInfo {
pub ram_below_gap: u64,
#[cfg(target_arch = "x86_64")]
pub ram_above_gap: u64,
#[cfg(target_arch = "aarch64")]
pub ram_start_addr: u64,
pub ram_last_addr: u64,
pub shm_start_addr: u64,
pub page_size: usize,
#[cfg(target_arch = "aarch64")]
pub fdt_addr: u64,
pub initrd_addr: u64,
pub firmware_addr: u64,
}
Expand All @@ -25,9 +29,8 @@ pub mod aarch64;

#[cfg(target_arch = "aarch64")]
pub use aarch64::{
arch_memory_regions, configure_system, get_kernel_start, initrd_load_addr,
layout::CMDLINE_MAX_SIZE, layout::IRQ_BASE, layout::IRQ_MAX, layout::RESET_VECTOR, Error,
MMIO_MEM_START,
arch_memory_regions, configure_system, layout::CMDLINE_MAX_SIZE, layout::IRQ_BASE,
layout::IRQ_MAX, layout::RESET_VECTOR, Error, MMIO_MEM_START,
};

/// Module for riscv64 related functionality.
Expand All @@ -36,9 +39,8 @@ pub mod riscv64;

#[cfg(target_arch = "riscv64")]
pub use riscv64::{
arch_memory_regions, configure_system, get_kernel_start, initrd_load_addr,
layout::CMDLINE_MAX_SIZE, layout::IRQ_BASE, layout::IRQ_MAX, layout::RESET_VECTOR, Error,
MMIO_MEM_START,
arch_memory_regions, configure_system, layout::CMDLINE_MAX_SIZE, layout::IRQ_BASE,
layout::IRQ_MAX, layout::RESET_VECTOR, Error, MMIO_MEM_START,
};

/// Module for x86_64 related functionality.
Expand All @@ -47,9 +49,9 @@ pub mod x86_64;

#[cfg(target_arch = "x86_64")]
pub use crate::x86_64::{
arch_memory_regions, configure_system, get_kernel_start, initrd_load_addr,
layout::CMDLINE_MAX_SIZE, layout::FIRMWARE_SIZE, layout::FIRMWARE_START, layout::IRQ_BASE,
layout::IRQ_MAX, layout::MMIO_MEM_START, layout::RESET_VECTOR, Error,
arch_memory_regions, configure_system, layout::CMDLINE_MAX_SIZE, layout::FIRMWARE_SIZE,
layout::FIRMWARE_START, layout::IRQ_BASE, layout::IRQ_MAX, layout::MMIO_MEM_START,
layout::RESET_VECTOR, Error,
};

/// Type for returning public functions outcome.
Expand Down
21 changes: 0 additions & 21 deletions src/arch/src/riscv64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,27 +67,6 @@ pub fn configure_system(
Ok(())
}

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

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

// Auxiliary function to get the address where the device tree blob is loaded.
pub fn get_fdt_addr(_mem: &GuestMemoryMmap) -> u64 {
// If the memory allocated is smaller than the size allocated for the FDT,
Expand Down
25 changes: 1 addition & 24 deletions src/arch/src/x86_64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ use crate::x86_64::layout::{FIRMWARE_SIZE, FIRMWARE_START};
use crate::{ArchMemoryInfo, InitrdConfig};
use arch_gen::x86::bootparam::{boot_params, E820_RAM};
use vm_memory::Bytes;
use vm_memory::{
Address, ByteValued, GuestAddress, GuestMemory, GuestMemoryMmap, GuestMemoryRegion,
};
use vm_memory::{Address, ByteValued, GuestAddress, GuestMemoryMmap};
use vmm_sys_util::align_upwards;

// This is a workaround to the Rust enforcement specifying that any implementation of a foreign
Expand Down Expand Up @@ -238,27 +236,6 @@ pub fn arch_memory_regions(
(info, regions)
}

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

/// Returns the memory address where the initrd could be loaded.
pub fn initrd_load_addr(guest_mem: &GuestMemoryMmap, initrd_size: usize) -> super::Result<u64> {
let first_region = guest_mem
.find_region(GuestAddress::new(0))
.ok_or(Error::InitrdAddress)?;
// It's safe to cast to usize because the size of a region can't be greater than usize.
let lowmem_size = first_region.len() as usize;

if lowmem_size < initrd_size {
return Err(Error::InitrdAddress);
}

let align_to_pagesize = |address| address & !(super::PAGE_SIZE - 1);
Ok(align_to_pagesize(lowmem_size - initrd_size) as u64)
}

/// Configures the system and should be called once per vm before starting vcpu threads.
///
/// # Arguments
Expand Down
7 changes: 3 additions & 4 deletions src/devices/src/fdt/aarch64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use std::{io, result};
use crate::legacy::gic::GICDevice;
use crate::legacy::IrqChip;
use crate::DeviceType;
use arch::aarch64::get_fdt_addr;
use arch::aarch64::layout::{GTIMER_HYP, GTIMER_PHYS, GTIMER_SEC, GTIMER_VIRT};
use arch::{ArchMemoryInfo, InitrdConfig};
use vm_fdt::{Error as FdtError, FdtWriter};
Expand Down Expand Up @@ -112,7 +111,7 @@ pub fn create_fdt<T: DeviceInfoForFDT + Clone + Debug>(
let fdt_final = fdt.finish()?;

// Write FDT to memory.
let fdt_address = GuestAddress(get_fdt_addr(guest_mem));
let fdt_address = GuestAddress(arch_memory_info.fdt_addr);
guest_mem
.write_slice(fdt_final.as_slice(), fdt_address)
.map_err(Error::WriteFDTToMemory)?;
Expand Down Expand Up @@ -177,10 +176,10 @@ fn create_memory_node(
_guest_mem: &GuestMemoryMmap,
arch_memory_info: &ArchMemoryInfo,
) -> Result<()> {
let mem_size = arch_memory_info.ram_last_addr - arch::aarch64::layout::DRAM_MEM_START;
let mem_size = arch_memory_info.ram_last_addr - arch_memory_info.ram_start_addr;
// See https://github.com/torvalds/linux/blob/master/Documentation/devicetree/booting-without-of.txt#L960
// for an explanation of this.
let mem_reg_prop = generate_prop64(&[arch::aarch64::layout::DRAM_MEM_START, mem_size]);
let mem_reg_prop = generate_prop64(&[arch_memory_info.ram_start_addr, mem_size]);

let mem_node = fdt.begin_node("memory")?;
fdt.property_string("device_type", "memory")?;
Expand Down
Loading