From 420c873dbd152bd83f497f54a9fc553b6bc382ad Mon Sep 17 00:00:00 2001 From: Andri Saar Date: Fri, 9 Aug 2024 18:19:59 +0000 Subject: [PATCH] Move the rest of the operations into the HAL trait. I don't particularly like how `Platform` permeates everyhing now, but that'll be a fight for a different day. And some of the base structures in the crate hierarchy indeed need a cleanup, as the SEV crates are now leaking into TDX. But that will be a fight for a different day as well. Bug: 350496083 Change-Id: I85bd2ce572a2ef784093cc30053aa13a82b42fd3 --- stage0/src/acpi.rs | 22 ++- stage0/src/allocator.rs | 38 ++-- stage0/src/apic.rs | 116 ++++++------ stage0/src/fw_cfg.rs | 12 +- stage0/src/hal/base/mmio.rs | 3 +- stage0/src/hal/base/mod.rs | 54 +++++- stage0/src/hal/mod.rs | 234 +++++++++++-------------- stage0/src/hal/sev/accept_memory.rs | 13 +- stage0/src/hal/sev/dice_attestation.rs | 10 +- stage0/src/hal/sev/mod.rs | 220 +++++++++++++---------- stage0/src/hal/sev/msr.rs | 43 ----- stage0/src/initramfs.rs | 4 +- stage0/src/kernel.rs | 6 +- stage0/src/lib.rs | 24 +-- stage0/src/msr.rs | 56 +++--- stage0/src/paging.rs | 43 +++-- stage0/src/smp.rs | 13 +- stage0/src/zero_page.rs | 7 +- stage0_bin_tdx/Cargo.lock | 4 + stage0_bin_tdx/Cargo.toml | 4 + stage0_bin_tdx/src/main.rs | 46 +++++ 21 files changed, 540 insertions(+), 432 deletions(-) delete mode 100644 stage0/src/hal/sev/msr.rs diff --git a/stage0/src/acpi.rs b/stage0/src/acpi.rs index 08d355401d9..ed31c8fb2ca 100644 --- a/stage0/src/acpi.rs +++ b/stage0/src/acpi.rs @@ -112,7 +112,11 @@ impl Allocate { Zone::from_repr(self.zone) } - fn invoke(&self, fwcfg: &mut FwCfg, acpi_digest: &mut Sha256) -> Result<(), &'static str> { + fn invoke( + &self, + fwcfg: &mut FwCfg

, + acpi_digest: &mut Sha256, + ) -> Result<(), &'static str> { let file = fwcfg.find(self.file()).unwrap(); let name = self.file().to_str().map_err(|_| "invalid file name")?; @@ -465,7 +469,11 @@ enum Command<'a> { } impl Command<'_> { - pub fn invoke(&self, fwcfg: &mut FwCfg, acpi_digest: &mut Sha256) -> Result<(), &'static str> { + pub fn invoke( + &self, + fwcfg: &mut FwCfg

, + acpi_digest: &mut Sha256, + ) -> Result<(), &'static str> { match self { Command::Allocate(allocate) => allocate.invoke(fwcfg, acpi_digest), Command::AddPointer(add_pointer) => add_pointer.invoke(), @@ -500,7 +508,11 @@ impl RomfileCommand { } } - fn invoke(&self, fwcfg: &mut FwCfg, acpi_digest: &mut Sha256) -> Result<(), &'static str> { + fn invoke( + &self, + fwcfg: &mut FwCfg

, + acpi_digest: &mut Sha256, + ) -> Result<(), &'static str> { if self.tag > CommandTag::VMM_SPECIFIC && self.tag().is_none() { log::warn!("ignoring proprietary ACPI linker command with tag {:#x}", self.tag); return Ok(()); @@ -520,8 +532,8 @@ impl RomfileCommand { /// Populates the ACPI tables per linking instructions in `etc/table-loader`. /// /// Returns the address of the RSDP table. -pub fn build_acpi_tables( - fwcfg: &mut FwCfg, +pub fn build_acpi_tables( + fwcfg: &mut FwCfg

, acpi_digest: &mut Sha256, ) -> Result<&'static Rsdp, &'static str> { let file = diff --git a/stage0/src/allocator.rs b/stage0/src/allocator.rs index 743b4717c21..01b78f5f980 100644 --- a/stage0/src/allocator.rs +++ b/stage0/src/allocator.rs @@ -17,6 +17,7 @@ use alloc::boxed::Box; use core::{ alloc::{AllocError, Allocator, Layout}, + marker::PhantomData, mem::MaybeUninit, ops::{Deref, DerefMut}, ptr::NonNull, @@ -30,7 +31,10 @@ use x86_64::{ VirtAddr, }; -use crate::paging::{share_page, unshare_page}; +use crate::{ + paging::{share_page, unshare_page}, + Platform, +}; struct Inner { index: AtomicUsize, @@ -108,17 +112,18 @@ unsafe impl Allocator for BumpAllocator { /// they could well fit on one page, currently that'd use 8K of memory. /// That, however, is an implementation detail, and may change in the future. #[repr(transparent)] -struct SharedAllocator { +struct SharedAllocator { inner: A, + _phantom: PhantomData

, } -impl SharedAllocator { +impl SharedAllocator { fn new(allocator: A) -> Self { - Self { inner: allocator } + Self { inner: allocator, _phantom: PhantomData } } } -unsafe impl Allocator for SharedAllocator { +unsafe impl Allocator for SharedAllocator { fn allocate(&self, layout: Layout) -> Result, AllocError> { let layout = layout.align_to(Size4KiB::SIZE as usize).map_err(|_| AllocError)?.pad_to_align(); @@ -126,7 +131,7 @@ unsafe impl Allocator for SharedAllocator { for offset in (0..allocation.len()).step_by(Size4KiB::SIZE as usize) { // Safety: the allocation has succeeded and the offset won't exceed the size of // the allocation. - share_page(Page::containing_address(VirtAddr::from_ptr(unsafe { + share_page::

(Page::containing_address(VirtAddr::from_ptr(unsafe { allocation.as_non_null_ptr().as_ptr().add(offset) }))) } @@ -142,7 +147,7 @@ unsafe impl Allocator for SharedAllocator { for offset in (0..layout.size()).step_by(Size4KiB::SIZE as usize) { // Safety: the allocation has succeeded and the offset won't exceed the size of // the allocation. - unshare_page(Page::containing_address(VirtAddr::from_ptr(unsafe { + unshare_page::

(Page::containing_address(VirtAddr::from_ptr(unsafe { ptr.as_ptr().add(offset) }))) } @@ -151,11 +156,11 @@ unsafe impl Allocator for SharedAllocator { } /// Stores a data structure on a shared page. -pub struct Shared { - inner: Box>, +pub struct Shared { + inner: Box>, } -impl Shared { +impl Shared { pub fn new_in(t: T, alloc: A) -> Self where A: 'static, @@ -172,20 +177,21 @@ impl Shared { /// was used for the original allocation of the `Shared`. /// /// Again, see `Box::from_raw_in` for more details. - pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Shared { + pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Shared { Self { inner: Box::from_raw_in(raw, SharedAllocator::new(alloc)) } } /// See `Box::leak` for documentation. - pub fn leak<'a>(s: Shared) -> &'a mut T + pub fn leak<'a>(s: Shared) -> &'a mut T where A: 'a, + P: 'a, { Box::leak(s.inner) } } -impl Deref for Shared { +impl Deref for Shared { type Target = T; fn deref(&self) -> &Self::Target { @@ -193,19 +199,19 @@ impl Deref for Shared { } } -impl DerefMut for Shared { +impl DerefMut for Shared { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } } -impl AsRef for Shared { +impl AsRef for Shared { fn as_ref(&self) -> &T { &self.inner } } -impl AsMut for Shared { +impl AsMut for Shared { fn as_mut(&mut self) -> &mut T { &mut self.inner } diff --git a/stage0/src/apic.rs b/stage0/src/apic.rs index 440a4320f2c..ec7360fcb48 100644 --- a/stage0/src/apic.rs +++ b/stage0/src/apic.rs @@ -16,10 +16,14 @@ use x86_64::{structures::paging::Size4KiB, PhysAddr}; -use crate::msr::{ - ApicBase, ApicBaseFlags, ApicErrorFlags, DestinationMode, DestinationShorthand, Level, - MessageType, SpuriousInterruptFlags, TriggerMode, X2ApicErrorStatusRegister, X2ApicIdRegister, - X2ApicInterruptCommandRegister, X2ApicSpuriousInterruptRegister, X2ApicVersionRegister, +use crate::{ + msr::{ + ApicBase, ApicBaseFlags, ApicErrorFlags, DestinationMode, DestinationShorthand, Level, + MessageType, SpuriousInterruptFlags, TriggerMode, X2ApicErrorStatusRegister, + X2ApicIdRegister, X2ApicInterruptCommandRegister, X2ApicSpuriousInterruptRegister, + X2ApicVersionRegister, + }, + Platform, }; /// Interrupt Command. @@ -29,7 +33,7 @@ use crate::msr::{ /// See Section 16.5 (Interprocessor Interrupts) and Section 16/13 (x2APIC /// Interrupt Command Register Operations) in the AMD64 Architecture /// Programmer's Manual, Volume 2 for more details. -trait InterprocessorInterrupt { +trait InterprocessorInterrupt { /// Sends an IPI (inter-processor interrupt) to another LAPIC in the system. #[allow(clippy::too_many_arguments)] fn send( @@ -48,7 +52,7 @@ trait InterprocessorInterrupt { /// /// See Section 16.4.6 (APIC Error Interrupts) in the AMD64 Architecture /// Programmer's Manual, Volume 2 for more details. -trait ErrorStatus { +trait ErrorStatus { #[allow(unused)] fn read(&self) -> ApicErrorFlags; fn clear(&mut self); @@ -58,14 +62,14 @@ trait ErrorStatus { /// /// For APIC, it's 4 bits; xAPIC, 8 bits; x2APIC, 32 bits. trait ApicId { - fn apic_id(&self) -> u32; + fn apic_id(&self) -> u32; } /// APIC Version. /// /// See Section 16.3.4 (APIC Version Register) in the AMD64 Architecture /// Programmer's Manual, Volume 2 for more details. -trait ApicVersion { +trait ApicVersion

{ fn read(&self) -> (bool, u8, u8); } @@ -73,7 +77,7 @@ trait ApicVersion { /// /// See Section 16.4.7 (Spurious Interrupts) in the AMD64 Architecture /// Programmer's Manual, Volume 2 for more details. -trait SpuriousInterrupts { +trait SpuriousInterrupts

{ fn read(&self) -> (SpuriousInterruptFlags, u8); fn write(&mut self, flags: SpuriousInterruptFlags, vec: u8); } @@ -82,7 +86,7 @@ mod xapic { use x86_64::{structures::paging::Size4KiB, PhysAddr}; use super::{ApicErrorFlags, SpuriousInterruptFlags}; - use crate::hal; + use crate::{hal, Platform}; // We divide the offset by 4 as we're indexing by u32's, not bytes. const APIC_ID_REGISTER_OFFSET: usize = 0x020 / core::mem::size_of::(); @@ -110,12 +114,12 @@ mod xapic { /// /// See Section 16.3.3 in the AMD64 Architecture Programmer's Manual, /// Volume 2 for the register format. - fn apic_id(&self) -> u32 { + fn apic_id(&self) -> u32 { self.read(APIC_ID_REGISTER_OFFSET) >> 24 } } - impl> super::InterprocessorInterrupt for Xapic { + impl super::InterprocessorInterrupt

for Xapic> { fn send( &mut self, destination: u32, @@ -145,7 +149,7 @@ mod xapic { } } - impl> super::ErrorStatus for Xapic { + impl super::ErrorStatus

for Xapic> { fn read(&self) -> ApicErrorFlags { ApicErrorFlags::from_bits_truncate(self.read(ERROR_STATUS_REGISTER_OFFSET)) } @@ -156,7 +160,7 @@ mod xapic { } } - impl> super::ApicVersion for Xapic { + impl super::ApicVersion

for Xapic> { fn read(&self) -> (bool, u8, u8) { let val = self.read(APIC_VERSION_REGISTER_OFFSET); @@ -168,7 +172,7 @@ mod xapic { } } - impl> super::SpuriousInterrupts for Xapic { + impl super::SpuriousInterrupts

for Xapic> { fn read(&self) -> (SpuriousInterruptFlags, u8) { let val = self.read(SPURIOUS_INTERRUPT_REGISTER_OFFSET); @@ -183,26 +187,29 @@ mod xapic { /// Safety: caller needs to guarantee that `apic_base` points to the APIC /// MMIO memory. - pub(crate) unsafe fn init(apic_base: PhysAddr) -> Xapic> { + pub(crate) unsafe fn init(apic_base: PhysAddr) -> Xapic> { Xapic { mmio: P::mmio::(apic_base) } } } mod x2apic { use super::{ApicErrorFlags, SpuriousInterruptFlags}; - use crate::msr::{ - X2ApicErrorStatusRegister, X2ApicIdRegister, X2ApicInterruptCommandRegister, - X2ApicSpuriousInterruptRegister, X2ApicVersionRegister, + use crate::{ + msr::{ + X2ApicErrorStatusRegister, X2ApicIdRegister, X2ApicInterruptCommandRegister, + X2ApicSpuriousInterruptRegister, X2ApicVersionRegister, + }, + Platform, }; impl super::ApicId for X2ApicIdRegister { - fn apic_id(&self) -> u32 { + fn apic_id(&self) -> u32 { // Safety: we've estabished we're using x2APIC, so accessing the MSR is safe. - unsafe { Self::apic_id() } + unsafe { Self::apic_id::

() } } } - impl super::InterprocessorInterrupt for X2ApicInterruptCommandRegister { + impl super::InterprocessorInterrupt

for X2ApicInterruptCommandRegister { fn send( &mut self, destination: u32, @@ -215,7 +222,7 @@ mod x2apic { ) -> Result<(), &'static str> { // Safety: we've estabished we're using x2APIC, so accessing the MSR is safe. unsafe { - Self::send( + Self::send::

( vector, message_type, destination_mode, @@ -229,33 +236,33 @@ mod x2apic { } } - impl super::ErrorStatus for X2ApicErrorStatusRegister { + impl super::ErrorStatus

for X2ApicErrorStatusRegister { fn read(&self) -> ApicErrorFlags { // Safety: we've estabished we're using x2APIC, so accessing the MSR is safe. - unsafe { Self::read() } + unsafe { Self::read::

() } } fn clear(&mut self) { // Safety: we've estabished we're using x2APIC, so accessing the MSR is safe. - unsafe { Self::clear() } + unsafe { Self::clear::

() } } } - impl super::ApicVersion for X2ApicVersionRegister { + impl super::ApicVersion

for X2ApicVersionRegister { fn read(&self) -> (bool, u8, u8) { // Safety: we've estabished we're using x2APIC, so accessing the MSR is safe. - unsafe { Self::read() } + unsafe { Self::read::

() } } } - impl super::SpuriousInterrupts for X2ApicSpuriousInterruptRegister { + impl super::SpuriousInterrupts

for X2ApicSpuriousInterruptRegister { fn read(&self) -> (SpuriousInterruptFlags, u8) { // Safety: we've estabished we're using x2APIC, so accessing the MSR is safe. - unsafe { Self::read() } + unsafe { Self::read::

() } } fn write(&mut self, flags: SpuriousInterruptFlags, vec: u8) { // Safety: we've estabished we're using x2APIC, so accessing the MSR is safe. - unsafe { Self::write(flags, vec) }; + unsafe { Self::write::

(flags, vec) }; } } } @@ -279,25 +286,25 @@ pub struct Lapic> { } impl> Lapic { - pub fn enable = M>>() -> Result { + pub fn enable = M>>() -> Result { let x2apic = P::cpuid(0x0000_0001).ecx & (1 << 21) > 0; // See Section 16.9 in the AMD64 Architecture Programmer's Manual, Volume 2 for // explanation of the initialization procedure. - let (aba, mut flags) = ApicBase::read(); + let (aba, mut flags) = ApicBase::read::

(); if !flags.contains(ApicBaseFlags::AE) { flags |= ApicBaseFlags::AE; - ApicBase::write(aba, flags); + ApicBase::write::

(aba, flags); } if x2apic && !flags.contains(ApicBaseFlags::EXTD) { // Enable x2APIC, if available. flags |= ApicBaseFlags::EXTD; - ApicBase::write(aba, flags); + ApicBase::write::

(aba, flags); } let mut apic = if x2apic { log::info!("Using x2APIC for AP initialization."); Lapic { - apic_id: unsafe { X2ApicIdRegister::apic_id() }, + apic_id: unsafe { X2ApicIdRegister::apic_id::

() }, interface: Apic::X2apic( X2ApicInterruptCommandRegister, X2ApicErrorStatusRegister, @@ -309,43 +316,47 @@ impl> Lapic { log::info!("Using xAPIC for AP initialization."); // Safety: we trust the address provided by the ApicBase MSR. let apic = unsafe { xapic::init::

(aba) }; - Lapic { apic_id: apic.apic_id(), interface: Apic::Xapic(apic) } + Lapic { apic_id: apic.apic_id::

(), interface: Apic::Xapic(apic) } }; // Version should be between [0x10...0x20). - let (_, _, version) = apic.apic_version().read(); + let (_, _, version) = apic.apic_version::

().read(); if !(0x10..0x20).contains(&version) { log::warn!("LAPIC version: {:x}", version); return Err("LAPIC version not in valid range"); } - let (flags, vec) = apic.spurious_interrupt_register().read(); + let (flags, vec) = apic.spurious_interrupt_register::

().read(); if !flags.contains(SpuriousInterruptFlags::ASE) { - apic.spurious_interrupt_register().write(flags | SpuriousInterruptFlags::ASE, vec) + apic.spurious_interrupt_register::

().write(flags | SpuriousInterruptFlags::ASE, vec) } Ok(apic) } - fn error_status(&mut self) -> &mut dyn ErrorStatus { + fn error_status = M>>(&mut self) -> &mut dyn ErrorStatus

{ match &mut self.interface { Apic::Xapic(regs) => regs, Apic::X2apic(_, ref mut err, _, _) => err, } } - fn interrupt_command(&mut self) -> &mut dyn InterprocessorInterrupt { + fn interrupt_command = M>>( + &mut self, + ) -> &mut dyn InterprocessorInterrupt

{ match &mut self.interface { Apic::Xapic(regs) => regs, Apic::X2apic(ref mut icr, _, _, _) => icr, } } - fn apic_version(&mut self) -> &mut dyn ApicVersion { + fn apic_version = M>>(&mut self) -> &mut dyn ApicVersion

{ match &mut self.interface { Apic::Xapic(regs) => regs, Apic::X2apic(_, _, ver, _) => ver, } } - fn spurious_interrupt_register(&mut self) -> &mut dyn SpuriousInterrupts { + fn spurious_interrupt_register = M>>( + &mut self, + ) -> &mut dyn SpuriousInterrupts

{ match &mut self.interface { Apic::Xapic(regs) => regs, Apic::X2apic(_, _, _, spi) => spi, @@ -353,9 +364,12 @@ impl> Lapic { } /// Sends an INIT IPI to the local APIC specified by `destination`. - pub fn send_init_ipi(&mut self, destination: u32) -> Result<(), &'static str> { - self.error_status().clear(); - self.interrupt_command().send( + pub fn send_init_ipi = M>>( + &mut self, + destination: u32, + ) -> Result<(), &'static str> { + self.error_status::

().clear(); + self.interrupt_command::

().send( destination, 0, MessageType::Init, @@ -364,7 +378,7 @@ impl> Lapic { TriggerMode::Level, DestinationShorthand::DestinationField, )?; - self.interrupt_command().send( + self.interrupt_command::

().send( destination, 0, MessageType::Init, @@ -376,7 +390,7 @@ impl> Lapic { } /// Sends a STARTUP IPI (SIPI) to the local APIC specified by `destination`. - pub fn send_startup_ipi( + pub fn send_startup_ipi = M>>( &mut self, destination: u32, vector: PhysAddr, @@ -388,8 +402,8 @@ impl> Lapic { if vector > 0x100000 { return Err("startup vector needs to be in the first megabyte of memory"); } - self.error_status().clear(); - self.interrupt_command().send( + self.error_status::

().clear(); + self.interrupt_command::

().send( destination, (vector / 0x1000) as u8, MessageType::Startup, diff --git a/stage0/src/fw_cfg.rs b/stage0/src/fw_cfg.rs index 854c17885ab..c9cebf69995 100644 --- a/stage0/src/fw_cfg.rs +++ b/stage0/src/fw_cfg.rs @@ -144,17 +144,17 @@ impl core::fmt::Debug for DirEntry { /// Wrapper for the QEMU Firmware Configuration device. /// /// See for more details. -pub struct FwCfg { +pub struct FwCfg { selector: Port, data: Port, dma_high: Port, dma_low: Port, - dma_buf: Shared, - dma_access: Shared, + dma_buf: Shared, + dma_access: Shared, dma_enabled: bool, } -impl FwCfg { +impl FwCfg

{ /// # Safety /// /// While we do probe for the existence of the QEMU fw_cfg device, reading @@ -164,9 +164,7 @@ impl FwCfg { /// /// The caller has to guarantee that at least doing the probe will not cause /// any adverse effects. - pub unsafe fn new( - alloc: &'static BootAllocator, - ) -> Result { + pub unsafe fn new(alloc: &'static BootAllocator) -> Result { let mut fwcfg = Self { selector: PortFactory::new::

().new_writer(FWCFG_PORT_SELECTOR), data: PortFactory::new::

().new_reader(FWCFG_PORT_DATA), diff --git a/stage0/src/hal/base/mmio.rs b/stage0/src/hal/base/mmio.rs index 7f32101790e..4e7d7a73f77 100644 --- a/stage0/src/hal/base/mmio.rs +++ b/stage0/src/hal/base/mmio.rs @@ -23,6 +23,7 @@ use x86_64::{ PhysAddr, VirtAddr, }; +use super::Base; use crate::paging::{PageEncryption, PageTableEntry, PAGE_TABLE_REFS}; pub struct Mmio { @@ -49,7 +50,7 @@ impl Mmio { } let mut tables = PAGE_TABLE_REFS.get().unwrap().lock(); let old_pte = tables.pt_0[mmio_memory.p1_index()].clone(); - tables.pt_0[mmio_memory.p1_index()].set_address( + tables.pt_0[mmio_memory.p1_index()].set_address::( base_address, PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_CACHE, PageEncryption::Unencrypted, diff --git a/stage0/src/hal/base/mod.rs b/stage0/src/hal/base/mod.rs index 5abaa273440..87e63ec5320 100644 --- a/stage0/src/hal/base/mod.rs +++ b/stage0/src/hal/base/mod.rs @@ -19,15 +19,19 @@ mod mmio; use core::arch::x86_64::{CpuidResult, __cpuid}; pub use mmio::*; -pub use oak_stage0_dice::{ - mock_attestation_report as get_attestation, mock_derived_key as get_derived_key, -}; +use oak_dice::evidence::TeePlatform; +use oak_linux_boot_params::BootE820Entry; +use oak_sev_guest::msr::PageAssignment; +use oak_sev_snp_attestation_report::{AttestationReport, REPORT_DATA_SIZE}; +use oak_stage0_dice::DerivedKey; pub use x86_64::registers::model_specific::Msr; use x86_64::structures::{ - paging::PageSize, + paging::{Page, PageSize, Size4KiB}, port::{PortRead, PortWrite}, }; +use crate::{paging::PageEncryption, zero_page::ZeroPage}; + pub struct Base {} impl crate::Platform for Base { @@ -68,4 +72,46 @@ impl crate::Platform for Base { u32::write_to_port(port, value); Ok(()) } + + fn early_initialize_platform() {} + + fn initialize_platform(_e820_table: &[BootE820Entry]) {} + + fn deinit_platform() {} + + fn populate_zero_page(_zero_page: &mut ZeroPage) {} + + fn get_attestation( + report_data: [u8; REPORT_DATA_SIZE], + ) -> Result { + oak_stage0_dice::mock_attestation_report(report_data) + } + + fn get_derived_key() -> Result { + oak_stage0_dice::mock_derived_key() + } + + fn change_page_state(_page: Page, _state: PageAssignment) {} + + fn revalidate_page(_page: Page) {} + + fn page_table_mask(_encryption_state: PageEncryption) -> u64 { + 0 + } + + fn encrypted() -> u64 { + 0 + } + + fn tee_platform() -> TeePlatform { + TeePlatform::None + } + + unsafe fn read_msr(msr: u32) -> u64 { + Msr::new(msr).read() + } + + unsafe fn write_msr(msr: u32, value: u64) { + Msr::new(msr).write(value) + } } diff --git a/stage0/src/hal/mod.rs b/stage0/src/hal/mod.rs index f0db7d92973..49f45c125e4 100644 --- a/stage0/src/hal/mod.rs +++ b/stage0/src/hal/mod.rs @@ -78,6 +78,100 @@ pub trait Platform { unsafe fn write_u16_to_port(port: u16, value: u16) -> Result<(), &'static str>; unsafe fn read_u32_from_port(port: u16) -> Result; unsafe fn write_u32_to_port(port: u16, value: u32) -> Result<(), &'static str>; + + /// Platform-specific early initialization. + /// + /// This sets up the bare minimum to get things going; for example, under + /// SEV-ES and above, we set up the GHCB here, but nothing more. + /// + /// This gets executed very soon after stage0 starts and comes with many + /// restrictions: + /// - You do not have access to logging. + /// - You do not have access to heap allocator (BOOT_ALLOCATOR will still + /// work). + fn early_initialize_platform(); + + /// Platform-specific intialization. + /// + /// This gets executed after `early_initalize_platform()` and some other + /// auxiliary services, such as logging, have been set up; the main purpose + /// is to accept all guest memory so that we can set up a heap + /// allocator. + /// + /// This does mean you do not have access to the heap allocator + /// (BOOT_ALLOCATOR will still work). + fn initialize_platform(e820_table: &[BootE820Entry]); + + /// Platform-specific cleanups just before stage0 jumps to the kernel. + /// + /// The assumption is that after this operation there will no longer be any + /// memory allocations or uses of the logging interface. + fn deinit_platform(); + + /// Populates platform-specific information in the zero page. + /// + /// Example: locations of the SEV Secrets and CPUID pages. + fn populate_zero_page(zero_page: &mut ZeroPage); + + /// Returns an attestation report. + /// + /// If AMD SEV-SNP is enabled it returns a valid hardware-rooted attestation + /// report. In other cases it generates an empty attestation report for + /// testing. The additional data will be set in both cases to bind the + /// DICE chain to the attestation report. + /// + /// # Arguments + /// + /// * `report_data` - The custom data that must be included in the report. + /// This is typically used to bind information (such as the hash of a + /// public key) to the report. + fn get_attestation( + report_data: [u8; REPORT_DATA_SIZE], + ) -> Result; + + /// Requests a derived key. + /// + /// The key is derived from the VCEK. The key derivation mixes in the VM + /// launch measurement and guest policy and uses VMPL0. + /// + /// We use this key as the unique device secret for deriving compound + /// devices identifiers for each layer, and eventually a sealing key in + /// the last layer. + fn get_derived_key() -> Result; + + /// Ask for the page state to be changed by the hypervisor. + fn change_page_state(page: Page, state: PageAssignment); + + /// Validate one page of memory. + /// + /// This operation is required for SEV after going from a SHARED state to a + /// PRIVATE state. + fn revalidate_page(page: Page); + + /// Mask to use in the page tables for the given encrypion state. + /// + /// SEV and TDX have opposite behaviours: for SEV, encrypted pages are + /// marked; for TDX, unencrypted pages are marked. + fn page_table_mask(encryption_state: PageEncryption) -> u64; + + /// Encrypted/shared bit mask irrespective of its semantics. + fn encrypted() -> u64; + + fn tee_platform() -> TeePlatform; + + /// Read a MSR. + /// + /// ## Safety + /// + /// The caller must guarantee that the MSR is valid. + unsafe fn read_msr(msr: u32) -> u64; + + /// Write to a MSR. + /// + /// ## Safety + /// + /// The caller must guarantee that the MSR is valid. + unsafe fn write_msr(msr: u32, value: u64); } pub use base::Base; #[cfg(feature = "sev")] @@ -86,18 +180,12 @@ pub use sev::Sev; /// Wrapper that can access a MSR either directly or through the GHCB, depending /// on the environment. pub struct Msr { - #[cfg(feature = "sev")] msr_id: u32, - msr: base::Msr, } impl Msr { pub const fn new(reg: u32) -> Self { - Self { - #[cfg(feature = "sev")] - msr_id: reg, - msr: base::Msr::new(reg), - } + Self { msr_id: reg } } /// Read the MSR. @@ -105,11 +193,8 @@ impl Msr { /// ## Safety /// /// The caller must guarantee that the MSR is valid. - pub unsafe fn read(&self) -> u64 { - #[cfg(feature = "sev")] - return sev::read_msr(&self.msr, self.msr_id); - #[cfg(not(feature = "sev"))] - return self.msr.read(); + pub unsafe fn read(&self) -> u64 { + P::read_msr(self.msr_id) } /// Write the MSR. @@ -117,11 +202,8 @@ impl Msr { /// ## Safety /// /// The caller must guarantee that the MSR is valid. - pub unsafe fn write(&mut self, val: u64) { - #[cfg(feature = "sev")] - return sev::write_msr(&mut self.msr, self.msr_id, val); - #[cfg(not(feature = "sev"))] - return self.msr.write(val); + pub unsafe fn write(&mut self, val: u64) { + P::write_msr(self.msr_id, val); } } @@ -205,121 +287,3 @@ impl PortWriter for Port { (self.write)(self.port, value) } } - -/// Platform-specific early initialization. -/// -/// This sets up the bare minimum to get things going; for example, under -/// SEV-ES and above, we set up the GHCB here, but nothing more. -/// -/// This gets executed very soon after stage0 starts and comes with many -/// restrictions: -/// - You do not have access to logging. -/// - You do not have access to heap allocator (BOOT_ALLOCATOR will still -/// work). -pub fn early_initialize_platform() { - #[cfg(feature = "sev")] - sev::early_initialize_platform(); -} - -/// Platform-specific intialization. -/// -/// This gets executed after `early_initalize_platform()` and some other -/// auxiliary services, such as logging, have been set up; the main purpose is -/// to accept all guest memory so that we can set up a heap allocator. -/// -/// This does mean you do not have access to the heap allocator (BOOT_ALLOCATOR -/// will still work). -pub fn initialize_platform(e820_table: &[BootE820Entry]) { - #[cfg(feature = "sev")] - sev::initialize_platform(e820_table) -} - -/// Platform-specific cleanups just before stage0 jumps to the kernel. -/// -/// The assumption is that after this operation there will no longer be any -/// memory allocations or uses of the logging interface. -pub fn deinit_platform() { - #[cfg(feature = "sev")] - sev::deinit_platform(); -} - -pub fn populate_zero_page(zero_page: &mut ZeroPage) { - #[cfg(feature = "sev")] - sev::populate_zero_page(zero_page); -} - -/// Returns an attestation report. -/// -/// If AMD SEV-SNP is enabled it returns a valid hardware-rooted attestation -/// report. In other cases it generates an empty attestation report for testing. -/// The additional data will be set in both cases to bind the DICE chain to the -/// attestation report. -/// -/// # Arguments -/// -/// * `report_data` - The custom data that must be included in the report. This -/// is typically used to bind information (such as the hash of a public key) -/// to the report. -pub fn get_attestation( - report_data: [u8; REPORT_DATA_SIZE], -) -> Result { - #[cfg(feature = "sev")] - return sev::get_attestation(report_data); - #[cfg(not(feature = "sev"))] - return base::get_attestation(report_data); -} - -/// Requests a derived key. -/// -/// The key is derived from the VCEK. The key derivation mixes in the VM launch -/// measurement and guest policy and uses VMPL0. -/// -/// We use this key as the unique device secret for deriving compound devices -/// identifiers for each layer, and eventually a sealing key in the last layer. -pub fn get_derived_key() -> Result { - #[cfg(feature = "sev")] - return sev::get_derived_key(); - #[cfg(not(feature = "sev"))] - return base::get_derived_key(); -} - -/// Ask for the page state to be changed by the hypervisor. -pub fn change_page_state(page: Page, state: PageAssignment) { - #[cfg(feature = "sev")] - sev::change_page_state(page, state).unwrap(); -} - -/// Validate one page of memory. -/// -/// This operation is required for SEV after going from a SHARED state to a -/// PRIVATE state. -pub fn revalidate_page(page: Page) { - #[cfg(feature = "sev")] - sev::revalidate_page(page).unwrap(); -} - -/// Mask to use in the page tables for the given encrypion state. -/// -/// SEV and TDX have opposite behaviours: for SEV, encrypted pages are marked; -/// for TDX, unencrypted pages are marked. -pub fn page_table_mask(encryption_state: PageEncryption) -> u64 { - #[cfg(feature = "sev")] - return sev::page_table_mask(encryption_state); - #[cfg(not(feature = "sev"))] - return 0; -} - -/// Encrypted/shared bit mask irrespective of its semantics. -pub fn encrypted() -> u64 { - #[cfg(feature = "sev")] - return sev::encrypted(); - #[cfg(not(feature = "sev"))] - return 0; -} - -pub fn tee_platform() -> TeePlatform { - #[cfg(feature = "sev")] - return sev::tee_platform(); - #[cfg(not(feature = "sev"))] - return TeePlatform::None; -} diff --git a/stage0/src/hal/sev/accept_memory.rs b/stage0/src/hal/sev/accept_memory.rs index df3fd4d03a8..867806c2118 100644 --- a/stage0/src/hal/sev/accept_memory.rs +++ b/stage0/src/hal/sev/accept_memory.rs @@ -32,7 +32,10 @@ use x86_64::{ use zeroize::Zeroize; use super::{sev_status, GHCB_WRAPPER}; -use crate::paging::{PageEncryption, PageTable}; +use crate::{ + paging::{PageEncryption, PageTable}, + Sev, +}; // // Page tables come in three sizes: for 1 GiB, 2 MiB and 4 KiB pages. However, @@ -110,7 +113,7 @@ where .iter_mut() .filter_map(|entry| range.next().map(|frame| (entry, frame))) .map(|(entry, frame)| { - entry.set_address( + entry.set_address::( frame.start_address(), PageTableFlags::PRESENT | flags, PageEncryption::Encrypted, @@ -129,7 +132,7 @@ where .zip(pages) .filter(|(entry, _)| !entry.is_unused()) .map(|(entry, page)| (entry, page.pvalidate(success_counter))) - .map(|(entry, result)| result.or_else(|err| f(entry.address(), err))) + .map(|(entry, result)| result.or_else(|err| f(entry.address::(), err))) .find(|result| result.is_err()) { return err; @@ -268,7 +271,7 @@ pub fn validate_memory(e820_table: &[BootE820Entry]) { if page_tables.pdpt[1].flags().contains(PageTableFlags::PRESENT) { panic!("PDPT[1] is in use"); } - page_tables.pdpt[1].set_address( + page_tables.pdpt[1].set_address::( PhysAddr::new(&validation_pd.page_table as *const _ as u64), PageTableFlags::PRESENT, PageEncryption::Encrypted, @@ -282,7 +285,7 @@ pub fn validate_memory(e820_table: &[BootE820Entry]) { if page_tables.pd_0[1].flags().contains(PageTableFlags::PRESENT) { panic!("PD_0[1] is in use"); } - page_tables.pd_0[1].set_address( + page_tables.pd_0[1].set_address::( PhysAddr::new(&validation_pt.page_table as *const _ as u64), PageTableFlags::PRESENT, PageEncryption::Encrypted, diff --git a/stage0/src/hal/sev/dice_attestation.rs b/stage0/src/hal/sev/dice_attestation.rs index 8db437ec16e..a160ded9ef3 100644 --- a/stage0/src/hal/sev/dice_attestation.rs +++ b/stage0/src/hal/sev/dice_attestation.rs @@ -30,7 +30,7 @@ use zerocopy::{AsBytes, FromBytes}; use zeroize::Zeroize; use super::{GHCB_WRAPPER, SEV_SECRETS}; -use crate::allocator::Shared; +use crate::{allocator::Shared, Platform}; /// Cryptographic helper to encrypt and decrypt messages for the GHCB guest /// message protocol. @@ -62,9 +62,9 @@ fn send_guest_message_request< let mut guard = GUEST_MESSAGE_ENCRYPTOR.lock(); let encryptor = guard.as_mut().ok_or("guest message encryptor is not initialized")?; let alloc = &crate::SHORT_TERM_ALLOC; - let mut request_message = Shared::new_in(GuestMessage::new(), alloc); + let mut request_message = Shared::<_, _, super::Sev>::new_in(GuestMessage::new(), alloc); encryptor.encrypt_message(request, request_message.as_mut())?; - let response_message = Shared::new_in(GuestMessage::new(), alloc); + let response_message = Shared::<_, _, super::Sev>::new_in(GuestMessage::new(), alloc); let request_address = PhysAddr::new(VirtAddr::from_ptr(request_message.as_ref()).as_u64()); let response_address = PhysAddr::new(VirtAddr::from_ptr(response_message.as_ref()).as_u64()); @@ -90,7 +90,7 @@ pub fn get_attestation( } Ok(attestation_response.report) } else { - crate::hal::base::get_attestation(report_data) + crate::hal::Base::get_attestation(report_data) } } @@ -102,6 +102,6 @@ pub fn get_derived_key() -> Result { let key_response: KeyResponse = send_guest_message_request(key_request)?; Ok(key_response.derived_key) } else { - crate::hal::base::get_derived_key() + crate::hal::Base::get_derived_key() } } diff --git a/stage0/src/hal/sev/mod.rs b/stage0/src/hal/sev/mod.rs index ae54a120199..962cc7b385a 100644 --- a/stage0/src/hal/sev/mod.rs +++ b/stage0/src/hal/sev/mod.rs @@ -17,20 +17,17 @@ mod accept_memory; mod dice_attestation; mod mmio; -mod msr; use alloc::boxed::Box; use core::{arch::x86_64::CpuidResult, mem::MaybeUninit}; -pub use accept_memory::*; -pub use dice_attestation::*; -pub use msr::*; use oak_core::sync::OnceCell; use oak_dice::evidence::TeePlatform; use oak_linux_boot_params::BootE820Entry; use oak_sev_guest::{ ap_jump_table::ApJumpTable, cpuid::CpuidInput, ghcb::GhcbProtocol, msr::SevStatus, }; +use oak_sev_snp_attestation_report::AttestationReport; use spinning_top::{lock_api::MutexGuard, RawSpinlock, Spinlock}; use x86_64::{ instructions::port::{PortRead, PortWrite}, @@ -38,6 +35,7 @@ use x86_64::{ PhysAddr, VirtAddr, }; +use super::Base; use crate::{ allocator::Shared, paging::PageEncryption, zero_page::ZeroPage, BootAllocator, BOOT_ALLOC, }; @@ -64,7 +62,8 @@ impl Ghcb { } pub fn init(&self, alloc: &'static BootAllocator) { - let ghcb = Shared::leak(Shared::new_in(oak_sev_guest::ghcb::Ghcb::default(), alloc)); + let ghcb = + Shared::leak(Shared::<_, _, Sev>::new_in(oak_sev_guest::ghcb::Ghcb::default(), alloc)); ghcb.reset(); // We can't use `.expect()` here as Spinlock doesn't implement `fmt::Debug`. @@ -96,7 +95,7 @@ impl Ghcb { /// after the function returns. pub unsafe fn deinit(&self, alloc: &'static BootAllocator) { let ghcb = self.ghcb.deinit().unwrap().into_inner().into_inner(); - let _ = Shared::from_raw_in(ghcb, alloc); + let _ = Shared::<_, _, Sev>::from_raw_in(ghcb, alloc); } pub fn get( @@ -125,6 +124,16 @@ fn sev_status() -> SevStatus { unsafe { SEV_STATUS } } +/// Returns the location of the ENCRYPTED bit when running under AMD SEV. +pub(crate) fn encrypted() -> u64 { + #[no_mangle] + static mut ENCRYPTED: u64 = 0; + + // Safety: we don't allow mutation and this is initialized in the bootstrap + // assembly. + unsafe { ENCRYPTED } +} + pub struct Sev {} impl crate::Platform for Sev { @@ -194,109 +203,144 @@ impl crate::Platform for Sev { Ok(()) } } -} -pub fn early_initialize_platform() { - // If we're under SEV-ES or SNP, we need a GHCB block for communication (SNP - // implies SEV-ES). - if sev_status().contains(SevStatus::SEV_ES_ENABLED) { - GHCB_WRAPPER.init(&BOOT_ALLOC); + fn early_initialize_platform() { + // If we're under SEV-ES or SNP, we need a GHCB block for communication (SNP + // implies SEV-ES). + if sev_status().contains(SevStatus::SEV_ES_ENABLED) { + GHCB_WRAPPER.init(&BOOT_ALLOC); + } + if sev_status().contains(SevStatus::SEV_ENABLED) { + // Safety: This is safe for SEV-ES and SNP because we're using an originally + // supported mode of the Pentium 6: Write-protect, with MTRR enabled. + // If we get CPUID reads working, we may want to check that MTRR is + // supported, but only if we want to support very old processors. + // However, note that, this branch is only executed if + // we have encryption, and this wouldn't be true for very old processors. + unsafe { + crate::msr::MTRRDefType::write::( + crate::msr::MTRRDefTypeFlags::MTRR_ENABLE, + crate::msr::MemoryType::WP, + ); + } + } + } + + fn initialize_platform(e820_table: &[BootE820Entry]) { + log::info!("Enabled SEV features: {:?}", sev_status()); + if sev_status().contains(SevStatus::SNP_ACTIVE) { + dice_attestation::init_guest_message_encryptor() + .expect("couldn't initialize guest message encryptor"); + accept_memory::validate_memory(e820_table) + } + + // Register the AP Jump Table, if required. + if sev_status().contains(SevStatus::SEV_ES_ENABLED) { + // This assumes identity mapping. Which we have in stage0. + let jump_table_pa = AP_JUMP_TABLE.as_ptr() as u64; + if sev_status().contains(SevStatus::SNP_ACTIVE) { + // Under SNP we need to place the jump table address in the secrets page. + // Safety: we don't care about the contents of the secrets page beyond writing + // our jump table address into it. + let secrets = unsafe { SEV_SECRETS.assume_init_mut() }; + secrets.guest_area_0.ap_jump_table_pa = jump_table_pa; + } else { + // Plain old SEV-ES, use the GHCB protocol. + if let Some(mut ghcb) = GHCB_WRAPPER.get() { + ghcb.set_ap_jump_table(PhysAddr::new(jump_table_pa)) + .expect("failed to set AP Jump Table"); + } + } + } } - if sev_status().contains(SevStatus::SEV_ENABLED) { - // Safety: This is safe for SEV-ES and SNP because we're using an originally - // supported mode of the Pentium 6: Write-protect, with MTRR enabled. - // If we get CPUID reads working, we may want to check that MTRR is - // supported, but only if we want to support very old processors. - // However, note that, this branch is only executed if - // we have encryption, and this wouldn't be true for very old processors. - unsafe { - crate::msr::MTRRDefType::write( - crate::msr::MTRRDefTypeFlags::MTRR_ENABLE, - crate::msr::MemoryType::WP, - ); + + fn populate_zero_page(zero_page: &mut ZeroPage) { + if sev_status().contains(SevStatus::SNP_ACTIVE) { + // Safety: we're only interested in the pointer value of SEV_SECRETS, not its + // contents. + let cc_blob = Box::leak(Box::new_in( + oak_linux_boot_params::CCBlobSevInfo::new( + unsafe { SEV_SECRETS.as_ptr() }, + SEV_CPUID.as_ptr(), + ), + &BOOT_ALLOC, + )); + let setup_data = Box::leak(Box::new_in( + oak_linux_boot_params::CCSetupData::new(cc_blob), + &BOOT_ALLOC, + )); + + zero_page.add_setup_data(setup_data); } } -} -pub fn initialize_platform(e820_table: &[BootE820Entry]) { - log::info!("Enabled SEV features: {:?}", sev_status()); - if sev_status().contains(SevStatus::SNP_ACTIVE) { - dice_attestation::init_guest_message_encryptor() - .expect("couldn't initialize guest message encryptor"); - accept_memory::validate_memory(e820_table) + fn deinit_platform() { + if sev_status().contains(SevStatus::SNP_ACTIVE) && GHCB_WRAPPER.get().is_some() { + // Safety: we're in the last moments of stage0 and nobody should access the GHCB + // beyond this point. + unsafe { GHCB_WRAPPER.deinit(&BOOT_ALLOC) }; + } } - // Register the AP Jump Table, if required. - if sev_status().contains(SevStatus::SEV_ES_ENABLED) { - // This assumes identity mapping. Which we have in stage0. - let jump_table_pa = AP_JUMP_TABLE.as_ptr() as u64; + fn tee_platform() -> TeePlatform { if sev_status().contains(SevStatus::SNP_ACTIVE) { - // Under SNP we need to place the jump table address in the secrets page. - // Safety: we don't care about the contents of the secrets page beyond writing - // our jump table address into it. - let secrets = unsafe { SEV_SECRETS.assume_init_mut() }; - secrets.guest_area_0.ap_jump_table_pa = jump_table_pa; + TeePlatform::AmdSevSnp } else { - // Plain old SEV-ES, use the GHCB protocol. - if let Some(mut ghcb) = GHCB_WRAPPER.get() { - ghcb.set_ap_jump_table(PhysAddr::new(jump_table_pa)) - .expect("failed to set AP Jump Table"); + TeePlatform::None + } + } + + fn page_table_mask(encryption_state: PageEncryption) -> u64 { + if sev_status().contains(SevStatus::SEV_ENABLED) { + match encryption_state { + PageEncryption::Encrypted => encrypted(), + PageEncryption::Unencrypted => 0, } + } else { + 0 } } -} -pub fn populate_zero_page(zero_page: &mut ZeroPage) { - if sev_status().contains(SevStatus::SNP_ACTIVE) { - // Safety: we're only interested in the pointer value of SEV_SECRETS, not its - // contents. - let cc_blob = Box::leak(Box::new_in( - oak_linux_boot_params::CCBlobSevInfo::new( - unsafe { SEV_SECRETS.as_ptr() }, - SEV_CPUID.as_ptr(), - ), - &BOOT_ALLOC, - )); - let setup_data = - Box::leak(Box::new_in(oak_linux_boot_params::CCSetupData::new(cc_blob), &BOOT_ALLOC)); - - zero_page.add_setup_data(setup_data); + fn get_attestation( + report_data: [u8; oak_sev_snp_attestation_report::REPORT_DATA_SIZE], + ) -> Result { + dice_attestation::get_attestation(report_data) } -} -pub fn deinit_platform() { - if sev_status().contains(SevStatus::SNP_ACTIVE) && GHCB_WRAPPER.get().is_some() { - // Safety: we're in the last moments of stage0 and nobody should access the GHCB - // beyond this point. - unsafe { GHCB_WRAPPER.deinit(&BOOT_ALLOC) }; + fn get_derived_key() -> Result { + dice_attestation::get_derived_key() } -} -pub fn tee_platform() -> TeePlatform { - if sev_status().contains(SevStatus::SNP_ACTIVE) { - TeePlatform::AmdSevSnp - } else { - TeePlatform::None + fn change_page_state( + page: x86_64::structures::paging::Page, + state: oak_sev_guest::msr::PageAssignment, + ) { + accept_memory::change_page_state(page, state).expect("failed to change page state"); } -} -/// Returns the location of the ENCRYPTED bit when running under AMD SEV. -pub(crate) fn encrypted() -> u64 { - #[no_mangle] - static mut ENCRYPTED: u64 = 0; + fn revalidate_page( + page: x86_64::structures::paging::Page, + ) { + accept_memory::revalidate_page(page).expect("failed to revalidate memory"); + } - // Safety: we don't allow mutation and this is initialized in the bootstrap - // assembly. - unsafe { ENCRYPTED } -} + fn encrypted() -> u64 { + encrypted() + } + + unsafe fn read_msr(msr_id: u32) -> u64 { + if let Some(mut ghcb) = GHCB_WRAPPER.get() { + ghcb.msr_read(msr_id).expect("couldn't read the MSR using the GHCB protocol") + } else { + Base::read_msr(msr_id) + } + } -pub fn page_table_mask(encryption_state: PageEncryption) -> u64 { - if sev_status().contains(SevStatus::SEV_ENABLED) { - match encryption_state { - PageEncryption::Encrypted => encrypted(), - PageEncryption::Unencrypted => 0, + unsafe fn write_msr(msr_id: u32, val: u64) { + if let Some(mut ghcb) = GHCB_WRAPPER.get() { + ghcb.msr_write(msr_id, val).expect("couldn't write the MSR using the GHCB protocol") + } else { + Base::write_msr(msr_id, val) } - } else { - 0 } } diff --git a/stage0/src/hal/sev/msr.rs b/stage0/src/hal/sev/msr.rs deleted file mode 100644 index 5db7e324a03..00000000000 --- a/stage0/src/hal/sev/msr.rs +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright 2024 The Project Oak Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -use super::GHCB_WRAPPER; - -/// Read a MSR. -/// -/// ## Safety -/// -/// The caller must guarantee that the MSR is valid. -pub unsafe fn read_msr(msr: &crate::hal::base::Msr, msr_id: u32) -> u64 { - if let Some(mut ghcb) = GHCB_WRAPPER.get() { - ghcb.msr_read(msr_id).expect("couldn't read the MSR using the GHCB protocol") - } else { - msr.read() - } -} - -/// Write to a MSR. -/// -/// ## Safety -/// -/// The caller must guarantee that the MSR is valid. -pub unsafe fn write_msr(msr: &mut crate::hal::base::Msr, msr_id: u32, val: u64) { - if let Some(mut ghcb) = GHCB_WRAPPER.get() { - ghcb.msr_write(msr_id, val).expect("couldn't write the MSR using the GHCB protocol") - } else { - msr.write(val) - } -} diff --git a/stage0/src/initramfs.rs b/stage0/src/initramfs.rs index 5eaeef9670f..0c1540e2d8e 100644 --- a/stage0/src/initramfs.rs +++ b/stage0/src/initramfs.rs @@ -31,8 +31,8 @@ const INITIAL_RAM_DISK_FILE_PATH: &[u8] = b"opt/stage0/initramfs\0"; /// /// If it finds a RAM disk it returns the byte slice where it is loaded. If not /// it returns `None`. -pub fn try_load_initial_ram_disk( - fw_cfg: &mut FwCfg, +pub fn try_load_initial_ram_disk( + fw_cfg: &mut FwCfg

, e820_table: &[BootE820Entry], kernel_info: &KernelInfo, ) -> Option<&'static [u8]> { diff --git a/stage0/src/kernel.rs b/stage0/src/kernel.rs index 34e5b78635d..a1c5f3a5061 100644 --- a/stage0/src/kernel.rs +++ b/stage0/src/kernel.rs @@ -87,7 +87,7 @@ impl Default for KernelInfo { /// /// We first try to read it using the traditional selector. If it is not /// available there we try to read it using a custom file path. -pub fn try_load_cmdline(fw_cfg: &mut FwCfg) -> Option { +pub fn try_load_cmdline(fw_cfg: &mut FwCfg

) -> Option { let (cmdline_file, buffer_size) = if let Some(cmdline_file) = fw_cfg.get_cmdline_file() { // The provided value is already null-terminated. let size = cmdline_file.size(); @@ -124,8 +124,8 @@ pub fn try_load_cmdline(fw_cfg: &mut FwCfg) -> Option { /// /// If it finds a kernel it returns the information about the kernel, otherwise /// `None`. -pub fn try_load_kernel_image( - fw_cfg: &mut FwCfg, +pub fn try_load_kernel_image( + fw_cfg: &mut FwCfg

, e820_table: &[BootE820Entry], ) -> Option { let (file, bzimage) = if let Some(file) = fw_cfg.get_kernel_file() { diff --git a/stage0/src/lib.rs b/stage0/src/lib.rs index 44e17bf94d6..393bc89ae30 100644 --- a/stage0/src/lib.rs +++ b/stage0/src/lib.rs @@ -63,6 +63,7 @@ mod zero_page; pub use hal::Platform; #[cfg(feature = "sev")] pub use hal::Sev; +pub use zero_page::ZeroPage; type Measurement = [u8; 32]; @@ -124,20 +125,19 @@ pub unsafe fn jump_to_kernel( /// * `encrypted` - If not zero, the `encrypted`-th bit will be set in the page /// tables. pub fn rust64_start() -> ! { - paging::init_page_table_refs(); - hal::early_initialize_platform(); + paging::init_page_table_refs::

(); + P::early_initialize_platform(); logging::init_logging::

(); log::info!("starting..."); // Safety: we assume there won't be any other hardware devices using the fw_cfg // IO ports. - let mut fwcfg = - unsafe { fw_cfg::FwCfg::new::

(&BOOT_ALLOC) }.expect("fw_cfg device not found!"); + let mut fwcfg = unsafe { fw_cfg::FwCfg::new(&BOOT_ALLOC) }.expect("fw_cfg device not found!"); let mut zero_page = Box::new_in(zero_page::ZeroPage::new(), &BOOT_ALLOC); zero_page.fill_e820_table::

(&mut fwcfg); - hal::initialize_platform(zero_page.e820_table()); + P::initialize_platform(zero_page.e820_table()); /* Set up the machine according to the 64-bit Linux boot protocol. * See https://www.kernel.org/doc/html/latest/x86/boot.html#id1 for the particular requirements. @@ -162,7 +162,7 @@ pub fn rust64_start() -> ! { create_idt(idt); idt.load(); - paging::map_additional_memory(); + paging::map_additional_memory::

(); // Initialize the short-term heap. Any allocations that rely on a global // allocator before this point will fail. @@ -171,7 +171,7 @@ pub fn rust64_start() -> ! { let setup_data_sha2_256_digest = zero_page.try_fill_hdr_from_setup_data(&mut fwcfg).unwrap_or_default(); - hal::populate_zero_page(&mut zero_page); + P::populate_zero_page(&mut zero_page); let cmdline = kernel::try_load_cmdline(&mut fwcfg).unwrap_or_default(); let cmdline_sha2_256_digest = cmdline.measure(); @@ -262,13 +262,13 @@ pub fn rust64_start() -> ! { eventlog_sha2_256_digest, }; - let tee_platform = hal::tee_platform(); + let tee_platform = P::tee_platform(); let dice_data = Box::leak(Box::new_in( oak_stage0_dice::generate_dice_data( &measurements, - hal::get_attestation, - hal::get_derived_key, + P::get_attestation, + P::get_derived_key, tee_platform, ), &crate::BOOT_ALLOC, @@ -321,8 +321,8 @@ pub fn rust64_start() -> ! { // After the call to `deinit_platform`: // - Do not log anything any more. // - Do not allocate memory. - hal::deinit_platform(); - paging::remap_first_huge_page(); + P::deinit_platform(); + paging::remap_first_huge_page::

(); unsafe { jump_to_kernel(entry, zero_page); diff --git a/stage0/src/msr.rs b/stage0/src/msr.rs index c54ff8fb712..646a36fcd6c 100644 --- a/stage0/src/msr.rs +++ b/stage0/src/msr.rs @@ -18,7 +18,7 @@ use bitflags::bitflags; use strum::FromRepr; use x86_64::PhysAddr; -use crate::hal::Msr; +use crate::{hal::Msr, Platform}; bitflags! { /// Flags in the APIC Base Address Register (MSR 0x1B) @@ -52,24 +52,24 @@ pub struct ApicBase; impl ApicBase { const MSR: Msr = Msr::new(0x0000_001B); - fn write_raw(value: u64) { + fn write_raw(value: u64) { let mut msr = Self::MSR; // Safety: the APIC base register is supported in all modern CPUs. - unsafe { msr.write(value) } + unsafe { msr.write::

(value) } } /// Returns the APIC Base Address and flags. - pub fn read() -> (PhysAddr, ApicBaseFlags) { + pub fn read() -> (PhysAddr, ApicBaseFlags) { // Safety: the APIC base register is supported in all modern CPUs. - let val = unsafe { Self::MSR.read() }; + let val = unsafe { Self::MSR.read::

() }; let aba = PhysAddr::new(val & 0x000F_FFFF_FFFF_F000u64); let flags = ApicBaseFlags::from_bits_truncate(val); (aba, flags) } - pub fn write(aba: PhysAddr, flags: ApicBaseFlags) { - Self::write_raw(flags.bits() | aba.as_u64()); + pub fn write(aba: PhysAddr, flags: ApicBaseFlags) { + Self::write_raw::

(flags.bits() | aba.as_u64()); } } @@ -113,12 +113,12 @@ impl MTRRDefType { // The underlying model specific register. const MSR: Msr = Msr::new(0x0000_02FF); - pub fn read() -> (MTRRDefTypeFlags, MemoryType) { + pub fn read() -> (MTRRDefTypeFlags, MemoryType) { // If the GHCB is available we are running on SEV-ES or SEV-SNP, so we use the // GHCB protocol to read the MSR, otherwise we read the MSR directly. // Safety: This is safe because this MSR has been supported since the P6 family // of Pentium processors (see https://en.wikipedia.org/wiki/Memory_type_range_register). - let msr_value = unsafe { Self::MSR.read() }; + let msr_value = unsafe { Self::MSR.read::

() }; let memory_type: MemoryType = (msr_value as u8).try_into().expect("invalid MemoryType value"); (MTRRDefTypeFlags::from_bits_truncate(msr_value), memory_type) @@ -143,13 +143,13 @@ impl MTRRDefType { /// When called with MTRRDefType::MTRR_ENABLE and MemoryType::WP, this /// operation is safe because this specific MSR and mode has been /// supported since the P6 family of Pentium processors (see ). - pub unsafe fn write(flags: MTRRDefTypeFlags, default_type: MemoryType) { + pub unsafe fn write(flags: MTRRDefTypeFlags, default_type: MemoryType) { // Preserve values of reserved bits. - let (old_flags, _old_memory_type) = Self::read(); + let (old_flags, _old_memory_type) = Self::read::

(); let reserved = old_flags.bits() & !MTRRDefTypeFlags::all().bits(); let new_value = reserved | flags.bits() | (default_type as u64); let mut msr = Self::MSR; - msr.write(new_value); + msr.write::

(new_value); } } @@ -165,8 +165,8 @@ pub struct X2ApicIdRegister; impl X2ApicIdRegister { const MSR: Msr = Msr::new(0x0000_00802); - pub unsafe fn apic_id() -> u32 { - (Self::MSR.read() & 0xFFFF_FFFF) as u32 + pub unsafe fn apic_id() -> u32 { + (Self::MSR.read::

() & 0xFFFF_FFFF) as u32 } } @@ -178,8 +178,8 @@ impl X2ApicVersionRegister { } impl X2ApicVersionRegister { - pub unsafe fn read() -> (bool, u8, u8) { - let val = Self::MSR.read(); + pub unsafe fn read() -> (bool, u8, u8) { + let val = Self::MSR.read::

(); ( val & (1 << 31) > 0, // EAS @@ -211,17 +211,17 @@ impl X2ApicSpuriousInterruptRegister { } impl X2ApicSpuriousInterruptRegister { - pub unsafe fn read() -> (SpuriousInterruptFlags, u8) { - let val = Self::MSR.read(); + pub unsafe fn read() -> (SpuriousInterruptFlags, u8) { + let val = Self::MSR.read::

(); (SpuriousInterruptFlags::from_bits_truncate((val & 0xFFFF_FF00) as u32), (val & 0xFF) as u8) } - pub unsafe fn write(flags: SpuriousInterruptFlags, vec: u8) { + pub unsafe fn write(flags: SpuriousInterruptFlags, vec: u8) { // Safety: we've estabished we're using x2APIC, so accessing the MSR is safe. let val = flags.bits() as u64 | vec as u64; let mut msr = Self::MSR; - unsafe { msr.write(val) }; + unsafe { msr.write::

(val) }; } } @@ -267,18 +267,18 @@ impl X2ApicErrorStatusRegister { impl X2ApicErrorStatusRegister { #[allow(unused)] - pub unsafe fn read() -> ApicErrorFlags { - let val = Self::MSR.read(); + pub unsafe fn read() -> ApicErrorFlags { + let val = Self::MSR.read::

(); ApicErrorFlags::from_bits_truncate(val.try_into().unwrap()) } - pub unsafe fn write(val: ApicErrorFlags) { + pub unsafe fn write(val: ApicErrorFlags) { let mut msr = Self::MSR; - msr.write(val.bits() as u64) + msr.write::

(val.bits() as u64) } - pub unsafe fn clear() { - Self::write(ApicErrorFlags::empty()) + pub unsafe fn clear() { + Self::write::

(ApicErrorFlags::empty()) } } @@ -382,7 +382,7 @@ pub struct X2ApicInterruptCommandRegister; impl X2ApicInterruptCommandRegister { const MSR: Msr = Msr::new(0x0000_00830); - pub unsafe fn send( + pub unsafe fn send( vec: u8, mt: MessageType, dm: DestinationMode, @@ -400,6 +400,6 @@ impl X2ApicInterruptCommandRegister { value |= vec as u64; let mut msr = Self::MSR; - unsafe { msr.write(value) } + unsafe { msr.write::

(value) } } } diff --git a/stage0/src/paging.rs b/stage0/src/paging.rs index ab217d46132..5fc27f1d61f 100644 --- a/stage0/src/paging.rs +++ b/stage0/src/paging.rs @@ -32,7 +32,7 @@ use x86_64::{ PhysAddr, }; -use crate::{BootAllocator, BOOT_ALLOC}; +use crate::{BootAllocator, Platform, BOOT_ALLOC}; pub static mut PML4: PageTable = PageTable::new(); pub static mut PDPT: PageTable = PageTable::new(); @@ -123,14 +123,19 @@ pub struct PageTableEntry(BasePageTableEntry); impl PageTableEntry { /// Map the entry to the specified address with the specified flags and /// encryption state. - pub fn set_address(&mut self, addr: PhysAddr, flags: PageTableFlags, state: PageEncryption) { - let addr = PhysAddr::new(addr.as_u64() | crate::hal::page_table_mask(state)); + pub fn set_address( + &mut self, + addr: PhysAddr, + flags: PageTableFlags, + state: PageEncryption, + ) { + let addr = PhysAddr::new(addr.as_u64() | P::page_table_mask(state)); self.0.set_addr(addr, flags); } /// Returns the physical address mapped by this entry. May be zero. - pub fn address(&self) -> PhysAddr { - PhysAddr::new(self.0.addr().as_u64() & !crate::hal::encrypted()) + pub fn address(&self) -> PhysAddr { + PhysAddr::new(self.0.addr().as_u64() & !P::encrypted()) } /// Returns whether the entry is zero. @@ -172,7 +177,7 @@ pub enum PageEncryption { } /// Initialises the page table references. -pub fn init_page_table_refs() { +pub fn init_page_table_refs() { // Safety: accessing the mutable statics here is safe since we only do it once // and protect the mutable references with a mutex. This function can only // be called once, since updating `PAGE_TABLE_REFS` twice will panic. @@ -186,13 +191,13 @@ pub fn init_page_table_refs() { // using an identity mapping between virtual and physical addresses. let mut pt_0 = Box::new_in(PageTable::new(), &BOOT_ALLOC); pt_0.iter_mut().enumerate().skip(1).for_each(|(i, entry)| { - entry.set_address( + entry.set_address::

( PhysAddr::new((i as u64) * Size4KiB::SIZE), PageTableFlags::PRESENT | PageTableFlags::WRITABLE, PageEncryption::Encrypted, ); }); - pd_0[0].set_address( + pd_0[0].set_address::

( PhysAddr::new(pt_0.as_ref() as *const _ as usize as u64), PageTableFlags::PRESENT | PageTableFlags::WRITABLE, PageEncryption::Encrypted, @@ -209,12 +214,12 @@ pub fn init_page_table_refs() { /// Maps the first 1GiB of memory using 2MiB hugepages, except for the first /// 2MiB that was already mapped as 512 4KiB pages. -pub fn map_additional_memory() { +pub fn map_additional_memory() { { let mut page_tables = PAGE_TABLE_REFS.get().expect("page tables not initiallized").lock(); let pd = &mut page_tables.pd_0; pd.iter_mut().enumerate().skip(1).for_each(|(i, entry)| { - entry.set_address( + entry.set_address::

( PhysAddr::new((i as u64) * Size2MiB::SIZE), PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::HUGE_PAGE, PageEncryption::Encrypted, @@ -227,12 +232,12 @@ pub fn map_additional_memory() { // Remaps the first 2MiB of memory, which was previously mapped as 512 4KiB // pages, as a single 2MiB huge page again. -pub fn remap_first_huge_page() { +pub fn remap_first_huge_page() { { let mut page_tables = PAGE_TABLE_REFS.get().expect("page tables not initiallized").lock(); let pd = &mut page_tables.pd_0; - pd[0].set_address( + pd[0].set_address::

( PhysAddr::new(0x0), PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::HUGE_PAGE, PageEncryption::Encrypted, @@ -243,7 +248,7 @@ pub fn remap_first_huge_page() { } /// Shares a single 4KiB page with the hypervisor. -pub fn share_page(page: Page) { +pub fn share_page(page: Page) { let page_start = page.start_address().as_u64(); // Only the first 2MiB is mapped as 4KiB pages, so make sure we fall in that // range. @@ -252,7 +257,7 @@ pub fn share_page(page: Page) { { let mut page_tables = crate::paging::PAGE_TABLE_REFS.get().unwrap().lock(); let pt = &mut page_tables.pt_0; - pt[page.p1_index()].set_address( + pt[page.p1_index()].set_address::

( PhysAddr::new(page_start), PageTableFlags::PRESENT | PageTableFlags::WRITABLE, PageEncryption::Unencrypted, @@ -260,22 +265,22 @@ pub fn share_page(page: Page) { } flush_all(); - crate::hal::change_page_state(page, PageAssignment::Shared); + P::change_page_state(page, PageAssignment::Shared); } /// Stops sharing a single 4KiB page with the hypervisor when running with AMD /// SEV-SNP enabled. -pub fn unshare_page(page: Page) { +pub fn unshare_page(page: Page) { let page_start = page.start_address().as_u64(); // Only the first 2MiB is mapped as 4KiB pages, so make sure we fall in that // range. assert!(page_start < Size2MiB::SIZE); - crate::hal::change_page_state(page, PageAssignment::Private); + P::change_page_state(page, PageAssignment::Private); // Mark the page as encrypted. { let mut page_tables = crate::paging::PAGE_TABLE_REFS.get().unwrap().lock(); let pt = &mut page_tables.pt_0; - pt[page.p1_index()].set_address( + pt[page.p1_index()].set_address::

( PhysAddr::new(page_start), PageTableFlags::PRESENT | PageTableFlags::WRITABLE, PageEncryption::Encrypted, @@ -284,5 +289,5 @@ pub fn unshare_page(page: Page) { flush_all(); // We have to revalidate the page again after un-sharing it. - crate::hal::revalidate_page(page); + P::revalidate_page(page); } diff --git a/stage0/src/smp.rs b/stage0/src/smp.rs index dc1171a2589..0745e3a0c6e 100644 --- a/stage0/src/smp.rs +++ b/stage0/src/smp.rs @@ -26,6 +26,7 @@ use crate::{ acpi_tables::{LocalApicFlags, Madt, ProcessorLocalApic, ProcessorLocalX2Apic, Rsdp}, apic::Lapic, pic::disable_pic8259, + Platform, }; extern "C" { @@ -40,11 +41,11 @@ extern "C" { #[link_section = ".ap_bss"] static LIVE_AP_COUNT: AtomicU32 = AtomicU32::new(0); -pub fn start_ap>( - lapic: &mut Lapic, +pub fn start_ap( + lapic: &mut Lapic>, physical_apic_id: u32, ) -> Result<(), &'static str> { - lapic.send_init_ipi(physical_apic_id)?; + lapic.send_init_ipi::

(physical_apic_id)?; // TODO(#4235): wait 10 ms. The numbers chosen here are arbitrary and have no // connection to actual seconds. for _ in 1..(1 << 15) { @@ -58,7 +59,7 @@ pub fn start_ap>( // Safety: we're not going to dereference the memory, we're just interested in // the pointer value. let vector = unsafe { &AP_START as *const _ as u64 }; - lapic.send_startup_ipi(physical_apic_id, PhysAddr::new(vector))?; + lapic.send_startup_ipi::

(physical_apic_id, PhysAddr::new(vector))?; // TODO(#4235): wait 200 us (instead of _some_ unknown amount of time); send // SIPI again if the core hasn't started for _ in 1..(1 << 20) { @@ -77,7 +78,7 @@ pub fn start_ap>( } // TODO(#4235): Bootstrap the APs. -pub fn bootstrap_aps(rsdp: &Rsdp) -> Result<(), &'static str> { +pub fn bootstrap_aps(rsdp: &Rsdp) -> Result<(), &'static str> { // If XSDT exists, then per ACPI spec we have to prefer that. If it doesn't, see // if we can use the old RSDT. (If we have neither XSDT or RSDT, the ACPI // tables are broken.) @@ -132,7 +133,7 @@ pub fn bootstrap_aps(rsdp: &Rsdp) -> Result<(), &'stati } expected_aps += 1; - start_ap(&mut lapic, remote_lapic_id)?; + start_ap::

(&mut lapic, remote_lapic_id)?; } // Wait until all APs have told they are online. Or we time out waiting for diff --git a/stage0/src/zero_page.rs b/stage0/src/zero_page.rs index 84e29f02372..3740c567b94 100644 --- a/stage0/src/zero_page.rs +++ b/stage0/src/zero_page.rs @@ -71,7 +71,10 @@ impl ZeroPage { /// /// Returns the measurement (SHA2-384 digest) of the setup data if it was /// found, otherwise the measurement is all zeros. - pub fn try_fill_hdr_from_setup_data(&mut self, fw_cfg: &mut FwCfg) -> Option<[u8; 32]> { + pub fn try_fill_hdr_from_setup_data( + &mut self, + fw_cfg: &mut FwCfg

, + ) -> Option<[u8; 32]> { let file = fw_cfg.get_setup_file()?; let size = file.size(); // We temporarily copy the setup data to the end of available mapped virtual @@ -117,7 +120,7 @@ impl ZeroPage { /// /// We first try to read "etc/e820" via the QEMU fw_cfg interface, and if /// that is not available, fall back to querying RTC NVRAM. - pub fn fill_e820_table(&mut self, fw_cfg: &mut FwCfg) { + pub fn fill_e820_table(&mut self, fw_cfg: &mut FwCfg

) { // Try to load the E820 table from fw_cfg. // Safety: BootE820Entry has the same structure as what qemu uses, and we're // limiting ourselves to up to 128 entries. diff --git a/stage0_bin_tdx/Cargo.lock b/stage0_bin_tdx/Cargo.lock index 92ef314a33b..1bd29911d28 100644 --- a/stage0_bin_tdx/Cargo.lock +++ b/stage0_bin_tdx/Cargo.lock @@ -612,6 +612,10 @@ dependencies = [ name = "oak_stage0_bin_tdx" version = "0.1.0" dependencies = [ + "oak_dice", + "oak_linux_boot_params", + "oak_sev_guest", + "oak_sev_snp_attestation_report", "oak_stage0", "oak_tdx_guest", "x86_64", diff --git a/stage0_bin_tdx/Cargo.toml b/stage0_bin_tdx/Cargo.toml index c4947bb1e21..5080a1e1680 100644 --- a/stage0_bin_tdx/Cargo.toml +++ b/stage0_bin_tdx/Cargo.toml @@ -10,6 +10,10 @@ resolver = "2" members = ["."] [dependencies] +oak_dice = { path = "../oak_dice" } +oak_linux_boot_params = { path = "../oak_linux_boot_params" } +oak_sev_guest = { path = "../oak_sev_guest" } +oak_sev_snp_attestation_report = { path = "../oak_sev_snp_attestation_report" } oak_stage0 = { path = "../stage0" } oak_tdx_guest = { path = "../oak_tdx_guest" } x86_64 = "*" diff --git a/stage0_bin_tdx/src/main.rs b/stage0_bin_tdx/src/main.rs index b73d9b30bf9..9407e043d51 100644 --- a/stage0_bin_tdx/src/main.rs +++ b/stage0_bin_tdx/src/main.rs @@ -146,6 +146,52 @@ impl oak_stage0::Platform for Tdx { unsafe fn write_u32_to_port(_: u16, _: u32) -> Result<(), &'static str> { todo!() } + + fn early_initialize_platform() { + todo!() + } + fn initialize_platform(_: &[oak_linux_boot_params::BootE820Entry]) { + todo!() + } + fn deinit_platform() { + todo!() + } + fn populate_zero_page(_: &mut oak_stage0::ZeroPage) { + todo!() + } + fn get_attestation( + _: [u8; 64], + ) -> Result { + todo!() + } + fn get_derived_key() -> Result<[u8; 32], &'static str> { + todo!() + } + fn change_page_state( + _: x86_64::structures::paging::Page, + _: oak_sev_guest::msr::PageAssignment, + ) { + todo!() + } + fn revalidate_page(_: x86_64::structures::paging::Page) { + todo!() + } + fn page_table_mask(_: oak_stage0::paging::PageEncryption) -> u64 { + todo!() + } + fn encrypted() -> u64 { + todo!() + } + fn tee_platform() -> oak_dice::evidence::TeePlatform { + todo!() + } + unsafe fn read_msr(_: u32) -> u64 { + todo!() + } + + unsafe fn write_msr(_: u32, _: u64) { + todo!() + } } /// Entry point for the Rust code in the stage0 BIOS.