From 99c72a25b125c774a7b0520635da2a39f6b50b49 Mon Sep 17 00:00:00 2001 From: Akira Moroo Date: Sun, 27 Nov 2022 19:06:37 +0900 Subject: [PATCH] bootinfo: Add architecture-independent memory entry `E820Entry` is used in `boot::Info` trait, which is x86_64-dependent memory entry data structure. It's confusing if e820 is used in other architectures. This commit introduces an architecture-independent memory entry `bootinfo::MemoryEntry` and replaces `boot::Info` with `bootinfo::Info`. This change is suggested in [1]. [1] https://github.com/cloud-hypervisor/rust-hypervisor-firmware/pull/205#discussion_r1028921329 Signed-off-by: Akira Moroo --- src/boot.rs | 85 ++++++++++++++++++++++++++++++++++++++----------- src/bootinfo.rs | 32 +++++++++++++++++++ src/bzimage.rs | 5 +-- src/coreboot.rs | 27 ++++++++++------ src/efi/mod.rs | 23 +++++++------ src/loader.rs | 7 ++-- src/main.rs | 5 +-- src/pvh.rs | 26 +++++++++------ 8 files changed, 155 insertions(+), 55 deletions(-) create mode 100644 src/bootinfo.rs diff --git a/src/boot.rs b/src/boot.rs index 2b8be358..379524e2 100644 --- a/src/boot.rs +++ b/src/boot.rs @@ -1,24 +1,15 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2022 Akira Moroo + use core::mem; use crate::{ + bootinfo::{EntryType, Info, MemoryEntry}, common, fat::{Error, Read}, mem::MemoryRegion, }; -// Common data needed for all boot paths -pub trait Info { - // Name of for this boot protocol - fn name(&self) -> &str; - // Starting address of the Root System Descriptor Pointer - fn rsdp_addr(&self) -> u64; - // The kernel command line (not including null terminator) - fn cmdline(&self) -> &[u8]; - // Methods to access the E820 Memory map - fn num_entries(&self) -> u8; - fn entry(&self, idx: u8) -> E820Entry; -} - #[derive(Clone, Copy, Debug)] #[repr(C, packed)] pub struct E820Entry { @@ -29,6 +20,61 @@ pub struct E820Entry { impl E820Entry { pub const RAM_TYPE: u32 = 1; + pub const RESERVED_TYPE: u32 = 2; + pub const ACPI_RECLAIMABLE_TYPE: u32 = 3; + pub const ACPI_NVS_TYPE: u32 = 4; + pub const BAD_TYPE: u32 = 5; + pub const VENDOR_RESERVED_TYPE: u32 = 6; // coreboot only + pub const COREBOOT_TABLE_TYPE: u32 = 16; // coreboot only +} + +impl From for EntryType { + fn from(value: u32) -> Self { + match value { + E820Entry::RAM_TYPE => Self::Ram, + E820Entry::RESERVED_TYPE => Self::Reserved, + E820Entry::ACPI_RECLAIMABLE_TYPE => Self::AcpiReclaimable, + E820Entry::ACPI_NVS_TYPE => Self::AcpiNvs, + E820Entry::BAD_TYPE => Self::Bad, + E820Entry::VENDOR_RESERVED_TYPE => Self::VendorReserved, + E820Entry::COREBOOT_TABLE_TYPE => Self::CorebootTable, + _ => panic!("Unsupported e820 type"), + } + } +} + +impl From for u32 { + fn from(value: EntryType) -> Self { + match value { + EntryType::Ram => E820Entry::RAM_TYPE, + EntryType::Reserved => E820Entry::RESERVED_TYPE, + EntryType::AcpiReclaimable => E820Entry::ACPI_RECLAIMABLE_TYPE, + EntryType::AcpiNvs => E820Entry::ACPI_NVS_TYPE, + EntryType::Bad => E820Entry::BAD_TYPE, + EntryType::VendorReserved => E820Entry::VENDOR_RESERVED_TYPE, + EntryType::CorebootTable => E820Entry::COREBOOT_TABLE_TYPE, + } + } +} + +impl From for E820Entry { + fn from(value: MemoryEntry) -> Self { + Self { + addr: value.addr, + size: value.size, + entry_type: u32::from(value.entry_type), + } + } +} + +impl From for MemoryEntry { + fn from(value: E820Entry) -> Self { + Self { + addr: value.addr, + size: value.size, + entry_type: EntryType::from(value.entry_type), + } + } } // The so-called "zeropage" @@ -80,9 +126,9 @@ impl Default for Params { impl Params { pub fn set_entries(&mut self, info: &dyn Info) { - self.e820_entries = info.num_entries(); + self.e820_entries = info.num_entries() as u8; for i in 0..self.e820_entries { - self.e820_table[i as usize] = info.entry(i); + self.e820_table[i as usize] = info.entry(i as usize).into(); } } } @@ -97,12 +143,13 @@ impl Info for Params { fn cmdline(&self) -> &[u8] { unsafe { common::from_cstring(self.hdr.cmd_line_ptr as u64) } } - fn num_entries(&self) -> u8 { - self.e820_entries + fn num_entries(&self) -> usize { + self.e820_entries as usize } - fn entry(&self, idx: u8) -> E820Entry { + fn entry(&self, idx: usize) -> MemoryEntry { assert!(idx < self.num_entries()); - self.e820_table[idx as usize] + let entry = self.e820_table[idx]; + MemoryEntry::from(entry) } } diff --git a/src/bootinfo.rs b/src/bootinfo.rs new file mode 100644 index 00000000..99d18f97 --- /dev/null +++ b/src/bootinfo.rs @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2022 Akira Moroo + +// Common data needed for all boot paths +pub trait Info { + // Name of for this boot protocol + fn name(&self) -> &str; + // Starting address of the Root System Descriptor Pointer + fn rsdp_addr(&self) -> u64; + // The kernel command line (not including null terminator) + fn cmdline(&self) -> &[u8]; + // Methods to access the Memory map + fn num_entries(&self) -> usize; + fn entry(&self, idx: usize) -> MemoryEntry; +} + +pub struct MemoryEntry { + pub addr: u64, + pub size: u64, + pub entry_type: EntryType, +} + +#[derive(PartialEq)] +pub enum EntryType { + Ram, + Reserved, + AcpiReclaimable, + AcpiNvs, + Bad, + VendorReserved, + CorebootTable, +} diff --git a/src/bzimage.rs b/src/bzimage.rs index 0f11faa9..a3af89b5 100644 --- a/src/bzimage.rs +++ b/src/bzimage.rs @@ -15,7 +15,8 @@ use atomic_refcell::AtomicRefCell; use crate::{ block::SectorBuf, - boot::{E820Entry, Header, Info, Params}, + boot::{Header, Params}, + bootinfo::{EntryType, Info}, fat::{self, Read}, mem::MemoryRegion, }; @@ -95,7 +96,7 @@ impl Kernel { let mut current_addr = None; for i in 0..self.0.num_entries() { let entry = self.0.entry(i); - if entry.entry_type != E820Entry::RAM_TYPE { + if entry.entry_type != EntryType::Ram { continue; } diff --git a/src/coreboot.rs b/src/coreboot.rs index 6fc285fa..8e0e103f 100644 --- a/src/coreboot.rs +++ b/src/coreboot.rs @@ -5,7 +5,7 @@ use core::mem::size_of; -use crate::boot::{E820Entry, Info}; +use crate::bootinfo::{EntryType, Info, MemoryEntry}; #[derive(Debug)] #[repr(C)] @@ -38,6 +38,7 @@ struct Forward { forward: u64, } +#[derive(Clone, Copy)] #[repr(packed, C)] struct MemMapEntry { addr: u64, @@ -45,6 +46,16 @@ struct MemMapEntry { entry_type: u32, } +impl From for MemoryEntry { + fn from(value: MemMapEntry) -> Self { + Self { + addr: value.addr, + size: value.size, + entry_type: EntryType::from(value.entry_type), + } + } +} + #[derive(Debug)] #[repr(C)] pub struct StartInfo { @@ -88,21 +99,17 @@ impl Info for StartInfo { fn cmdline(&self) -> &[u8] { b"" } - fn num_entries(&self) -> u8 { + fn num_entries(&self) -> usize { if self.memmap_addr == 0 { return 0; } - self.memmap_entries as u8 + self.memmap_entries } - fn entry(&self, idx: u8) -> E820Entry { + fn entry(&self, idx: usize) -> MemoryEntry { assert!(idx < self.num_entries()); let ptr = self.memmap_addr as *const MemMapEntry; - let entry = unsafe { &*ptr.offset(idx as isize) }; - E820Entry { - addr: entry.addr, - size: entry.size, - entry_type: entry.entry_type, - } + let entry = unsafe { &*ptr.add(idx) }; + MemoryEntry::from(*entry) } } diff --git a/src/efi/mod.rs b/src/efi/mod.rs index 687a3516..53f6ab19 100644 --- a/src/efi/mod.rs +++ b/src/efi/mod.rs @@ -34,7 +34,7 @@ use r_efi::{ system::{ConfigurationTable, RuntimeServices}, }; -use crate::boot; +use crate::bootinfo; use crate::layout; use crate::rtc; @@ -916,16 +916,19 @@ const PAGE_SIZE: u64 = 4096; const HEAP_SIZE: usize = 256 * 1024 * 1024; // Populate allocator from E820, fixed ranges for the firmware and the loaded binary. -fn populate_allocator(info: &dyn boot::Info, image_address: u64, image_size: u64) { +fn populate_allocator(info: &dyn bootinfo::Info, image_address: u64, image_size: u64) { for i in 0..info.num_entries() { let entry = info.entry(i); - if entry.entry_type == boot::E820Entry::RAM_TYPE { - ALLOCATOR.borrow_mut().add_initial_allocation( - efi::CONVENTIONAL_MEMORY, - entry.size / PAGE_SIZE, - entry.addr, - efi::MEMORY_WB, - ); + match entry.entry_type { + bootinfo::EntryType::Ram => { + ALLOCATOR.borrow_mut().add_initial_allocation( + efi::CONVENTIONAL_MEMORY, + entry.size / PAGE_SIZE, + entry.addr, + efi::MEMORY_WB, + ); + } + _ => continue, } } @@ -1057,7 +1060,7 @@ pub fn efi_exec( address: u64, loaded_address: u64, loaded_size: u64, - info: &dyn boot::Info, + info: &dyn bootinfo::Info, fs: &crate::fat::Filesystem, block: *const crate::block::VirtioBlockDevice, ) { diff --git a/src/loader.rs b/src/loader.rs index 2b7fb85c..896adbc5 100644 --- a/src/loader.rs +++ b/src/loader.rs @@ -14,7 +14,7 @@ use crate::{ block::SectorBuf, - boot, + bootinfo, bzimage::{self, Kernel}, common::ascii_strip, fat::{self, Read}, @@ -217,7 +217,10 @@ fn default_entry_path(fs: &fat::Filesystem) -> Result<[u8; 260], Error> { Ok(entry_path) } -pub fn load_default_entry(fs: &fat::Filesystem, info: &dyn boot::Info) -> Result { +pub fn load_default_entry( + fs: &fat::Filesystem, + info: &dyn bootinfo::Info, +) -> Result { let default_entry_path = default_entry_path(fs)?; let default_entry_path = ascii_strip(&default_entry_path); diff --git a/src/main.rs b/src/main.rs index a069a1a6..0a84aeab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,6 +35,7 @@ mod common; mod arch; mod block; mod boot; +mod bootinfo; mod bzimage; #[cfg(target_arch = "x86_64")] mod cmos; @@ -75,7 +76,7 @@ fn panic(_: &PanicInfo) -> ! { const VIRTIO_PCI_VENDOR_ID: u16 = 0x1af4; const VIRTIO_PCI_BLOCK_DEVICE_ID: u16 = 0x1042; -fn boot_from_device(device: &mut block::VirtioBlockDevice, info: &dyn boot::Info) -> bool { +fn boot_from_device(device: &mut block::VirtioBlockDevice, info: &dyn bootinfo::Info) -> bool { if let Err(err) = device.init() { log!("Error configuring block device: {:?}", err); return false; @@ -153,7 +154,7 @@ pub extern "C" fn rust64_start(#[cfg(not(feature = "coreboot"))] pvh_info: &pvh: } #[cfg(target_arch = "x86_64")] -fn main(info: &dyn boot::Info) -> ! { +fn main(info: &dyn bootinfo::Info) -> ! { log!("\nBooting with {}", info.name()); pci::print_bus(); diff --git a/src/pvh.rs b/src/pvh.rs index e495a780..cfcee444 100644 --- a/src/pvh.rs +++ b/src/pvh.rs @@ -1,7 +1,7 @@ use core::mem::size_of; use crate::{ - boot::{E820Entry, Info}, + bootinfo::{EntryType, Info, MemoryEntry}, common, }; @@ -30,6 +30,16 @@ struct MemMapEntry { _pad: u32, } +impl From for MemoryEntry { + fn from(value: MemMapEntry) -> Self { + Self { + addr: value.addr, + size: value.size, + entry_type: EntryType::from(value.entry_type), + } + } +} + impl Info for StartInfo { fn name(&self) -> &str { "PVH Boot Protocol" @@ -40,22 +50,18 @@ impl Info for StartInfo { fn cmdline(&self) -> &[u8] { unsafe { common::from_cstring(self.cmdline_paddr) } } - fn num_entries(&self) -> u8 { + fn num_entries(&self) -> usize { // memmap_paddr and memmap_entries only exist in version 1 or later if self.version < 1 || self.memmap_paddr == 0 { return 0; } - self.memmap_entries as u8 + self.memmap_entries as usize } - fn entry(&self, idx: u8) -> E820Entry { + fn entry(&self, idx: usize) -> MemoryEntry { assert!(idx < self.num_entries()); let ptr = self.memmap_paddr as *const MemMapEntry; - let entry = unsafe { *ptr.offset(idx as isize) }; - E820Entry { - addr: entry.addr, - size: entry.size, - entry_type: entry.entry_type, - } + let entry = unsafe { *ptr.add(idx) }; + MemoryEntry::from(entry) } }