-
Notifications
You must be signed in to change notification settings - Fork 48
Initial implementation of supervisor #1385
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
kuqin12
wants to merge
7
commits into
OpenDevicePartnership:feature/supv
Choose a base branch
from
kuqin12:supv_init
base: feature/supv
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
e530b23
Add the mm_services
kuqin12 54fe81f
[supv] save state support for supv
kuqin12 b7dd466
[supv] supv syscall index definitions
kuqin12 f6559ed
[supv] supervisor core changes
kuqin12 895d40e
[user] user module changes
kuqin12 bb00083
[supv] cargo changes
kuqin12 221a7a5
default sdk/patina/Cargo.toml
kuqin12 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,3 +15,4 @@ | |
| pub mod cpu; | ||
| pub mod interrupts; | ||
| pub mod paging; | ||
| pub mod save_state; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,355 @@ | ||
| //! SMRAM Save State Architecture Definitions | ||
| //! | ||
| //! Provides platform-independent types and feature-gated vendor-specific | ||
| //! register maps for reading the SMRAM save state area. | ||
| //! | ||
| //! ## Vendor Selection | ||
| //! | ||
| //! The active vendor is selected at **build time** via Cargo features on the | ||
| //! `patina_internal_cpu` crate: | ||
| //! | ||
| //! - `save_state_intel` — Intel x64 SMRAM save state map. | ||
| //! - `save_state_amd` — AMD64 SMRAM save state map. | ||
| //! | ||
| //! Exactly one must be enabled. Re-exported items are available through the | ||
| //! `register_info()` function, which resolves to the active vendor's lookup at | ||
| //! compile time. | ||
| //! | ||
| //! ## Overview | ||
| //! | ||
| //! The common types (`MmSaveStateRegister`, `RegisterInfo`, etc.) are always | ||
| //! available. The vendor modules contain only the register-to-offset lookup | ||
| //! table and any vendor-specific constants (e.g. IO trap field layout). | ||
| //! | ||
| //! ## License | ||
| //! | ||
| //! Copyright (c) Microsoft Corporation. | ||
| //! | ||
| //! SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| // Vendor-specific submodules — exactly one is compiled in. | ||
| #[cfg(feature = "save_state_intel")] | ||
| pub mod intel; | ||
|
|
||
| #[cfg(feature = "save_state_amd")] | ||
| pub mod amd; | ||
|
|
||
| /// `EFI_MM_SAVE_STATE_REGISTER` values from the PI Specification. | ||
| /// | ||
| /// These correspond to the registers that can be read from the SMRAM save | ||
| /// state area via `EFI_MM_CPU_PROTOCOL.ReadSaveState()`. | ||
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| #[repr(u64)] | ||
| pub enum MmSaveStateRegister { | ||
| // Descriptor table bases | ||
| /// GDT base address. | ||
| GdtBase = 4, | ||
| /// IDT base address. | ||
| IdtBase = 5, | ||
| /// LDT base address. | ||
| LdtBase = 6, | ||
| /// GDT limit. | ||
| GdtLimit = 7, | ||
| /// IDT limit. | ||
| IdtLimit = 8, | ||
| /// LDT limit. | ||
| LdtLimit = 9, | ||
| /// LDT information. | ||
| LdtInfo = 10, | ||
|
|
||
| // Segment selectors | ||
| /// ES selector. | ||
| Es = 20, | ||
| /// CS selector. | ||
| Cs = 21, | ||
| /// SS selector. | ||
| Ss = 22, | ||
| /// DS selector. | ||
| Ds = 23, | ||
| /// FS selector. | ||
| Fs = 24, | ||
| /// GS selector. | ||
| Gs = 25, | ||
| /// LDTR selector. | ||
| LdtrSel = 26, | ||
| /// TR selector. | ||
| TrSel = 27, | ||
|
|
||
| // Debug registers | ||
| /// DR7. | ||
| Dr7 = 28, | ||
| /// DR6. | ||
| Dr6 = 29, | ||
|
|
||
| // Extended general-purpose registers (x86_64 only) | ||
| /// R8. | ||
| R8 = 30, | ||
| /// R9. | ||
| R9 = 31, | ||
| /// R10. | ||
| R10 = 32, | ||
| /// R11. | ||
| R11 = 33, | ||
| /// R12. | ||
| R12 = 34, | ||
| /// R13. | ||
| R13 = 35, | ||
| /// R14. | ||
| R14 = 36, | ||
| /// R15. | ||
| R15 = 37, | ||
|
|
||
| // General-purpose registers | ||
| /// RAX. | ||
| Rax = 38, | ||
| /// RBX. | ||
| Rbx = 39, | ||
| /// RCX. | ||
| Rcx = 40, | ||
| /// RDX. | ||
| Rdx = 41, | ||
| /// RSP. | ||
| Rsp = 42, | ||
| /// RBP. | ||
| Rbp = 43, | ||
| /// RSI. | ||
| Rsi = 44, | ||
| /// RDI. | ||
| Rdi = 45, | ||
| /// RIP. | ||
| Rip = 46, | ||
|
|
||
| // Flags and control registers | ||
| /// RFLAGS. | ||
| Rflags = 51, | ||
| /// CR0. | ||
| Cr0 = 52, | ||
| /// CR3. | ||
| Cr3 = 53, | ||
| /// CR4. | ||
| Cr4 = 54, | ||
|
|
||
| // Pseudo-registers | ||
| /// I/O operation information. | ||
| Io = 512, | ||
| /// Long Mode Active indicator. | ||
| Lma = 513, | ||
| /// Processor identifier (APIC ID). | ||
| ProcessorId = 514, | ||
| } | ||
|
|
||
| impl MmSaveStateRegister { | ||
| /// Creates a register from a raw `EFI_MM_SAVE_STATE_REGISTER` value. | ||
| pub fn from_u64(value: u64) -> Option<Self> { | ||
| match value { | ||
| 4 => Some(Self::GdtBase), | ||
| 5 => Some(Self::IdtBase), | ||
| 6 => Some(Self::LdtBase), | ||
| 7 => Some(Self::GdtLimit), | ||
| 8 => Some(Self::IdtLimit), | ||
| 9 => Some(Self::LdtLimit), | ||
| 10 => Some(Self::LdtInfo), | ||
| 20 => Some(Self::Es), | ||
| 21 => Some(Self::Cs), | ||
| 22 => Some(Self::Ss), | ||
| 23 => Some(Self::Ds), | ||
| 24 => Some(Self::Fs), | ||
| 25 => Some(Self::Gs), | ||
| 26 => Some(Self::LdtrSel), | ||
| 27 => Some(Self::TrSel), | ||
| 28 => Some(Self::Dr7), | ||
| 29 => Some(Self::Dr6), | ||
| 30 => Some(Self::R8), | ||
| 31 => Some(Self::R9), | ||
| 32 => Some(Self::R10), | ||
| 33 => Some(Self::R11), | ||
| 34 => Some(Self::R12), | ||
| 35 => Some(Self::R13), | ||
| 36 => Some(Self::R14), | ||
| 37 => Some(Self::R15), | ||
| 38 => Some(Self::Rax), | ||
| 39 => Some(Self::Rbx), | ||
| 40 => Some(Self::Rcx), | ||
| 41 => Some(Self::Rdx), | ||
| 42 => Some(Self::Rsp), | ||
| 43 => Some(Self::Rbp), | ||
| 44 => Some(Self::Rsi), | ||
| 45 => Some(Self::Rdi), | ||
| 46 => Some(Self::Rip), | ||
| 51 => Some(Self::Rflags), | ||
| 52 => Some(Self::Cr0), | ||
| 53 => Some(Self::Cr3), | ||
| 54 => Some(Self::Cr4), | ||
| 512 => Some(Self::Io), | ||
| 513 => Some(Self::Lma), | ||
| 514 => Some(Self::ProcessorId), | ||
| _ => None, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Size of [`MmSaveStateIoInfo`] in bytes. | ||
| pub const IO_INFO_SIZE: usize = 24; | ||
|
|
||
| /// `EFI_MM_SAVE_STATE_IO_TYPE_INPUT` (1). | ||
| pub const IO_TYPE_INPUT: u32 = 1; | ||
| /// `EFI_MM_SAVE_STATE_IO_TYPE_OUTPUT` (2). | ||
| pub const IO_TYPE_OUTPUT: u32 = 2; | ||
|
|
||
| /// `EFI_MM_SAVE_STATE_IO_WIDTH_UINT8` (0). | ||
| pub const IO_WIDTH_UINT8: u32 = 0; | ||
| /// `EFI_MM_SAVE_STATE_IO_WIDTH_UINT16` (1). | ||
| pub const IO_WIDTH_UINT16: u32 = 1; | ||
| /// `EFI_MM_SAVE_STATE_IO_WIDTH_UINT32` (2). | ||
| pub const IO_WIDTH_UINT32: u32 = 2; | ||
|
|
||
| /// IA32_EFER.LMA bit (bit 10). | ||
| pub const IA32_EFER_LMA: u64 = 1 << 10; | ||
|
|
||
| /// LMA value: processor was in 32-bit mode. | ||
| pub const LMA_32BIT: u64 = 32; | ||
| /// LMA value: processor was in 64-bit mode. | ||
| pub const LMA_64BIT: u64 = 64; | ||
|
|
||
| /// Size of one `EFI_PROCESSOR_INFORMATION` entry (PI 1.7+). | ||
| /// | ||
| /// Layout: `ProcessorId`(8) + `StatusFlag`(4) + `CpuPhysicalLocation`(12) + | ||
| /// `ExtendedProcessorInformation`(24) = 48 bytes. | ||
| pub const PROCESSOR_INFO_ENTRY_SIZE: usize = 48; | ||
|
|
||
| /// Layout descriptor for a register in the SMRAM save state map. | ||
| /// | ||
| /// For 8-byte registers the value may be stored as two dwords at potentially | ||
| /// non-contiguous offsets (e.g. Intel GDT/IDT/LDT base). `lo_offset` gives | ||
| /// the low dword; `hi_offset` gives the high dword. | ||
| /// | ||
| /// For registers narrower than 8 bytes, `hi_offset` is 0 and only the low | ||
| /// dword location is used. | ||
| #[derive(Debug, Clone, Copy)] | ||
| pub struct RegisterInfo { | ||
| /// Offset of the low (or only) dword from the save state base. | ||
| pub lo_offset: u16, | ||
| /// Offset of the high dword. 0 for registers < 8 bytes. | ||
| pub hi_offset: u16, | ||
| /// Native width in bytes as stored in the save state (1, 2, 4, or 8). | ||
| pub native_width: u8, | ||
| } | ||
|
|
||
| /// Vendor-specific save state field offsets and behaviour that differ between | ||
| /// Intel and AMD. Provided by the active vendor module. | ||
| pub struct VendorConstants { | ||
| /// Offset of `SMMRevId` within the save state map. | ||
| pub smmrevid_offset: u16, | ||
| /// Offset of the IO information field (Intel `IOMisc`, AMD `IO_DWord`). | ||
| pub io_info_offset: u16, | ||
| /// Offset of `IA32_EFER` / `EFER`. | ||
| pub efer_offset: u16, | ||
| /// Offset of `_RAX` (used for IO data reads). | ||
| pub rax_offset: u16, | ||
| /// Minimum `SMMRevId` that supports IO information. | ||
| pub min_rev_id_io: u32, | ||
| /// Whether the LMA pseudo-register always returns 64-bit. | ||
| /// | ||
| /// AMD64 processors always operate in 64-bit mode during SMM, so | ||
| /// they skip the EFER.LMA check and always return LMA_64BIT. | ||
| pub lma_always_64: bool, | ||
| } | ||
|
|
||
| /// Parsed I/O trap information extracted from the vendor-specific IO field. | ||
| /// | ||
| /// Returned by [`parse_io_field`] after decoding the vendor's raw IO bits. | ||
| #[derive(Debug, Clone, Copy)] | ||
| pub struct ParsedIoInfo { | ||
| /// I/O type: [`IO_TYPE_INPUT`] (1) or [`IO_TYPE_OUTPUT`] (2). | ||
| pub io_type: u32, | ||
| /// I/O width: [`IO_WIDTH_UINT8`], [`IO_WIDTH_UINT16`], or [`IO_WIDTH_UINT32`]. | ||
| pub io_width: u32, | ||
| /// Number of bytes transferred (1, 2, or 4). | ||
| pub byte_count: usize, | ||
| /// I/O port address. | ||
| pub io_port: u32, | ||
| } | ||
|
|
||
| /// `EFI_MM_SAVE_STATE_IO_INFO` — written to the user buffer when reading | ||
| /// the IO pseudo-register. | ||
| #[repr(C)] | ||
| #[derive(Debug, Clone, Copy, Default)] | ||
| pub struct MmSaveStateIoInfo { | ||
| /// I/O data value (from RAX, zero-extended). | ||
| pub io_data: u64, | ||
| /// I/O port address. | ||
| pub io_port: u64, | ||
| /// I/O width enum (`EFI_MM_SAVE_STATE_IO_WIDTH`). | ||
| pub io_width: u32, | ||
| /// I/O type enum (`EFI_MM_SAVE_STATE_IO_TYPE`). | ||
| pub io_type: u32, | ||
| } | ||
|
|
||
| const _: () = assert!(core::mem::size_of::<MmSaveStateIoInfo>() == IO_INFO_SIZE); | ||
|
|
||
| /// Returns the [`VendorConstants`] for the active vendor (selected at build time). | ||
| #[cfg(feature = "save_state_intel")] | ||
| pub fn vendor_constants() -> &'static VendorConstants { | ||
| &intel::VENDOR_CONSTANTS | ||
| } | ||
|
|
||
| /// Returns the [`VendorConstants`] for the active vendor (selected at build time). | ||
| #[cfg(feature = "save_state_amd")] | ||
| pub fn vendor_constants() -> &'static VendorConstants { | ||
| &amd::VENDOR_CONSTANTS | ||
| } | ||
|
|
||
| /// Returns the [`RegisterInfo`] for a given register in the active vendor's | ||
| /// save state map. | ||
| /// | ||
| /// Returns `None` for pseudo-registers (IO, LMA, ProcessorId) and for | ||
| /// registers not supported by the active vendor's 64-bit save state layout. | ||
| #[cfg(feature = "save_state_intel")] | ||
| pub fn register_info(reg: MmSaveStateRegister) -> Option<RegisterInfo> { | ||
| intel::register_info(reg) | ||
| } | ||
|
|
||
| /// Returns the [`RegisterInfo`] for a given register in the active vendor's | ||
| /// save state map. | ||
| #[cfg(feature = "save_state_amd")] | ||
| pub fn register_info(reg: MmSaveStateRegister) -> Option<RegisterInfo> { | ||
| amd::register_info(reg) | ||
| } | ||
|
|
||
| /// Parses the vendor-specific I/O information field from the save state. | ||
| /// | ||
| /// Returns `None` if the field indicates no I/O instruction triggered the SMI | ||
| /// (Intel: `SmiFlag` not set) or if the I/O type/width is not a simple IN/OUT. | ||
| #[cfg(feature = "save_state_intel")] | ||
| pub fn parse_io_field(io_field: u32) -> Option<ParsedIoInfo> { | ||
| intel::parse_io_field(io_field) | ||
| } | ||
|
|
||
| /// Parses the vendor-specific I/O information field from the save state. | ||
| #[cfg(feature = "save_state_amd")] | ||
| pub fn parse_io_field(io_field: u32) -> Option<ParsedIoInfo> { | ||
| amd::parse_io_field(io_field) | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn test_register_from_u64() { | ||
| assert_eq!(MmSaveStateRegister::from_u64(38), Some(MmSaveStateRegister::Rax)); | ||
| assert_eq!(MmSaveStateRegister::from_u64(512), Some(MmSaveStateRegister::Io)); | ||
| assert_eq!(MmSaveStateRegister::from_u64(514), Some(MmSaveStateRegister::ProcessorId)); | ||
| assert_eq!(MmSaveStateRegister::from_u64(999), None); | ||
| assert_eq!(MmSaveStateRegister::from_u64(0), None); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_io_info_struct_layout() { | ||
| assert_eq!(core::mem::size_of::<MmSaveStateIoInfo>(), 24); | ||
| assert_eq!(core::mem::offset_of!(MmSaveStateIoInfo, io_data), 0); | ||
| assert_eq!(core::mem::offset_of!(MmSaveStateIoInfo, io_port), 8); | ||
| assert_eq!(core::mem::offset_of!(MmSaveStateIoInfo, io_width), 16); | ||
| assert_eq!(core::mem::offset_of!(MmSaveStateIoInfo, io_type), 20); | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the newer crate layout as mentioned earlier.