diff --git a/Cargo.lock b/Cargo.lock index 09f1f1c9..0b448601 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -232,6 +232,7 @@ dependencies = [ "fdt", "heapless", "log", + "pvh", "r-efi", "rand", "ssh2", @@ -350,6 +351,27 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -433,6 +455,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "pvh" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f108169c5107949cc3480e412a25f0b583be3f974df3a45b8478a79eb02f62f3" +dependencies = [ + "bitflags 2.11.0", + "num_enum", +] + [[package]] name = "quote" version = "1.0.38" diff --git a/Cargo.toml b/Cargo.toml index 18160cd3..ee581939 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ fdt = "0.1.5" chrono = { version = "0.4", default-features = false } [target.'cfg(target_arch = "x86_64")'.dependencies] +pvh = "0.1" uart_16550 = "0.4.0" x86_64 = { version = "0.15.4", default-features = false, features = [ "instructions", diff --git a/src/common.rs b/src/common.rs index f0c1820a..07b4af9d 100644 --- a/src/common.rs +++ b/src/common.rs @@ -15,21 +15,6 @@ macro_rules! container_of_mut { }}; } -// SAFETY: Requires that addr point to a static, null-terminated C-string. -// The returned slice does not include the null-terminator. -#[cfg(all(target_arch = "x86_64", not(feature = "coreboot")))] -pub unsafe fn from_cstring(addr: u64) -> &'static [u8] { - if addr == 0 { - return &[]; - } - let start = addr as *const u8; - let mut size: usize = 0; - while start.add(size).read() != 0 { - size += 1; - } - core::slice::from_raw_parts(start, size) -} - pub fn ascii_strip(s: &[u8]) -> &str { core::str::from_utf8(s).unwrap().trim_matches(char::from(0)) } diff --git a/src/main.rs b/src/main.rs index 5928863d..d1d7bc18 100644 --- a/src/main.rs +++ b/src/main.rs @@ -179,7 +179,7 @@ fn boot_from_device( #[cfg(target_arch = "x86_64")] #[no_mangle] -pub extern "C" fn rust64_start(#[cfg(not(feature = "coreboot"))] pvh_info: &pvh::StartInfo) -> ! { +pub extern "C" fn rust64_start(#[cfg(not(feature = "coreboot"))] start_info_paddr: u32) -> ! { serial::PORT.borrow_mut().init(); logger::init(); @@ -187,12 +187,14 @@ pub extern "C" fn rust64_start(#[cfg(not(feature = "coreboot"))] pvh_info: &pvh: arch::x86_64::paging::setup(); #[cfg(feature = "coreboot")] - let info = &coreboot::StartInfo::default(); + let info = coreboot::StartInfo::default(); #[cfg(not(feature = "coreboot"))] - let info = pvh_info; + let info = unsafe { + ::pvh::start_info::reader::StartInfoReader::from_paddr_identity(start_info_paddr).unwrap() + }; - main(info) + main(&info) } #[cfg(target_arch = "aarch64")] diff --git a/src/pvh.rs b/src/pvh.rs index ed7c8ad8..f5d9053e 100644 --- a/src/pvh.rs +++ b/src/pvh.rs @@ -1,70 +1,41 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Google LLC -use core::mem::size_of; +use pvh::start_info::{ + reader::{MemMap, StartInfoReader}, + MemmapTableEntry, +}; use crate::{ bootinfo::{EntryType, Info, MemoryEntry}, - common, layout::MemoryDescriptor, }; -// Structures from xen/include/public/arch-x86/hvm/start_info.h -#[derive(Debug)] -#[repr(C)] -pub struct StartInfo { - magic: [u8; 4], - version: u32, - flags: u32, - nr_modules: u32, - modlist_paddr: u64, - cmdline_paddr: u64, - rsdp_paddr: u64, - memmap_paddr: u64, - memmap_entries: u32, - _pad: u32, -} - -#[derive(Clone, Copy, Debug)] -#[repr(C)] -struct MemMapEntry { - addr: u64, - size: u64, - entry_type: u32, - _pad: u32, -} - -impl From for MemoryEntry { - fn from(value: MemMapEntry) -> Self { +impl From for MemoryEntry { + fn from(value: MemmapTableEntry) -> Self { Self { addr: value.addr, size: value.size, - entry_type: EntryType::from(value.entry_type), + entry_type: EntryType::from(value.ty), } } } -impl Info for StartInfo { +impl Info for StartInfoReader<'_, M> { fn name(&self) -> &str { "PVH Boot Protocol" } fn rsdp_addr(&self) -> Option { - Some(self.rsdp_paddr) + Some(self.raw().rsdp_paddr) } fn cmdline(&self) -> &[u8] { - unsafe { common::from_cstring(self.cmdline_paddr) } + self.cmdline().unwrap_or_default().to_bytes() } 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 usize + self.memmap().len() } fn entry(&self, idx: usize) -> MemoryEntry { - assert!(idx < self.num_entries()); - let ptr = self.memmap_paddr as *const MemMapEntry; - let entry = unsafe { *ptr.add(idx) }; + let entry = self.memmap()[idx]; MemoryEntry::from(entry) } fn kernel_load_addr(&self) -> u64 { @@ -77,34 +48,7 @@ impl Info for StartInfo { // The PVH Boot Protocol starts at the 32-bit entrypoint to our firmware. extern "C" { - fn ram32_start(); + fn ram32_start() -> !; } -// The kind/name/desc of the PHV ELF Note are from xen/include/public/elfnote.h. -// This is the "Physical entry point into the kernel". -const XEN_ELFNOTE_PHYS32_ENTRY: u32 = 18; -type Name = [u8; 4]; -type Desc = unsafe extern "C" fn(); - -// We make sure our ELF Note has an alignment of 4 for maximum compatibility. -// Some software (QEMU) calculates padding incorectly if alignment != 4. -#[repr(C, packed(4))] -struct Note { - name_size: u32, - desc_size: u32, - kind: u32, - name: Name, - desc: Desc, -} - -// This is: ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY, .quad ram32_start) -#[cfg(not(test))] -#[link_section = ".note"] -#[used] -static PVH_NOTE: Note = Note { - name_size: size_of::() as u32, - desc_size: size_of::() as u32, - kind: XEN_ELFNOTE_PHYS32_ENTRY, - name: *b"Xen\0", - desc: ram32_start, -}; +pvh::xen_elfnote_phys32_entry!(ram32_start); diff --git a/x86_64-unknown-none.ld b/x86_64-unknown-none.ld index 81a3f8d2..9cf2b098 100644 --- a/x86_64-unknown-none.ld +++ b/x86_64-unknown-none.ld @@ -14,7 +14,7 @@ SECTIONS /* Mapping the program headers and note into RAM makes the file smaller. */ . = ram_min; . += SIZEOF_HEADERS; - .note : { *(.note) } :note :ram + .note : { *(.note .note.*) } :note :ram /* These sections are mapped into RAM from the file. Omitting :ram from later sections avoids emitting empty sections in the final binary. */