From f8d0b242c85c20faabbf4d6b8eba9a0b0167c0ab Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Tue, 10 Mar 2026 17:07:11 -0700 Subject: [PATCH 01/26] Patina MM related changes --- components/patina_mm/Cargo.toml | 1 + components/patina_mm/src/comm_buffer_hob.rs | 187 ++++++ .../patina_mm/src/component/communicator.rs | 3 +- components/patina_mm/src/config.rs | 105 +-- components/patina_mm/src/lib.rs | 7 +- components/patina_mm/src/protocol.rs | 1 + .../src/protocol/mm_supervisor_request.rs | 226 +++++++ .../patina_mm_integration/common/constants.rs | 51 +- .../patina_mm_integration/common/handlers.rs | 108 +--- .../component_integration_tests.rs | 14 +- .../mm_supervisor/communication_tests.rs | 48 +- sdk/patina/src/lib.rs | 2 + sdk/patina/src/mm_services.rs | 612 ++++++++++++++++++ 13 files changed, 1111 insertions(+), 254 deletions(-) create mode 100644 components/patina_mm/src/comm_buffer_hob.rs create mode 100644 components/patina_mm/src/protocol/mm_supervisor_request.rs create mode 100644 sdk/patina/src/mm_services.rs diff --git a/components/patina_mm/Cargo.toml b/components/patina_mm/Cargo.toml index a69d1da55..90a4fedb9 100644 --- a/components/patina_mm/Cargo.toml +++ b/components/patina_mm/Cargo.toml @@ -34,3 +34,4 @@ x86_64 = { workspace = true, features = [ doc = [] mockall = ["dep:mockall", "std"] std = [] +alloc = [] diff --git a/components/patina_mm/src/comm_buffer_hob.rs b/components/patina_mm/src/comm_buffer_hob.rs new file mode 100644 index 000000000..ef06fef6a --- /dev/null +++ b/components/patina_mm/src/comm_buffer_hob.rs @@ -0,0 +1,187 @@ +//! Management Mode (MM) Header and Buffer HOB Definitions +//! +//! Defines the header and buffer HOB structures necessary for the MM environment to be initialized and used by components +//! dependent on MM details. +//! +//! ## MM HOB Usage +//! +//! It is expected that the MM HOB buffer will be initialized by the environment that registers services for the +//! platform. The HOBs can have platform-fixed values assigned during their initialization. It should be common +//! for at least the communication buffers to be populated as a mutable HOB during boot time. It is +//! recommended for a "MM HOB" component to handle all MM HOB details with minimal other MM related +//! dependencies and lock the HOBs so they are available for components that depend on the immutable HOB +//! to perform MM operations. +//! +//! ## License +//! +//! Copyright (C) Microsoft Corporation. +//! +//! SPDX-License-Identifier: Apache-2.0 +//! + +use r_efi::efi; +use patina::Guid; +use zerocopy_derive::{FromBytes, Immutable, KnownLayout}; + +// ============================================================================= +// GUIDs +// ============================================================================= + +/// GUID for the MM communication buffer HOB (`gMmCommBufferHobGuid`). +/// +/// `{ 0x6c2a2520, 0x0131, 0x4aee, { 0xa7, 0x50, 0xcc, 0x38, 0x4a, 0xac, 0xe8, 0xc6 } }` +pub const MM_COMM_BUFFER_HOB_GUID: efi::Guid = efi::Guid::from_fields( + 0x6c2a2520, + 0x0131, + 0x4aee, + 0xa7, + 0x50, + &[0xcc, 0x38, 0x4a, 0xac, 0xe8, 0xc6], +); + +/// MM Common Buffer HOB Data Structure. +/// +/// Describes the communication buffer region passed via HOB from PEI to MM. +#[repr(C, packed)] +#[derive(Debug, Clone, Copy)] +pub struct MmCommonBufferHobData { + /// Physical start address of the common region. + pub physical_start: u64, + /// Number of pages in the communication buffer region. + pub number_of_pages: u64, + /// Pointer to `MmCommBufferStatus` structure. + pub status_buffer: u64, +} + +/// MM Communication Buffer Status +/// +/// Shared structure between DXE and MM environments to communicate the status +/// of MM communication operations. This structure is written by DXE before +/// triggering an MMI and read/written by MM during MMI processing. +/// +/// This is a structure currently used in some MM Supervisor MM implementations. +#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)] +#[repr(C)] +pub struct MmCommBufferStatus { + /// Whether the data in the fixed MM communication buffer is valid when entering from non-MM to MM. + /// Must be set to TRUE before triggering MMI, will be set to FALSE by MM after processing. + pub is_comm_buffer_valid: u8, + + /// The channel used to communicate with MM. + /// FALSE = user buffer, TRUE = supervisor buffer + pub talk_to_supervisor: u8, + + /// The return status when returning from MM to non-MM. + pub return_status: u64, + + /// The size in bytes of the output buffer when returning from MM to non-MM. + pub return_buffer_size: u64, +} + +impl Default for MmCommBufferStatus { + #[coverage(off)] + fn default() -> Self { + Self::new() + } +} + +impl MmCommBufferStatus { + /// Create a new mailbox status with all fields zeroed + pub const fn new() -> Self { + Self { is_comm_buffer_valid: 0, talk_to_supervisor: 0, return_status: 0, return_buffer_size: 0 } + } +} + +/// UEFI MM Communicate Header +/// +/// A standard header that must be present at the beginning of any MM communication buffer. +/// +/// ## Notes +/// +/// - This only supports V1 and V2 of the MM Communicate header format. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct EfiMmCommunicateHeader { + /// Allows for disambiguation of the message format. + /// Used to identify the registered MM handlers that should be given the message. + header_guid: patina::BinaryGuid, + /// The size of Data (in bytes) and does not include the size of the header. + message_length: usize, +} + +impl EfiMmCommunicateHeader { + /// Create a new communicate header with the specified GUID and message length. + pub fn new(header_guid: Guid, message_length: usize) -> Self { + Self { header_guid: header_guid.to_efi_guid().into(), message_length } + } + + /// Returns the communicate header as a slice of bytes using safe conversion. + /// + /// Useful if byte-level access to the header structure is needed. + pub fn as_bytes(&self) -> &[u8] { + // SAFETY: EfiMmCommunicateHeader is repr(C) with well-defined layout and size + unsafe { core::slice::from_raw_parts(self as *const _ as *const u8, Self::size()) } + } + + /// Returns the size of the header in bytes. + pub const fn size() -> usize { + core::mem::size_of::() + } + + /// Get the header GUID from the communication buffer. + /// + /// Returns `Some(guid)` if the buffer has been properly initialized with a GUID, + /// or `None` if the buffer is not initialized. + /// + /// # Returns + /// + /// The GUID from the communication header if available. + /// + /// # Errors + /// + /// Returns an error if the communication buffer header cannot be read. + pub fn header_guid(&self) -> Guid<'_> { + Guid::from_ref(&self.header_guid) + } + + /// Returns the message length from this communicate header. + /// + /// The length represents the size of the message data that follows the header. + /// + /// # Returns + /// + /// The length in bytes of the message data (excluding the header size). + pub const fn message_length(&self) -> usize { + self.message_length + } +} + +// ============================================================================= +// Communication Structures +// ============================================================================= + +/// EFI_MM_ENTRY_CONTEXT structure. +/// +/// Processor information and functionality needed by MM Foundation. +/// Matches the C `EFI_MM_ENTRY_CONTEXT` / `EFI_SMM_ENTRY_CONTEXT` from PI specification. +/// +/// Layout (x86_64, all fields 8 bytes): +/// - `mm_startup_this_ap`: Function pointer for `EFI_MM_STARTUP_THIS_AP` +/// - `currently_executing_cpu`: Index of the processor executing the MM Foundation +/// - `number_of_cpus`: Total number of possible processors in the platform (1-based) +/// - `cpu_save_state_size`: Pointer to array of save state sizes per CPU +/// - `cpu_save_state`: Pointer to array of CPU save state pointers +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct EfiMmEntryContext { + /// Function pointer for EFI_MM_STARTUP_THIS_AP. + pub mm_startup_this_ap: u64, + /// Index of the currently executing CPU. + pub currently_executing_cpu: u64, + /// Total number of CPUs (1-based). + pub number_of_cpus: u64, + /// Pointer to array of per-CPU save state sizes. + pub cpu_save_state_size: u64, + /// Pointer to array of per-CPU save state pointers. + pub cpu_save_state: u64, +} diff --git a/components/patina_mm/src/component/communicator.rs b/components/patina_mm/src/component/communicator.rs index e6f7646e8..e93e68fd0 100644 --- a/components/patina_mm/src/component/communicator.rs +++ b/components/patina_mm/src/component/communicator.rs @@ -16,7 +16,8 @@ mod comm_buffer_update; use crate::{ - config::{CommunicateBuffer, EfiMmCommunicateHeader, MmCommunicationConfiguration}, + config::{CommunicateBuffer, MmCommunicationConfiguration}, + comm_buffer_hob::EfiMmCommunicateHeader, service::SwMmiTrigger, }; use patina::{ diff --git a/components/patina_mm/src/config.rs b/components/patina_mm/src/config.rs index 958dbf420..b1ec43e7b 100644 --- a/components/patina_mm/src/config.rs +++ b/components/patina_mm/src/config.rs @@ -23,46 +23,7 @@ use alloc::vec::Vec; use core::{fmt, pin::Pin, ptr::NonNull}; use patina::{BinaryGuid, Guid, base::UEFI_PAGE_MASK}; -use zerocopy_derive::*; - -/// MM Communication Buffer Status -/// -/// Shared structure between DXE and MM environments to communicate the status -/// of MM communication operations. This structure is written by DXE before -/// triggering an MMI and read/written by MM during MMI processing. -/// -/// This is a structure currently used in some MM Supervisor MM implementations. -#[derive(Debug, Clone, Copy, FromBytes, IntoBytes, Immutable, KnownLayout)] -#[repr(C, packed)] -pub struct MmCommBufferStatus { - /// Whether the data in the fixed MM communication buffer is valid when entering from non-MM to MM. - /// Must be set to TRUE before triggering MMI, will be set to FALSE by MM after processing. - pub is_comm_buffer_valid: u8, - - /// The channel used to communicate with MM. - /// FALSE = user buffer, TRUE = supervisor buffer - pub talk_to_supervisor: u8, - - /// The return status when returning from MM to non-MM. - pub return_status: u64, - - /// The size in bytes of the output buffer when returning from MM to non-MM. - pub return_buffer_size: u64, -} - -impl Default for MmCommBufferStatus { - #[coverage(off)] - fn default() -> Self { - Self::new() - } -} - -impl MmCommBufferStatus { - /// Create a new mailbox status with all fields zeroed - pub const fn new() -> Self { - Self { is_comm_buffer_valid: 0, talk_to_supervisor: 0, return_status: 0, return_buffer_size: 0 } - } -} +use crate::comm_buffer_hob::{MmCommBufferStatus, EfiMmCommunicateHeader}; /// Management Mode (MM) Configuration /// @@ -119,70 +80,6 @@ impl fmt::Display for MmCommunicationConfiguration { } } -/// UEFI MM Communicate Header -/// -/// A standard header that must be present at the beginning of any MM communication buffer. -/// -/// ## Notes -/// -/// - This only supports V1 and V2 of the MM Communicate header format. -#[derive(Debug, Clone, Copy)] -#[repr(C)] -pub struct EfiMmCommunicateHeader { - /// Allows for disambiguation of the message format. - /// Used to identify the registered MM handlers that should be given the message. - header_guid: patina::BinaryGuid, - /// The size of Data (in bytes) and does not include the size of the header. - message_length: usize, -} - -impl EfiMmCommunicateHeader { - /// Create a new communicate header with the specified GUID and message length. - pub fn new(header_guid: Guid, message_length: usize) -> Self { - Self { header_guid: header_guid.to_efi_guid().into(), message_length } - } - - /// Returns the communicate header as a slice of bytes using safe conversion. - /// - /// Useful if byte-level access to the header structure is needed. - pub fn as_bytes(&self) -> &[u8] { - // SAFETY: EfiMmCommunicateHeader is repr(C) with well-defined layout and size - unsafe { core::slice::from_raw_parts(self as *const _ as *const u8, Self::size()) } - } - - /// Returns the size of the header in bytes. - pub const fn size() -> usize { - core::mem::size_of::() - } - - /// Get the header GUID from the communication buffer. - /// - /// Returns `Some(guid)` if the buffer has been properly initialized with a GUID, - /// or `None` if the buffer is not initialized. - /// - /// # Returns - /// - /// The GUID from the communication header if available. - /// - /// # Errors - /// - /// Returns an error if the communication buffer header cannot be read. - pub fn header_guid(&self) -> Guid<'_> { - Guid::from_ref(&self.header_guid) - } - - /// Returns the message length from this communicate header. - /// - /// The length represents the size of the message data that follows the header. - /// - /// # Returns - /// - /// The length in bytes of the message data (excluding the header size). - pub const fn message_length(&self) -> usize { - self.message_length - } -} - /// MM Communicator Service Status Codes #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum CommunicateBufferStatus { diff --git a/components/patina_mm/src/lib.rs b/components/patina_mm/src/lib.rs index 7ab1d99e1..43b681245 100644 --- a/components/patina_mm/src/lib.rs +++ b/components/patina_mm/src/lib.rs @@ -6,7 +6,12 @@ #![cfg_attr(all(not(feature = "std"), not(test), not(feature = "mockall")), no_std)] #![feature(coverage_attribute)] +#[cfg(any(test, feature = "alloc"))] pub mod component; +#[cfg(any(test, feature = "alloc"))] +pub mod service; +#[cfg(any(test, feature = "alloc"))] pub mod config; + +pub mod comm_buffer_hob; pub mod protocol; -pub mod service; diff --git a/components/patina_mm/src/protocol.rs b/components/patina_mm/src/protocol.rs index cf73116f5..89493e062 100644 --- a/components/patina_mm/src/protocol.rs +++ b/components/patina_mm/src/protocol.rs @@ -9,3 +9,4 @@ //! SPDX-License-Identifier: Apache-2.0 pub mod mm_comm_buffer_update; +pub mod mm_supervisor_request; diff --git a/components/patina_mm/src/protocol/mm_supervisor_request.rs b/components/patina_mm/src/protocol/mm_supervisor_request.rs new file mode 100644 index 000000000..46c20e54a --- /dev/null +++ b/components/patina_mm/src/protocol/mm_supervisor_request.rs @@ -0,0 +1,226 @@ +//! MM Supervisor Request Protocol Definitions +//! +//! This module provides the shared protocol structures and constants for MM Supervisor +//! request handling. These types define the communication contract between the supervisor +//! and its clients (DXE, tests, etc.). +//! +//! ## Overview +//! +//! The MM Supervisor uses a structured request/response protocol. Requests are sent via +//! the MM communicate buffer and consist of an [`MmSupervisorRequestHeader`] followed by +//! request-specific payload data. The supervisor processes the request and writes back +//! a response header (with result status) followed by response-specific data. +//! +//! ## License +//! +//! Copyright (C) Microsoft Corporation. +//! +//! SPDX-License-Identifier: Apache-2.0 + +use zerocopy::FromBytes; +use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout}; +use r_efi::efi::Guid; + +// GUID for gMmSupervisorRequestHandlerGuid +// { 0x8c633b23, 0x1260, 0x4ea6, { 0x83, 0xf, 0x7d, 0xdc, 0x97, 0x38, 0x21, 0x11 } } +/// GUID for the MM Supervisor Request Handler protocol. +pub const MM_SUPERVISOR_REQUEST_HANDLER_GUID: Guid = Guid::from_fields( + 0x8c633b23, + 0x1260, + 0x4ea6, + 0x83, + 0x0F, + &[0x7d, 0xdc, 0x97, 0x38, 0x21, 0x11], +); + +/// MM Supervisor request header. +/// +/// This header is present at the start of every supervisor request buffer. It identifies +/// the request type and carries the result status on response. +/// +/// ## Layout +/// +/// ```text +/// Offset Size Field +/// 0x00 4 signature - Must be [`SIGNATURE`] ('MSUP' as little-endian u32) +/// 0x04 4 revision - Protocol revision, must be <= [`REVISION`] +/// 0x08 4 request - Request type (see [`requests`] module) +/// 0x0C 4 reserved - Reserved for alignment, must be 0 +/// 0x10 8 result - Return status (0 = success, set by supervisor on response) +/// ``` +#[derive(Debug, Clone, Copy, FromBytes, IntoBytes, Immutable, KnownLayout)] +#[repr(C)] +pub struct MmSupervisorRequestHeader { + /// Signature to identify the request ('MSUP' as little-endian). + pub signature: u32, + /// Revision of the request protocol. + pub revision: u32, + /// The specific request type (see [`requests`] module constants). + pub request: u32, + /// Reserved for alignment, must be 0. + pub reserved: u32, + /// Result status. Set by the supervisor on response (0 = success). + pub result: u64, +} + +impl MmSupervisorRequestHeader { + /// Size of the header in bytes. + pub const SIZE: usize = core::mem::size_of::(); + + /// Validates the header signature and revision. + pub fn is_valid(&self) -> bool { + self.signature == SIGNATURE && self.revision <= REVISION + } + + /// Reads a header from a byte slice. + /// + /// Returns `None` if the slice is too small or misaligned. + pub fn from_bytes(bytes: &[u8]) -> Option { + if bytes.len() < Self::SIZE { + return None; + } + Self::read_from_bytes(&bytes[..Self::SIZE]).ok() + } +} + +/// Response from MM Supervisor version info request. +/// +/// Returned as the payload following an [`MmSupervisorRequestHeader`] when the request +/// type is [`requests::VERSION_INFO`]. +/// +/// ## Layout +/// +/// ```text +/// Offset Size Field +/// 0x00 4 version - Supervisor version +/// 0x04 4 patch_level - Supervisor patch level +/// 0x08 8 max_supervisor_request_level - Highest supported request type +/// ``` +#[derive(Debug, Clone, Copy, FromBytes, IntoBytes, Immutable, KnownLayout)] +#[repr(C)] +pub struct MmSupervisorVersionInfo { + /// Version of the MM Supervisor. + pub version: u32, + /// Patch level. + pub patch_level: u32, + /// Maximum supported supervisor request level (highest valid request type value). + pub max_supervisor_request_level: u64, +} + +impl MmSupervisorVersionInfo { + /// Size of the version info structure in bytes. + pub const SIZE: usize = core::mem::size_of::(); + + /// Reads version info from a byte slice. + /// + /// Returns `None` if the slice is too small or misaligned. + pub fn from_bytes(bytes: &[u8]) -> Option { + if bytes.len() < Self::SIZE { + return None; + } + Self::read_from_bytes(&bytes[..Self::SIZE]).ok() + } +} + +// ============================================================================ +// Protocol Constants +// ============================================================================ + +/// The expected signature value ('MSUP' as little-endian u32). +pub const SIGNATURE: u32 = 0x5055534D; + +/// Current revision of the request protocol. +pub const REVISION: u32 = 1; + +/// Standard MM Supervisor request types. +/// +/// Each variant corresponds to a specific supervisor operation. The enum is `#[repr(u32)]` +/// to match the wire format of [`MmSupervisorRequestHeader::request`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum RequestType { + /// Request to unblock memory regions. + UnblockMem = 0x0001, + /// Request to fetch security policy. + FetchPolicy = 0x0002, + /// Request for version information. + VersionInfo = 0x0003, + /// Request to update communication buffer. + CommUpdate = 0x0004, +} + +impl RequestType { + /// The highest valid request type value. + pub const MAX: u64 = Self::CommUpdate as u64; +} + +impl TryFrom for RequestType { + type Error = u32; + + fn try_from(value: u32) -> Result { + match value { + 0x0001 => Ok(Self::UnblockMem), + 0x0002 => Ok(Self::FetchPolicy), + 0x0003 => Ok(Self::VersionInfo), + 0x0004 => Ok(Self::CommUpdate), + other => Err(other), + } + } +} + +/// Deprecated module — use [`RequestType`] enum variants instead. +/// +/// Kept temporarily for backward compatibility. +pub mod requests { + use super::RequestType; + /// Request to unblock memory regions. + pub const UNBLOCK_MEM: u32 = RequestType::UnblockMem as u32; + /// Request to fetch security policy. + pub const FETCH_POLICY: u32 = RequestType::FetchPolicy as u32; + /// Request for version information. + pub const VERSION_INFO: u32 = RequestType::VersionInfo as u32; + /// Request to update communication buffer. + pub const COMM_UPDATE: u32 = RequestType::CommUpdate as u32; +} + +/// Response status constants. +pub mod responses { + /// Operation completed successfully. + pub const SUCCESS: u64 = 0; + /// Operation failed with error. + pub const ERROR: u64 = 0xFFFFFFFFFFFFFFFF; +} + +// ============================================================================ +// Unblock Memory Params +// ============================================================================ + +use r_efi::efi; + +/// MM Supervisor Unblock Memory Parameters. +/// +/// Matches the C `MM_SUPERVISOR_UNBLOCK_MEMORY_PARAMS` layout. The C header +/// defines this under `#pragma pack(push, 1)`, but because `efi::MemoryDescriptor` +/// (40 bytes) and `Guid` (16 bytes) are both naturally aligned, the packed +/// and natural layouts are identical (56 bytes total). +/// +/// ## Layout +/// +/// ```text +/// Offset Size Field +/// 0x00 40 memory_descriptor - EFI_MEMORY_DESCRIPTOR (r-efi efi::MemoryDescriptor) +/// 0x28 16 identifier_guid - Requester identification GUID +/// ``` +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct MmSupervisorUnblockMemoryParams { + /// Memory descriptor identifying the region to unblock. + pub memory_descriptor: efi::MemoryDescriptor, + /// GUID identifying the requesting driver/module. + pub identifier_guid: Guid, +} + +impl MmSupervisorUnblockMemoryParams { + /// Size of this structure in bytes (56). + pub const SIZE: usize = core::mem::size_of::(); +} diff --git a/components/patina_mm/tests/patina_mm_integration/common/constants.rs b/components/patina_mm/tests/patina_mm_integration/common/constants.rs index fe6aea748..f4dd24b0a 100644 --- a/components/patina_mm/tests/patina_mm_integration/common/constants.rs +++ b/components/patina_mm/tests/patina_mm_integration/common/constants.rs @@ -11,52 +11,29 @@ use patina::base::SIZE_4KB; /// Standard test buffer size pub const TEST_BUFFER_SIZE: usize = SIZE_4KB; -/// MM Supervisor constants and definitions +/// MM Supervisor constants and definitions for testing. /// -/// Note: These values are only used for testing. They're not meant to be -/// accurate or used in production code. +/// Protocol constants (SIGNATURE, REVISION, request types) are re-exported from the +/// shared [`patina_mm::protocol::mm_supervisor_request`] module. Test-specific values +/// (VERSION, PATCH_LEVEL, etc.) are defined here as mock data. pub mod mm_supv { - /// Supervisor signature bytes - pub const SIGNATURE: [u8; 4] = [b'M', b'S', b'U', b'P']; + // Re-export shared protocol constants + pub use patina_mm::protocol::mm_supervisor_request::{ + SIGNATURE, REVISION, + RequestType, requests, responses, + }; - /// Communication protocol revision - pub const REVISION: u32 = 1; + /// Request signature as a DWORD (same as shared SIGNATURE, kept for test compatibility) + pub const REQUEST_SIGNATURE: u32 = SIGNATURE; - /// Request signature as a DWORD - pub const REQUEST_SIGNATURE: u32 = 0x5055534D; // 'MSUP' - - /// Supervisor version + /// Mock supervisor version for testing pub const VERSION: u32 = 0x00130008; - /// Supervisor patch level + /// Mock supervisor patch level for testing pub const PATCH_LEVEL: u32 = 0x00010001; - /// Maximum request level supported + /// Mock maximum request level supported pub const MAX_REQUEST_LEVEL: u64 = 0x0000000000000004; // COMM_UPDATE - - /// Request type constants - pub mod requests { - /// Request for unblocking memory regions - pub const UNBLOCK_MEM: u32 = 0x0001; - - /// Request to fetch security policy - pub const FETCH_POLICY: u32 = 0x0002; - - /// Request version information - pub const VERSION_INFO: u32 = 0x0003; - - /// Request to update the communication buffer address - pub const COMM_UPDATE: u32 = 0x0004; - } - - /// Response code constants - pub mod responses { - /// Operation completed successfully - pub const SUCCESS: u64 = 0; - - /// Operation failed with error - pub const ERROR: u64 = 0xFFFFFFFFFFFFFFFF; - } } /// Test GUIDs for different handlers diff --git a/components/patina_mm/tests/patina_mm_integration/common/handlers.rs b/components/patina_mm/tests/patina_mm_integration/common/handlers.rs index d0def8752..e27fb4ac2 100644 --- a/components/patina_mm/tests/patina_mm_integration/common/handlers.rs +++ b/components/patina_mm/tests/patina_mm_integration/common/handlers.rs @@ -20,8 +20,13 @@ use crate::patina_mm_integration::common::constants::*; extern crate alloc; use alloc::{string::String, vec::Vec}; -use zerocopy::{FromBytes, IntoBytes}; -use zerocopy_derive::*; +pub use zerocopy::IntoBytes; + +// Import shared protocol types from patina_mm +pub use patina_mm::protocol::mm_supervisor_request::{ + MmSupervisorRequestHeader, + MmSupervisorVersionInfo, +}; /// Standardized error type for MM handlers #[derive(Debug, Clone, PartialEq, Eq)] @@ -109,64 +114,6 @@ impl MmHandler for VersionInfoHandler { } } -/// MM Supervisor request header -#[derive(Debug, Clone, Copy, IntoBytes, FromBytes, Immutable)] -#[repr(C)] -pub struct MmSupervisorRequestHeader { - pub signature: u32, - pub revision: u32, - pub request: u32, - pub reserved: u32, - pub result: u64, -} - -impl MmSupervisorRequestHeader { - const SIZE: usize = core::mem::size_of::(); - - /// Converts a byte slice to a MmSupervisorRequestHeader - #[allow(dead_code)] // // Usage not recognized - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() < Self::SIZE { - return Err(MmHandlerError::InvalidInput("Buffer too small for header".to_string())); - } - - Self::read_from_bytes(&bytes[..Self::SIZE]) - .map_err(|_| MmHandlerError::InvalidInput("Failed to parse header from bytes".to_string())) - } - - /// Converts a MmSupervisorRequestHeader instance to a byte vector - pub fn to_bytes(self) -> Vec { - self.as_bytes().to_vec() - } -} - -/// MM Supervisor version information -#[derive(Debug, Clone, Copy, IntoBytes, FromBytes, Immutable)] -#[repr(C)] -pub struct MmSupervisorVersionInfo { - pub version: u32, - pub patch_level: u32, - pub max_supervisor_request_level: u64, -} - -impl MmSupervisorVersionInfo { - const SIZE: usize = core::mem::size_of::(); - - #[allow(dead_code)] // Usage not recognized - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() < Self::SIZE { - return Err(MmHandlerError::InvalidInput("Buffer too small for version info".to_string())); - } - - Self::read_from_bytes(&bytes[..Self::SIZE]) - .map_err(|_| MmHandlerError::InvalidInput("Failed to parse version info from bytes".to_string())) - } - - fn to_bytes(self) -> Vec { - self.as_bytes().to_vec() - } -} - /// MM Supervisor handler for testing supervisor communication patterns pub struct MmSupervisorHandler { #[allow(dead_code)] // Usage not recognized @@ -182,7 +129,7 @@ impl MmSupervisorHandler { let response_header = MmSupervisorRequestHeader { signature: mm_supv::REQUEST_SIGNATURE, revision: mm_supv::REVISION, - request: mm_supv::requests::VERSION_INFO, + request: mm_supv::RequestType::VersionInfo as u32, reserved: 0, result: 0, // Success }; @@ -194,8 +141,8 @@ impl MmSupervisorHandler { }; let mut response = Vec::new(); - response.extend_from_slice(&response_header.to_bytes()); - response.extend_from_slice(&version_info.to_bytes()); + response.extend_from_slice(response_header.as_bytes()); + response.extend_from_slice(version_info.as_bytes()); log::debug!(target: "supervisor_handler", "Generated get info response: {} bytes", response.len()); Ok(response) @@ -205,7 +152,7 @@ impl MmSupervisorHandler { let response_header = MmSupervisorRequestHeader { signature: mm_supv::REQUEST_SIGNATURE, revision: mm_supv::REVISION, - request: mm_supv::requests::FETCH_POLICY, + request: mm_supv::RequestType::FetchPolicy as u32, reserved: 0, result: 0, // Success }; @@ -213,7 +160,7 @@ impl MmSupervisorHandler { let capabilities: u64 = 0x00000007; // Mock capabilities value let mut response = Vec::new(); - response.extend_from_slice(&response_header.to_bytes()); + response.extend_from_slice(response_header.as_bytes()); response.extend_from_slice(&capabilities.to_le_bytes()); log::debug!(target: "supervisor_handler", "Generated get capabilities response: {} bytes", response.len()); @@ -224,7 +171,7 @@ impl MmSupervisorHandler { let response_header = MmSupervisorRequestHeader { signature: mm_supv::REQUEST_SIGNATURE, revision: mm_supv::REVISION, - request: mm_supv::requests::COMM_UPDATE, + request: mm_supv::RequestType::CommUpdate as u32, reserved: 0, result: 0, // Success }; @@ -233,7 +180,7 @@ impl MmSupervisorHandler { let update_result: u32 = 0x00000001; // Success status let mut response = Vec::new(); - response.extend_from_slice(&response_header.to_bytes()); + response.extend_from_slice(response_header.as_bytes()); response.extend_from_slice(&update_result.to_le_bytes()); log::debug!(target: "supervisor_handler", "Generated comm update response: {} bytes", response.len()); @@ -244,7 +191,7 @@ impl MmSupervisorHandler { let response_header = MmSupervisorRequestHeader { signature: mm_supv::REQUEST_SIGNATURE, revision: mm_supv::REVISION, - request: mm_supv::requests::UNBLOCK_MEM, + request: mm_supv::RequestType::UnblockMem as u32, reserved: 0, result: 0, // Success }; @@ -253,7 +200,7 @@ impl MmSupervisorHandler { let unblock_status: u64 = 0x0000000000000001; // Success - memory regions unblocked let mut response = Vec::new(); - response.extend_from_slice(&response_header.to_bytes()); + response.extend_from_slice(response_header.as_bytes()); response.extend_from_slice(&unblock_status.to_le_bytes()); log::debug!(target: "supervisor_handler", "Generated unblock mem response: {} bytes", response.len()); @@ -273,7 +220,8 @@ impl MmHandler for MmSupervisorHandler { ))); } - let request_header = MmSupervisorRequestHeader::from_bytes(data)?; + let request_header = MmSupervisorRequestHeader::from_bytes(data) + .ok_or_else(|| MmHandlerError::InvalidInput("Failed to parse header from bytes".to_string()))?; // Validate signature if request_header.signature != mm_supv::REQUEST_SIGNATURE { @@ -294,24 +242,24 @@ impl MmHandler for MmSupervisorHandler { } // Process based on request type - match request_header.request { - mm_supv::requests::VERSION_INFO => { + match mm_supv::RequestType::try_from(request_header.request) { + Ok(mm_supv::RequestType::VersionInfo) => { log::debug!(target: "supervisor_handler", "Processing get info request"); self.handle_get_info_request() } - mm_supv::requests::FETCH_POLICY => { + Ok(mm_supv::RequestType::FetchPolicy) => { log::debug!(target: "supervisor_handler", "Processing fetch policy request"); self.handle_get_capabilities_request() } - mm_supv::requests::COMM_UPDATE => { + Ok(mm_supv::RequestType::CommUpdate) => { log::debug!(target: "supervisor_handler", "Processing comm update request"); self.handle_comm_update_request() } - mm_supv::requests::UNBLOCK_MEM => { + Ok(mm_supv::RequestType::UnblockMem) => { log::debug!(target: "supervisor_handler", "Processing unblock mem request"); self.handle_unblock_mem_request() } - _ => { + Err(_) => { log::warn!(target: "supervisor_handler", "Unsupported request type: 0x{:08X}", request_header.request); // Return error response @@ -324,7 +272,7 @@ impl MmHandler for MmSupervisorHandler { }; let mut response = Vec::new(); - response.extend_from_slice(&error_header.to_bytes()); + response.extend_from_slice(error_header.as_bytes()); Ok(response) } } @@ -482,11 +430,11 @@ mod tests { result: 0x123456789ABCDEF0, }; - let bytes = original.to_bytes(); + let bytes = original.as_bytes(); assert_eq!(bytes.len(), MmSupervisorRequestHeader::SIZE); - let recovered = MmSupervisorRequestHeader::from_bytes(&bytes); - assert!(recovered.is_ok(), "Should successfully parse the header"); + let recovered = MmSupervisorRequestHeader::from_bytes(bytes); + assert!(recovered.is_some(), "Should successfully parse the header"); let recovered = recovered.unwrap(); assert_eq!(recovered.signature, original.signature); diff --git a/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs b/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs index e175f7b91..8fe80767f 100644 --- a/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs +++ b/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs @@ -156,14 +156,14 @@ fn test_real_component_mm_supervisor_version_request() { // Create MM Supervisor version request using the actual structures let version_request = MmSupervisorRequestHeader { - signature: u32::from_le_bytes(mm_supv::SIGNATURE), + signature: mm_supv::SIGNATURE, revision: mm_supv::REVISION, - request: mm_supv::requests::VERSION_INFO, + request: mm_supv::RequestType::VersionInfo as u32, reserved: 0, result: 0, }; - let request_bytes = version_request.to_bytes(); + let request_bytes = version_request.as_bytes().to_vec(); // Send the request using the real component framework let result = framework.communicate(&Guid::from_ref(&test_guids::MM_SUPERVISOR), &request_bytes); @@ -183,7 +183,7 @@ fn test_real_component_mm_supervisor_version_request() { // Verify header fields assert_eq!(response_header.signature, mm_supv::REQUEST_SIGNATURE, "Response signature should match"); assert_eq!(response_header.revision, mm_supv::REVISION, "Response revision should match"); - assert_eq!(response_header.request, mm_supv::requests::VERSION_INFO, "Response request type should match"); + assert_eq!(response_header.request, mm_supv::RequestType::VersionInfo as u32, "Response request type should match"); assert_eq!(response_header.result, 0, "Response should indicate success"); // Parse version info from response @@ -275,15 +275,15 @@ fn test_real_component_multiple_handlers() { // Test MM supervisor handler let supervisor_request = MmSupervisorRequestHeader { - signature: u32::from_le_bytes(mm_supv::SIGNATURE), + signature: mm_supv::SIGNATURE, revision: mm_supv::REVISION, - request: mm_supv::requests::FETCH_POLICY, + request: mm_supv::RequestType::FetchPolicy as u32, reserved: 0, result: 0, }; let supervisor_result = - framework.communicate(&Guid::from_ref(&test_guids::MM_SUPERVISOR), &supervisor_request.to_bytes()); + framework.communicate(&Guid::from_ref(&test_guids::MM_SUPERVISOR), &supervisor_request.as_bytes().to_vec()); assert!(supervisor_result.is_ok(), "Supervisor communication should succeed"); // Both handlers should work independently through the real component infrastructure diff --git a/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs b/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs index c4cb5bd3c..0459389ae 100644 --- a/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs +++ b/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs @@ -25,14 +25,14 @@ fn test_mm_supervisor_version_request_integration() { // Create MM Supervisor version request using safe operations let version_request = MmSupervisorRequestHeader { - signature: u32::from_le_bytes(mm_supv::SIGNATURE), + signature: mm_supv::SIGNATURE, revision: mm_supv::REVISION, - request: mm_supv::requests::VERSION_INFO, + request: mm_supv::RequestType::VersionInfo as u32, reserved: 0, result: 0, }; - let request_bytes = version_request.to_bytes(); + let request_bytes = version_request.as_bytes().to_vec(); // Send the request using framework let result = framework.communicate(&test_guids::MM_SUPERVISOR, &request_bytes); @@ -75,14 +75,14 @@ fn test_mm_supervisor_capabilities_request() { // Create capabilities request using safe operations let capabilities_request = MmSupervisorRequestHeader { - signature: u32::from_le_bytes(mm_supv::SIGNATURE), + signature: mm_supv::SIGNATURE, revision: mm_supv::REVISION, - request: mm_supv::requests::FETCH_POLICY, + request: mm_supv::RequestType::FetchPolicy as u32, reserved: 0, result: 0, }; - let request_bytes = capabilities_request.to_bytes(); + let request_bytes = capabilities_request.as_bytes().to_vec(); // Send the request using framework let result = framework.communicate(&test_guids::MM_SUPERVISOR, &request_bytes); @@ -124,14 +124,14 @@ fn test_mm_supervisor_invalid_request() { // Create invalid request using safe operations let invalid_request = MmSupervisorRequestHeader { - signature: u32::from_le_bytes(mm_supv::SIGNATURE), + signature: mm_supv::SIGNATURE, revision: mm_supv::REVISION, request: 0xFFFF, // Invalid request type reserved: 0, result: 0, }; - let request_bytes = invalid_request.to_bytes(); + let request_bytes = invalid_request.as_bytes().to_vec(); // Send the request using framework let result = framework.communicate(&test_guids::MM_SUPERVISOR, &request_bytes); @@ -154,12 +154,12 @@ fn test_mm_supervisor_invalid_signature() { let invalid_request = MmSupervisorRequestHeader { signature: u32::from_le_bytes([b'I', b'N', b'V', b'D']), // Invalid signature revision: mm_supv::REVISION, - request: mm_supv::requests::VERSION_INFO, + request: mm_supv::RequestType::VersionInfo as u32, reserved: 0, result: 0, }; - let request_bytes = invalid_request.to_bytes(); + let request_bytes = invalid_request.as_bytes().to_vec(); // Test handler directly let result = mm_supervisor.handle_request(&request_bytes); @@ -207,15 +207,15 @@ fn test_mm_supervisor_builder_integration() { // Test MM Supervisor handler as well let version_request = MmSupervisorRequestHeader { - signature: u32::from_le_bytes(mm_supv::SIGNATURE), + signature: mm_supv::SIGNATURE, revision: mm_supv::REVISION, - request: mm_supv::requests::VERSION_INFO, + request: mm_supv::RequestType::VersionInfo as u32, reserved: 0, result: 0, }; // Use framework directly instead of mm_comm_service - let request_data = version_request.to_bytes(); // Convert to bytes + let request_data = version_request.as_bytes().to_vec(); // Convert to bytes let supervisor_result = framework.communicate(&test_guids::MM_SUPERVISOR, &request_data); assert!(supervisor_result.is_ok(), "MM Supervisor should work"); @@ -229,14 +229,14 @@ fn test_safe_message_parsing_with_mm_supervisor() { let mut buffer = vec![0u8; TEST_BUFFER_SIZE]; let version_request = MmSupervisorRequestHeader { - signature: u32::from_le_bytes(mm_supv::SIGNATURE), + signature: mm_supv::SIGNATURE, revision: mm_supv::REVISION, - request: mm_supv::requests::VERSION_INFO, + request: mm_supv::RequestType::VersionInfo as u32, reserved: 0, result: 0, }; - let request_data = version_request.to_bytes(); + let request_data = version_request.as_bytes().to_vec(); // Test writing MM Supervisor message safely let mut parser = MmMessageParser::new(&mut buffer); @@ -267,14 +267,14 @@ fn test_mm_supervisor_comm_update_request() { // Create communication buffer update request using COMM_UPDATE constant let comm_update_request = MmSupervisorRequestHeader { - signature: u32::from_le_bytes(mm_supv::SIGNATURE), + signature: mm_supv::SIGNATURE, revision: mm_supv::REVISION, - request: mm_supv::requests::COMM_UPDATE, + request: mm_supv::RequestType::CommUpdate as u32, reserved: 0, result: 0, }; - let request_bytes = comm_update_request.to_bytes(); + let request_bytes = comm_update_request.as_bytes().to_vec(); // Send the request using framework let result = framework.communicate(&test_guids::MM_SUPERVISOR, &request_bytes); @@ -289,7 +289,7 @@ fn test_mm_supervisor_comm_update_request() { // Parse response header safely let response_header = MmSupervisorRequestHeader::from_bytes(&response).expect("Should parse response header"); - assert_eq!(response_header.request, mm_supv::requests::COMM_UPDATE, "Response should be for COMM_UPDATE request"); + assert_eq!(response_header.request, mm_supv::RequestType::CommUpdate as u32, "Response should be for COMM_UPDATE request"); assert_eq!(response_header.result, mm_supv::responses::SUCCESS, "Comm update request should succeed"); // Parse update result safely @@ -315,14 +315,14 @@ fn test_mm_supervisor_unblock_mem_request() { // Create memory unblock request using UNBLOCK_MEM constant let unblock_mem_request = MmSupervisorRequestHeader { - signature: u32::from_le_bytes(mm_supv::SIGNATURE), + signature: mm_supv::SIGNATURE, revision: mm_supv::REVISION, - request: mm_supv::requests::UNBLOCK_MEM, // This uses the constant! + request: mm_supv::RequestType::UnblockMem as u32, reserved: 0, result: 0, }; - let request_bytes = unblock_mem_request.to_bytes(); + let request_bytes = unblock_mem_request.as_bytes().to_vec(); // Send the request using framework let result = framework.communicate(&test_guids::MM_SUPERVISOR, &request_bytes); @@ -337,7 +337,7 @@ fn test_mm_supervisor_unblock_mem_request() { // Parse response header safely let response_header = MmSupervisorRequestHeader::from_bytes(&response).expect("Should parse response header"); - assert_eq!(response_header.request, mm_supv::requests::UNBLOCK_MEM, "Response should be for UNBLOCK_MEM request"); + assert_eq!(response_header.request, mm_supv::RequestType::UnblockMem as u32, "Response should be for UNBLOCK_MEM request"); assert_eq!(response_header.result, mm_supv::responses::SUCCESS, "Unblock mem request should succeed"); // Parse unblock status safely diff --git a/sdk/patina/src/lib.rs b/sdk/patina/src/lib.rs index 52c6e85c0..8e1c67049 100644 --- a/sdk/patina/src/lib.rs +++ b/sdk/patina/src/lib.rs @@ -50,6 +50,8 @@ pub mod guids; pub mod hash; pub mod log; #[cfg(any(test, feature = "alloc"))] +pub mod mm_services; +#[cfg(any(test, feature = "alloc"))] pub mod performance; pub mod pi; #[cfg(any(test, feature = "alloc"))] diff --git a/sdk/patina/src/mm_services.rs b/sdk/patina/src/mm_services.rs new file mode 100644 index 000000000..70244eaef --- /dev/null +++ b/sdk/patina/src/mm_services.rs @@ -0,0 +1,612 @@ +//! MM (Management Mode) Services type definitions and trait. +//! +//! This module provides the Rust definitions for the PI `EFI_MM_SYSTEM_TABLE` +//! and an `MmServices` trait that wraps the raw C function-pointer table with +//! safe Rust method signatures, following the same pattern as +//! [`boot_services::BootServices`](crate::boot_services::BootServices). +//! +//! ## Layout +//! +//! * [`EfiMmSystemTable`] — `#[repr(C)]` struct matching the C +//! `_EFI_MM_SYSTEM_TABLE` layout from `PiMmCis.h`. +//! * [`MmServices`] — Safe Rust trait exposing the system-table services. +//! * [`StandardMmServices`] — Concrete wrapper around `*mut EfiMmSystemTable` +//! that implements `MmServices` by calling through the function pointers. +//! +//! Cores (e.g., `patina_mm_user_core`) allocate an `EfiMmSystemTable`, populate +//! its function pointers with their own `extern "efiapi"` thunks, and hand the +//! raw pointer to dispatched MM drivers. Drivers that want safe access can wrap +//! it in a `StandardMmServices`. +//! +//! ## License +//! +//! Copyright (c) Microsoft Corporation. +//! +//! SPDX-License-Identifier: Apache-2.0 +//! + +use core::ffi::c_void; + +use r_efi::efi; +use spin::Once; + +// ============================================================================= +// MM System Table Signature and Revision +// ============================================================================= + +/// MMST signature: `'S', 'M', 'S', 'T'` (same as C `MM_MMST_SIGNATURE`). +pub const MM_MMST_SIGNATURE: u64 = 0x5453_4D53; + +/// PI Specification version encoded as `(major << 16) | minor`. +/// PI 1.8 → `0x0001_0050`. +pub const MM_SYSTEM_TABLE_REVISION: u32 = (1 << 16) | 80; + +// ============================================================================= +// EFI_MM_CPU_IO_PROTOCOL (embedded in MMST) +// ============================================================================= + +/// A single MM I/O access function pointer. +/// +/// Matches the C typedef `EFI_MM_CPU_IO`: +/// ```c +/// typedef EFI_STATUS (EFIAPI *EFI_MM_CPU_IO)( +/// IN CONST EFI_MM_CPU_IO_PROTOCOL *This, +/// IN EFI_MM_IO_WIDTH Width, +/// IN UINT64 Address, +/// IN UINTN Count, +/// IN OUT VOID *Buffer +/// ); +/// ``` +pub type MmCpuIoFn = unsafe extern "efiapi" fn( + this: *const MmCpuIoAccess, + width: usize, + address: u64, + count: usize, + buffer: *mut c_void, +) -> efi::Status; + +/// MM CPU I/O access pair (Read + Write). +/// +/// Matches `EFI_MM_IO_ACCESS`. +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct MmCpuIoAccess { + pub read: MmCpuIoFn, + pub write: MmCpuIoFn, +} + +/// The `EFI_MM_CPU_IO_PROTOCOL` embedded in the system table. +/// +/// ```c +/// typedef struct _EFI_MM_CPU_IO_PROTOCOL { +/// EFI_MM_IO_ACCESS Mem; +/// EFI_MM_IO_ACCESS Io; +/// } EFI_MM_CPU_IO_PROTOCOL; +/// ``` +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct MmCpuIoProtocol { + pub mem: MmCpuIoAccess, + pub io: MmCpuIoAccess, +} + +// ============================================================================= +// Function pointer types matching PiMmCis.h typedefs +// ============================================================================= + +/// `EFI_MM_INSTALL_CONFIGURATION_TABLE` +pub type MmInstallConfigurationTableFn = unsafe extern "efiapi" fn( + system_table: *const EfiMmSystemTable, + guid: *const efi::Guid, + table: *mut c_void, + table_size: usize, +) -> efi::Status; + +/// `EFI_ALLOCATE_POOL` (shared with Boot Services) +pub type MmAllocatePoolFn = unsafe extern "efiapi" fn( + pool_type: efi::MemoryType, + size: usize, + buffer: *mut *mut c_void, +) -> efi::Status; + +/// `EFI_FREE_POOL` (shared with Boot Services) +pub type MmFreePoolFn = unsafe extern "efiapi" fn( + buffer: *mut c_void, +) -> efi::Status; + +/// `EFI_ALLOCATE_PAGES` (shared with Boot Services) +pub type MmAllocatePagesFn = unsafe extern "efiapi" fn( + alloc_type: efi::AllocateType, + memory_type: efi::MemoryType, + pages: usize, + memory: *mut efi::PhysicalAddress, +) -> efi::Status; + +/// `EFI_FREE_PAGES` (shared with Boot Services) +pub type MmFreePagesFn = unsafe extern "efiapi" fn( + memory: efi::PhysicalAddress, + pages: usize, +) -> efi::Status; + +/// `EFI_MM_STARTUP_THIS_AP` +pub type MmStartupThisApFn = unsafe extern "efiapi" fn( + procedure: usize, + cpu_number: usize, + proc_arguments: *mut c_void, +) -> efi::Status; + +/// `EFI_INSTALL_PROTOCOL_INTERFACE` (shared with Boot Services) +pub type MmInstallProtocolInterfaceFn = unsafe extern "efiapi" fn( + handle: *mut efi::Handle, + protocol: *mut efi::Guid, + interface_type: efi::InterfaceType, + interface: *mut c_void, +) -> efi::Status; + +/// `EFI_UNINSTALL_PROTOCOL_INTERFACE` (shared with Boot Services) +pub type MmUninstallProtocolInterfaceFn = unsafe extern "efiapi" fn( + handle: efi::Handle, + protocol: *mut efi::Guid, + interface: *mut c_void, +) -> efi::Status; + +/// `EFI_HANDLE_PROTOCOL` (shared with Boot Services) +pub type MmHandleProtocolFn = unsafe extern "efiapi" fn( + handle: efi::Handle, + protocol: *mut efi::Guid, + interface: *mut *mut c_void, +) -> efi::Status; + +/// `EFI_MM_REGISTER_PROTOCOL_NOTIFY` +pub type MmRegisterProtocolNotifyFn = unsafe extern "efiapi" fn( + protocol: *const efi::Guid, + function: usize, + registration: *mut *mut c_void, +) -> efi::Status; + +/// `EFI_LOCATE_HANDLE` (shared with Boot Services) +pub type MmLocateHandleFn = unsafe extern "efiapi" fn( + search_type: efi::LocateSearchType, + protocol: *mut efi::Guid, + search_key: *mut c_void, + buffer_size: *mut usize, + buffer: *mut efi::Handle, +) -> efi::Status; + +/// `EFI_LOCATE_PROTOCOL` (shared with Boot Services) +pub type MmLocateProtocolFn = unsafe extern "efiapi" fn( + protocol: *mut efi::Guid, + registration: *mut c_void, + interface: *mut *mut c_void, +) -> efi::Status; + +/// `EFI_MM_INTERRUPT_MANAGE` +pub type MmiManageFn = unsafe extern "efiapi" fn( + handler_type: *const efi::Guid, + context: *const c_void, + comm_buffer: *mut c_void, + comm_buffer_size: *mut usize, +) -> efi::Status; + +/// MMI handler entry point. +/// +/// Matches the C typedef `EFI_MM_HANDLER_ENTRY_POINT`. +pub type MmiHandlerEntryPoint = unsafe extern "efiapi" fn( + dispatch_handle: efi::Handle, + context: *const c_void, + comm_buffer: *mut c_void, + comm_buffer_size: *mut usize, +) -> efi::Status; + +/// `EFI_MM_INTERRUPT_REGISTER` +pub type MmiHandlerRegisterFn = unsafe extern "efiapi" fn( + handler: MmiHandlerEntryPoint, + handler_type: *const efi::Guid, + dispatch_handle: *mut efi::Handle, +) -> efi::Status; + +/// `EFI_MM_INTERRUPT_UNREGISTER` +pub type MmiHandlerUnregisterFn = unsafe extern "efiapi" fn( + dispatch_handle: efi::Handle, +) -> efi::Status; + +// ============================================================================= +// EFI_MM_SYSTEM_TABLE (#[repr(C)]) +// ============================================================================= + +/// The Management Mode System Table (MMST). +/// +/// This is the `#[repr(C)]` Rust definition of the C `_EFI_MM_SYSTEM_TABLE` +/// from `PiMmCis.h`. The table pointer is passed as the second argument to +/// every MM driver's entry point: +/// +/// ```c +/// EFI_STATUS EFIAPI DriverEntry(EFI_HANDLE ImageHandle, EFI_MM_SYSTEM_TABLE *MmSt); +/// ``` +#[repr(C)] +pub struct EfiMmSystemTable { + // ---- Table Header ---- + pub hdr: efi::TableHeader, + + // ---- Firmware info ---- + /// Pointer to a NUL-terminated UCS-2 vendor string (may be null). + pub mm_firmware_vendor: *mut u16, + /// Firmware revision number. + pub mm_firmware_revision: u32, + + // ---- Configuration Table ---- + pub mm_install_configuration_table: MmInstallConfigurationTableFn, + + // ---- I/O services (embedded protocol) ---- + pub mm_io: MmCpuIoProtocol, + + // ---- Memory services ---- + pub mm_allocate_pool: MmAllocatePoolFn, + pub mm_free_pool: MmFreePoolFn, + pub mm_allocate_pages: MmAllocatePagesFn, + pub mm_free_pages: MmFreePagesFn, + + // ---- MP service ---- + pub mm_startup_this_ap: MmStartupThisApFn, + + // ---- CPU information ---- + pub currently_executing_cpu: usize, + pub number_of_cpus: usize, + pub cpu_save_state_size: *mut usize, + pub cpu_save_state: *mut *mut c_void, + + // ---- Extensibility table ---- + pub number_of_table_entries: usize, + pub mm_configuration_table: *mut efi::ConfigurationTable, + + // ---- Protocol services ---- + pub mm_install_protocol_interface: MmInstallProtocolInterfaceFn, + pub mm_uninstall_protocol_interface: MmUninstallProtocolInterfaceFn, + pub mm_handle_protocol: MmHandleProtocolFn, + pub mm_register_protocol_notify: MmRegisterProtocolNotifyFn, + pub mm_locate_handle: MmLocateHandleFn, + pub mm_locate_protocol: MmLocateProtocolFn, + + // ---- MMI management ---- + pub mmi_manage: MmiManageFn, + pub mmi_handler_register: MmiHandlerRegisterFn, + pub mmi_handler_unregister: MmiHandlerUnregisterFn, +} + +// SAFETY: The system table is allocated once and its pointer is shared read-only +// with dispatched drivers. Internal mutation goes through synchronized databases. +unsafe impl Send for EfiMmSystemTable {} +unsafe impl Sync for EfiMmSystemTable {} + +// ============================================================================= +// StandardMmServices +// ============================================================================= + +/// Wrapper around a raw `*mut EfiMmSystemTable` pointer that implements +/// [`MmServices`] by calling through the C function-pointer table. +/// +/// This is the MM equivalent of +/// [`StandardBootServices`](crate::boot_services::StandardBootServices). +pub struct StandardMmServices { + efi_mm_system_table: Once<*mut EfiMmSystemTable>, +} + +// SAFETY: The raw pointer is only written once (protected by `Once`) and the +// underlying table is not expected to change after initialisation. +unsafe impl Sync for StandardMmServices {} +unsafe impl Send for StandardMmServices {} + +impl StandardMmServices { + /// Create a new `StandardMmServices` from an existing system table pointer. + pub fn new(mm_system_table: *mut EfiMmSystemTable) -> Self { + let this = Self::new_uninit(); + this.init(mm_system_table); + this + } + + /// Create an uninitialised instance. + pub const fn new_uninit() -> Self { + Self { efi_mm_system_table: Once::new() } + } + + /// Initialise with the given system table pointer. + pub fn init(&self, mm_system_table: *mut EfiMmSystemTable) { + self.efi_mm_system_table.call_once(|| mm_system_table); + } + + /// Returns `true` if the instance has been initialised. + pub fn is_init(&self) -> bool { + self.efi_mm_system_table.is_completed() + } + + /// Returns the raw system table pointer (panics if uninitialised). + pub fn as_mut_ptr(&self) -> *mut EfiMmSystemTable { + *self.efi_mm_system_table.get().expect("StandardMmServices is not initialized!") + } +} + +impl Clone for StandardMmServices { + fn clone(&self) -> Self { + if let Some(ptr) = self.efi_mm_system_table.get() { + StandardMmServices::new(*ptr) + } else { + StandardMmServices::new_uninit() + } + } +} + +impl core::fmt::Debug for StandardMmServices { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if !self.is_init() { + return f.debug_struct("StandardMmServices").field("table", &"Not Initialized").finish(); + } + f.debug_struct("StandardMmServices").field("table", &self.as_mut_ptr()).finish() + } +} + +// ============================================================================= +// MmServices Trait +// ============================================================================= + +/// Safe Rust interface to the MM System Table services. +/// +/// This is the MM analogue of +/// [`BootServices`](crate::boot_services::BootServices). +/// Each method maps 1:1 to a function pointer in [`EfiMmSystemTable`]. +pub trait MmServices { + // ---- Memory services ------------------------------------------------ + + /// Allocate pool memory. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmAllocatePool` + fn allocate_pool(&self, pool_type: efi::MemoryType, size: usize) -> Result<*mut u8, efi::Status>; + + /// Free pool memory. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmFreePool` + fn free_pool(&self, buffer: *mut u8) -> Result<(), efi::Status>; + + /// Allocate pages. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmAllocatePages` + fn allocate_pages( + &self, + alloc_type: efi::AllocateType, + memory_type: efi::MemoryType, + pages: usize, + ) -> Result; + + /// Free pages. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmFreePages` + fn free_pages(&self, memory: u64, pages: usize) -> Result<(), efi::Status>; + + // ---- Protocol services ---------------------------------------------- + + /// Install a protocol interface on a handle. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmInstallProtocolInterface` + /// + /// # Safety + /// + /// `interface` must be a valid pointer to the protocol structure or null. + unsafe fn install_protocol_interface( + &self, + handle: *mut efi::Handle, + protocol: &efi::Guid, + interface_type: efi::InterfaceType, + interface: *mut c_void, + ) -> Result<(), efi::Status>; + + /// Uninstall a protocol interface from a handle. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmUninstallProtocolInterface` + /// + /// # Safety + /// + /// `interface` must match the pointer that was installed. + unsafe fn uninstall_protocol_interface( + &self, + handle: efi::Handle, + protocol: &efi::Guid, + interface: *mut c_void, + ) -> Result<(), efi::Status>; + + /// Query a handle for a protocol. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmHandleProtocol` + /// + /// # Safety + /// + /// The returned pointer must be used carefully to avoid aliasing violations. + unsafe fn handle_protocol( + &self, + handle: efi::Handle, + protocol: &efi::Guid, + ) -> Result<*mut c_void, efi::Status>; + + /// Locate the first device that supports a protocol. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmLocateProtocol` + /// + /// # Safety + /// + /// The returned pointer must be used carefully to avoid aliasing violations. + unsafe fn locate_protocol( + &self, + protocol: &efi::Guid, + ) -> Result<*mut c_void, efi::Status>; + + // ---- MMI management ------------------------------------------------- + + /// Manage (dispatch) an MMI. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmiManage` + fn mmi_manage( + &self, + handler_type: Option<&efi::Guid>, + context: *const c_void, + comm_buffer: *mut c_void, + comm_buffer_size: *mut usize, + ) -> efi::Status; + + /// Register an MMI handler. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmiHandlerRegister` + fn mmi_handler_register( + &self, + handler: MmiHandlerEntryPoint, + handler_type: Option<&efi::Guid>, + ) -> Result; + + /// Unregister an MMI handler. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmiHandlerUnRegister` + fn mmi_handler_unregister( + &self, + dispatch_handle: efi::Handle, + ) -> Result<(), efi::Status>; +} + +// ============================================================================= +// MmServices implementation for StandardMmServices +// ============================================================================= + +impl MmServices for StandardMmServices { + fn allocate_pool(&self, pool_type: efi::MemoryType, size: usize) -> Result<*mut u8, efi::Status> { + let mmst = unsafe { &*self.as_mut_ptr() }; + let mut buffer: *mut c_void = core::ptr::null_mut(); + let status = unsafe { (mmst.mm_allocate_pool)(pool_type, size, &mut buffer) }; + if status == efi::Status::SUCCESS { + Ok(buffer as *mut u8) + } else { + Err(status) + } + } + + fn free_pool(&self, buffer: *mut u8) -> Result<(), efi::Status> { + let mmst = unsafe { &*self.as_mut_ptr() }; + let status = unsafe { (mmst.mm_free_pool)(buffer as *mut c_void) }; + if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } + } + + fn allocate_pages( + &self, + alloc_type: efi::AllocateType, + memory_type: efi::MemoryType, + pages: usize, + ) -> Result { + let mmst = unsafe { &*self.as_mut_ptr() }; + let mut memory: efi::PhysicalAddress = 0; + let status = unsafe { (mmst.mm_allocate_pages)(alloc_type, memory_type, pages, &mut memory) }; + if status == efi::Status::SUCCESS { Ok(memory) } else { Err(status) } + } + + fn free_pages(&self, memory: u64, pages: usize) -> Result<(), efi::Status> { + let mmst = unsafe { &*self.as_mut_ptr() }; + let status = unsafe { (mmst.mm_free_pages)(memory, pages) }; + if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } + } + + unsafe fn install_protocol_interface( + &self, + handle: *mut efi::Handle, + protocol: &efi::Guid, + interface_type: efi::InterfaceType, + interface: *mut c_void, + ) -> Result<(), efi::Status> { + let mmst = unsafe { &*self.as_mut_ptr() }; + let status = unsafe { + (mmst.mm_install_protocol_interface)( + handle, + protocol as *const efi::Guid as *mut efi::Guid, + interface_type, + interface, + ) + }; + if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } + } + + unsafe fn uninstall_protocol_interface( + &self, + handle: efi::Handle, + protocol: &efi::Guid, + interface: *mut c_void, + ) -> Result<(), efi::Status> { + let mmst = unsafe { &*self.as_mut_ptr() }; + let status = unsafe { + (mmst.mm_uninstall_protocol_interface)( + handle, + protocol as *const efi::Guid as *mut efi::Guid, + interface, + ) + }; + if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } + } + + unsafe fn handle_protocol( + &self, + handle: efi::Handle, + protocol: &efi::Guid, + ) -> Result<*mut c_void, efi::Status> { + let mmst = unsafe { &*self.as_mut_ptr() }; + let mut interface: *mut c_void = core::ptr::null_mut(); + let status = unsafe { + (mmst.mm_handle_protocol)( + handle, + protocol as *const efi::Guid as *mut efi::Guid, + &mut interface, + ) + }; + if status == efi::Status::SUCCESS { Ok(interface) } else { Err(status) } + } + + unsafe fn locate_protocol( + &self, + protocol: &efi::Guid, + ) -> Result<*mut c_void, efi::Status> { + let mmst = unsafe { &*self.as_mut_ptr() }; + let mut interface: *mut c_void = core::ptr::null_mut(); + let status = unsafe { + (mmst.mm_locate_protocol)( + protocol as *const efi::Guid as *mut efi::Guid, + core::ptr::null_mut(), + &mut interface, + ) + }; + if status == efi::Status::SUCCESS { Ok(interface) } else { Err(status) } + } + + fn mmi_manage( + &self, + handler_type: Option<&efi::Guid>, + context: *const c_void, + comm_buffer: *mut c_void, + comm_buffer_size: *mut usize, + ) -> efi::Status { + let mmst = unsafe { &*self.as_mut_ptr() }; + let guid_ptr = handler_type.map_or(core::ptr::null(), |g| g as *const efi::Guid); + unsafe { (mmst.mmi_manage)(guid_ptr, context, comm_buffer, comm_buffer_size) } + } + + fn mmi_handler_register( + &self, + handler: MmiHandlerEntryPoint, + handler_type: Option<&efi::Guid>, + ) -> Result { + let mmst = unsafe { &*self.as_mut_ptr() }; + let guid_ptr = handler_type.map_or(core::ptr::null(), |g| g as *const efi::Guid); + let mut dispatch_handle: efi::Handle = core::ptr::null_mut(); + let status = unsafe { (mmst.mmi_handler_register)(handler, guid_ptr, &mut dispatch_handle) }; + if status == efi::Status::SUCCESS { Ok(dispatch_handle) } else { Err(status) } + } + + fn mmi_handler_unregister( + &self, + dispatch_handle: efi::Handle, + ) -> Result<(), efi::Status> { + let mmst = unsafe { &*self.as_mut_ptr() }; + let status = unsafe { (mmst.mmi_handler_unregister)(dispatch_handle) }; + if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } + } +} From 34093d1d5d9a8e9b470a161e920c4415895bea9c Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Tue, 17 Mar 2026 21:51:09 -0700 Subject: [PATCH 02/26] Use new GUID format --- components/patina_mm/src/comm_buffer_hob.rs | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/components/patina_mm/src/comm_buffer_hob.rs b/components/patina_mm/src/comm_buffer_hob.rs index ef06fef6a..bf41651b8 100644 --- a/components/patina_mm/src/comm_buffer_hob.rs +++ b/components/patina_mm/src/comm_buffer_hob.rs @@ -19,25 +19,14 @@ //! SPDX-License-Identifier: Apache-2.0 //! -use r_efi::efi; -use patina::Guid; +use patina::{Guid, BinaryGuid}; use zerocopy_derive::{FromBytes, Immutable, KnownLayout}; -// ============================================================================= -// GUIDs -// ============================================================================= - /// GUID for the MM communication buffer HOB (`gMmCommBufferHobGuid`). /// /// `{ 0x6c2a2520, 0x0131, 0x4aee, { 0xa7, 0x50, 0xcc, 0x38, 0x4a, 0xac, 0xe8, 0xc6 } }` -pub const MM_COMM_BUFFER_HOB_GUID: efi::Guid = efi::Guid::from_fields( - 0x6c2a2520, - 0x0131, - 0x4aee, - 0xa7, - 0x50, - &[0xcc, 0x38, 0x4a, 0xac, 0xe8, 0xc6], -); +pub const MM_COMM_BUFFER_HOB_GUID: BinaryGuid = + BinaryGuid::from_string("6c2a2520-0131-4aee-a750-cc384aace8c6"); /// MM Common Buffer HOB Data Structure. /// @@ -156,10 +145,6 @@ impl EfiMmCommunicateHeader { } } -// ============================================================================= -// Communication Structures -// ============================================================================= - /// EFI_MM_ENTRY_CONTEXT structure. /// /// Processor information and functionality needed by MM Foundation. From 9585d379431057fbc75a18314f7cada69fd264d5 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Tue, 17 Mar 2026 21:55:24 -0700 Subject: [PATCH 03/26] some cleanup --- sdk/patina/src/mm_services.rs | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/sdk/patina/src/mm_services.rs b/sdk/patina/src/mm_services.rs index 70244eaef..1b5d5120b 100644 --- a/sdk/patina/src/mm_services.rs +++ b/sdk/patina/src/mm_services.rs @@ -30,10 +30,6 @@ use core::ffi::c_void; use r_efi::efi; use spin::Once; -// ============================================================================= -// MM System Table Signature and Revision -// ============================================================================= - /// MMST signature: `'S', 'M', 'S', 'T'` (same as C `MM_MMST_SIGNATURE`). pub const MM_MMST_SIGNATURE: u64 = 0x5453_4D53; @@ -41,10 +37,6 @@ pub const MM_MMST_SIGNATURE: u64 = 0x5453_4D53; /// PI 1.8 → `0x0001_0050`. pub const MM_SYSTEM_TABLE_REVISION: u32 = (1 << 16) | 80; -// ============================================================================= -// EFI_MM_CPU_IO_PROTOCOL (embedded in MMST) -// ============================================================================= - /// A single MM I/O access function pointer. /// /// Matches the C typedef `EFI_MM_CPU_IO`: @@ -90,10 +82,6 @@ pub struct MmCpuIoProtocol { pub io: MmCpuIoAccess, } -// ============================================================================= -// Function pointer types matching PiMmCis.h typedefs -// ============================================================================= - /// `EFI_MM_INSTALL_CONFIGURATION_TABLE` pub type MmInstallConfigurationTableFn = unsafe extern "efiapi" fn( system_table: *const EfiMmSystemTable, @@ -210,10 +198,6 @@ pub type MmiHandlerUnregisterFn = unsafe extern "efiapi" fn( dispatch_handle: efi::Handle, ) -> efi::Status; -// ============================================================================= -// EFI_MM_SYSTEM_TABLE (#[repr(C)]) -// ============================================================================= - /// The Management Mode System Table (MMST). /// /// This is the `#[repr(C)]` Rust definition of the C `_EFI_MM_SYSTEM_TABLE` @@ -278,10 +262,6 @@ pub struct EfiMmSystemTable { unsafe impl Send for EfiMmSystemTable {} unsafe impl Sync for EfiMmSystemTable {} -// ============================================================================= -// StandardMmServices -// ============================================================================= - /// Wrapper around a raw `*mut EfiMmSystemTable` pointer that implements /// [`MmServices`] by calling through the C function-pointer table. /// @@ -344,18 +324,12 @@ impl core::fmt::Debug for StandardMmServices { } } -// ============================================================================= -// MmServices Trait -// ============================================================================= - /// Safe Rust interface to the MM System Table services. /// /// This is the MM analogue of /// [`BootServices`](crate::boot_services::BootServices). /// Each method maps 1:1 to a function pointer in [`EfiMmSystemTable`]. pub trait MmServices { - // ---- Memory services ------------------------------------------------ - /// Allocate pool memory. /// /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmAllocatePool` @@ -381,8 +355,6 @@ pub trait MmServices { /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmFreePages` fn free_pages(&self, memory: u64, pages: usize) -> Result<(), efi::Status>; - // ---- Protocol services ---------------------------------------------- - /// Install a protocol interface on a handle. /// /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmInstallProtocolInterface` @@ -437,8 +409,6 @@ pub trait MmServices { protocol: &efi::Guid, ) -> Result<*mut c_void, efi::Status>; - // ---- MMI management ------------------------------------------------- - /// Manage (dispatch) an MMI. /// /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmiManage` @@ -468,10 +438,6 @@ pub trait MmServices { ) -> Result<(), efi::Status>; } -// ============================================================================= -// MmServices implementation for StandardMmServices -// ============================================================================= - impl MmServices for StandardMmServices { fn allocate_pool(&self, pool_type: efi::MemoryType, size: usize) -> Result<*mut u8, efi::Status> { let mmst = unsafe { &*self.as_mut_ptr() }; From 8addd46ec63e809b1b0f2e0732ae92c9e5a820f4 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Tue, 17 Mar 2026 22:08:21 -0700 Subject: [PATCH 04/26] some more cleanup? --- .../src/protocol/mm_supervisor_request.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/components/patina_mm/src/protocol/mm_supervisor_request.rs b/components/patina_mm/src/protocol/mm_supervisor_request.rs index 46c20e54a..5c590e156 100644 --- a/components/patina_mm/src/protocol/mm_supervisor_request.rs +++ b/components/patina_mm/src/protocol/mm_supervisor_request.rs @@ -19,19 +19,13 @@ use zerocopy::FromBytes; use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout}; -use r_efi::efi::Guid; +use patina::{Guid, BinaryGuid}; // GUID for gMmSupervisorRequestHandlerGuid // { 0x8c633b23, 0x1260, 0x4ea6, { 0x83, 0xf, 0x7d, 0xdc, 0x97, 0x38, 0x21, 0x11 } } /// GUID for the MM Supervisor Request Handler protocol. -pub const MM_SUPERVISOR_REQUEST_HANDLER_GUID: Guid = Guid::from_fields( - 0x8c633b23, - 0x1260, - 0x4ea6, - 0x83, - 0x0F, - &[0x7d, 0xdc, 0x97, 0x38, 0x21, 0x11], -); +pub const MM_SUPERVISOR_REQUEST_HANDLER_GUID: BinaryGuid = + BinaryGuid::from_string("8c633b23-1260-4ea6-830f-7ddc97382111"); /// MM Supervisor request header. /// @@ -217,7 +211,7 @@ pub struct MmSupervisorUnblockMemoryParams { /// Memory descriptor identifying the region to unblock. pub memory_descriptor: efi::MemoryDescriptor, /// GUID identifying the requesting driver/module. - pub identifier_guid: Guid, + pub identifier_guid: BinaryGuid, } impl MmSupervisorUnblockMemoryParams { From bf79f0f9b07b88dff5a4994fd938015b105c612f Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Wed, 18 Mar 2026 00:42:32 -0700 Subject: [PATCH 05/26] misspell --- sdk/patina/src/mm_services.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sdk/patina/src/mm_services.rs b/sdk/patina/src/mm_services.rs index 1b5d5120b..c19d7206f 100644 --- a/sdk/patina/src/mm_services.rs +++ b/sdk/patina/src/mm_services.rs @@ -272,7 +272,7 @@ pub struct StandardMmServices { } // SAFETY: The raw pointer is only written once (protected by `Once`) and the -// underlying table is not expected to change after initialisation. +// underlying table is not expected to change after initialization. unsafe impl Sync for StandardMmServices {} unsafe impl Send for StandardMmServices {} @@ -284,22 +284,22 @@ impl StandardMmServices { this } - /// Create an uninitialised instance. + /// Create an uninitialized instance. pub const fn new_uninit() -> Self { Self { efi_mm_system_table: Once::new() } } - /// Initialise with the given system table pointer. + /// Initialize with the given system table pointer. pub fn init(&self, mm_system_table: *mut EfiMmSystemTable) { self.efi_mm_system_table.call_once(|| mm_system_table); } - /// Returns `true` if the instance has been initialised. + /// Returns `true` if the instance has been initialized. pub fn is_init(&self) -> bool { self.efi_mm_system_table.is_completed() } - /// Returns the raw system table pointer (panics if uninitialised). + /// Returns the raw system table pointer (panics if uninitialized). pub fn as_mut_ptr(&self) -> *mut EfiMmSystemTable { *self.efi_mm_system_table.get().expect("StandardMmServices is not initialized!") } From e1a7297b1de249c02c9bdbbe9fe878d3177fce32 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Wed, 18 Mar 2026 11:20:18 -0700 Subject: [PATCH 06/26] fmt --- components/patina_mm/src/comm_buffer_hob.rs | 343 +++-- .../patina_mm/src/component/communicator.rs | 2 +- components/patina_mm/src/config.rs | 2 +- components/patina_mm/src/lib.rs | 4 +- .../src/protocol/mm_supervisor_request.rs | 440 +++---- .../patina_mm_integration/common/constants.rs | 5 +- .../patina_mm_integration/common/handlers.rs | 5 +- .../mm_supervisor/communication_tests.rs | 12 +- sdk/patina/src/mm_services.rs | 1108 ++++++++--------- 9 files changed, 937 insertions(+), 984 deletions(-) diff --git a/components/patina_mm/src/comm_buffer_hob.rs b/components/patina_mm/src/comm_buffer_hob.rs index bf41651b8..09088e2bd 100644 --- a/components/patina_mm/src/comm_buffer_hob.rs +++ b/components/patina_mm/src/comm_buffer_hob.rs @@ -1,172 +1,171 @@ -//! Management Mode (MM) Header and Buffer HOB Definitions -//! -//! Defines the header and buffer HOB structures necessary for the MM environment to be initialized and used by components -//! dependent on MM details. -//! -//! ## MM HOB Usage -//! -//! It is expected that the MM HOB buffer will be initialized by the environment that registers services for the -//! platform. The HOBs can have platform-fixed values assigned during their initialization. It should be common -//! for at least the communication buffers to be populated as a mutable HOB during boot time. It is -//! recommended for a "MM HOB" component to handle all MM HOB details with minimal other MM related -//! dependencies and lock the HOBs so they are available for components that depend on the immutable HOB -//! to perform MM operations. -//! -//! ## License -//! -//! Copyright (C) Microsoft Corporation. -//! -//! SPDX-License-Identifier: Apache-2.0 -//! - -use patina::{Guid, BinaryGuid}; -use zerocopy_derive::{FromBytes, Immutable, KnownLayout}; - -/// GUID for the MM communication buffer HOB (`gMmCommBufferHobGuid`). -/// -/// `{ 0x6c2a2520, 0x0131, 0x4aee, { 0xa7, 0x50, 0xcc, 0x38, 0x4a, 0xac, 0xe8, 0xc6 } }` -pub const MM_COMM_BUFFER_HOB_GUID: BinaryGuid = - BinaryGuid::from_string("6c2a2520-0131-4aee-a750-cc384aace8c6"); - -/// MM Common Buffer HOB Data Structure. -/// -/// Describes the communication buffer region passed via HOB from PEI to MM. -#[repr(C, packed)] -#[derive(Debug, Clone, Copy)] -pub struct MmCommonBufferHobData { - /// Physical start address of the common region. - pub physical_start: u64, - /// Number of pages in the communication buffer region. - pub number_of_pages: u64, - /// Pointer to `MmCommBufferStatus` structure. - pub status_buffer: u64, -} - -/// MM Communication Buffer Status -/// -/// Shared structure between DXE and MM environments to communicate the status -/// of MM communication operations. This structure is written by DXE before -/// triggering an MMI and read/written by MM during MMI processing. -/// -/// This is a structure currently used in some MM Supervisor MM implementations. -#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)] -#[repr(C)] -pub struct MmCommBufferStatus { - /// Whether the data in the fixed MM communication buffer is valid when entering from non-MM to MM. - /// Must be set to TRUE before triggering MMI, will be set to FALSE by MM after processing. - pub is_comm_buffer_valid: u8, - - /// The channel used to communicate with MM. - /// FALSE = user buffer, TRUE = supervisor buffer - pub talk_to_supervisor: u8, - - /// The return status when returning from MM to non-MM. - pub return_status: u64, - - /// The size in bytes of the output buffer when returning from MM to non-MM. - pub return_buffer_size: u64, -} - -impl Default for MmCommBufferStatus { - #[coverage(off)] - fn default() -> Self { - Self::new() - } -} - -impl MmCommBufferStatus { - /// Create a new mailbox status with all fields zeroed - pub const fn new() -> Self { - Self { is_comm_buffer_valid: 0, talk_to_supervisor: 0, return_status: 0, return_buffer_size: 0 } - } -} - -/// UEFI MM Communicate Header -/// -/// A standard header that must be present at the beginning of any MM communication buffer. -/// -/// ## Notes -/// -/// - This only supports V1 and V2 of the MM Communicate header format. -#[derive(Debug, Clone, Copy)] -#[repr(C)] -pub struct EfiMmCommunicateHeader { - /// Allows for disambiguation of the message format. - /// Used to identify the registered MM handlers that should be given the message. - header_guid: patina::BinaryGuid, - /// The size of Data (in bytes) and does not include the size of the header. - message_length: usize, -} - -impl EfiMmCommunicateHeader { - /// Create a new communicate header with the specified GUID and message length. - pub fn new(header_guid: Guid, message_length: usize) -> Self { - Self { header_guid: header_guid.to_efi_guid().into(), message_length } - } - - /// Returns the communicate header as a slice of bytes using safe conversion. - /// - /// Useful if byte-level access to the header structure is needed. - pub fn as_bytes(&self) -> &[u8] { - // SAFETY: EfiMmCommunicateHeader is repr(C) with well-defined layout and size - unsafe { core::slice::from_raw_parts(self as *const _ as *const u8, Self::size()) } - } - - /// Returns the size of the header in bytes. - pub const fn size() -> usize { - core::mem::size_of::() - } - - /// Get the header GUID from the communication buffer. - /// - /// Returns `Some(guid)` if the buffer has been properly initialized with a GUID, - /// or `None` if the buffer is not initialized. - /// - /// # Returns - /// - /// The GUID from the communication header if available. - /// - /// # Errors - /// - /// Returns an error if the communication buffer header cannot be read. - pub fn header_guid(&self) -> Guid<'_> { - Guid::from_ref(&self.header_guid) - } - - /// Returns the message length from this communicate header. - /// - /// The length represents the size of the message data that follows the header. - /// - /// # Returns - /// - /// The length in bytes of the message data (excluding the header size). - pub const fn message_length(&self) -> usize { - self.message_length - } -} - -/// EFI_MM_ENTRY_CONTEXT structure. -/// -/// Processor information and functionality needed by MM Foundation. -/// Matches the C `EFI_MM_ENTRY_CONTEXT` / `EFI_SMM_ENTRY_CONTEXT` from PI specification. -/// -/// Layout (x86_64, all fields 8 bytes): -/// - `mm_startup_this_ap`: Function pointer for `EFI_MM_STARTUP_THIS_AP` -/// - `currently_executing_cpu`: Index of the processor executing the MM Foundation -/// - `number_of_cpus`: Total number of possible processors in the platform (1-based) -/// - `cpu_save_state_size`: Pointer to array of save state sizes per CPU -/// - `cpu_save_state`: Pointer to array of CPU save state pointers -#[derive(Debug, Clone, Copy)] -#[repr(C)] -pub struct EfiMmEntryContext { - /// Function pointer for EFI_MM_STARTUP_THIS_AP. - pub mm_startup_this_ap: u64, - /// Index of the currently executing CPU. - pub currently_executing_cpu: u64, - /// Total number of CPUs (1-based). - pub number_of_cpus: u64, - /// Pointer to array of per-CPU save state sizes. - pub cpu_save_state_size: u64, - /// Pointer to array of per-CPU save state pointers. - pub cpu_save_state: u64, -} +//! Management Mode (MM) Header and Buffer HOB Definitions +//! +//! Defines the header and buffer HOB structures necessary for the MM environment to be initialized and used by components +//! dependent on MM details. +//! +//! ## MM HOB Usage +//! +//! It is expected that the MM HOB buffer will be initialized by the environment that registers services for the +//! platform. The HOBs can have platform-fixed values assigned during their initialization. It should be common +//! for at least the communication buffers to be populated as a mutable HOB during boot time. It is +//! recommended for a "MM HOB" component to handle all MM HOB details with minimal other MM related +//! dependencies and lock the HOBs so they are available for components that depend on the immutable HOB +//! to perform MM operations. +//! +//! ## License +//! +//! Copyright (C) Microsoft Corporation. +//! +//! SPDX-License-Identifier: Apache-2.0 +//! + +use patina::{BinaryGuid, Guid}; +use zerocopy_derive::{FromBytes, Immutable, KnownLayout}; + +/// GUID for the MM communication buffer HOB (`gMmCommBufferHobGuid`). +/// +/// `{ 0x6c2a2520, 0x0131, 0x4aee, { 0xa7, 0x50, 0xcc, 0x38, 0x4a, 0xac, 0xe8, 0xc6 } }` +pub const MM_COMM_BUFFER_HOB_GUID: BinaryGuid = BinaryGuid::from_string("6c2a2520-0131-4aee-a750-cc384aace8c6"); + +/// MM Common Buffer HOB Data Structure. +/// +/// Describes the communication buffer region passed via HOB from PEI to MM. +#[repr(C, packed)] +#[derive(Debug, Clone, Copy)] +pub struct MmCommonBufferHobData { + /// Physical start address of the common region. + pub physical_start: u64, + /// Number of pages in the communication buffer region. + pub number_of_pages: u64, + /// Pointer to `MmCommBufferStatus` structure. + pub status_buffer: u64, +} + +/// MM Communication Buffer Status +/// +/// Shared structure between DXE and MM environments to communicate the status +/// of MM communication operations. This structure is written by DXE before +/// triggering an MMI and read/written by MM during MMI processing. +/// +/// This is a structure currently used in some MM Supervisor MM implementations. +#[derive(Debug, Clone, Copy, FromBytes, Immutable, KnownLayout)] +#[repr(C)] +pub struct MmCommBufferStatus { + /// Whether the data in the fixed MM communication buffer is valid when entering from non-MM to MM. + /// Must be set to TRUE before triggering MMI, will be set to FALSE by MM after processing. + pub is_comm_buffer_valid: u8, + + /// The channel used to communicate with MM. + /// FALSE = user buffer, TRUE = supervisor buffer + pub talk_to_supervisor: u8, + + /// The return status when returning from MM to non-MM. + pub return_status: u64, + + /// The size in bytes of the output buffer when returning from MM to non-MM. + pub return_buffer_size: u64, +} + +impl Default for MmCommBufferStatus { + #[coverage(off)] + fn default() -> Self { + Self::new() + } +} + +impl MmCommBufferStatus { + /// Create a new mailbox status with all fields zeroed + pub const fn new() -> Self { + Self { is_comm_buffer_valid: 0, talk_to_supervisor: 0, return_status: 0, return_buffer_size: 0 } + } +} + +/// UEFI MM Communicate Header +/// +/// A standard header that must be present at the beginning of any MM communication buffer. +/// +/// ## Notes +/// +/// - This only supports V1 and V2 of the MM Communicate header format. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct EfiMmCommunicateHeader { + /// Allows for disambiguation of the message format. + /// Used to identify the registered MM handlers that should be given the message. + header_guid: patina::BinaryGuid, + /// The size of Data (in bytes) and does not include the size of the header. + message_length: usize, +} + +impl EfiMmCommunicateHeader { + /// Create a new communicate header with the specified GUID and message length. + pub fn new(header_guid: Guid, message_length: usize) -> Self { + Self { header_guid: header_guid.to_efi_guid().into(), message_length } + } + + /// Returns the communicate header as a slice of bytes using safe conversion. + /// + /// Useful if byte-level access to the header structure is needed. + pub fn as_bytes(&self) -> &[u8] { + // SAFETY: EfiMmCommunicateHeader is repr(C) with well-defined layout and size + unsafe { core::slice::from_raw_parts(self as *const _ as *const u8, Self::size()) } + } + + /// Returns the size of the header in bytes. + pub const fn size() -> usize { + core::mem::size_of::() + } + + /// Get the header GUID from the communication buffer. + /// + /// Returns `Some(guid)` if the buffer has been properly initialized with a GUID, + /// or `None` if the buffer is not initialized. + /// + /// # Returns + /// + /// The GUID from the communication header if available. + /// + /// # Errors + /// + /// Returns an error if the communication buffer header cannot be read. + pub fn header_guid(&self) -> Guid<'_> { + Guid::from_ref(&self.header_guid) + } + + /// Returns the message length from this communicate header. + /// + /// The length represents the size of the message data that follows the header. + /// + /// # Returns + /// + /// The length in bytes of the message data (excluding the header size). + pub const fn message_length(&self) -> usize { + self.message_length + } +} + +/// EFI_MM_ENTRY_CONTEXT structure. +/// +/// Processor information and functionality needed by MM Foundation. +/// Matches the C `EFI_MM_ENTRY_CONTEXT` / `EFI_SMM_ENTRY_CONTEXT` from PI specification. +/// +/// Layout (x86_64, all fields 8 bytes): +/// - `mm_startup_this_ap`: Function pointer for `EFI_MM_STARTUP_THIS_AP` +/// - `currently_executing_cpu`: Index of the processor executing the MM Foundation +/// - `number_of_cpus`: Total number of possible processors in the platform (1-based) +/// - `cpu_save_state_size`: Pointer to array of save state sizes per CPU +/// - `cpu_save_state`: Pointer to array of CPU save state pointers +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct EfiMmEntryContext { + /// Function pointer for EFI_MM_STARTUP_THIS_AP. + pub mm_startup_this_ap: u64, + /// Index of the currently executing CPU. + pub currently_executing_cpu: u64, + /// Total number of CPUs (1-based). + pub number_of_cpus: u64, + /// Pointer to array of per-CPU save state sizes. + pub cpu_save_state_size: u64, + /// Pointer to array of per-CPU save state pointers. + pub cpu_save_state: u64, +} diff --git a/components/patina_mm/src/component/communicator.rs b/components/patina_mm/src/component/communicator.rs index e93e68fd0..5a65d4c08 100644 --- a/components/patina_mm/src/component/communicator.rs +++ b/components/patina_mm/src/component/communicator.rs @@ -16,8 +16,8 @@ mod comm_buffer_update; use crate::{ - config::{CommunicateBuffer, MmCommunicationConfiguration}, comm_buffer_hob::EfiMmCommunicateHeader, + config::{CommunicateBuffer, MmCommunicationConfiguration}, service::SwMmiTrigger, }; use patina::{ diff --git a/components/patina_mm/src/config.rs b/components/patina_mm/src/config.rs index b1ec43e7b..cea551faf 100644 --- a/components/patina_mm/src/config.rs +++ b/components/patina_mm/src/config.rs @@ -22,8 +22,8 @@ extern crate alloc; use alloc::vec::Vec; use core::{fmt, pin::Pin, ptr::NonNull}; +use crate::comm_buffer_hob::{EfiMmCommunicateHeader, MmCommBufferStatus}; use patina::{BinaryGuid, Guid, base::UEFI_PAGE_MASK}; -use crate::comm_buffer_hob::{MmCommBufferStatus, EfiMmCommunicateHeader}; /// Management Mode (MM) Configuration /// diff --git a/components/patina_mm/src/lib.rs b/components/patina_mm/src/lib.rs index 43b681245..55cab8254 100644 --- a/components/patina_mm/src/lib.rs +++ b/components/patina_mm/src/lib.rs @@ -9,9 +9,9 @@ #[cfg(any(test, feature = "alloc"))] pub mod component; #[cfg(any(test, feature = "alloc"))] -pub mod service; -#[cfg(any(test, feature = "alloc"))] pub mod config; +#[cfg(any(test, feature = "alloc"))] +pub mod service; pub mod comm_buffer_hob; pub mod protocol; diff --git a/components/patina_mm/src/protocol/mm_supervisor_request.rs b/components/patina_mm/src/protocol/mm_supervisor_request.rs index 5c590e156..33fa5a854 100644 --- a/components/patina_mm/src/protocol/mm_supervisor_request.rs +++ b/components/patina_mm/src/protocol/mm_supervisor_request.rs @@ -1,220 +1,220 @@ -//! MM Supervisor Request Protocol Definitions -//! -//! This module provides the shared protocol structures and constants for MM Supervisor -//! request handling. These types define the communication contract between the supervisor -//! and its clients (DXE, tests, etc.). -//! -//! ## Overview -//! -//! The MM Supervisor uses a structured request/response protocol. Requests are sent via -//! the MM communicate buffer and consist of an [`MmSupervisorRequestHeader`] followed by -//! request-specific payload data. The supervisor processes the request and writes back -//! a response header (with result status) followed by response-specific data. -//! -//! ## License -//! -//! Copyright (C) Microsoft Corporation. -//! -//! SPDX-License-Identifier: Apache-2.0 - -use zerocopy::FromBytes; -use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout}; -use patina::{Guid, BinaryGuid}; - -// GUID for gMmSupervisorRequestHandlerGuid -// { 0x8c633b23, 0x1260, 0x4ea6, { 0x83, 0xf, 0x7d, 0xdc, 0x97, 0x38, 0x21, 0x11 } } -/// GUID for the MM Supervisor Request Handler protocol. -pub const MM_SUPERVISOR_REQUEST_HANDLER_GUID: BinaryGuid = - BinaryGuid::from_string("8c633b23-1260-4ea6-830f-7ddc97382111"); - -/// MM Supervisor request header. -/// -/// This header is present at the start of every supervisor request buffer. It identifies -/// the request type and carries the result status on response. -/// -/// ## Layout -/// -/// ```text -/// Offset Size Field -/// 0x00 4 signature - Must be [`SIGNATURE`] ('MSUP' as little-endian u32) -/// 0x04 4 revision - Protocol revision, must be <= [`REVISION`] -/// 0x08 4 request - Request type (see [`requests`] module) -/// 0x0C 4 reserved - Reserved for alignment, must be 0 -/// 0x10 8 result - Return status (0 = success, set by supervisor on response) -/// ``` -#[derive(Debug, Clone, Copy, FromBytes, IntoBytes, Immutable, KnownLayout)] -#[repr(C)] -pub struct MmSupervisorRequestHeader { - /// Signature to identify the request ('MSUP' as little-endian). - pub signature: u32, - /// Revision of the request protocol. - pub revision: u32, - /// The specific request type (see [`requests`] module constants). - pub request: u32, - /// Reserved for alignment, must be 0. - pub reserved: u32, - /// Result status. Set by the supervisor on response (0 = success). - pub result: u64, -} - -impl MmSupervisorRequestHeader { - /// Size of the header in bytes. - pub const SIZE: usize = core::mem::size_of::(); - - /// Validates the header signature and revision. - pub fn is_valid(&self) -> bool { - self.signature == SIGNATURE && self.revision <= REVISION - } - - /// Reads a header from a byte slice. - /// - /// Returns `None` if the slice is too small or misaligned. - pub fn from_bytes(bytes: &[u8]) -> Option { - if bytes.len() < Self::SIZE { - return None; - } - Self::read_from_bytes(&bytes[..Self::SIZE]).ok() - } -} - -/// Response from MM Supervisor version info request. -/// -/// Returned as the payload following an [`MmSupervisorRequestHeader`] when the request -/// type is [`requests::VERSION_INFO`]. -/// -/// ## Layout -/// -/// ```text -/// Offset Size Field -/// 0x00 4 version - Supervisor version -/// 0x04 4 patch_level - Supervisor patch level -/// 0x08 8 max_supervisor_request_level - Highest supported request type -/// ``` -#[derive(Debug, Clone, Copy, FromBytes, IntoBytes, Immutable, KnownLayout)] -#[repr(C)] -pub struct MmSupervisorVersionInfo { - /// Version of the MM Supervisor. - pub version: u32, - /// Patch level. - pub patch_level: u32, - /// Maximum supported supervisor request level (highest valid request type value). - pub max_supervisor_request_level: u64, -} - -impl MmSupervisorVersionInfo { - /// Size of the version info structure in bytes. - pub const SIZE: usize = core::mem::size_of::(); - - /// Reads version info from a byte slice. - /// - /// Returns `None` if the slice is too small or misaligned. - pub fn from_bytes(bytes: &[u8]) -> Option { - if bytes.len() < Self::SIZE { - return None; - } - Self::read_from_bytes(&bytes[..Self::SIZE]).ok() - } -} - -// ============================================================================ -// Protocol Constants -// ============================================================================ - -/// The expected signature value ('MSUP' as little-endian u32). -pub const SIGNATURE: u32 = 0x5055534D; - -/// Current revision of the request protocol. -pub const REVISION: u32 = 1; - -/// Standard MM Supervisor request types. -/// -/// Each variant corresponds to a specific supervisor operation. The enum is `#[repr(u32)]` -/// to match the wire format of [`MmSupervisorRequestHeader::request`]. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(u32)] -pub enum RequestType { - /// Request to unblock memory regions. - UnblockMem = 0x0001, - /// Request to fetch security policy. - FetchPolicy = 0x0002, - /// Request for version information. - VersionInfo = 0x0003, - /// Request to update communication buffer. - CommUpdate = 0x0004, -} - -impl RequestType { - /// The highest valid request type value. - pub const MAX: u64 = Self::CommUpdate as u64; -} - -impl TryFrom for RequestType { - type Error = u32; - - fn try_from(value: u32) -> Result { - match value { - 0x0001 => Ok(Self::UnblockMem), - 0x0002 => Ok(Self::FetchPolicy), - 0x0003 => Ok(Self::VersionInfo), - 0x0004 => Ok(Self::CommUpdate), - other => Err(other), - } - } -} - -/// Deprecated module — use [`RequestType`] enum variants instead. -/// -/// Kept temporarily for backward compatibility. -pub mod requests { - use super::RequestType; - /// Request to unblock memory regions. - pub const UNBLOCK_MEM: u32 = RequestType::UnblockMem as u32; - /// Request to fetch security policy. - pub const FETCH_POLICY: u32 = RequestType::FetchPolicy as u32; - /// Request for version information. - pub const VERSION_INFO: u32 = RequestType::VersionInfo as u32; - /// Request to update communication buffer. - pub const COMM_UPDATE: u32 = RequestType::CommUpdate as u32; -} - -/// Response status constants. -pub mod responses { - /// Operation completed successfully. - pub const SUCCESS: u64 = 0; - /// Operation failed with error. - pub const ERROR: u64 = 0xFFFFFFFFFFFFFFFF; -} - -// ============================================================================ -// Unblock Memory Params -// ============================================================================ - -use r_efi::efi; - -/// MM Supervisor Unblock Memory Parameters. -/// -/// Matches the C `MM_SUPERVISOR_UNBLOCK_MEMORY_PARAMS` layout. The C header -/// defines this under `#pragma pack(push, 1)`, but because `efi::MemoryDescriptor` -/// (40 bytes) and `Guid` (16 bytes) are both naturally aligned, the packed -/// and natural layouts are identical (56 bytes total). -/// -/// ## Layout -/// -/// ```text -/// Offset Size Field -/// 0x00 40 memory_descriptor - EFI_MEMORY_DESCRIPTOR (r-efi efi::MemoryDescriptor) -/// 0x28 16 identifier_guid - Requester identification GUID -/// ``` -#[derive(Debug, Clone, Copy)] -#[repr(C)] -pub struct MmSupervisorUnblockMemoryParams { - /// Memory descriptor identifying the region to unblock. - pub memory_descriptor: efi::MemoryDescriptor, - /// GUID identifying the requesting driver/module. - pub identifier_guid: BinaryGuid, -} - -impl MmSupervisorUnblockMemoryParams { - /// Size of this structure in bytes (56). - pub const SIZE: usize = core::mem::size_of::(); -} +//! MM Supervisor Request Protocol Definitions +//! +//! This module provides the shared protocol structures and constants for MM Supervisor +//! request handling. These types define the communication contract between the supervisor +//! and its clients (DXE, tests, etc.). +//! +//! ## Overview +//! +//! The MM Supervisor uses a structured request/response protocol. Requests are sent via +//! the MM communicate buffer and consist of an [`MmSupervisorRequestHeader`] followed by +//! request-specific payload data. The supervisor processes the request and writes back +//! a response header (with result status) followed by response-specific data. +//! +//! ## License +//! +//! Copyright (C) Microsoft Corporation. +//! +//! SPDX-License-Identifier: Apache-2.0 + +use patina::{BinaryGuid, Guid}; +use zerocopy::FromBytes; +use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout}; + +// GUID for gMmSupervisorRequestHandlerGuid +// { 0x8c633b23, 0x1260, 0x4ea6, { 0x83, 0xf, 0x7d, 0xdc, 0x97, 0x38, 0x21, 0x11 } } +/// GUID for the MM Supervisor Request Handler protocol. +pub const MM_SUPERVISOR_REQUEST_HANDLER_GUID: BinaryGuid = + BinaryGuid::from_string("8c633b23-1260-4ea6-830f-7ddc97382111"); + +/// MM Supervisor request header. +/// +/// This header is present at the start of every supervisor request buffer. It identifies +/// the request type and carries the result status on response. +/// +/// ## Layout +/// +/// ```text +/// Offset Size Field +/// 0x00 4 signature - Must be [`SIGNATURE`] ('MSUP' as little-endian u32) +/// 0x04 4 revision - Protocol revision, must be <= [`REVISION`] +/// 0x08 4 request - Request type (see [`requests`] module) +/// 0x0C 4 reserved - Reserved for alignment, must be 0 +/// 0x10 8 result - Return status (0 = success, set by supervisor on response) +/// ``` +#[derive(Debug, Clone, Copy, FromBytes, IntoBytes, Immutable, KnownLayout)] +#[repr(C)] +pub struct MmSupervisorRequestHeader { + /// Signature to identify the request ('MSUP' as little-endian). + pub signature: u32, + /// Revision of the request protocol. + pub revision: u32, + /// The specific request type (see [`requests`] module constants). + pub request: u32, + /// Reserved for alignment, must be 0. + pub reserved: u32, + /// Result status. Set by the supervisor on response (0 = success). + pub result: u64, +} + +impl MmSupervisorRequestHeader { + /// Size of the header in bytes. + pub const SIZE: usize = core::mem::size_of::(); + + /// Validates the header signature and revision. + pub fn is_valid(&self) -> bool { + self.signature == SIGNATURE && self.revision <= REVISION + } + + /// Reads a header from a byte slice. + /// + /// Returns `None` if the slice is too small or misaligned. + pub fn from_bytes(bytes: &[u8]) -> Option { + if bytes.len() < Self::SIZE { + return None; + } + Self::read_from_bytes(&bytes[..Self::SIZE]).ok() + } +} + +/// Response from MM Supervisor version info request. +/// +/// Returned as the payload following an [`MmSupervisorRequestHeader`] when the request +/// type is [`requests::VERSION_INFO`]. +/// +/// ## Layout +/// +/// ```text +/// Offset Size Field +/// 0x00 4 version - Supervisor version +/// 0x04 4 patch_level - Supervisor patch level +/// 0x08 8 max_supervisor_request_level - Highest supported request type +/// ``` +#[derive(Debug, Clone, Copy, FromBytes, IntoBytes, Immutable, KnownLayout)] +#[repr(C)] +pub struct MmSupervisorVersionInfo { + /// Version of the MM Supervisor. + pub version: u32, + /// Patch level. + pub patch_level: u32, + /// Maximum supported supervisor request level (highest valid request type value). + pub max_supervisor_request_level: u64, +} + +impl MmSupervisorVersionInfo { + /// Size of the version info structure in bytes. + pub const SIZE: usize = core::mem::size_of::(); + + /// Reads version info from a byte slice. + /// + /// Returns `None` if the slice is too small or misaligned. + pub fn from_bytes(bytes: &[u8]) -> Option { + if bytes.len() < Self::SIZE { + return None; + } + Self::read_from_bytes(&bytes[..Self::SIZE]).ok() + } +} + +// ============================================================================ +// Protocol Constants +// ============================================================================ + +/// The expected signature value ('MSUP' as little-endian u32). +pub const SIGNATURE: u32 = 0x5055534D; + +/// Current revision of the request protocol. +pub const REVISION: u32 = 1; + +/// Standard MM Supervisor request types. +/// +/// Each variant corresponds to a specific supervisor operation. The enum is `#[repr(u32)]` +/// to match the wire format of [`MmSupervisorRequestHeader::request`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum RequestType { + /// Request to unblock memory regions. + UnblockMem = 0x0001, + /// Request to fetch security policy. + FetchPolicy = 0x0002, + /// Request for version information. + VersionInfo = 0x0003, + /// Request to update communication buffer. + CommUpdate = 0x0004, +} + +impl RequestType { + /// The highest valid request type value. + pub const MAX: u64 = Self::CommUpdate as u64; +} + +impl TryFrom for RequestType { + type Error = u32; + + fn try_from(value: u32) -> Result { + match value { + 0x0001 => Ok(Self::UnblockMem), + 0x0002 => Ok(Self::FetchPolicy), + 0x0003 => Ok(Self::VersionInfo), + 0x0004 => Ok(Self::CommUpdate), + other => Err(other), + } + } +} + +/// Deprecated module — use [`RequestType`] enum variants instead. +/// +/// Kept temporarily for backward compatibility. +pub mod requests { + use super::RequestType; + /// Request to unblock memory regions. + pub const UNBLOCK_MEM: u32 = RequestType::UnblockMem as u32; + /// Request to fetch security policy. + pub const FETCH_POLICY: u32 = RequestType::FetchPolicy as u32; + /// Request for version information. + pub const VERSION_INFO: u32 = RequestType::VersionInfo as u32; + /// Request to update communication buffer. + pub const COMM_UPDATE: u32 = RequestType::CommUpdate as u32; +} + +/// Response status constants. +pub mod responses { + /// Operation completed successfully. + pub const SUCCESS: u64 = 0; + /// Operation failed with error. + pub const ERROR: u64 = 0xFFFFFFFFFFFFFFFF; +} + +// ============================================================================ +// Unblock Memory Params +// ============================================================================ + +use r_efi::efi; + +/// MM Supervisor Unblock Memory Parameters. +/// +/// Matches the C `MM_SUPERVISOR_UNBLOCK_MEMORY_PARAMS` layout. The C header +/// defines this under `#pragma pack(push, 1)`, but because `efi::MemoryDescriptor` +/// (40 bytes) and `Guid` (16 bytes) are both naturally aligned, the packed +/// and natural layouts are identical (56 bytes total). +/// +/// ## Layout +/// +/// ```text +/// Offset Size Field +/// 0x00 40 memory_descriptor - EFI_MEMORY_DESCRIPTOR (r-efi efi::MemoryDescriptor) +/// 0x28 16 identifier_guid - Requester identification GUID +/// ``` +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct MmSupervisorUnblockMemoryParams { + /// Memory descriptor identifying the region to unblock. + pub memory_descriptor: efi::MemoryDescriptor, + /// GUID identifying the requesting driver/module. + pub identifier_guid: BinaryGuid, +} + +impl MmSupervisorUnblockMemoryParams { + /// Size of this structure in bytes (56). + pub const SIZE: usize = core::mem::size_of::(); +} diff --git a/components/patina_mm/tests/patina_mm_integration/common/constants.rs b/components/patina_mm/tests/patina_mm_integration/common/constants.rs index f4dd24b0a..009df7746 100644 --- a/components/patina_mm/tests/patina_mm_integration/common/constants.rs +++ b/components/patina_mm/tests/patina_mm_integration/common/constants.rs @@ -18,10 +18,7 @@ pub const TEST_BUFFER_SIZE: usize = SIZE_4KB; /// (VERSION, PATCH_LEVEL, etc.) are defined here as mock data. pub mod mm_supv { // Re-export shared protocol constants - pub use patina_mm::protocol::mm_supervisor_request::{ - SIGNATURE, REVISION, - RequestType, requests, responses, - }; + pub use patina_mm::protocol::mm_supervisor_request::{REVISION, RequestType, SIGNATURE, requests, responses}; /// Request signature as a DWORD (same as shared SIGNATURE, kept for test compatibility) pub const REQUEST_SIGNATURE: u32 = SIGNATURE; diff --git a/components/patina_mm/tests/patina_mm_integration/common/handlers.rs b/components/patina_mm/tests/patina_mm_integration/common/handlers.rs index e27fb4ac2..4e60ff18f 100644 --- a/components/patina_mm/tests/patina_mm_integration/common/handlers.rs +++ b/components/patina_mm/tests/patina_mm_integration/common/handlers.rs @@ -23,10 +23,7 @@ use alloc::{string::String, vec::Vec}; pub use zerocopy::IntoBytes; // Import shared protocol types from patina_mm -pub use patina_mm::protocol::mm_supervisor_request::{ - MmSupervisorRequestHeader, - MmSupervisorVersionInfo, -}; +pub use patina_mm::protocol::mm_supervisor_request::{MmSupervisorRequestHeader, MmSupervisorVersionInfo}; /// Standardized error type for MM handlers #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs b/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs index 0459389ae..ca6027cc8 100644 --- a/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs +++ b/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs @@ -289,7 +289,11 @@ fn test_mm_supervisor_comm_update_request() { // Parse response header safely let response_header = MmSupervisorRequestHeader::from_bytes(&response).expect("Should parse response header"); - assert_eq!(response_header.request, mm_supv::RequestType::CommUpdate as u32, "Response should be for COMM_UPDATE request"); + assert_eq!( + response_header.request, + mm_supv::RequestType::CommUpdate as u32, + "Response should be for COMM_UPDATE request" + ); assert_eq!(response_header.result, mm_supv::responses::SUCCESS, "Comm update request should succeed"); // Parse update result safely @@ -337,7 +341,11 @@ fn test_mm_supervisor_unblock_mem_request() { // Parse response header safely let response_header = MmSupervisorRequestHeader::from_bytes(&response).expect("Should parse response header"); - assert_eq!(response_header.request, mm_supv::RequestType::UnblockMem as u32, "Response should be for UNBLOCK_MEM request"); + assert_eq!( + response_header.request, + mm_supv::RequestType::UnblockMem as u32, + "Response should be for UNBLOCK_MEM request" + ); assert_eq!(response_header.result, mm_supv::responses::SUCCESS, "Unblock mem request should succeed"); // Parse unblock status safely diff --git a/sdk/patina/src/mm_services.rs b/sdk/patina/src/mm_services.rs index c19d7206f..7ebdcb651 100644 --- a/sdk/patina/src/mm_services.rs +++ b/sdk/patina/src/mm_services.rs @@ -1,578 +1,530 @@ -//! MM (Management Mode) Services type definitions and trait. -//! -//! This module provides the Rust definitions for the PI `EFI_MM_SYSTEM_TABLE` -//! and an `MmServices` trait that wraps the raw C function-pointer table with -//! safe Rust method signatures, following the same pattern as -//! [`boot_services::BootServices`](crate::boot_services::BootServices). -//! -//! ## Layout -//! -//! * [`EfiMmSystemTable`] — `#[repr(C)]` struct matching the C -//! `_EFI_MM_SYSTEM_TABLE` layout from `PiMmCis.h`. -//! * [`MmServices`] — Safe Rust trait exposing the system-table services. -//! * [`StandardMmServices`] — Concrete wrapper around `*mut EfiMmSystemTable` -//! that implements `MmServices` by calling through the function pointers. -//! -//! Cores (e.g., `patina_mm_user_core`) allocate an `EfiMmSystemTable`, populate -//! its function pointers with their own `extern "efiapi"` thunks, and hand the -//! raw pointer to dispatched MM drivers. Drivers that want safe access can wrap -//! it in a `StandardMmServices`. -//! -//! ## License -//! -//! Copyright (c) Microsoft Corporation. -//! -//! SPDX-License-Identifier: Apache-2.0 -//! - -use core::ffi::c_void; - -use r_efi::efi; -use spin::Once; - -/// MMST signature: `'S', 'M', 'S', 'T'` (same as C `MM_MMST_SIGNATURE`). -pub const MM_MMST_SIGNATURE: u64 = 0x5453_4D53; - -/// PI Specification version encoded as `(major << 16) | minor`. -/// PI 1.8 → `0x0001_0050`. -pub const MM_SYSTEM_TABLE_REVISION: u32 = (1 << 16) | 80; - -/// A single MM I/O access function pointer. -/// -/// Matches the C typedef `EFI_MM_CPU_IO`: -/// ```c -/// typedef EFI_STATUS (EFIAPI *EFI_MM_CPU_IO)( -/// IN CONST EFI_MM_CPU_IO_PROTOCOL *This, -/// IN EFI_MM_IO_WIDTH Width, -/// IN UINT64 Address, -/// IN UINTN Count, -/// IN OUT VOID *Buffer -/// ); -/// ``` -pub type MmCpuIoFn = unsafe extern "efiapi" fn( - this: *const MmCpuIoAccess, - width: usize, - address: u64, - count: usize, - buffer: *mut c_void, -) -> efi::Status; - -/// MM CPU I/O access pair (Read + Write). -/// -/// Matches `EFI_MM_IO_ACCESS`. -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct MmCpuIoAccess { - pub read: MmCpuIoFn, - pub write: MmCpuIoFn, -} - -/// The `EFI_MM_CPU_IO_PROTOCOL` embedded in the system table. -/// -/// ```c -/// typedef struct _EFI_MM_CPU_IO_PROTOCOL { -/// EFI_MM_IO_ACCESS Mem; -/// EFI_MM_IO_ACCESS Io; -/// } EFI_MM_CPU_IO_PROTOCOL; -/// ``` -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct MmCpuIoProtocol { - pub mem: MmCpuIoAccess, - pub io: MmCpuIoAccess, -} - -/// `EFI_MM_INSTALL_CONFIGURATION_TABLE` -pub type MmInstallConfigurationTableFn = unsafe extern "efiapi" fn( - system_table: *const EfiMmSystemTable, - guid: *const efi::Guid, - table: *mut c_void, - table_size: usize, -) -> efi::Status; - -/// `EFI_ALLOCATE_POOL` (shared with Boot Services) -pub type MmAllocatePoolFn = unsafe extern "efiapi" fn( - pool_type: efi::MemoryType, - size: usize, - buffer: *mut *mut c_void, -) -> efi::Status; - -/// `EFI_FREE_POOL` (shared with Boot Services) -pub type MmFreePoolFn = unsafe extern "efiapi" fn( - buffer: *mut c_void, -) -> efi::Status; - -/// `EFI_ALLOCATE_PAGES` (shared with Boot Services) -pub type MmAllocatePagesFn = unsafe extern "efiapi" fn( - alloc_type: efi::AllocateType, - memory_type: efi::MemoryType, - pages: usize, - memory: *mut efi::PhysicalAddress, -) -> efi::Status; - -/// `EFI_FREE_PAGES` (shared with Boot Services) -pub type MmFreePagesFn = unsafe extern "efiapi" fn( - memory: efi::PhysicalAddress, - pages: usize, -) -> efi::Status; - -/// `EFI_MM_STARTUP_THIS_AP` -pub type MmStartupThisApFn = unsafe extern "efiapi" fn( - procedure: usize, - cpu_number: usize, - proc_arguments: *mut c_void, -) -> efi::Status; - -/// `EFI_INSTALL_PROTOCOL_INTERFACE` (shared with Boot Services) -pub type MmInstallProtocolInterfaceFn = unsafe extern "efiapi" fn( - handle: *mut efi::Handle, - protocol: *mut efi::Guid, - interface_type: efi::InterfaceType, - interface: *mut c_void, -) -> efi::Status; - -/// `EFI_UNINSTALL_PROTOCOL_INTERFACE` (shared with Boot Services) -pub type MmUninstallProtocolInterfaceFn = unsafe extern "efiapi" fn( - handle: efi::Handle, - protocol: *mut efi::Guid, - interface: *mut c_void, -) -> efi::Status; - -/// `EFI_HANDLE_PROTOCOL` (shared with Boot Services) -pub type MmHandleProtocolFn = unsafe extern "efiapi" fn( - handle: efi::Handle, - protocol: *mut efi::Guid, - interface: *mut *mut c_void, -) -> efi::Status; - -/// `EFI_MM_REGISTER_PROTOCOL_NOTIFY` -pub type MmRegisterProtocolNotifyFn = unsafe extern "efiapi" fn( - protocol: *const efi::Guid, - function: usize, - registration: *mut *mut c_void, -) -> efi::Status; - -/// `EFI_LOCATE_HANDLE` (shared with Boot Services) -pub type MmLocateHandleFn = unsafe extern "efiapi" fn( - search_type: efi::LocateSearchType, - protocol: *mut efi::Guid, - search_key: *mut c_void, - buffer_size: *mut usize, - buffer: *mut efi::Handle, -) -> efi::Status; - -/// `EFI_LOCATE_PROTOCOL` (shared with Boot Services) -pub type MmLocateProtocolFn = unsafe extern "efiapi" fn( - protocol: *mut efi::Guid, - registration: *mut c_void, - interface: *mut *mut c_void, -) -> efi::Status; - -/// `EFI_MM_INTERRUPT_MANAGE` -pub type MmiManageFn = unsafe extern "efiapi" fn( - handler_type: *const efi::Guid, - context: *const c_void, - comm_buffer: *mut c_void, - comm_buffer_size: *mut usize, -) -> efi::Status; - -/// MMI handler entry point. -/// -/// Matches the C typedef `EFI_MM_HANDLER_ENTRY_POINT`. -pub type MmiHandlerEntryPoint = unsafe extern "efiapi" fn( - dispatch_handle: efi::Handle, - context: *const c_void, - comm_buffer: *mut c_void, - comm_buffer_size: *mut usize, -) -> efi::Status; - -/// `EFI_MM_INTERRUPT_REGISTER` -pub type MmiHandlerRegisterFn = unsafe extern "efiapi" fn( - handler: MmiHandlerEntryPoint, - handler_type: *const efi::Guid, - dispatch_handle: *mut efi::Handle, -) -> efi::Status; - -/// `EFI_MM_INTERRUPT_UNREGISTER` -pub type MmiHandlerUnregisterFn = unsafe extern "efiapi" fn( - dispatch_handle: efi::Handle, -) -> efi::Status; - -/// The Management Mode System Table (MMST). -/// -/// This is the `#[repr(C)]` Rust definition of the C `_EFI_MM_SYSTEM_TABLE` -/// from `PiMmCis.h`. The table pointer is passed as the second argument to -/// every MM driver's entry point: -/// -/// ```c -/// EFI_STATUS EFIAPI DriverEntry(EFI_HANDLE ImageHandle, EFI_MM_SYSTEM_TABLE *MmSt); -/// ``` -#[repr(C)] -pub struct EfiMmSystemTable { - // ---- Table Header ---- - pub hdr: efi::TableHeader, - - // ---- Firmware info ---- - /// Pointer to a NUL-terminated UCS-2 vendor string (may be null). - pub mm_firmware_vendor: *mut u16, - /// Firmware revision number. - pub mm_firmware_revision: u32, - - // ---- Configuration Table ---- - pub mm_install_configuration_table: MmInstallConfigurationTableFn, - - // ---- I/O services (embedded protocol) ---- - pub mm_io: MmCpuIoProtocol, - - // ---- Memory services ---- - pub mm_allocate_pool: MmAllocatePoolFn, - pub mm_free_pool: MmFreePoolFn, - pub mm_allocate_pages: MmAllocatePagesFn, - pub mm_free_pages: MmFreePagesFn, - - // ---- MP service ---- - pub mm_startup_this_ap: MmStartupThisApFn, - - // ---- CPU information ---- - pub currently_executing_cpu: usize, - pub number_of_cpus: usize, - pub cpu_save_state_size: *mut usize, - pub cpu_save_state: *mut *mut c_void, - - // ---- Extensibility table ---- - pub number_of_table_entries: usize, - pub mm_configuration_table: *mut efi::ConfigurationTable, - - // ---- Protocol services ---- - pub mm_install_protocol_interface: MmInstallProtocolInterfaceFn, - pub mm_uninstall_protocol_interface: MmUninstallProtocolInterfaceFn, - pub mm_handle_protocol: MmHandleProtocolFn, - pub mm_register_protocol_notify: MmRegisterProtocolNotifyFn, - pub mm_locate_handle: MmLocateHandleFn, - pub mm_locate_protocol: MmLocateProtocolFn, - - // ---- MMI management ---- - pub mmi_manage: MmiManageFn, - pub mmi_handler_register: MmiHandlerRegisterFn, - pub mmi_handler_unregister: MmiHandlerUnregisterFn, -} - -// SAFETY: The system table is allocated once and its pointer is shared read-only -// with dispatched drivers. Internal mutation goes through synchronized databases. -unsafe impl Send for EfiMmSystemTable {} -unsafe impl Sync for EfiMmSystemTable {} - -/// Wrapper around a raw `*mut EfiMmSystemTable` pointer that implements -/// [`MmServices`] by calling through the C function-pointer table. -/// -/// This is the MM equivalent of -/// [`StandardBootServices`](crate::boot_services::StandardBootServices). -pub struct StandardMmServices { - efi_mm_system_table: Once<*mut EfiMmSystemTable>, -} - -// SAFETY: The raw pointer is only written once (protected by `Once`) and the -// underlying table is not expected to change after initialization. -unsafe impl Sync for StandardMmServices {} -unsafe impl Send for StandardMmServices {} - -impl StandardMmServices { - /// Create a new `StandardMmServices` from an existing system table pointer. - pub fn new(mm_system_table: *mut EfiMmSystemTable) -> Self { - let this = Self::new_uninit(); - this.init(mm_system_table); - this - } - - /// Create an uninitialized instance. - pub const fn new_uninit() -> Self { - Self { efi_mm_system_table: Once::new() } - } - - /// Initialize with the given system table pointer. - pub fn init(&self, mm_system_table: *mut EfiMmSystemTable) { - self.efi_mm_system_table.call_once(|| mm_system_table); - } - - /// Returns `true` if the instance has been initialized. - pub fn is_init(&self) -> bool { - self.efi_mm_system_table.is_completed() - } - - /// Returns the raw system table pointer (panics if uninitialized). - pub fn as_mut_ptr(&self) -> *mut EfiMmSystemTable { - *self.efi_mm_system_table.get().expect("StandardMmServices is not initialized!") - } -} - -impl Clone for StandardMmServices { - fn clone(&self) -> Self { - if let Some(ptr) = self.efi_mm_system_table.get() { - StandardMmServices::new(*ptr) - } else { - StandardMmServices::new_uninit() - } - } -} - -impl core::fmt::Debug for StandardMmServices { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - if !self.is_init() { - return f.debug_struct("StandardMmServices").field("table", &"Not Initialized").finish(); - } - f.debug_struct("StandardMmServices").field("table", &self.as_mut_ptr()).finish() - } -} - -/// Safe Rust interface to the MM System Table services. -/// -/// This is the MM analogue of -/// [`BootServices`](crate::boot_services::BootServices). -/// Each method maps 1:1 to a function pointer in [`EfiMmSystemTable`]. -pub trait MmServices { - /// Allocate pool memory. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmAllocatePool` - fn allocate_pool(&self, pool_type: efi::MemoryType, size: usize) -> Result<*mut u8, efi::Status>; - - /// Free pool memory. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmFreePool` - fn free_pool(&self, buffer: *mut u8) -> Result<(), efi::Status>; - - /// Allocate pages. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmAllocatePages` - fn allocate_pages( - &self, - alloc_type: efi::AllocateType, - memory_type: efi::MemoryType, - pages: usize, - ) -> Result; - - /// Free pages. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmFreePages` - fn free_pages(&self, memory: u64, pages: usize) -> Result<(), efi::Status>; - - /// Install a protocol interface on a handle. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmInstallProtocolInterface` - /// - /// # Safety - /// - /// `interface` must be a valid pointer to the protocol structure or null. - unsafe fn install_protocol_interface( - &self, - handle: *mut efi::Handle, - protocol: &efi::Guid, - interface_type: efi::InterfaceType, - interface: *mut c_void, - ) -> Result<(), efi::Status>; - - /// Uninstall a protocol interface from a handle. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmUninstallProtocolInterface` - /// - /// # Safety - /// - /// `interface` must match the pointer that was installed. - unsafe fn uninstall_protocol_interface( - &self, - handle: efi::Handle, - protocol: &efi::Guid, - interface: *mut c_void, - ) -> Result<(), efi::Status>; - - /// Query a handle for a protocol. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmHandleProtocol` - /// - /// # Safety - /// - /// The returned pointer must be used carefully to avoid aliasing violations. - unsafe fn handle_protocol( - &self, - handle: efi::Handle, - protocol: &efi::Guid, - ) -> Result<*mut c_void, efi::Status>; - - /// Locate the first device that supports a protocol. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmLocateProtocol` - /// - /// # Safety - /// - /// The returned pointer must be used carefully to avoid aliasing violations. - unsafe fn locate_protocol( - &self, - protocol: &efi::Guid, - ) -> Result<*mut c_void, efi::Status>; - - /// Manage (dispatch) an MMI. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmiManage` - fn mmi_manage( - &self, - handler_type: Option<&efi::Guid>, - context: *const c_void, - comm_buffer: *mut c_void, - comm_buffer_size: *mut usize, - ) -> efi::Status; - - /// Register an MMI handler. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmiHandlerRegister` - fn mmi_handler_register( - &self, - handler: MmiHandlerEntryPoint, - handler_type: Option<&efi::Guid>, - ) -> Result; - - /// Unregister an MMI handler. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmiHandlerUnRegister` - fn mmi_handler_unregister( - &self, - dispatch_handle: efi::Handle, - ) -> Result<(), efi::Status>; -} - -impl MmServices for StandardMmServices { - fn allocate_pool(&self, pool_type: efi::MemoryType, size: usize) -> Result<*mut u8, efi::Status> { - let mmst = unsafe { &*self.as_mut_ptr() }; - let mut buffer: *mut c_void = core::ptr::null_mut(); - let status = unsafe { (mmst.mm_allocate_pool)(pool_type, size, &mut buffer) }; - if status == efi::Status::SUCCESS { - Ok(buffer as *mut u8) - } else { - Err(status) - } - } - - fn free_pool(&self, buffer: *mut u8) -> Result<(), efi::Status> { - let mmst = unsafe { &*self.as_mut_ptr() }; - let status = unsafe { (mmst.mm_free_pool)(buffer as *mut c_void) }; - if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } - } - - fn allocate_pages( - &self, - alloc_type: efi::AllocateType, - memory_type: efi::MemoryType, - pages: usize, - ) -> Result { - let mmst = unsafe { &*self.as_mut_ptr() }; - let mut memory: efi::PhysicalAddress = 0; - let status = unsafe { (mmst.mm_allocate_pages)(alloc_type, memory_type, pages, &mut memory) }; - if status == efi::Status::SUCCESS { Ok(memory) } else { Err(status) } - } - - fn free_pages(&self, memory: u64, pages: usize) -> Result<(), efi::Status> { - let mmst = unsafe { &*self.as_mut_ptr() }; - let status = unsafe { (mmst.mm_free_pages)(memory, pages) }; - if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } - } - - unsafe fn install_protocol_interface( - &self, - handle: *mut efi::Handle, - protocol: &efi::Guid, - interface_type: efi::InterfaceType, - interface: *mut c_void, - ) -> Result<(), efi::Status> { - let mmst = unsafe { &*self.as_mut_ptr() }; - let status = unsafe { - (mmst.mm_install_protocol_interface)( - handle, - protocol as *const efi::Guid as *mut efi::Guid, - interface_type, - interface, - ) - }; - if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } - } - - unsafe fn uninstall_protocol_interface( - &self, - handle: efi::Handle, - protocol: &efi::Guid, - interface: *mut c_void, - ) -> Result<(), efi::Status> { - let mmst = unsafe { &*self.as_mut_ptr() }; - let status = unsafe { - (mmst.mm_uninstall_protocol_interface)( - handle, - protocol as *const efi::Guid as *mut efi::Guid, - interface, - ) - }; - if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } - } - - unsafe fn handle_protocol( - &self, - handle: efi::Handle, - protocol: &efi::Guid, - ) -> Result<*mut c_void, efi::Status> { - let mmst = unsafe { &*self.as_mut_ptr() }; - let mut interface: *mut c_void = core::ptr::null_mut(); - let status = unsafe { - (mmst.mm_handle_protocol)( - handle, - protocol as *const efi::Guid as *mut efi::Guid, - &mut interface, - ) - }; - if status == efi::Status::SUCCESS { Ok(interface) } else { Err(status) } - } - - unsafe fn locate_protocol( - &self, - protocol: &efi::Guid, - ) -> Result<*mut c_void, efi::Status> { - let mmst = unsafe { &*self.as_mut_ptr() }; - let mut interface: *mut c_void = core::ptr::null_mut(); - let status = unsafe { - (mmst.mm_locate_protocol)( - protocol as *const efi::Guid as *mut efi::Guid, - core::ptr::null_mut(), - &mut interface, - ) - }; - if status == efi::Status::SUCCESS { Ok(interface) } else { Err(status) } - } - - fn mmi_manage( - &self, - handler_type: Option<&efi::Guid>, - context: *const c_void, - comm_buffer: *mut c_void, - comm_buffer_size: *mut usize, - ) -> efi::Status { - let mmst = unsafe { &*self.as_mut_ptr() }; - let guid_ptr = handler_type.map_or(core::ptr::null(), |g| g as *const efi::Guid); - unsafe { (mmst.mmi_manage)(guid_ptr, context, comm_buffer, comm_buffer_size) } - } - - fn mmi_handler_register( - &self, - handler: MmiHandlerEntryPoint, - handler_type: Option<&efi::Guid>, - ) -> Result { - let mmst = unsafe { &*self.as_mut_ptr() }; - let guid_ptr = handler_type.map_or(core::ptr::null(), |g| g as *const efi::Guid); - let mut dispatch_handle: efi::Handle = core::ptr::null_mut(); - let status = unsafe { (mmst.mmi_handler_register)(handler, guid_ptr, &mut dispatch_handle) }; - if status == efi::Status::SUCCESS { Ok(dispatch_handle) } else { Err(status) } - } - - fn mmi_handler_unregister( - &self, - dispatch_handle: efi::Handle, - ) -> Result<(), efi::Status> { - let mmst = unsafe { &*self.as_mut_ptr() }; - let status = unsafe { (mmst.mmi_handler_unregister)(dispatch_handle) }; - if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } - } -} +//! MM (Management Mode) Services type definitions and trait. +//! +//! This module provides the Rust definitions for the PI `EFI_MM_SYSTEM_TABLE` +//! and an `MmServices` trait that wraps the raw C function-pointer table with +//! safe Rust method signatures, following the same pattern as +//! [`boot_services::BootServices`](crate::boot_services::BootServices). +//! +//! ## Layout +//! +//! * [`EfiMmSystemTable`] — `#[repr(C)]` struct matching the C +//! `_EFI_MM_SYSTEM_TABLE` layout from `PiMmCis.h`. +//! * [`MmServices`] — Safe Rust trait exposing the system-table services. +//! * [`StandardMmServices`] — Concrete wrapper around `*mut EfiMmSystemTable` +//! that implements `MmServices` by calling through the function pointers. +//! +//! Cores (e.g., `patina_mm_user_core`) allocate an `EfiMmSystemTable`, populate +//! its function pointers with their own `extern "efiapi"` thunks, and hand the +//! raw pointer to dispatched MM drivers. Drivers that want safe access can wrap +//! it in a `StandardMmServices`. +//! +//! ## License +//! +//! Copyright (c) Microsoft Corporation. +//! +//! SPDX-License-Identifier: Apache-2.0 +//! + +use core::ffi::c_void; + +use r_efi::efi; +use spin::Once; + +/// MMST signature: `'S', 'M', 'S', 'T'` (same as C `MM_MMST_SIGNATURE`). +pub const MM_MMST_SIGNATURE: u64 = 0x5453_4D53; + +/// PI Specification version encoded as `(major << 16) | minor`. +/// PI 1.8 → `0x0001_0050`. +pub const MM_SYSTEM_TABLE_REVISION: u32 = (1 << 16) | 80; + +/// A single MM I/O access function pointer. +/// +/// Matches the C typedef `EFI_MM_CPU_IO`: +/// ```c +/// typedef EFI_STATUS (EFIAPI *EFI_MM_CPU_IO)( +/// IN CONST EFI_MM_CPU_IO_PROTOCOL *This, +/// IN EFI_MM_IO_WIDTH Width, +/// IN UINT64 Address, +/// IN UINTN Count, +/// IN OUT VOID *Buffer +/// ); +/// ``` +pub type MmCpuIoFn = unsafe extern "efiapi" fn( + this: *const MmCpuIoAccess, + width: usize, + address: u64, + count: usize, + buffer: *mut c_void, +) -> efi::Status; + +/// MM CPU I/O access pair (Read + Write). +/// +/// Matches `EFI_MM_IO_ACCESS`. +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct MmCpuIoAccess { + pub read: MmCpuIoFn, + pub write: MmCpuIoFn, +} + +/// The `EFI_MM_CPU_IO_PROTOCOL` embedded in the system table. +/// +/// ```c +/// typedef struct _EFI_MM_CPU_IO_PROTOCOL { +/// EFI_MM_IO_ACCESS Mem; +/// EFI_MM_IO_ACCESS Io; +/// } EFI_MM_CPU_IO_PROTOCOL; +/// ``` +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct MmCpuIoProtocol { + pub mem: MmCpuIoAccess, + pub io: MmCpuIoAccess, +} + +/// `EFI_MM_INSTALL_CONFIGURATION_TABLE` +pub type MmInstallConfigurationTableFn = unsafe extern "efiapi" fn( + system_table: *const EfiMmSystemTable, + guid: *const efi::Guid, + table: *mut c_void, + table_size: usize, +) -> efi::Status; + +/// `EFI_ALLOCATE_POOL` (shared with Boot Services) +pub type MmAllocatePoolFn = + unsafe extern "efiapi" fn(pool_type: efi::MemoryType, size: usize, buffer: *mut *mut c_void) -> efi::Status; + +/// `EFI_FREE_POOL` (shared with Boot Services) +pub type MmFreePoolFn = unsafe extern "efiapi" fn(buffer: *mut c_void) -> efi::Status; + +/// `EFI_ALLOCATE_PAGES` (shared with Boot Services) +pub type MmAllocatePagesFn = unsafe extern "efiapi" fn( + alloc_type: efi::AllocateType, + memory_type: efi::MemoryType, + pages: usize, + memory: *mut efi::PhysicalAddress, +) -> efi::Status; + +/// `EFI_FREE_PAGES` (shared with Boot Services) +pub type MmFreePagesFn = unsafe extern "efiapi" fn(memory: efi::PhysicalAddress, pages: usize) -> efi::Status; + +/// `EFI_MM_STARTUP_THIS_AP` +pub type MmStartupThisApFn = + unsafe extern "efiapi" fn(procedure: usize, cpu_number: usize, proc_arguments: *mut c_void) -> efi::Status; + +/// `EFI_INSTALL_PROTOCOL_INTERFACE` (shared with Boot Services) +pub type MmInstallProtocolInterfaceFn = unsafe extern "efiapi" fn( + handle: *mut efi::Handle, + protocol: *mut efi::Guid, + interface_type: efi::InterfaceType, + interface: *mut c_void, +) -> efi::Status; + +/// `EFI_UNINSTALL_PROTOCOL_INTERFACE` (shared with Boot Services) +pub type MmUninstallProtocolInterfaceFn = + unsafe extern "efiapi" fn(handle: efi::Handle, protocol: *mut efi::Guid, interface: *mut c_void) -> efi::Status; + +/// `EFI_HANDLE_PROTOCOL` (shared with Boot Services) +pub type MmHandleProtocolFn = unsafe extern "efiapi" fn( + handle: efi::Handle, + protocol: *mut efi::Guid, + interface: *mut *mut c_void, +) -> efi::Status; + +/// `EFI_MM_REGISTER_PROTOCOL_NOTIFY` +pub type MmRegisterProtocolNotifyFn = unsafe extern "efiapi" fn( + protocol: *const efi::Guid, + function: usize, + registration: *mut *mut c_void, +) -> efi::Status; + +/// `EFI_LOCATE_HANDLE` (shared with Boot Services) +pub type MmLocateHandleFn = unsafe extern "efiapi" fn( + search_type: efi::LocateSearchType, + protocol: *mut efi::Guid, + search_key: *mut c_void, + buffer_size: *mut usize, + buffer: *mut efi::Handle, +) -> efi::Status; + +/// `EFI_LOCATE_PROTOCOL` (shared with Boot Services) +pub type MmLocateProtocolFn = unsafe extern "efiapi" fn( + protocol: *mut efi::Guid, + registration: *mut c_void, + interface: *mut *mut c_void, +) -> efi::Status; + +/// `EFI_MM_INTERRUPT_MANAGE` +pub type MmiManageFn = unsafe extern "efiapi" fn( + handler_type: *const efi::Guid, + context: *const c_void, + comm_buffer: *mut c_void, + comm_buffer_size: *mut usize, +) -> efi::Status; + +/// MMI handler entry point. +/// +/// Matches the C typedef `EFI_MM_HANDLER_ENTRY_POINT`. +pub type MmiHandlerEntryPoint = unsafe extern "efiapi" fn( + dispatch_handle: efi::Handle, + context: *const c_void, + comm_buffer: *mut c_void, + comm_buffer_size: *mut usize, +) -> efi::Status; + +/// `EFI_MM_INTERRUPT_REGISTER` +pub type MmiHandlerRegisterFn = unsafe extern "efiapi" fn( + handler: MmiHandlerEntryPoint, + handler_type: *const efi::Guid, + dispatch_handle: *mut efi::Handle, +) -> efi::Status; + +/// `EFI_MM_INTERRUPT_UNREGISTER` +pub type MmiHandlerUnregisterFn = unsafe extern "efiapi" fn(dispatch_handle: efi::Handle) -> efi::Status; + +/// The Management Mode System Table (MMST). +/// +/// This is the `#[repr(C)]` Rust definition of the C `_EFI_MM_SYSTEM_TABLE` +/// from `PiMmCis.h`. The table pointer is passed as the second argument to +/// every MM driver's entry point: +/// +/// ```c +/// EFI_STATUS EFIAPI DriverEntry(EFI_HANDLE ImageHandle, EFI_MM_SYSTEM_TABLE *MmSt); +/// ``` +#[repr(C)] +pub struct EfiMmSystemTable { + // ---- Table Header ---- + pub hdr: efi::TableHeader, + + // ---- Firmware info ---- + /// Pointer to a NUL-terminated UCS-2 vendor string (may be null). + pub mm_firmware_vendor: *mut u16, + /// Firmware revision number. + pub mm_firmware_revision: u32, + + // ---- Configuration Table ---- + pub mm_install_configuration_table: MmInstallConfigurationTableFn, + + // ---- I/O services (embedded protocol) ---- + pub mm_io: MmCpuIoProtocol, + + // ---- Memory services ---- + pub mm_allocate_pool: MmAllocatePoolFn, + pub mm_free_pool: MmFreePoolFn, + pub mm_allocate_pages: MmAllocatePagesFn, + pub mm_free_pages: MmFreePagesFn, + + // ---- MP service ---- + pub mm_startup_this_ap: MmStartupThisApFn, + + // ---- CPU information ---- + pub currently_executing_cpu: usize, + pub number_of_cpus: usize, + pub cpu_save_state_size: *mut usize, + pub cpu_save_state: *mut *mut c_void, + + // ---- Extensibility table ---- + pub number_of_table_entries: usize, + pub mm_configuration_table: *mut efi::ConfigurationTable, + + // ---- Protocol services ---- + pub mm_install_protocol_interface: MmInstallProtocolInterfaceFn, + pub mm_uninstall_protocol_interface: MmUninstallProtocolInterfaceFn, + pub mm_handle_protocol: MmHandleProtocolFn, + pub mm_register_protocol_notify: MmRegisterProtocolNotifyFn, + pub mm_locate_handle: MmLocateHandleFn, + pub mm_locate_protocol: MmLocateProtocolFn, + + // ---- MMI management ---- + pub mmi_manage: MmiManageFn, + pub mmi_handler_register: MmiHandlerRegisterFn, + pub mmi_handler_unregister: MmiHandlerUnregisterFn, +} + +// SAFETY: The system table is allocated once and its pointer is shared read-only +// with dispatched drivers. Internal mutation goes through synchronized databases. +unsafe impl Send for EfiMmSystemTable {} +unsafe impl Sync for EfiMmSystemTable {} + +/// Wrapper around a raw `*mut EfiMmSystemTable` pointer that implements +/// [`MmServices`] by calling through the C function-pointer table. +/// +/// This is the MM equivalent of +/// [`StandardBootServices`](crate::boot_services::StandardBootServices). +pub struct StandardMmServices { + efi_mm_system_table: Once<*mut EfiMmSystemTable>, +} + +// SAFETY: The raw pointer is only written once (protected by `Once`) and the +// underlying table is not expected to change after initialization. +unsafe impl Sync for StandardMmServices {} +unsafe impl Send for StandardMmServices {} + +impl StandardMmServices { + /// Create a new `StandardMmServices` from an existing system table pointer. + pub fn new(mm_system_table: *mut EfiMmSystemTable) -> Self { + let this = Self::new_uninit(); + this.init(mm_system_table); + this + } + + /// Create an uninitialized instance. + pub const fn new_uninit() -> Self { + Self { efi_mm_system_table: Once::new() } + } + + /// Initialize with the given system table pointer. + pub fn init(&self, mm_system_table: *mut EfiMmSystemTable) { + self.efi_mm_system_table.call_once(|| mm_system_table); + } + + /// Returns `true` if the instance has been initialized. + pub fn is_init(&self) -> bool { + self.efi_mm_system_table.is_completed() + } + + /// Returns the raw system table pointer (panics if uninitialized). + pub fn as_mut_ptr(&self) -> *mut EfiMmSystemTable { + *self.efi_mm_system_table.get().expect("StandardMmServices is not initialized!") + } +} + +impl Clone for StandardMmServices { + fn clone(&self) -> Self { + if let Some(ptr) = self.efi_mm_system_table.get() { + StandardMmServices::new(*ptr) + } else { + StandardMmServices::new_uninit() + } + } +} + +impl core::fmt::Debug for StandardMmServices { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if !self.is_init() { + return f.debug_struct("StandardMmServices").field("table", &"Not Initialized").finish(); + } + f.debug_struct("StandardMmServices").field("table", &self.as_mut_ptr()).finish() + } +} + +/// Safe Rust interface to the MM System Table services. +/// +/// This is the MM analogue of +/// [`BootServices`](crate::boot_services::BootServices). +/// Each method maps 1:1 to a function pointer in [`EfiMmSystemTable`]. +pub trait MmServices { + /// Allocate pool memory. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmAllocatePool` + fn allocate_pool(&self, pool_type: efi::MemoryType, size: usize) -> Result<*mut u8, efi::Status>; + + /// Free pool memory. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmFreePool` + fn free_pool(&self, buffer: *mut u8) -> Result<(), efi::Status>; + + /// Allocate pages. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmAllocatePages` + fn allocate_pages( + &self, + alloc_type: efi::AllocateType, + memory_type: efi::MemoryType, + pages: usize, + ) -> Result; + + /// Free pages. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmFreePages` + fn free_pages(&self, memory: u64, pages: usize) -> Result<(), efi::Status>; + + /// Install a protocol interface on a handle. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmInstallProtocolInterface` + /// + /// # Safety + /// + /// `interface` must be a valid pointer to the protocol structure or null. + unsafe fn install_protocol_interface( + &self, + handle: *mut efi::Handle, + protocol: &efi::Guid, + interface_type: efi::InterfaceType, + interface: *mut c_void, + ) -> Result<(), efi::Status>; + + /// Uninstall a protocol interface from a handle. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmUninstallProtocolInterface` + /// + /// # Safety + /// + /// `interface` must match the pointer that was installed. + unsafe fn uninstall_protocol_interface( + &self, + handle: efi::Handle, + protocol: &efi::Guid, + interface: *mut c_void, + ) -> Result<(), efi::Status>; + + /// Query a handle for a protocol. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmHandleProtocol` + /// + /// # Safety + /// + /// The returned pointer must be used carefully to avoid aliasing violations. + unsafe fn handle_protocol(&self, handle: efi::Handle, protocol: &efi::Guid) -> Result<*mut c_void, efi::Status>; + + /// Locate the first device that supports a protocol. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmLocateProtocol` + /// + /// # Safety + /// + /// The returned pointer must be used carefully to avoid aliasing violations. + unsafe fn locate_protocol(&self, protocol: &efi::Guid) -> Result<*mut c_void, efi::Status>; + + /// Manage (dispatch) an MMI. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmiManage` + fn mmi_manage( + &self, + handler_type: Option<&efi::Guid>, + context: *const c_void, + comm_buffer: *mut c_void, + comm_buffer_size: *mut usize, + ) -> efi::Status; + + /// Register an MMI handler. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmiHandlerRegister` + fn mmi_handler_register( + &self, + handler: MmiHandlerEntryPoint, + handler_type: Option<&efi::Guid>, + ) -> Result; + + /// Unregister an MMI handler. + /// + /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmiHandlerUnRegister` + fn mmi_handler_unregister(&self, dispatch_handle: efi::Handle) -> Result<(), efi::Status>; +} + +impl MmServices for StandardMmServices { + fn allocate_pool(&self, pool_type: efi::MemoryType, size: usize) -> Result<*mut u8, efi::Status> { + let mmst = unsafe { &*self.as_mut_ptr() }; + let mut buffer: *mut c_void = core::ptr::null_mut(); + let status = unsafe { (mmst.mm_allocate_pool)(pool_type, size, &mut buffer) }; + if status == efi::Status::SUCCESS { Ok(buffer as *mut u8) } else { Err(status) } + } + + fn free_pool(&self, buffer: *mut u8) -> Result<(), efi::Status> { + let mmst = unsafe { &*self.as_mut_ptr() }; + let status = unsafe { (mmst.mm_free_pool)(buffer as *mut c_void) }; + if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } + } + + fn allocate_pages( + &self, + alloc_type: efi::AllocateType, + memory_type: efi::MemoryType, + pages: usize, + ) -> Result { + let mmst = unsafe { &*self.as_mut_ptr() }; + let mut memory: efi::PhysicalAddress = 0; + let status = unsafe { (mmst.mm_allocate_pages)(alloc_type, memory_type, pages, &mut memory) }; + if status == efi::Status::SUCCESS { Ok(memory) } else { Err(status) } + } + + fn free_pages(&self, memory: u64, pages: usize) -> Result<(), efi::Status> { + let mmst = unsafe { &*self.as_mut_ptr() }; + let status = unsafe { (mmst.mm_free_pages)(memory, pages) }; + if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } + } + + unsafe fn install_protocol_interface( + &self, + handle: *mut efi::Handle, + protocol: &efi::Guid, + interface_type: efi::InterfaceType, + interface: *mut c_void, + ) -> Result<(), efi::Status> { + let mmst = unsafe { &*self.as_mut_ptr() }; + let status = unsafe { + (mmst.mm_install_protocol_interface)( + handle, + protocol as *const efi::Guid as *mut efi::Guid, + interface_type, + interface, + ) + }; + if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } + } + + unsafe fn uninstall_protocol_interface( + &self, + handle: efi::Handle, + protocol: &efi::Guid, + interface: *mut c_void, + ) -> Result<(), efi::Status> { + let mmst = unsafe { &*self.as_mut_ptr() }; + let status = unsafe { + (mmst.mm_uninstall_protocol_interface)(handle, protocol as *const efi::Guid as *mut efi::Guid, interface) + }; + if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } + } + + unsafe fn handle_protocol(&self, handle: efi::Handle, protocol: &efi::Guid) -> Result<*mut c_void, efi::Status> { + let mmst = unsafe { &*self.as_mut_ptr() }; + let mut interface: *mut c_void = core::ptr::null_mut(); + let status = unsafe { + (mmst.mm_handle_protocol)(handle, protocol as *const efi::Guid as *mut efi::Guid, &mut interface) + }; + if status == efi::Status::SUCCESS { Ok(interface) } else { Err(status) } + } + + unsafe fn locate_protocol(&self, protocol: &efi::Guid) -> Result<*mut c_void, efi::Status> { + let mmst = unsafe { &*self.as_mut_ptr() }; + let mut interface: *mut c_void = core::ptr::null_mut(); + let status = unsafe { + (mmst.mm_locate_protocol)( + protocol as *const efi::Guid as *mut efi::Guid, + core::ptr::null_mut(), + &mut interface, + ) + }; + if status == efi::Status::SUCCESS { Ok(interface) } else { Err(status) } + } + + fn mmi_manage( + &self, + handler_type: Option<&efi::Guid>, + context: *const c_void, + comm_buffer: *mut c_void, + comm_buffer_size: *mut usize, + ) -> efi::Status { + let mmst = unsafe { &*self.as_mut_ptr() }; + let guid_ptr = handler_type.map_or(core::ptr::null(), |g| g as *const efi::Guid); + unsafe { (mmst.mmi_manage)(guid_ptr, context, comm_buffer, comm_buffer_size) } + } + + fn mmi_handler_register( + &self, + handler: MmiHandlerEntryPoint, + handler_type: Option<&efi::Guid>, + ) -> Result { + let mmst = unsafe { &*self.as_mut_ptr() }; + let guid_ptr = handler_type.map_or(core::ptr::null(), |g| g as *const efi::Guid); + let mut dispatch_handle: efi::Handle = core::ptr::null_mut(); + let status = unsafe { (mmst.mmi_handler_register)(handler, guid_ptr, &mut dispatch_handle) }; + if status == efi::Status::SUCCESS { Ok(dispatch_handle) } else { Err(status) } + } + + fn mmi_handler_unregister(&self, dispatch_handle: efi::Handle) -> Result<(), efi::Status> { + let mmst = unsafe { &*self.as_mut_ptr() }; + let status = unsafe { (mmst.mmi_handler_unregister)(dispatch_handle) }; + if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } + } +} From 21aae10d1a1a91de78c639c9a508991cb7303ad2 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Wed, 18 Mar 2026 13:03:29 -0700 Subject: [PATCH 07/26] fixing some build breaks --- components/patina_mm/Cargo.toml | 5 ++-- .../patina_mm/src/component/communicator.rs | 8 +++--- .../communicator/comm_buffer_update.rs | 4 +-- components/patina_mm/src/config.rs | 1 - components/patina_mm/src/lib.rs | 3 ++ .../src/protocol/mm_supervisor_request.rs | 28 ++----------------- .../patina_mm/tests/patina_mm_integration.rs | 1 + .../framework/core_functionality_tests.rs | 6 ++-- .../mm_communicator/stress_tests.rs | 2 -- .../tests/patina_mm_integration/mod.rs | 2 ++ components/patina_performance/Cargo.toml | 2 +- 11 files changed, 20 insertions(+), 42 deletions(-) diff --git a/components/patina_mm/Cargo.toml b/components/patina_mm/Cargo.toml index 90a4fedb9..8091ef374 100644 --- a/components/patina_mm/Cargo.toml +++ b/components/patina_mm/Cargo.toml @@ -23,7 +23,6 @@ zerocopy-derive = { workspace = true } env_logger = { workspace = true } mockall = { workspace = true } patina = { workspace = true, features = ["mockall"] } -patina_dxe_core = { path = "../../patina_dxe_core"} [target.'cfg(target_arch="x86_64")'.dependencies] x86_64 = { workspace = true, features = [ @@ -31,7 +30,7 @@ x86_64 = { workspace = true, features = [ ] } [features] -doc = [] +doc = ['alloc'] mockall = ["dep:mockall", "std"] -std = [] +std = ['alloc'] alloc = [] diff --git a/components/patina_mm/src/component/communicator.rs b/components/patina_mm/src/component/communicator.rs index 5a65d4c08..5e27c8ac0 100644 --- a/components/patina_mm/src/component/communicator.rs +++ b/components/patina_mm/src/component/communicator.rs @@ -28,7 +28,7 @@ use patina::{ service::{IntoService, Service}, }, }; -extern crate alloc; + use alloc::{boxed::Box, vec::Vec}; use core::{ @@ -374,14 +374,14 @@ mod tests { communicator::{MmCommunicator, MockMmExecutor}, sw_mmi_manager::SwMmiManager, }, - config::{CommunicateBuffer, MmCommBufferStatus, MmCommunicationConfiguration}, + config::{CommunicateBuffer, MmCommunicationConfiguration}, + comm_buffer_hob::MmCommBufferStatus, }; use patina::component::{IntoComponent, Storage}; use core::{cell::RefCell, pin::Pin}; - extern crate alloc; - use alloc::vec::Vec; + use std::vec::Vec; /// Simple MM Executor for unit tests that simulates MM handlers echoing request data back as the response struct EchoMmExecutor; diff --git a/components/patina_mm/src/component/communicator/comm_buffer_update.rs b/components/patina_mm/src/component/communicator/comm_buffer_update.rs index 1289e23ed..f771c53e0 100644 --- a/components/patina_mm/src/component/communicator/comm_buffer_update.rs +++ b/components/patina_mm/src/component/communicator/comm_buffer_update.rs @@ -23,7 +23,6 @@ use zerocopy::FromBytes; use core::sync::atomic::{AtomicBool, AtomicPtr, Ordering}; -extern crate alloc; use alloc::boxed::Box; /// Context for the MM Comm Buffer Update Protocol notify callback @@ -289,8 +288,7 @@ mod tests { }; use patina::boot_services::StandardBootServices; - extern crate alloc; - use alloc::{boxed::Box, vec}; + use alloc::boxed::Box; /// Helper to create a test protocol notify context without boot services fn create_test_context( diff --git a/components/patina_mm/src/config.rs b/components/patina_mm/src/config.rs index cea551faf..9a360b7d4 100644 --- a/components/patina_mm/src/config.rs +++ b/components/patina_mm/src/config.rs @@ -18,7 +18,6 @@ //! //! SPDX-License-Identifier: Apache-2.0 //! -extern crate alloc; use alloc::vec::Vec; use core::{fmt, pin::Pin, ptr::NonNull}; diff --git a/components/patina_mm/src/lib.rs b/components/patina_mm/src/lib.rs index 55cab8254..c42cc9e21 100644 --- a/components/patina_mm/src/lib.rs +++ b/components/patina_mm/src/lib.rs @@ -6,6 +6,9 @@ #![cfg_attr(all(not(feature = "std"), not(test), not(feature = "mockall")), no_std)] #![feature(coverage_attribute)] +#[cfg(any(test, feature = "alloc"))] +extern crate alloc; + #[cfg(any(test, feature = "alloc"))] pub mod component; #[cfg(any(test, feature = "alloc"))] diff --git a/components/patina_mm/src/protocol/mm_supervisor_request.rs b/components/patina_mm/src/protocol/mm_supervisor_request.rs index 33fa5a854..7a3b7a8cd 100644 --- a/components/patina_mm/src/protocol/mm_supervisor_request.rs +++ b/components/patina_mm/src/protocol/mm_supervisor_request.rs @@ -17,9 +17,7 @@ //! //! SPDX-License-Identifier: Apache-2.0 -use patina::{BinaryGuid, Guid}; -use zerocopy::FromBytes; -use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout}; +use patina::BinaryGuid; // GUID for gMmSupervisorRequestHandlerGuid // { 0x8c633b23, 0x1260, 0x4ea6, { 0x83, 0xf, 0x7d, 0xdc, 0x97, 0x38, 0x21, 0x11 } } @@ -42,7 +40,7 @@ pub const MM_SUPERVISOR_REQUEST_HANDLER_GUID: BinaryGuid = /// 0x0C 4 reserved - Reserved for alignment, must be 0 /// 0x10 8 result - Return status (0 = success, set by supervisor on response) /// ``` -#[derive(Debug, Clone, Copy, FromBytes, IntoBytes, Immutable, KnownLayout)] +#[derive(Debug, Clone, Copy, zerocopy_derive::FromBytes, zerocopy_derive::IntoBytes, zerocopy_derive::Immutable, zerocopy_derive::KnownLayout)] #[repr(C)] pub struct MmSupervisorRequestHeader { /// Signature to identify the request ('MSUP' as little-endian). @@ -65,16 +63,6 @@ impl MmSupervisorRequestHeader { pub fn is_valid(&self) -> bool { self.signature == SIGNATURE && self.revision <= REVISION } - - /// Reads a header from a byte slice. - /// - /// Returns `None` if the slice is too small or misaligned. - pub fn from_bytes(bytes: &[u8]) -> Option { - if bytes.len() < Self::SIZE { - return None; - } - Self::read_from_bytes(&bytes[..Self::SIZE]).ok() - } } /// Response from MM Supervisor version info request. @@ -90,7 +78,7 @@ impl MmSupervisorRequestHeader { /// 0x04 4 patch_level - Supervisor patch level /// 0x08 8 max_supervisor_request_level - Highest supported request type /// ``` -#[derive(Debug, Clone, Copy, FromBytes, IntoBytes, Immutable, KnownLayout)] +#[derive(Debug, Clone, Copy, zerocopy_derive::FromBytes, zerocopy_derive::IntoBytes, zerocopy_derive::Immutable, zerocopy_derive::KnownLayout)] #[repr(C)] pub struct MmSupervisorVersionInfo { /// Version of the MM Supervisor. @@ -104,16 +92,6 @@ pub struct MmSupervisorVersionInfo { impl MmSupervisorVersionInfo { /// Size of the version info structure in bytes. pub const SIZE: usize = core::mem::size_of::(); - - /// Reads version info from a byte slice. - /// - /// Returns `None` if the slice is too small or misaligned. - pub fn from_bytes(bytes: &[u8]) -> Option { - if bytes.len() < Self::SIZE { - return None; - } - Self::read_from_bytes(&bytes[..Self::SIZE]).ok() - } } // ============================================================================ diff --git a/components/patina_mm/tests/patina_mm_integration.rs b/components/patina_mm/tests/patina_mm_integration.rs index a280aa414..2c79ea31e 100644 --- a/components/patina_mm/tests/patina_mm_integration.rs +++ b/components/patina_mm/tests/patina_mm_integration.rs @@ -9,5 +9,6 @@ //! //! SPDX-License-Identifier: Apache-2.0 +#[cfg(any(test, feature = "alloc"))] #[path = "patina_mm_integration/mod.rs"] mod patina_mm_integration; diff --git a/components/patina_mm/tests/patina_mm_integration/framework/core_functionality_tests.rs b/components/patina_mm/tests/patina_mm_integration/framework/core_functionality_tests.rs index 27336ddf5..97b4ce979 100644 --- a/components/patina_mm/tests/patina_mm_integration/framework/core_functionality_tests.rs +++ b/components/patina_mm/tests/patina_mm_integration/framework/core_functionality_tests.rs @@ -12,14 +12,14 @@ use patina::{BinaryGuid, Guid}; use patina_mm::{ component::communicator::{MmCommunication, MmCommunicator, MmExecutor, Status}, - config::{CommunicateBuffer, EfiMmCommunicateHeader}, + config::CommunicateBuffer, + comm_buffer_hob::EfiMmCommunicateHeader, }; use core::pin::Pin; use std::collections::HashMap; -extern crate alloc; -use alloc::{boxed::Box, vec::Vec}; +use std::vec::Vec; /// Lightweight MM handler used for testing struct TestHandler { diff --git a/components/patina_mm/tests/patina_mm_integration/mm_communicator/stress_tests.rs b/components/patina_mm/tests/patina_mm_integration/mm_communicator/stress_tests.rs index 1b25e78f1..182190609 100644 --- a/components/patina_mm/tests/patina_mm_integration/mm_communicator/stress_tests.rs +++ b/components/patina_mm/tests/patina_mm_integration/mm_communicator/stress_tests.rs @@ -10,8 +10,6 @@ use crate::patina_mm_integration::common::{constants::*, framework::*}; -extern crate alloc; -use alloc::{boxed::Box, format, vec, vec::Vec}; use core::pin::Pin; use patina::{ Guid, diff --git a/components/patina_mm/tests/patina_mm_integration/mod.rs b/components/patina_mm/tests/patina_mm_integration/mod.rs index 768468cc3..db638cf76 100644 --- a/components/patina_mm/tests/patina_mm_integration/mod.rs +++ b/components/patina_mm/tests/patina_mm_integration/mod.rs @@ -31,6 +31,8 @@ //! //! SPDX-License-Identifier: Apache-2.0 +extern crate alloc; + // Common utilities available to all test modules mod common; diff --git a/components/patina_performance/Cargo.toml b/components/patina_performance/Cargo.toml index 73f113f2e..40479ea07 100644 --- a/components/patina_performance/Cargo.toml +++ b/components/patina_performance/Cargo.toml @@ -17,7 +17,7 @@ uuid = { workspace = true } mu_rust_helpers = { workspace = true } patina = { workspace = true } -patina_mm = { workspace = true } +patina_mm = { workspace = true, features = ["alloc"] } zerocopy = { workspace = true } zerocopy-derive = { workspace = true } From 09f66d21e229ebe50cadddbee4b834415a3317e7 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Wed, 18 Mar 2026 13:18:41 -0700 Subject: [PATCH 08/26] fmt 2 --- .../patina_mm/src/component/communicator.rs | 2 +- .../src/protocol/mm_supervisor_request.rs | 20 +++++++++++++++++-- .../framework/core_functionality_tests.rs | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/components/patina_mm/src/component/communicator.rs b/components/patina_mm/src/component/communicator.rs index 5e27c8ac0..554e47612 100644 --- a/components/patina_mm/src/component/communicator.rs +++ b/components/patina_mm/src/component/communicator.rs @@ -370,12 +370,12 @@ impl Default for MmCommunicator { mod tests { use super::*; use crate::{ + comm_buffer_hob::MmCommBufferStatus, component::{ communicator::{MmCommunicator, MockMmExecutor}, sw_mmi_manager::SwMmiManager, }, config::{CommunicateBuffer, MmCommunicationConfiguration}, - comm_buffer_hob::MmCommBufferStatus, }; use patina::component::{IntoComponent, Storage}; diff --git a/components/patina_mm/src/protocol/mm_supervisor_request.rs b/components/patina_mm/src/protocol/mm_supervisor_request.rs index 7a3b7a8cd..958f6070f 100644 --- a/components/patina_mm/src/protocol/mm_supervisor_request.rs +++ b/components/patina_mm/src/protocol/mm_supervisor_request.rs @@ -40,7 +40,15 @@ pub const MM_SUPERVISOR_REQUEST_HANDLER_GUID: BinaryGuid = /// 0x0C 4 reserved - Reserved for alignment, must be 0 /// 0x10 8 result - Return status (0 = success, set by supervisor on response) /// ``` -#[derive(Debug, Clone, Copy, zerocopy_derive::FromBytes, zerocopy_derive::IntoBytes, zerocopy_derive::Immutable, zerocopy_derive::KnownLayout)] +#[derive( + Debug, + Clone, + Copy, + zerocopy_derive::FromBytes, + zerocopy_derive::IntoBytes, + zerocopy_derive::Immutable, + zerocopy_derive::KnownLayout +)] #[repr(C)] pub struct MmSupervisorRequestHeader { /// Signature to identify the request ('MSUP' as little-endian). @@ -78,7 +86,15 @@ impl MmSupervisorRequestHeader { /// 0x04 4 patch_level - Supervisor patch level /// 0x08 8 max_supervisor_request_level - Highest supported request type /// ``` -#[derive(Debug, Clone, Copy, zerocopy_derive::FromBytes, zerocopy_derive::IntoBytes, zerocopy_derive::Immutable, zerocopy_derive::KnownLayout)] +#[derive( + Debug, + Clone, + Copy, + zerocopy_derive::FromBytes, + zerocopy_derive::IntoBytes, + zerocopy_derive::Immutable, + zerocopy_derive::KnownLayout +)] #[repr(C)] pub struct MmSupervisorVersionInfo { /// Version of the MM Supervisor. diff --git a/components/patina_mm/tests/patina_mm_integration/framework/core_functionality_tests.rs b/components/patina_mm/tests/patina_mm_integration/framework/core_functionality_tests.rs index 97b4ce979..8d1ac5c41 100644 --- a/components/patina_mm/tests/patina_mm_integration/framework/core_functionality_tests.rs +++ b/components/patina_mm/tests/patina_mm_integration/framework/core_functionality_tests.rs @@ -11,9 +11,9 @@ use patina::{BinaryGuid, Guid}; use patina_mm::{ + comm_buffer_hob::EfiMmCommunicateHeader, component::communicator::{MmCommunication, MmCommunicator, MmExecutor, Status}, config::CommunicateBuffer, - comm_buffer_hob::EfiMmCommunicateHeader, }; use core::pin::Pin; From 2522226f1b1d492566e872ee2903905c64703012 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Wed, 18 Mar 2026 14:08:14 -0700 Subject: [PATCH 09/26] build break again? --- .../src/protocol/mm_supervisor_request.rs | 21 +++++++++++++++++++ .../patina_mm_integration/common/constants.rs | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/components/patina_mm/src/protocol/mm_supervisor_request.rs b/components/patina_mm/src/protocol/mm_supervisor_request.rs index 958f6070f..5592dbe99 100644 --- a/components/patina_mm/src/protocol/mm_supervisor_request.rs +++ b/components/patina_mm/src/protocol/mm_supervisor_request.rs @@ -18,6 +18,7 @@ //! SPDX-License-Identifier: Apache-2.0 use patina::BinaryGuid; +use zerocopy::FromBytes; // GUID for gMmSupervisorRequestHandlerGuid // { 0x8c633b23, 0x1260, 0x4ea6, { 0x83, 0xf, 0x7d, 0xdc, 0x97, 0x38, 0x21, 0x11 } } @@ -71,6 +72,16 @@ impl MmSupervisorRequestHeader { pub fn is_valid(&self) -> bool { self.signature == SIGNATURE && self.revision <= REVISION } + + /// Reads a header from a byte slice. + /// + /// Returns `None` if the slice is too small or misaligned. + pub fn from_bytes(bytes: &[u8]) -> Option { + if bytes.len() < Self::SIZE { + return None; + } + Self::read_from_bytes(&bytes[..Self::SIZE]).ok() + } } /// Response from MM Supervisor version info request. @@ -108,6 +119,16 @@ pub struct MmSupervisorVersionInfo { impl MmSupervisorVersionInfo { /// Size of the version info structure in bytes. pub const SIZE: usize = core::mem::size_of::(); + + /// Reads version info from a byte slice. + /// + /// Returns `None` if the slice is too small or misaligned. + pub fn from_bytes(bytes: &[u8]) -> Option { + if bytes.len() < Self::SIZE { + return None; + } + Self::read_from_bytes(&bytes[..Self::SIZE]).ok() + } } // ============================================================================ diff --git a/components/patina_mm/tests/patina_mm_integration/common/constants.rs b/components/patina_mm/tests/patina_mm_integration/common/constants.rs index 009df7746..d4e4dbed3 100644 --- a/components/patina_mm/tests/patina_mm_integration/common/constants.rs +++ b/components/patina_mm/tests/patina_mm_integration/common/constants.rs @@ -18,7 +18,7 @@ pub const TEST_BUFFER_SIZE: usize = SIZE_4KB; /// (VERSION, PATCH_LEVEL, etc.) are defined here as mock data. pub mod mm_supv { // Re-export shared protocol constants - pub use patina_mm::protocol::mm_supervisor_request::{REVISION, RequestType, SIGNATURE, requests, responses}; + pub use patina_mm::protocol::mm_supervisor_request::{REVISION, RequestType, SIGNATURE, responses}; /// Request signature as a DWORD (same as shared SIGNATURE, kept for test compatibility) pub const REQUEST_SIGNATURE: u32 = SIGNATURE; From cd72bca88482fb649bb3d2302011ca48d9830dbe Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Wed, 18 Mar 2026 16:47:04 -0700 Subject: [PATCH 10/26] remove mm_services for now --- sdk/patina/src/lib.rs | 2 - sdk/patina/src/mm_services.rs | 530 ---------------------------------- 2 files changed, 532 deletions(-) delete mode 100644 sdk/patina/src/mm_services.rs diff --git a/sdk/patina/src/lib.rs b/sdk/patina/src/lib.rs index 8e1c67049..52c6e85c0 100644 --- a/sdk/patina/src/lib.rs +++ b/sdk/patina/src/lib.rs @@ -50,8 +50,6 @@ pub mod guids; pub mod hash; pub mod log; #[cfg(any(test, feature = "alloc"))] -pub mod mm_services; -#[cfg(any(test, feature = "alloc"))] pub mod performance; pub mod pi; #[cfg(any(test, feature = "alloc"))] diff --git a/sdk/patina/src/mm_services.rs b/sdk/patina/src/mm_services.rs deleted file mode 100644 index 7ebdcb651..000000000 --- a/sdk/patina/src/mm_services.rs +++ /dev/null @@ -1,530 +0,0 @@ -//! MM (Management Mode) Services type definitions and trait. -//! -//! This module provides the Rust definitions for the PI `EFI_MM_SYSTEM_TABLE` -//! and an `MmServices` trait that wraps the raw C function-pointer table with -//! safe Rust method signatures, following the same pattern as -//! [`boot_services::BootServices`](crate::boot_services::BootServices). -//! -//! ## Layout -//! -//! * [`EfiMmSystemTable`] — `#[repr(C)]` struct matching the C -//! `_EFI_MM_SYSTEM_TABLE` layout from `PiMmCis.h`. -//! * [`MmServices`] — Safe Rust trait exposing the system-table services. -//! * [`StandardMmServices`] — Concrete wrapper around `*mut EfiMmSystemTable` -//! that implements `MmServices` by calling through the function pointers. -//! -//! Cores (e.g., `patina_mm_user_core`) allocate an `EfiMmSystemTable`, populate -//! its function pointers with their own `extern "efiapi"` thunks, and hand the -//! raw pointer to dispatched MM drivers. Drivers that want safe access can wrap -//! it in a `StandardMmServices`. -//! -//! ## License -//! -//! Copyright (c) Microsoft Corporation. -//! -//! SPDX-License-Identifier: Apache-2.0 -//! - -use core::ffi::c_void; - -use r_efi::efi; -use spin::Once; - -/// MMST signature: `'S', 'M', 'S', 'T'` (same as C `MM_MMST_SIGNATURE`). -pub const MM_MMST_SIGNATURE: u64 = 0x5453_4D53; - -/// PI Specification version encoded as `(major << 16) | minor`. -/// PI 1.8 → `0x0001_0050`. -pub const MM_SYSTEM_TABLE_REVISION: u32 = (1 << 16) | 80; - -/// A single MM I/O access function pointer. -/// -/// Matches the C typedef `EFI_MM_CPU_IO`: -/// ```c -/// typedef EFI_STATUS (EFIAPI *EFI_MM_CPU_IO)( -/// IN CONST EFI_MM_CPU_IO_PROTOCOL *This, -/// IN EFI_MM_IO_WIDTH Width, -/// IN UINT64 Address, -/// IN UINTN Count, -/// IN OUT VOID *Buffer -/// ); -/// ``` -pub type MmCpuIoFn = unsafe extern "efiapi" fn( - this: *const MmCpuIoAccess, - width: usize, - address: u64, - count: usize, - buffer: *mut c_void, -) -> efi::Status; - -/// MM CPU I/O access pair (Read + Write). -/// -/// Matches `EFI_MM_IO_ACCESS`. -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct MmCpuIoAccess { - pub read: MmCpuIoFn, - pub write: MmCpuIoFn, -} - -/// The `EFI_MM_CPU_IO_PROTOCOL` embedded in the system table. -/// -/// ```c -/// typedef struct _EFI_MM_CPU_IO_PROTOCOL { -/// EFI_MM_IO_ACCESS Mem; -/// EFI_MM_IO_ACCESS Io; -/// } EFI_MM_CPU_IO_PROTOCOL; -/// ``` -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct MmCpuIoProtocol { - pub mem: MmCpuIoAccess, - pub io: MmCpuIoAccess, -} - -/// `EFI_MM_INSTALL_CONFIGURATION_TABLE` -pub type MmInstallConfigurationTableFn = unsafe extern "efiapi" fn( - system_table: *const EfiMmSystemTable, - guid: *const efi::Guid, - table: *mut c_void, - table_size: usize, -) -> efi::Status; - -/// `EFI_ALLOCATE_POOL` (shared with Boot Services) -pub type MmAllocatePoolFn = - unsafe extern "efiapi" fn(pool_type: efi::MemoryType, size: usize, buffer: *mut *mut c_void) -> efi::Status; - -/// `EFI_FREE_POOL` (shared with Boot Services) -pub type MmFreePoolFn = unsafe extern "efiapi" fn(buffer: *mut c_void) -> efi::Status; - -/// `EFI_ALLOCATE_PAGES` (shared with Boot Services) -pub type MmAllocatePagesFn = unsafe extern "efiapi" fn( - alloc_type: efi::AllocateType, - memory_type: efi::MemoryType, - pages: usize, - memory: *mut efi::PhysicalAddress, -) -> efi::Status; - -/// `EFI_FREE_PAGES` (shared with Boot Services) -pub type MmFreePagesFn = unsafe extern "efiapi" fn(memory: efi::PhysicalAddress, pages: usize) -> efi::Status; - -/// `EFI_MM_STARTUP_THIS_AP` -pub type MmStartupThisApFn = - unsafe extern "efiapi" fn(procedure: usize, cpu_number: usize, proc_arguments: *mut c_void) -> efi::Status; - -/// `EFI_INSTALL_PROTOCOL_INTERFACE` (shared with Boot Services) -pub type MmInstallProtocolInterfaceFn = unsafe extern "efiapi" fn( - handle: *mut efi::Handle, - protocol: *mut efi::Guid, - interface_type: efi::InterfaceType, - interface: *mut c_void, -) -> efi::Status; - -/// `EFI_UNINSTALL_PROTOCOL_INTERFACE` (shared with Boot Services) -pub type MmUninstallProtocolInterfaceFn = - unsafe extern "efiapi" fn(handle: efi::Handle, protocol: *mut efi::Guid, interface: *mut c_void) -> efi::Status; - -/// `EFI_HANDLE_PROTOCOL` (shared with Boot Services) -pub type MmHandleProtocolFn = unsafe extern "efiapi" fn( - handle: efi::Handle, - protocol: *mut efi::Guid, - interface: *mut *mut c_void, -) -> efi::Status; - -/// `EFI_MM_REGISTER_PROTOCOL_NOTIFY` -pub type MmRegisterProtocolNotifyFn = unsafe extern "efiapi" fn( - protocol: *const efi::Guid, - function: usize, - registration: *mut *mut c_void, -) -> efi::Status; - -/// `EFI_LOCATE_HANDLE` (shared with Boot Services) -pub type MmLocateHandleFn = unsafe extern "efiapi" fn( - search_type: efi::LocateSearchType, - protocol: *mut efi::Guid, - search_key: *mut c_void, - buffer_size: *mut usize, - buffer: *mut efi::Handle, -) -> efi::Status; - -/// `EFI_LOCATE_PROTOCOL` (shared with Boot Services) -pub type MmLocateProtocolFn = unsafe extern "efiapi" fn( - protocol: *mut efi::Guid, - registration: *mut c_void, - interface: *mut *mut c_void, -) -> efi::Status; - -/// `EFI_MM_INTERRUPT_MANAGE` -pub type MmiManageFn = unsafe extern "efiapi" fn( - handler_type: *const efi::Guid, - context: *const c_void, - comm_buffer: *mut c_void, - comm_buffer_size: *mut usize, -) -> efi::Status; - -/// MMI handler entry point. -/// -/// Matches the C typedef `EFI_MM_HANDLER_ENTRY_POINT`. -pub type MmiHandlerEntryPoint = unsafe extern "efiapi" fn( - dispatch_handle: efi::Handle, - context: *const c_void, - comm_buffer: *mut c_void, - comm_buffer_size: *mut usize, -) -> efi::Status; - -/// `EFI_MM_INTERRUPT_REGISTER` -pub type MmiHandlerRegisterFn = unsafe extern "efiapi" fn( - handler: MmiHandlerEntryPoint, - handler_type: *const efi::Guid, - dispatch_handle: *mut efi::Handle, -) -> efi::Status; - -/// `EFI_MM_INTERRUPT_UNREGISTER` -pub type MmiHandlerUnregisterFn = unsafe extern "efiapi" fn(dispatch_handle: efi::Handle) -> efi::Status; - -/// The Management Mode System Table (MMST). -/// -/// This is the `#[repr(C)]` Rust definition of the C `_EFI_MM_SYSTEM_TABLE` -/// from `PiMmCis.h`. The table pointer is passed as the second argument to -/// every MM driver's entry point: -/// -/// ```c -/// EFI_STATUS EFIAPI DriverEntry(EFI_HANDLE ImageHandle, EFI_MM_SYSTEM_TABLE *MmSt); -/// ``` -#[repr(C)] -pub struct EfiMmSystemTable { - // ---- Table Header ---- - pub hdr: efi::TableHeader, - - // ---- Firmware info ---- - /// Pointer to a NUL-terminated UCS-2 vendor string (may be null). - pub mm_firmware_vendor: *mut u16, - /// Firmware revision number. - pub mm_firmware_revision: u32, - - // ---- Configuration Table ---- - pub mm_install_configuration_table: MmInstallConfigurationTableFn, - - // ---- I/O services (embedded protocol) ---- - pub mm_io: MmCpuIoProtocol, - - // ---- Memory services ---- - pub mm_allocate_pool: MmAllocatePoolFn, - pub mm_free_pool: MmFreePoolFn, - pub mm_allocate_pages: MmAllocatePagesFn, - pub mm_free_pages: MmFreePagesFn, - - // ---- MP service ---- - pub mm_startup_this_ap: MmStartupThisApFn, - - // ---- CPU information ---- - pub currently_executing_cpu: usize, - pub number_of_cpus: usize, - pub cpu_save_state_size: *mut usize, - pub cpu_save_state: *mut *mut c_void, - - // ---- Extensibility table ---- - pub number_of_table_entries: usize, - pub mm_configuration_table: *mut efi::ConfigurationTable, - - // ---- Protocol services ---- - pub mm_install_protocol_interface: MmInstallProtocolInterfaceFn, - pub mm_uninstall_protocol_interface: MmUninstallProtocolInterfaceFn, - pub mm_handle_protocol: MmHandleProtocolFn, - pub mm_register_protocol_notify: MmRegisterProtocolNotifyFn, - pub mm_locate_handle: MmLocateHandleFn, - pub mm_locate_protocol: MmLocateProtocolFn, - - // ---- MMI management ---- - pub mmi_manage: MmiManageFn, - pub mmi_handler_register: MmiHandlerRegisterFn, - pub mmi_handler_unregister: MmiHandlerUnregisterFn, -} - -// SAFETY: The system table is allocated once and its pointer is shared read-only -// with dispatched drivers. Internal mutation goes through synchronized databases. -unsafe impl Send for EfiMmSystemTable {} -unsafe impl Sync for EfiMmSystemTable {} - -/// Wrapper around a raw `*mut EfiMmSystemTable` pointer that implements -/// [`MmServices`] by calling through the C function-pointer table. -/// -/// This is the MM equivalent of -/// [`StandardBootServices`](crate::boot_services::StandardBootServices). -pub struct StandardMmServices { - efi_mm_system_table: Once<*mut EfiMmSystemTable>, -} - -// SAFETY: The raw pointer is only written once (protected by `Once`) and the -// underlying table is not expected to change after initialization. -unsafe impl Sync for StandardMmServices {} -unsafe impl Send for StandardMmServices {} - -impl StandardMmServices { - /// Create a new `StandardMmServices` from an existing system table pointer. - pub fn new(mm_system_table: *mut EfiMmSystemTable) -> Self { - let this = Self::new_uninit(); - this.init(mm_system_table); - this - } - - /// Create an uninitialized instance. - pub const fn new_uninit() -> Self { - Self { efi_mm_system_table: Once::new() } - } - - /// Initialize with the given system table pointer. - pub fn init(&self, mm_system_table: *mut EfiMmSystemTable) { - self.efi_mm_system_table.call_once(|| mm_system_table); - } - - /// Returns `true` if the instance has been initialized. - pub fn is_init(&self) -> bool { - self.efi_mm_system_table.is_completed() - } - - /// Returns the raw system table pointer (panics if uninitialized). - pub fn as_mut_ptr(&self) -> *mut EfiMmSystemTable { - *self.efi_mm_system_table.get().expect("StandardMmServices is not initialized!") - } -} - -impl Clone for StandardMmServices { - fn clone(&self) -> Self { - if let Some(ptr) = self.efi_mm_system_table.get() { - StandardMmServices::new(*ptr) - } else { - StandardMmServices::new_uninit() - } - } -} - -impl core::fmt::Debug for StandardMmServices { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - if !self.is_init() { - return f.debug_struct("StandardMmServices").field("table", &"Not Initialized").finish(); - } - f.debug_struct("StandardMmServices").field("table", &self.as_mut_ptr()).finish() - } -} - -/// Safe Rust interface to the MM System Table services. -/// -/// This is the MM analogue of -/// [`BootServices`](crate::boot_services::BootServices). -/// Each method maps 1:1 to a function pointer in [`EfiMmSystemTable`]. -pub trait MmServices { - /// Allocate pool memory. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmAllocatePool` - fn allocate_pool(&self, pool_type: efi::MemoryType, size: usize) -> Result<*mut u8, efi::Status>; - - /// Free pool memory. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmFreePool` - fn free_pool(&self, buffer: *mut u8) -> Result<(), efi::Status>; - - /// Allocate pages. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmAllocatePages` - fn allocate_pages( - &self, - alloc_type: efi::AllocateType, - memory_type: efi::MemoryType, - pages: usize, - ) -> Result; - - /// Free pages. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmFreePages` - fn free_pages(&self, memory: u64, pages: usize) -> Result<(), efi::Status>; - - /// Install a protocol interface on a handle. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmInstallProtocolInterface` - /// - /// # Safety - /// - /// `interface` must be a valid pointer to the protocol structure or null. - unsafe fn install_protocol_interface( - &self, - handle: *mut efi::Handle, - protocol: &efi::Guid, - interface_type: efi::InterfaceType, - interface: *mut c_void, - ) -> Result<(), efi::Status>; - - /// Uninstall a protocol interface from a handle. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmUninstallProtocolInterface` - /// - /// # Safety - /// - /// `interface` must match the pointer that was installed. - unsafe fn uninstall_protocol_interface( - &self, - handle: efi::Handle, - protocol: &efi::Guid, - interface: *mut c_void, - ) -> Result<(), efi::Status>; - - /// Query a handle for a protocol. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmHandleProtocol` - /// - /// # Safety - /// - /// The returned pointer must be used carefully to avoid aliasing violations. - unsafe fn handle_protocol(&self, handle: efi::Handle, protocol: &efi::Guid) -> Result<*mut c_void, efi::Status>; - - /// Locate the first device that supports a protocol. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmLocateProtocol` - /// - /// # Safety - /// - /// The returned pointer must be used carefully to avoid aliasing violations. - unsafe fn locate_protocol(&self, protocol: &efi::Guid) -> Result<*mut c_void, efi::Status>; - - /// Manage (dispatch) an MMI. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmiManage` - fn mmi_manage( - &self, - handler_type: Option<&efi::Guid>, - context: *const c_void, - comm_buffer: *mut c_void, - comm_buffer_size: *mut usize, - ) -> efi::Status; - - /// Register an MMI handler. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmiHandlerRegister` - fn mmi_handler_register( - &self, - handler: MmiHandlerEntryPoint, - handler_type: Option<&efi::Guid>, - ) -> Result; - - /// Unregister an MMI handler. - /// - /// PI Spec: `EFI_MM_SYSTEM_TABLE.MmiHandlerUnRegister` - fn mmi_handler_unregister(&self, dispatch_handle: efi::Handle) -> Result<(), efi::Status>; -} - -impl MmServices for StandardMmServices { - fn allocate_pool(&self, pool_type: efi::MemoryType, size: usize) -> Result<*mut u8, efi::Status> { - let mmst = unsafe { &*self.as_mut_ptr() }; - let mut buffer: *mut c_void = core::ptr::null_mut(); - let status = unsafe { (mmst.mm_allocate_pool)(pool_type, size, &mut buffer) }; - if status == efi::Status::SUCCESS { Ok(buffer as *mut u8) } else { Err(status) } - } - - fn free_pool(&self, buffer: *mut u8) -> Result<(), efi::Status> { - let mmst = unsafe { &*self.as_mut_ptr() }; - let status = unsafe { (mmst.mm_free_pool)(buffer as *mut c_void) }; - if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } - } - - fn allocate_pages( - &self, - alloc_type: efi::AllocateType, - memory_type: efi::MemoryType, - pages: usize, - ) -> Result { - let mmst = unsafe { &*self.as_mut_ptr() }; - let mut memory: efi::PhysicalAddress = 0; - let status = unsafe { (mmst.mm_allocate_pages)(alloc_type, memory_type, pages, &mut memory) }; - if status == efi::Status::SUCCESS { Ok(memory) } else { Err(status) } - } - - fn free_pages(&self, memory: u64, pages: usize) -> Result<(), efi::Status> { - let mmst = unsafe { &*self.as_mut_ptr() }; - let status = unsafe { (mmst.mm_free_pages)(memory, pages) }; - if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } - } - - unsafe fn install_protocol_interface( - &self, - handle: *mut efi::Handle, - protocol: &efi::Guid, - interface_type: efi::InterfaceType, - interface: *mut c_void, - ) -> Result<(), efi::Status> { - let mmst = unsafe { &*self.as_mut_ptr() }; - let status = unsafe { - (mmst.mm_install_protocol_interface)( - handle, - protocol as *const efi::Guid as *mut efi::Guid, - interface_type, - interface, - ) - }; - if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } - } - - unsafe fn uninstall_protocol_interface( - &self, - handle: efi::Handle, - protocol: &efi::Guid, - interface: *mut c_void, - ) -> Result<(), efi::Status> { - let mmst = unsafe { &*self.as_mut_ptr() }; - let status = unsafe { - (mmst.mm_uninstall_protocol_interface)(handle, protocol as *const efi::Guid as *mut efi::Guid, interface) - }; - if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } - } - - unsafe fn handle_protocol(&self, handle: efi::Handle, protocol: &efi::Guid) -> Result<*mut c_void, efi::Status> { - let mmst = unsafe { &*self.as_mut_ptr() }; - let mut interface: *mut c_void = core::ptr::null_mut(); - let status = unsafe { - (mmst.mm_handle_protocol)(handle, protocol as *const efi::Guid as *mut efi::Guid, &mut interface) - }; - if status == efi::Status::SUCCESS { Ok(interface) } else { Err(status) } - } - - unsafe fn locate_protocol(&self, protocol: &efi::Guid) -> Result<*mut c_void, efi::Status> { - let mmst = unsafe { &*self.as_mut_ptr() }; - let mut interface: *mut c_void = core::ptr::null_mut(); - let status = unsafe { - (mmst.mm_locate_protocol)( - protocol as *const efi::Guid as *mut efi::Guid, - core::ptr::null_mut(), - &mut interface, - ) - }; - if status == efi::Status::SUCCESS { Ok(interface) } else { Err(status) } - } - - fn mmi_manage( - &self, - handler_type: Option<&efi::Guid>, - context: *const c_void, - comm_buffer: *mut c_void, - comm_buffer_size: *mut usize, - ) -> efi::Status { - let mmst = unsafe { &*self.as_mut_ptr() }; - let guid_ptr = handler_type.map_or(core::ptr::null(), |g| g as *const efi::Guid); - unsafe { (mmst.mmi_manage)(guid_ptr, context, comm_buffer, comm_buffer_size) } - } - - fn mmi_handler_register( - &self, - handler: MmiHandlerEntryPoint, - handler_type: Option<&efi::Guid>, - ) -> Result { - let mmst = unsafe { &*self.as_mut_ptr() }; - let guid_ptr = handler_type.map_or(core::ptr::null(), |g| g as *const efi::Guid); - let mut dispatch_handle: efi::Handle = core::ptr::null_mut(); - let status = unsafe { (mmst.mmi_handler_register)(handler, guid_ptr, &mut dispatch_handle) }; - if status == efi::Status::SUCCESS { Ok(dispatch_handle) } else { Err(status) } - } - - fn mmi_handler_unregister(&self, dispatch_handle: efi::Handle) -> Result<(), efi::Status> { - let mmst = unsafe { &*self.as_mut_ptr() }; - let status = unsafe { (mmst.mmi_handler_unregister)(dispatch_handle) }; - if status == efi::Status::SUCCESS { Ok(()) } else { Err(status) } - } -} From 8ca6f865e21abe3bce41e89a8a70538096db7b51 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Wed, 18 Mar 2026 16:53:49 -0700 Subject: [PATCH 11/26] revert some comments --- .../tests/patina_mm_integration/common/constants.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/components/patina_mm/tests/patina_mm_integration/common/constants.rs b/components/patina_mm/tests/patina_mm_integration/common/constants.rs index d4e4dbed3..4afe36fa8 100644 --- a/components/patina_mm/tests/patina_mm_integration/common/constants.rs +++ b/components/patina_mm/tests/patina_mm_integration/common/constants.rs @@ -11,14 +11,13 @@ use patina::base::SIZE_4KB; /// Standard test buffer size pub const TEST_BUFFER_SIZE: usize = SIZE_4KB; -/// MM Supervisor constants and definitions for testing. +/// MM Supervisor constants and definitions for testing /// -/// Protocol constants (SIGNATURE, REVISION, request types) are re-exported from the -/// shared [`patina_mm::protocol::mm_supervisor_request`] module. Test-specific values -/// (VERSION, PATCH_LEVEL, etc.) are defined here as mock data. +/// Note: These values are only used for testing. They're not meant to be +/// accurate or used in production code. pub mod mm_supv { // Re-export shared protocol constants - pub use patina_mm::protocol::mm_supervisor_request::{REVISION, RequestType, SIGNATURE, responses}; + use patina_mm::protocol::mm_supervisor_request::{REVISION, RequestType, SIGNATURE, responses}; /// Request signature as a DWORD (same as shared SIGNATURE, kept for test compatibility) pub const REQUEST_SIGNATURE: u32 = SIGNATURE; From 5e0b77b98085c6ddbb91c4c86f748ac29eebf66f Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Wed, 18 Mar 2026 17:18:33 -0700 Subject: [PATCH 12/26] fixing the docx --- components/patina_mm/Cargo.toml | 1 + .../patina_mm/tests/patina_mm_integration/common/constants.rs | 2 +- .../mm_communicator/component_integration_tests.rs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/components/patina_mm/Cargo.toml b/components/patina_mm/Cargo.toml index 8091ef374..9c74fe9a3 100644 --- a/components/patina_mm/Cargo.toml +++ b/components/patina_mm/Cargo.toml @@ -23,6 +23,7 @@ zerocopy-derive = { workspace = true } env_logger = { workspace = true } mockall = { workspace = true } patina = { workspace = true, features = ["mockall"] } +patina_dxe_core = { path = "../../patina_dxe_core" } [target.'cfg(target_arch="x86_64")'.dependencies] x86_64 = { workspace = true, features = [ diff --git a/components/patina_mm/tests/patina_mm_integration/common/constants.rs b/components/patina_mm/tests/patina_mm_integration/common/constants.rs index 4afe36fa8..699ad5229 100644 --- a/components/patina_mm/tests/patina_mm_integration/common/constants.rs +++ b/components/patina_mm/tests/patina_mm_integration/common/constants.rs @@ -17,7 +17,7 @@ pub const TEST_BUFFER_SIZE: usize = SIZE_4KB; /// accurate or used in production code. pub mod mm_supv { // Re-export shared protocol constants - use patina_mm::protocol::mm_supervisor_request::{REVISION, RequestType, SIGNATURE, responses}; + pub use patina_mm::protocol::mm_supervisor_request::{REVISION, RequestType, SIGNATURE, responses}; /// Request signature as a DWORD (same as shared SIGNATURE, kept for test compatibility) pub const REQUEST_SIGNATURE: u32 = SIGNATURE; diff --git a/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs b/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs index 8fe80767f..7aa9c61e2 100644 --- a/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs +++ b/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs @@ -283,7 +283,7 @@ fn test_real_component_multiple_handlers() { }; let supervisor_result = - framework.communicate(&Guid::from_ref(&test_guids::MM_SUPERVISOR), &supervisor_request.as_bytes().to_vec()); + framework.communicate(&Guid::from_ref(&test_guids::MM_SUPERVISOR), supervisor_request.as_bytes()); assert!(supervisor_result.is_ok(), "Supervisor communication should succeed"); // Both handlers should work independently through the real component infrastructure From f2463ce3e0e74d63c79b8de79d5343de44bed196 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Thu, 19 Mar 2026 11:15:29 -0700 Subject: [PATCH 13/26] simplify syntax --- .../patina_mm/src/protocol/mm_supervisor_request.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/components/patina_mm/src/protocol/mm_supervisor_request.rs b/components/patina_mm/src/protocol/mm_supervisor_request.rs index 5592dbe99..d63ae1cc6 100644 --- a/components/patina_mm/src/protocol/mm_supervisor_request.rs +++ b/components/patina_mm/src/protocol/mm_supervisor_request.rs @@ -77,10 +77,7 @@ impl MmSupervisorRequestHeader { /// /// Returns `None` if the slice is too small or misaligned. pub fn from_bytes(bytes: &[u8]) -> Option { - if bytes.len() < Self::SIZE { - return None; - } - Self::read_from_bytes(&bytes[..Self::SIZE]).ok() + Self::read_from_bytes(&bytes.get(..Self::SIZE)?).ok() } } @@ -124,10 +121,7 @@ impl MmSupervisorVersionInfo { /// /// Returns `None` if the slice is too small or misaligned. pub fn from_bytes(bytes: &[u8]) -> Option { - if bytes.len() < Self::SIZE { - return None; - } - Self::read_from_bytes(&bytes[..Self::SIZE]).ok() + Self::read_from_bytes(&bytes.get(..Self::SIZE)?).ok() } } From 423c801f3f3f9764179b7a5267b97ca620367303 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Thu, 19 Mar 2026 14:16:02 -0700 Subject: [PATCH 14/26] simplify content --- .../src/protocol/mm_supervisor_request.rs | 96 +++++++++++-------- .../patina_mm_integration/common/constants.rs | 11 +-- .../patina_mm_integration/common/handlers.rs | 53 +++++----- .../component_integration_tests.rs | 23 ++--- .../mm_supervisor/communication_tests.rs | 59 ++++++------ 5 files changed, 128 insertions(+), 114 deletions(-) diff --git a/components/patina_mm/src/protocol/mm_supervisor_request.rs b/components/patina_mm/src/protocol/mm_supervisor_request.rs index d63ae1cc6..782794bc3 100644 --- a/components/patina_mm/src/protocol/mm_supervisor_request.rs +++ b/components/patina_mm/src/protocol/mm_supervisor_request.rs @@ -19,6 +19,13 @@ use patina::BinaryGuid; use zerocopy::FromBytes; +use r_efi::efi; + +/// The expected signature value ('MSUP' as little-endian u32). +pub const SIGNATURE: u32 = 0x5055534D; + +/// Current revision of the request protocol. +pub const REVISION: u32 = 1; // GUID for gMmSupervisorRequestHandlerGuid // { 0x8c633b23, 0x1260, 0x4ea6, { 0x83, 0xf, 0x7d, 0xdc, 0x97, 0x38, 0x21, 0x11 } } @@ -125,22 +132,10 @@ impl MmSupervisorVersionInfo { } } -// ============================================================================ -// Protocol Constants -// ============================================================================ - -/// The expected signature value ('MSUP' as little-endian u32). -pub const SIGNATURE: u32 = 0x5055534D; - -/// Current revision of the request protocol. -pub const REVISION: u32 = 1; - -/// Standard MM Supervisor request types. +/// MM Supervisor request types. /// -/// Each variant corresponds to a specific supervisor operation. The enum is `#[repr(u32)]` -/// to match the wire format of [`MmSupervisorRequestHeader::request`]. +/// Each variant corresponds to a specific supervisor operation. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(u32)] pub enum RequestType { /// Request to unblock memory regions. UnblockMem = 0x0001, @@ -153,8 +148,10 @@ pub enum RequestType { } impl RequestType { - /// The highest valid request type value. - pub const MAX: u64 = Self::CommUpdate as u64; + /// Tries to convert a raw u64 value into a `RequestType`. + /// + /// Returns `Err(value)` if the value does not correspond to a valid request type. + pub const MAX_REQUEST_TYPE: u64 = Self::CommUpdate as u64; } impl TryFrom for RequestType { @@ -171,34 +168,57 @@ impl TryFrom for RequestType { } } -/// Deprecated module — use [`RequestType`] enum variants instead. +impl From for u32 { + fn from(request_type: RequestType) -> Self { + request_type as u32 + } +} + +/// Standard MM Supervisor response types. /// -/// Kept temporarily for backward compatibility. -pub mod requests { - use super::RequestType; - /// Request to unblock memory regions. - pub const UNBLOCK_MEM: u32 = RequestType::UnblockMem as u32; - /// Request to fetch security policy. - pub const FETCH_POLICY: u32 = RequestType::FetchPolicy as u32; - /// Request for version information. - pub const VERSION_INFO: u32 = RequestType::VersionInfo as u32; - /// Request to update communication buffer. - pub const COMM_UPDATE: u32 = RequestType::CommUpdate as u32; +/// Each variant corresponds to a specific supervisor operation. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ResponseType { + /// Response to unblock memory regions request. + Success = 0x0000, + /// Error: Invalid request index. + InvalidRequest = 0x0001, + /// Error: Invalid data buffer. + InvalidDataBuffer = 0x0002, + /// Error: Communication buffer initialization failed. + CommBufferInitError = 0x0003, } -/// Response status constants. -pub mod responses { - /// Operation completed successfully. - pub const SUCCESS: u64 = 0; - /// Operation failed with error. - pub const ERROR: u64 = 0xFFFFFFFFFFFFFFFF; +impl TryFrom for ResponseType { + type Error = u64; + + fn try_from(value: u64) -> Result { + match value { + 0x0000 => Ok(Self::Success), + 0x0001 => Ok(Self::InvalidRequest), + 0x0002 => Ok(Self::InvalidDataBuffer), + 0x0003 => Ok(Self::CommBufferInitError), + other => Err(other), + } + } } -// ============================================================================ -// Unblock Memory Params -// ============================================================================ +impl From for u64 { + fn from(response_type: ResponseType) -> Self { + response_type as u64 + } +} -use r_efi::efi; +impl From for efi::Status { + fn from(response_type: ResponseType) -> Self { + match response_type { + ResponseType::Success => efi::Status::SUCCESS, + ResponseType::InvalidRequest => efi::Status::INVALID_PARAMETER, + ResponseType::InvalidDataBuffer => efi::Status::BUFFER_TOO_SMALL, + ResponseType::CommBufferInitError => efi::Status::DEVICE_ERROR, + } + } +} /// MM Supervisor Unblock Memory Parameters. /// diff --git a/components/patina_mm/tests/patina_mm_integration/common/constants.rs b/components/patina_mm/tests/patina_mm_integration/common/constants.rs index 699ad5229..ab6729017 100644 --- a/components/patina_mm/tests/patina_mm_integration/common/constants.rs +++ b/components/patina_mm/tests/patina_mm_integration/common/constants.rs @@ -16,20 +16,11 @@ pub const TEST_BUFFER_SIZE: usize = SIZE_4KB; /// Note: These values are only used for testing. They're not meant to be /// accurate or used in production code. pub mod mm_supv { - // Re-export shared protocol constants - pub use patina_mm::protocol::mm_supervisor_request::{REVISION, RequestType, SIGNATURE, responses}; - - /// Request signature as a DWORD (same as shared SIGNATURE, kept for test compatibility) - pub const REQUEST_SIGNATURE: u32 = SIGNATURE; - /// Mock supervisor version for testing pub const VERSION: u32 = 0x00130008; - + /// Mock supervisor patch level for testing pub const PATCH_LEVEL: u32 = 0x00010001; - - /// Mock maximum request level supported - pub const MAX_REQUEST_LEVEL: u64 = 0x0000000000000004; // COMM_UPDATE } /// Test GUIDs for different handlers diff --git a/components/patina_mm/tests/patina_mm_integration/common/handlers.rs b/components/patina_mm/tests/patina_mm_integration/common/handlers.rs index 4e60ff18f..0be8cdb83 100644 --- a/components/patina_mm/tests/patina_mm_integration/common/handlers.rs +++ b/components/patina_mm/tests/patina_mm_integration/common/handlers.rs @@ -20,10 +20,11 @@ use crate::patina_mm_integration::common::constants::*; extern crate alloc; use alloc::{string::String, vec::Vec}; +use patina_mm::protocol::mm_supervisor_request::ResponseType; pub use zerocopy::IntoBytes; // Import shared protocol types from patina_mm -pub use patina_mm::protocol::mm_supervisor_request::{MmSupervisorRequestHeader, MmSupervisorVersionInfo}; +pub use patina_mm::protocol::mm_supervisor_request::{MmSupervisorRequestHeader, MmSupervisorVersionInfo, SIGNATURE, REVISION, RequestType}; /// Standardized error type for MM handlers #[derive(Debug, Clone, PartialEq, Eq)] @@ -124,9 +125,9 @@ impl MmSupervisorHandler { fn handle_get_info_request(&self) -> MmHandlerResult> { let response_header = MmSupervisorRequestHeader { - signature: mm_supv::REQUEST_SIGNATURE, - revision: mm_supv::REVISION, - request: mm_supv::RequestType::VersionInfo as u32, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::VersionInfo as u32, reserved: 0, result: 0, // Success }; @@ -134,7 +135,7 @@ impl MmSupervisorHandler { let version_info = MmSupervisorVersionInfo { version: mm_supv::VERSION, patch_level: mm_supv::PATCH_LEVEL, - max_supervisor_request_level: mm_supv::MAX_REQUEST_LEVEL, + max_supervisor_request_level: RequestType::MAX_REQUEST_TYPE, }; let mut response = Vec::new(); @@ -147,9 +148,9 @@ impl MmSupervisorHandler { fn handle_get_capabilities_request(&self) -> MmHandlerResult> { let response_header = MmSupervisorRequestHeader { - signature: mm_supv::REQUEST_SIGNATURE, - revision: mm_supv::REVISION, - request: mm_supv::RequestType::FetchPolicy as u32, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::FetchPolicy as u32, reserved: 0, result: 0, // Success }; @@ -166,9 +167,9 @@ impl MmSupervisorHandler { fn handle_comm_update_request(&self) -> MmHandlerResult> { let response_header = MmSupervisorRequestHeader { - signature: mm_supv::REQUEST_SIGNATURE, - revision: mm_supv::REVISION, - request: mm_supv::RequestType::CommUpdate as u32, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::CommUpdate as u32, reserved: 0, result: 0, // Success }; @@ -186,9 +187,9 @@ impl MmSupervisorHandler { fn handle_unblock_mem_request(&self) -> MmHandlerResult> { let response_header = MmSupervisorRequestHeader { - signature: mm_supv::REQUEST_SIGNATURE, - revision: mm_supv::REVISION, - request: mm_supv::RequestType::UnblockMem as u32, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::UnblockMem as u32, reserved: 0, result: 0, // Success }; @@ -221,38 +222,38 @@ impl MmHandler for MmSupervisorHandler { .ok_or_else(|| MmHandlerError::InvalidInput("Failed to parse header from bytes".to_string()))?; // Validate signature - if request_header.signature != mm_supv::REQUEST_SIGNATURE { + if request_header.signature != SIGNATURE { return Err(MmHandlerError::InvalidInput(format!( "Invalid signature: 0x{:08X}, expected 0x{:08X}", request_header.signature, - mm_supv::REQUEST_SIGNATURE + SIGNATURE ))); } // Validate revision - if request_header.revision != mm_supv::REVISION { + if request_header.revision != REVISION { return Err(MmHandlerError::InvalidInput(format!( "Invalid revision: 0x{:08X}, expected 0x{:08X}", request_header.revision, - mm_supv::REVISION + REVISION ))); } // Process based on request type - match mm_supv::RequestType::try_from(request_header.request) { - Ok(mm_supv::RequestType::VersionInfo) => { + match RequestType::try_from(request_header.request) { + Ok(RequestType::VersionInfo) => { log::debug!(target: "supervisor_handler", "Processing get info request"); self.handle_get_info_request() } - Ok(mm_supv::RequestType::FetchPolicy) => { + Ok(RequestType::FetchPolicy) => { log::debug!(target: "supervisor_handler", "Processing fetch policy request"); self.handle_get_capabilities_request() } - Ok(mm_supv::RequestType::CommUpdate) => { + Ok(RequestType::CommUpdate) => { log::debug!(target: "supervisor_handler", "Processing comm update request"); self.handle_comm_update_request() } - Ok(mm_supv::RequestType::UnblockMem) => { + Ok(RequestType::UnblockMem) => { log::debug!(target: "supervisor_handler", "Processing unblock mem request"); self.handle_unblock_mem_request() } @@ -261,11 +262,11 @@ impl MmHandler for MmSupervisorHandler { // Return error response let error_header = MmSupervisorRequestHeader { - signature: mm_supv::REQUEST_SIGNATURE, - revision: mm_supv::REVISION, + signature: SIGNATURE, + revision: REVISION, request: request_header.request, reserved: 0, - result: 0xFFFFFFFFFFFFFFFF, // Error + result: ResponseType::InvalidRequest.into(), // Error }; let mut response = Vec::new(); diff --git a/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs b/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs index 7aa9c61e2..9e9b042cd 100644 --- a/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs +++ b/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs @@ -20,6 +20,7 @@ use patina::{ use patina_mm::{ component::{communicator::MmCommunicator, sw_mmi_manager::SwMmiManager}, config::{CommunicateBuffer, MmCommunicationConfiguration}, + protocol::mm_supervisor_request::{RequestType, ResponseType, SIGNATURE, REVISION}, }; use core::pin::Pin; @@ -156,9 +157,9 @@ fn test_real_component_mm_supervisor_version_request() { // Create MM Supervisor version request using the actual structures let version_request = MmSupervisorRequestHeader { - signature: mm_supv::SIGNATURE, - revision: mm_supv::REVISION, - request: mm_supv::RequestType::VersionInfo as u32, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::VersionInfo.into(), reserved: 0, result: 0, }; @@ -181,10 +182,10 @@ fn test_real_component_mm_supervisor_version_request() { MmSupervisorRequestHeader::from_bytes(&response).expect("Should parse response header from real component"); // Verify header fields - assert_eq!(response_header.signature, mm_supv::REQUEST_SIGNATURE, "Response signature should match"); - assert_eq!(response_header.revision, mm_supv::REVISION, "Response revision should match"); - assert_eq!(response_header.request, mm_supv::RequestType::VersionInfo as u32, "Response request type should match"); - assert_eq!(response_header.result, 0, "Response should indicate success"); + assert_eq!(response_header.signature, SIGNATURE, "Response signature should match"); + assert_eq!(response_header.revision, REVISION, "Response revision should match"); + assert_eq!(response_header.request, RequestType::VersionInfo.into(), "Response request type should match"); + assert_eq!(response_header.result, ResponseType::Success.into(), "Response should indicate success"); // Parse version info from response let version_info_offset = core::mem::size_of::(); @@ -201,7 +202,7 @@ fn test_real_component_mm_supervisor_version_request() { assert_eq!( version_info.max_supervisor_request_level, - mm_supv::MAX_REQUEST_LEVEL, + RequestType::MAX_REQUEST_TYPE, "Max request level should match expected value" ); } @@ -275,9 +276,9 @@ fn test_real_component_multiple_handlers() { // Test MM supervisor handler let supervisor_request = MmSupervisorRequestHeader { - signature: mm_supv::SIGNATURE, - revision: mm_supv::REVISION, - request: mm_supv::RequestType::FetchPolicy as u32, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::FetchPolicy.into(), reserved: 0, result: 0, }; diff --git a/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs b/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs index ca6027cc8..ab5f2c436 100644 --- a/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs +++ b/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs @@ -15,6 +15,7 @@ //! SPDX-License-Identifier: Apache-2.0 use crate::patina_mm_integration::common::*; +use patina_mm::protocol::mm_supervisor_request::{SIGNATURE, REVISION, RequestType, ResponseType}; #[test] fn test_mm_supervisor_version_request_integration() { @@ -25,9 +26,9 @@ fn test_mm_supervisor_version_request_integration() { // Create MM Supervisor version request using safe operations let version_request = MmSupervisorRequestHeader { - signature: mm_supv::SIGNATURE, - revision: mm_supv::REVISION, - request: mm_supv::RequestType::VersionInfo as u32, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::VersionInfo.into(), reserved: 0, result: 0, }; @@ -51,7 +52,7 @@ fn test_mm_supervisor_version_request_integration() { assert_eq!(response_header.signature, version_request.signature, "Signature should match"); assert_eq!(response_header.revision, version_request.revision, "Revision should match"); assert_eq!(response_header.request, version_request.request, "Request type should match"); - assert_eq!(response_header.result, mm_supv::responses::SUCCESS, "Result should be success"); + assert_eq!(response_header.result, ResponseType::Success.into(), "Result should be success"); // Parse version info safely let version_info_offset = core::mem::size_of::(); @@ -75,9 +76,9 @@ fn test_mm_supervisor_capabilities_request() { // Create capabilities request using safe operations let capabilities_request = MmSupervisorRequestHeader { - signature: mm_supv::SIGNATURE, - revision: mm_supv::REVISION, - request: mm_supv::RequestType::FetchPolicy as u32, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::FetchPolicy.into(), reserved: 0, result: 0, }; @@ -97,7 +98,7 @@ fn test_mm_supervisor_capabilities_request() { // Parse response header safely let response_header = MmSupervisorRequestHeader::from_bytes(&response).expect("Should parse response header"); - assert_eq!(response_header.result, mm_supv::responses::SUCCESS, "Capabilities request should succeed"); + assert_eq!(response_header.result, ResponseType::Success.into(), "Capabilities request should succeed"); // Parse capabilities safely let capabilities_offset = core::mem::size_of::(); @@ -124,8 +125,8 @@ fn test_mm_supervisor_invalid_request() { // Create invalid request using safe operations let invalid_request = MmSupervisorRequestHeader { - signature: mm_supv::SIGNATURE, - revision: mm_supv::REVISION, + signature: SIGNATURE, + revision: REVISION, request: 0xFFFF, // Invalid request type reserved: 0, result: 0, @@ -142,7 +143,7 @@ fn test_mm_supervisor_invalid_request() { // Parse response header safely let response_header = MmSupervisorRequestHeader::from_bytes(&response).expect("Should parse response header"); - assert_eq!(response_header.result, mm_supv::responses::ERROR, "Invalid request should return error"); + assert_eq!(response_header.result, ResponseType::InvalidRequest.into(), "Invalid request should return error"); } #[test] @@ -153,8 +154,8 @@ fn test_mm_supervisor_invalid_signature() { // Create request with invalid signature using safe operations let invalid_request = MmSupervisorRequestHeader { signature: u32::from_le_bytes([b'I', b'N', b'V', b'D']), // Invalid signature - revision: mm_supv::REVISION, - request: mm_supv::RequestType::VersionInfo as u32, + revision: REVISION, + request: RequestType::VersionInfo.into(), reserved: 0, result: 0, }; @@ -207,9 +208,9 @@ fn test_mm_supervisor_builder_integration() { // Test MM Supervisor handler as well let version_request = MmSupervisorRequestHeader { - signature: mm_supv::SIGNATURE, - revision: mm_supv::REVISION, - request: mm_supv::RequestType::VersionInfo as u32, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::VersionInfo.into(), reserved: 0, result: 0, }; @@ -229,9 +230,9 @@ fn test_safe_message_parsing_with_mm_supervisor() { let mut buffer = vec![0u8; TEST_BUFFER_SIZE]; let version_request = MmSupervisorRequestHeader { - signature: mm_supv::SIGNATURE, - revision: mm_supv::REVISION, - request: mm_supv::RequestType::VersionInfo as u32, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::VersionInfo.into(), reserved: 0, result: 0, }; @@ -267,9 +268,9 @@ fn test_mm_supervisor_comm_update_request() { // Create communication buffer update request using COMM_UPDATE constant let comm_update_request = MmSupervisorRequestHeader { - signature: mm_supv::SIGNATURE, - revision: mm_supv::REVISION, - request: mm_supv::RequestType::CommUpdate as u32, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::CommUpdate.into(), reserved: 0, result: 0, }; @@ -291,10 +292,10 @@ fn test_mm_supervisor_comm_update_request() { assert_eq!( response_header.request, - mm_supv::RequestType::CommUpdate as u32, + RequestType::CommUpdate.into(), "Response should be for COMM_UPDATE request" ); - assert_eq!(response_header.result, mm_supv::responses::SUCCESS, "Comm update request should succeed"); + assert_eq!(response_header.result, ResponseType::Success.into(), "Comm update request should succeed"); // Parse update result safely let update_result_offset = core::mem::size_of::(); @@ -319,9 +320,9 @@ fn test_mm_supervisor_unblock_mem_request() { // Create memory unblock request using UNBLOCK_MEM constant let unblock_mem_request = MmSupervisorRequestHeader { - signature: mm_supv::SIGNATURE, - revision: mm_supv::REVISION, - request: mm_supv::RequestType::UnblockMem as u32, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::UnblockMem.into(), reserved: 0, result: 0, }; @@ -343,10 +344,10 @@ fn test_mm_supervisor_unblock_mem_request() { assert_eq!( response_header.request, - mm_supv::RequestType::UnblockMem as u32, + RequestType::UnblockMem.into(), "Response should be for UNBLOCK_MEM request" ); - assert_eq!(response_header.result, mm_supv::responses::SUCCESS, "Unblock mem request should succeed"); + assert_eq!(response_header.result, ResponseType::Success.into(), "Unblock mem request should succeed"); // Parse unblock status safely let unblock_status_offset = core::mem::size_of::(); From 928afe7db399c48ffefa862225a2706c3013cf5e Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Thu, 19 Mar 2026 14:53:23 -0700 Subject: [PATCH 15/26] fix clippy --- components/patina_mm/src/protocol/mm_supervisor_request.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/patina_mm/src/protocol/mm_supervisor_request.rs b/components/patina_mm/src/protocol/mm_supervisor_request.rs index 782794bc3..8d11146b8 100644 --- a/components/patina_mm/src/protocol/mm_supervisor_request.rs +++ b/components/patina_mm/src/protocol/mm_supervisor_request.rs @@ -84,7 +84,7 @@ impl MmSupervisorRequestHeader { /// /// Returns `None` if the slice is too small or misaligned. pub fn from_bytes(bytes: &[u8]) -> Option { - Self::read_from_bytes(&bytes.get(..Self::SIZE)?).ok() + Self::read_from_bytes(bytes.get(..Self::SIZE)?).ok() } } @@ -128,7 +128,7 @@ impl MmSupervisorVersionInfo { /// /// Returns `None` if the slice is too small or misaligned. pub fn from_bytes(bytes: &[u8]) -> Option { - Self::read_from_bytes(&bytes.get(..Self::SIZE)?).ok() + Self::read_from_bytes(bytes.get(..Self::SIZE)?).ok() } } From 46732df7f746e0a9fc0fea70a6334ab0d7f43e7a Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Thu, 19 Mar 2026 14:53:59 -0700 Subject: [PATCH 16/26] fmt --- .../src/protocol/mm_supervisor_request.rs | 2 +- .../patina_mm_integration/common/constants.rs | 2 +- .../tests/patina_mm_integration/common/handlers.rs | 10 +++++----- .../mm_communicator/component_integration_tests.rs | 2 +- .../mm_supervisor/communication_tests.rs | 14 +++----------- 5 files changed, 11 insertions(+), 19 deletions(-) diff --git a/components/patina_mm/src/protocol/mm_supervisor_request.rs b/components/patina_mm/src/protocol/mm_supervisor_request.rs index 8d11146b8..2236dcb71 100644 --- a/components/patina_mm/src/protocol/mm_supervisor_request.rs +++ b/components/patina_mm/src/protocol/mm_supervisor_request.rs @@ -18,8 +18,8 @@ //! SPDX-License-Identifier: Apache-2.0 use patina::BinaryGuid; -use zerocopy::FromBytes; use r_efi::efi; +use zerocopy::FromBytes; /// The expected signature value ('MSUP' as little-endian u32). pub const SIGNATURE: u32 = 0x5055534D; diff --git a/components/patina_mm/tests/patina_mm_integration/common/constants.rs b/components/patina_mm/tests/patina_mm_integration/common/constants.rs index ab6729017..d9011a868 100644 --- a/components/patina_mm/tests/patina_mm_integration/common/constants.rs +++ b/components/patina_mm/tests/patina_mm_integration/common/constants.rs @@ -18,7 +18,7 @@ pub const TEST_BUFFER_SIZE: usize = SIZE_4KB; pub mod mm_supv { /// Mock supervisor version for testing pub const VERSION: u32 = 0x00130008; - + /// Mock supervisor patch level for testing pub const PATCH_LEVEL: u32 = 0x00010001; } diff --git a/components/patina_mm/tests/patina_mm_integration/common/handlers.rs b/components/patina_mm/tests/patina_mm_integration/common/handlers.rs index 0be8cdb83..00e32b816 100644 --- a/components/patina_mm/tests/patina_mm_integration/common/handlers.rs +++ b/components/patina_mm/tests/patina_mm_integration/common/handlers.rs @@ -24,7 +24,9 @@ use patina_mm::protocol::mm_supervisor_request::ResponseType; pub use zerocopy::IntoBytes; // Import shared protocol types from patina_mm -pub use patina_mm::protocol::mm_supervisor_request::{MmSupervisorRequestHeader, MmSupervisorVersionInfo, SIGNATURE, REVISION, RequestType}; +pub use patina_mm::protocol::mm_supervisor_request::{ + MmSupervisorRequestHeader, MmSupervisorVersionInfo, REVISION, RequestType, SIGNATURE, +}; /// Standardized error type for MM handlers #[derive(Debug, Clone, PartialEq, Eq)] @@ -225,8 +227,7 @@ impl MmHandler for MmSupervisorHandler { if request_header.signature != SIGNATURE { return Err(MmHandlerError::InvalidInput(format!( "Invalid signature: 0x{:08X}, expected 0x{:08X}", - request_header.signature, - SIGNATURE + request_header.signature, SIGNATURE ))); } @@ -234,8 +235,7 @@ impl MmHandler for MmSupervisorHandler { if request_header.revision != REVISION { return Err(MmHandlerError::InvalidInput(format!( "Invalid revision: 0x{:08X}, expected 0x{:08X}", - request_header.revision, - REVISION + request_header.revision, REVISION ))); } diff --git a/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs b/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs index 9e9b042cd..c36228970 100644 --- a/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs +++ b/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs @@ -20,7 +20,7 @@ use patina::{ use patina_mm::{ component::{communicator::MmCommunicator, sw_mmi_manager::SwMmiManager}, config::{CommunicateBuffer, MmCommunicationConfiguration}, - protocol::mm_supervisor_request::{RequestType, ResponseType, SIGNATURE, REVISION}, + protocol::mm_supervisor_request::{REVISION, RequestType, ResponseType, SIGNATURE}, }; use core::pin::Pin; diff --git a/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs b/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs index ab5f2c436..6bc345b3c 100644 --- a/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs +++ b/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs @@ -15,7 +15,7 @@ //! SPDX-License-Identifier: Apache-2.0 use crate::patina_mm_integration::common::*; -use patina_mm::protocol::mm_supervisor_request::{SIGNATURE, REVISION, RequestType, ResponseType}; +use patina_mm::protocol::mm_supervisor_request::{REVISION, RequestType, ResponseType, SIGNATURE}; #[test] fn test_mm_supervisor_version_request_integration() { @@ -290,11 +290,7 @@ fn test_mm_supervisor_comm_update_request() { // Parse response header safely let response_header = MmSupervisorRequestHeader::from_bytes(&response).expect("Should parse response header"); - assert_eq!( - response_header.request, - RequestType::CommUpdate.into(), - "Response should be for COMM_UPDATE request" - ); + assert_eq!(response_header.request, RequestType::CommUpdate.into(), "Response should be for COMM_UPDATE request"); assert_eq!(response_header.result, ResponseType::Success.into(), "Comm update request should succeed"); // Parse update result safely @@ -342,11 +338,7 @@ fn test_mm_supervisor_unblock_mem_request() { // Parse response header safely let response_header = MmSupervisorRequestHeader::from_bytes(&response).expect("Should parse response header"); - assert_eq!( - response_header.request, - RequestType::UnblockMem.into(), - "Response should be for UNBLOCK_MEM request" - ); + assert_eq!(response_header.request, RequestType::UnblockMem.into(), "Response should be for UNBLOCK_MEM request"); assert_eq!(response_header.result, ResponseType::Success.into(), "Unblock mem request should succeed"); // Parse unblock status safely From 3b80b7839e9e2891c46ff06d6e40b3b3c3e090fc Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Thu, 19 Mar 2026 16:57:38 -0700 Subject: [PATCH 17/26] removed response type into u64 because it is actually from this into efi status --- .../src/protocol/mm_supervisor_request.rs | 42 +++++-------------- .../patina_mm_integration/common/handlers.rs | 3 +- .../component_integration_tests.rs | 6 ++- .../mm_supervisor/communication_tests.rs | 17 +++++--- 4 files changed, 28 insertions(+), 40 deletions(-) diff --git a/components/patina_mm/src/protocol/mm_supervisor_request.rs b/components/patina_mm/src/protocol/mm_supervisor_request.rs index 2236dcb71..32393dd7d 100644 --- a/components/patina_mm/src/protocol/mm_supervisor_request.rs +++ b/components/patina_mm/src/protocol/mm_supervisor_request.rs @@ -44,7 +44,7 @@ pub const MM_SUPERVISOR_REQUEST_HANDLER_GUID: BinaryGuid = /// Offset Size Field /// 0x00 4 signature - Must be [`SIGNATURE`] ('MSUP' as little-endian u32) /// 0x04 4 revision - Protocol revision, must be <= [`REVISION`] -/// 0x08 4 request - Request type (see [`requests`] module) +/// 0x08 4 request - Request type (see [`RequestType`] enum) /// 0x0C 4 reserved - Reserved for alignment, must be 0 /// 0x10 8 result - Return status (0 = success, set by supervisor on response) /// ``` @@ -63,11 +63,11 @@ pub struct MmSupervisorRequestHeader { pub signature: u32, /// Revision of the request protocol. pub revision: u32, - /// The specific request type (see [`requests`] module constants). + /// The specific request type (see [`RequestType`] enum). pub request: u32, /// Reserved for alignment, must be 0. pub reserved: u32, - /// Result status. Set by the supervisor on response (0 = success). + /// Result status. The value of this field follows the [`efi::Status`] definitions. pub result: u64, } @@ -91,7 +91,7 @@ impl MmSupervisorRequestHeader { /// Response from MM Supervisor version info request. /// /// Returned as the payload following an [`MmSupervisorRequestHeader`] when the request -/// type is [`requests::VERSION_INFO`]. +/// type is [`RequestType::VersionInfo`]. /// /// ## Layout /// @@ -176,43 +176,23 @@ impl From for u32 { /// Standard MM Supervisor response types. /// -/// Each variant corresponds to a specific supervisor operation. +/// Each variant corresponds to a specific response status that the supervisor can return. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ResponseType { - /// Response to unblock memory regions request. - Success = 0x0000, /// Error: Invalid request index. - InvalidRequest = 0x0001, + InvalidRequest, /// Error: Invalid data buffer. - InvalidDataBuffer = 0x0002, + InvalidDataBuffer, /// Error: Communication buffer initialization failed. - CommBufferInitError = 0x0003, -} - -impl TryFrom for ResponseType { - type Error = u64; - - fn try_from(value: u64) -> Result { - match value { - 0x0000 => Ok(Self::Success), - 0x0001 => Ok(Self::InvalidRequest), - 0x0002 => Ok(Self::InvalidDataBuffer), - 0x0003 => Ok(Self::CommBufferInitError), - other => Err(other), - } - } -} - -impl From for u64 { - fn from(response_type: ResponseType) -> Self { - response_type as u64 - } + CommBufferInitError, } +/// Maps `ResponseType` variants to corresponding [`efi::Status`] codes, because this is how +/// the supervisor request handlers map the [`MmSupervisorRequestHeader::result`] field in the +/// response header. impl From for efi::Status { fn from(response_type: ResponseType) -> Self { match response_type { - ResponseType::Success => efi::Status::SUCCESS, ResponseType::InvalidRequest => efi::Status::INVALID_PARAMETER, ResponseType::InvalidDataBuffer => efi::Status::BUFFER_TOO_SMALL, ResponseType::CommBufferInitError => efi::Status::DEVICE_ERROR, diff --git a/components/patina_mm/tests/patina_mm_integration/common/handlers.rs b/components/patina_mm/tests/patina_mm_integration/common/handlers.rs index 00e32b816..9192f3092 100644 --- a/components/patina_mm/tests/patina_mm_integration/common/handlers.rs +++ b/components/patina_mm/tests/patina_mm_integration/common/handlers.rs @@ -17,6 +17,7 @@ //! SPDX-License-Identifier: Apache-2.0 use crate::patina_mm_integration::common::constants::*; +use r_efi::efi; extern crate alloc; use alloc::{string::String, vec::Vec}; @@ -266,7 +267,7 @@ impl MmHandler for MmSupervisorHandler { revision: REVISION, request: request_header.request, reserved: 0, - result: ResponseType::InvalidRequest.into(), // Error + result: efi::Status::from(ResponseType::InvalidRequest).as_usize() as u64, // Error }; let mut response = Vec::new(); diff --git a/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs b/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs index c36228970..3d01d7c0b 100644 --- a/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs +++ b/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs @@ -20,11 +20,13 @@ use patina::{ use patina_mm::{ component::{communicator::MmCommunicator, sw_mmi_manager::SwMmiManager}, config::{CommunicateBuffer, MmCommunicationConfiguration}, - protocol::mm_supervisor_request::{REVISION, RequestType, ResponseType, SIGNATURE}, + protocol::mm_supervisor_request::{REVISION, RequestType, SIGNATURE}, }; use core::pin::Pin; +use r_efi::efi; + use crate::patina_mm_integration::common::*; #[test] @@ -185,7 +187,7 @@ fn test_real_component_mm_supervisor_version_request() { assert_eq!(response_header.signature, SIGNATURE, "Response signature should match"); assert_eq!(response_header.revision, REVISION, "Response revision should match"); assert_eq!(response_header.request, RequestType::VersionInfo.into(), "Response request type should match"); - assert_eq!(response_header.result, ResponseType::Success.into(), "Response should indicate success"); + assert_eq!(response_header.result, efi::Status::SUCCESS.as_usize() as u64, "Response should indicate success"); // Parse version info from response let version_info_offset = core::mem::size_of::(); diff --git a/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs b/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs index 6bc345b3c..aa6105a4c 100644 --- a/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs +++ b/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs @@ -15,7 +15,8 @@ //! SPDX-License-Identifier: Apache-2.0 use crate::patina_mm_integration::common::*; -use patina_mm::protocol::mm_supervisor_request::{REVISION, RequestType, ResponseType, SIGNATURE}; +use patina_mm::protocol::mm_supervisor_request::{REVISION, RequestType, SIGNATURE}; +use r_efi::efi; #[test] fn test_mm_supervisor_version_request_integration() { @@ -52,7 +53,7 @@ fn test_mm_supervisor_version_request_integration() { assert_eq!(response_header.signature, version_request.signature, "Signature should match"); assert_eq!(response_header.revision, version_request.revision, "Revision should match"); assert_eq!(response_header.request, version_request.request, "Request type should match"); - assert_eq!(response_header.result, ResponseType::Success.into(), "Result should be success"); + assert_eq!(response_header.result, efi::Status::SUCCESS.as_usize() as u64, "Result should be success"); // Parse version info safely let version_info_offset = core::mem::size_of::(); @@ -98,7 +99,7 @@ fn test_mm_supervisor_capabilities_request() { // Parse response header safely let response_header = MmSupervisorRequestHeader::from_bytes(&response).expect("Should parse response header"); - assert_eq!(response_header.result, ResponseType::Success.into(), "Capabilities request should succeed"); + assert_eq!(response_header.result, efi::Status::SUCCESS.as_usize() as u64, "Capabilities request should succeed"); // Parse capabilities safely let capabilities_offset = core::mem::size_of::(); @@ -143,7 +144,11 @@ fn test_mm_supervisor_invalid_request() { // Parse response header safely let response_header = MmSupervisorRequestHeader::from_bytes(&response).expect("Should parse response header"); - assert_eq!(response_header.result, ResponseType::InvalidRequest.into(), "Invalid request should return error"); + assert_eq!( + response_header.result, + efi::Status::INVALID_PARAMETER.as_usize() as u64, + "Invalid request should return error" + ); } #[test] @@ -291,7 +296,7 @@ fn test_mm_supervisor_comm_update_request() { let response_header = MmSupervisorRequestHeader::from_bytes(&response).expect("Should parse response header"); assert_eq!(response_header.request, RequestType::CommUpdate.into(), "Response should be for COMM_UPDATE request"); - assert_eq!(response_header.result, ResponseType::Success.into(), "Comm update request should succeed"); + assert_eq!(response_header.result, efi::Status::SUCCESS.as_usize() as u64, "Comm update request should succeed"); // Parse update result safely let update_result_offset = core::mem::size_of::(); @@ -339,7 +344,7 @@ fn test_mm_supervisor_unblock_mem_request() { let response_header = MmSupervisorRequestHeader::from_bytes(&response).expect("Should parse response header"); assert_eq!(response_header.request, RequestType::UnblockMem.into(), "Response should be for UNBLOCK_MEM request"); - assert_eq!(response_header.result, ResponseType::Success.into(), "Unblock mem request should succeed"); + assert_eq!(response_header.result, efi::Status::SUCCESS.as_usize() as u64, "Unblock mem request should succeed"); // Parse unblock status safely let unblock_status_offset = core::mem::size_of::(); From c4d6e4a76e117a99ed2cff07dbf51792e6f72890 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Thu, 19 Mar 2026 17:02:45 -0700 Subject: [PATCH 18/26] fix the size --- components/patina_mm/src/protocol/mm_supervisor_request.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/patina_mm/src/protocol/mm_supervisor_request.rs b/components/patina_mm/src/protocol/mm_supervisor_request.rs index 32393dd7d..24818ccf7 100644 --- a/components/patina_mm/src/protocol/mm_supervisor_request.rs +++ b/components/patina_mm/src/protocol/mm_supervisor_request.rs @@ -224,6 +224,6 @@ pub struct MmSupervisorUnblockMemoryParams { } impl MmSupervisorUnblockMemoryParams { - /// Size of this structure in bytes (56). + /// Size of this structure in bytes. pub const SIZE: usize = core::mem::size_of::(); } From 0176f549f941b1cb8fc62467a02606cfb8d35599 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Thu, 19 Mar 2026 17:08:26 -0700 Subject: [PATCH 19/26] signature fix --- components/patina_mm/src/protocol/mm_supervisor_request.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/patina_mm/src/protocol/mm_supervisor_request.rs b/components/patina_mm/src/protocol/mm_supervisor_request.rs index 24818ccf7..e284b7fac 100644 --- a/components/patina_mm/src/protocol/mm_supervisor_request.rs +++ b/components/patina_mm/src/protocol/mm_supervisor_request.rs @@ -21,8 +21,8 @@ use patina::BinaryGuid; use r_efi::efi; use zerocopy::FromBytes; -/// The expected signature value ('MSUP' as little-endian u32). -pub const SIGNATURE: u32 = 0x5055534D; +/// Signature value for the request header ('MSUP' as little-endian u32). +pub const SIGNATURE: u32 = u32::from_le_bytes([b'M', b'S', b'U', b'P']); /// Current revision of the request protocol. pub const REVISION: u32 = 1; From 2f1591d508748ada2316bad16951bd82ef931de9 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Thu, 19 Mar 2026 17:29:28 -0700 Subject: [PATCH 20/26] do not need known layout --- components/patina_mm/src/protocol/mm_supervisor_request.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/patina_mm/src/protocol/mm_supervisor_request.rs b/components/patina_mm/src/protocol/mm_supervisor_request.rs index e284b7fac..87f197d04 100644 --- a/components/patina_mm/src/protocol/mm_supervisor_request.rs +++ b/components/patina_mm/src/protocol/mm_supervisor_request.rs @@ -54,8 +54,7 @@ pub const MM_SUPERVISOR_REQUEST_HANDLER_GUID: BinaryGuid = Copy, zerocopy_derive::FromBytes, zerocopy_derive::IntoBytes, - zerocopy_derive::Immutable, - zerocopy_derive::KnownLayout + zerocopy_derive::Immutable )] #[repr(C)] pub struct MmSupervisorRequestHeader { From e15682fab353d349a8deebf22b98ecb2fce3f202 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Thu, 19 Mar 2026 17:32:05 -0700 Subject: [PATCH 21/26] fmt... --- .../patina_mm/src/protocol/mm_supervisor_request.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/components/patina_mm/src/protocol/mm_supervisor_request.rs b/components/patina_mm/src/protocol/mm_supervisor_request.rs index 87f197d04..c8d7bf242 100644 --- a/components/patina_mm/src/protocol/mm_supervisor_request.rs +++ b/components/patina_mm/src/protocol/mm_supervisor_request.rs @@ -48,14 +48,7 @@ pub const MM_SUPERVISOR_REQUEST_HANDLER_GUID: BinaryGuid = /// 0x0C 4 reserved - Reserved for alignment, must be 0 /// 0x10 8 result - Return status (0 = success, set by supervisor on response) /// ``` -#[derive( - Debug, - Clone, - Copy, - zerocopy_derive::FromBytes, - zerocopy_derive::IntoBytes, - zerocopy_derive::Immutable -)] +#[derive(Debug, Clone, Copy, zerocopy_derive::FromBytes, zerocopy_derive::IntoBytes, zerocopy_derive::Immutable)] #[repr(C)] pub struct MmSupervisorRequestHeader { /// Signature to identify the request ('MSUP' as little-endian). From a8667111ae546c5cd2259ebe0fe8333902c35c17 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Fri, 20 Mar 2026 11:14:01 -0700 Subject: [PATCH 22/26] fmt again --- components/patina_mm/src/lib.rs | 7 ------- sdk/patina/src/lib.rs | 1 + sdk/patina/src/management_mode.rs | 18 ++++++++++++++++++ .../src/management_mode}/comm_buffer_hob.rs | 0 .../patina/src/management_mode}/protocol.rs | 0 .../protocol/mm_comm_buffer_update.rs | 0 .../protocol/mm_supervisor_request.rs | 0 7 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 sdk/patina/src/management_mode.rs rename {components/patina_mm/src => sdk/patina/src/management_mode}/comm_buffer_hob.rs (100%) rename {components/patina_mm/src => sdk/patina/src/management_mode}/protocol.rs (100%) rename {components/patina_mm/src => sdk/patina/src/management_mode}/protocol/mm_comm_buffer_update.rs (100%) rename {components/patina_mm/src => sdk/patina/src/management_mode}/protocol/mm_supervisor_request.rs (100%) diff --git a/components/patina_mm/src/lib.rs b/components/patina_mm/src/lib.rs index c42cc9e21..e90a80f09 100644 --- a/components/patina_mm/src/lib.rs +++ b/components/patina_mm/src/lib.rs @@ -6,15 +6,8 @@ #![cfg_attr(all(not(feature = "std"), not(test), not(feature = "mockall")), no_std)] #![feature(coverage_attribute)] -#[cfg(any(test, feature = "alloc"))] extern crate alloc; -#[cfg(any(test, feature = "alloc"))] pub mod component; -#[cfg(any(test, feature = "alloc"))] pub mod config; -#[cfg(any(test, feature = "alloc"))] pub mod service; - -pub mod comm_buffer_hob; -pub mod protocol; diff --git a/sdk/patina/src/lib.rs b/sdk/patina/src/lib.rs index 52c6e85c0..9d9235efc 100644 --- a/sdk/patina/src/lib.rs +++ b/sdk/patina/src/lib.rs @@ -49,6 +49,7 @@ pub mod error; pub mod guids; pub mod hash; pub mod log; +pub mod management_mode; #[cfg(any(test, feature = "alloc"))] pub mod performance; pub mod pi; diff --git a/sdk/patina/src/management_mode.rs b/sdk/patina/src/management_mode.rs new file mode 100644 index 000000000..120dd30a8 --- /dev/null +++ b/sdk/patina/src/management_mode.rs @@ -0,0 +1,18 @@ +//! Management Mode (MM) SDK for Patina +//! +//! This crate provides the Management Mode (MM) related definitions for Patina. +//! +//! ## Features +//! +//! - `comm_buffer_hob`: Provides data and HOB definitions to support the MM communication. +//! - `protocol`: Contains MM-related protocol structures and definitions. +//! +//! ## License +//! +//! Copyright (C) Microsoft Corporation. +//! +//! SPDX-License-Identifier: Apache-2.0 +//! + +pub mod comm_buffer_hob; +pub mod protocol; diff --git a/components/patina_mm/src/comm_buffer_hob.rs b/sdk/patina/src/management_mode/comm_buffer_hob.rs similarity index 100% rename from components/patina_mm/src/comm_buffer_hob.rs rename to sdk/patina/src/management_mode/comm_buffer_hob.rs diff --git a/components/patina_mm/src/protocol.rs b/sdk/patina/src/management_mode/protocol.rs similarity index 100% rename from components/patina_mm/src/protocol.rs rename to sdk/patina/src/management_mode/protocol.rs diff --git a/components/patina_mm/src/protocol/mm_comm_buffer_update.rs b/sdk/patina/src/management_mode/protocol/mm_comm_buffer_update.rs similarity index 100% rename from components/patina_mm/src/protocol/mm_comm_buffer_update.rs rename to sdk/patina/src/management_mode/protocol/mm_comm_buffer_update.rs diff --git a/components/patina_mm/src/protocol/mm_supervisor_request.rs b/sdk/patina/src/management_mode/protocol/mm_supervisor_request.rs similarity index 100% rename from components/patina_mm/src/protocol/mm_supervisor_request.rs rename to sdk/patina/src/management_mode/protocol/mm_supervisor_request.rs From aba5443984a5dc55cdfb74e5734e7a3bf52a1313 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Fri, 20 Mar 2026 14:32:22 -0700 Subject: [PATCH 23/26] moved definitions into patina --- components/patina_mm/src/component/communicator.rs | 4 ++-- .../src/component/communicator/comm_buffer_update.rs | 7 ++----- components/patina_mm/src/config.rs | 2 +- components/patina_mm/tests/patina_mm_integration.rs | 1 - .../tests/patina_mm_integration/common/handlers.rs | 5 ++--- .../framework/core_functionality_tests.rs | 3 +-- .../mm_communicator/component_integration_tests.rs | 2 +- .../mm_supervisor/communication_tests.rs | 2 +- sdk/patina/src/management_mode.rs | 3 +++ sdk/patina/src/management_mode/comm_buffer_hob.rs | 4 ++-- .../src/management_mode/protocol/mm_comm_buffer_update.rs | 2 +- .../src/management_mode/protocol/mm_supervisor_request.rs | 2 +- 12 files changed, 17 insertions(+), 20 deletions(-) diff --git a/components/patina_mm/src/component/communicator.rs b/components/patina_mm/src/component/communicator.rs index 554e47612..9496fe2a9 100644 --- a/components/patina_mm/src/component/communicator.rs +++ b/components/patina_mm/src/component/communicator.rs @@ -16,7 +16,6 @@ mod comm_buffer_update; use crate::{ - comm_buffer_hob::EfiMmCommunicateHeader, config::{CommunicateBuffer, MmCommunicationConfiguration}, service::SwMmiTrigger, }; @@ -27,6 +26,7 @@ use patina::{ Storage, component, service::{IntoService, Service}, }, + management_mode::EfiMmCommunicateHeader, }; use alloc::{boxed::Box, vec::Vec}; @@ -370,7 +370,6 @@ impl Default for MmCommunicator { mod tests { use super::*; use crate::{ - comm_buffer_hob::MmCommBufferStatus, component::{ communicator::{MmCommunicator, MockMmExecutor}, sw_mmi_manager::SwMmiManager, @@ -378,6 +377,7 @@ mod tests { config::{CommunicateBuffer, MmCommunicationConfiguration}, }; use patina::component::{IntoComponent, Storage}; + use patina::management_mode::MmCommBufferStatus; use core::{cell::RefCell, pin::Pin}; diff --git a/components/patina_mm/src/component/communicator/comm_buffer_update.rs b/components/patina_mm/src/component/communicator/comm_buffer_update.rs index f771c53e0..c64a2c559 100644 --- a/components/patina_mm/src/component/communicator/comm_buffer_update.rs +++ b/components/patina_mm/src/component/communicator/comm_buffer_update.rs @@ -10,14 +10,11 @@ //! //! SPDX-License-Identifier: Apache-2.0 -use crate::{ - component::communicator::MmCommunicator, - config::CommunicateBuffer, - protocol::mm_comm_buffer_update::{self, MmCommBufferUpdateProtocol}, -}; +use crate::{component::communicator::MmCommunicator, config::CommunicateBuffer}; use patina::{ base::UEFI_PAGE_SIZE, boot_services::{BootServices, StandardBootServices, event::EventType, tpl::Tpl}, + management_mode::protocol::mm_comm_buffer_update::{self, MmCommBufferUpdateProtocol}, }; use zerocopy::FromBytes; diff --git a/components/patina_mm/src/config.rs b/components/patina_mm/src/config.rs index 9a360b7d4..2610c5c3f 100644 --- a/components/patina_mm/src/config.rs +++ b/components/patina_mm/src/config.rs @@ -21,7 +21,7 @@ use alloc::vec::Vec; use core::{fmt, pin::Pin, ptr::NonNull}; -use crate::comm_buffer_hob::{EfiMmCommunicateHeader, MmCommBufferStatus}; +use patina::management_mode::{EfiMmCommunicateHeader, MmCommBufferStatus}; use patina::{BinaryGuid, Guid, base::UEFI_PAGE_MASK}; /// Management Mode (MM) Configuration diff --git a/components/patina_mm/tests/patina_mm_integration.rs b/components/patina_mm/tests/patina_mm_integration.rs index 2c79ea31e..a280aa414 100644 --- a/components/patina_mm/tests/patina_mm_integration.rs +++ b/components/patina_mm/tests/patina_mm_integration.rs @@ -9,6 +9,5 @@ //! //! SPDX-License-Identifier: Apache-2.0 -#[cfg(any(test, feature = "alloc"))] #[path = "patina_mm_integration/mod.rs"] mod patina_mm_integration; diff --git a/components/patina_mm/tests/patina_mm_integration/common/handlers.rs b/components/patina_mm/tests/patina_mm_integration/common/handlers.rs index 9192f3092..ea21b709a 100644 --- a/components/patina_mm/tests/patina_mm_integration/common/handlers.rs +++ b/components/patina_mm/tests/patina_mm_integration/common/handlers.rs @@ -21,12 +21,11 @@ use r_efi::efi; extern crate alloc; use alloc::{string::String, vec::Vec}; -use patina_mm::protocol::mm_supervisor_request::ResponseType; pub use zerocopy::IntoBytes; // Import shared protocol types from patina_mm -pub use patina_mm::protocol::mm_supervisor_request::{ - MmSupervisorRequestHeader, MmSupervisorVersionInfo, REVISION, RequestType, SIGNATURE, +pub use patina::management_mode::protocol::mm_supervisor_request::{ + MmSupervisorRequestHeader, MmSupervisorVersionInfo, REVISION, RequestType, ResponseType, SIGNATURE, }; /// Standardized error type for MM handlers diff --git a/components/patina_mm/tests/patina_mm_integration/framework/core_functionality_tests.rs b/components/patina_mm/tests/patina_mm_integration/framework/core_functionality_tests.rs index 8d1ac5c41..5dc169895 100644 --- a/components/patina_mm/tests/patina_mm_integration/framework/core_functionality_tests.rs +++ b/components/patina_mm/tests/patina_mm_integration/framework/core_functionality_tests.rs @@ -9,9 +9,8 @@ //! //! SPDX-License-Identifier: Apache-2.0 -use patina::{BinaryGuid, Guid}; +use patina::{BinaryGuid, Guid, management_mode::EfiMmCommunicateHeader}; use patina_mm::{ - comm_buffer_hob::EfiMmCommunicateHeader, component::communicator::{MmCommunication, MmCommunicator, MmExecutor, Status}, config::CommunicateBuffer, }; diff --git a/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs b/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs index 3d01d7c0b..549ee293f 100644 --- a/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs +++ b/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs @@ -16,11 +16,11 @@ use patina::{ Guid, component::{IntoComponent, Storage}, + management_mode::protocol::mm_supervisor_request::{REVISION, RequestType, SIGNATURE}, }; use patina_mm::{ component::{communicator::MmCommunicator, sw_mmi_manager::SwMmiManager}, config::{CommunicateBuffer, MmCommunicationConfiguration}, - protocol::mm_supervisor_request::{REVISION, RequestType, SIGNATURE}, }; use core::pin::Pin; diff --git a/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs b/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs index aa6105a4c..2cc2b4ee8 100644 --- a/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs +++ b/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs @@ -15,7 +15,7 @@ //! SPDX-License-Identifier: Apache-2.0 use crate::patina_mm_integration::common::*; -use patina_mm::protocol::mm_supervisor_request::{REVISION, RequestType, SIGNATURE}; +use patina::management_mode::protocol::mm_supervisor_request::{REVISION, RequestType, SIGNATURE}; use r_efi::efi; #[test] diff --git a/sdk/patina/src/management_mode.rs b/sdk/patina/src/management_mode.rs index 120dd30a8..deacb45c8 100644 --- a/sdk/patina/src/management_mode.rs +++ b/sdk/patina/src/management_mode.rs @@ -16,3 +16,6 @@ pub mod comm_buffer_hob; pub mod protocol; + +// Re-export commonly used items for easier access +pub use comm_buffer_hob::{EfiMmCommunicateHeader, MmCommBufferStatus}; diff --git a/sdk/patina/src/management_mode/comm_buffer_hob.rs b/sdk/patina/src/management_mode/comm_buffer_hob.rs index 09088e2bd..905a13535 100644 --- a/sdk/patina/src/management_mode/comm_buffer_hob.rs +++ b/sdk/patina/src/management_mode/comm_buffer_hob.rs @@ -19,7 +19,7 @@ //! SPDX-License-Identifier: Apache-2.0 //! -use patina::{BinaryGuid, Guid}; +use crate::{BinaryGuid, Guid}; use zerocopy_derive::{FromBytes, Immutable, KnownLayout}; /// GUID for the MM communication buffer HOB (`gMmCommBufferHobGuid`). @@ -92,7 +92,7 @@ impl MmCommBufferStatus { pub struct EfiMmCommunicateHeader { /// Allows for disambiguation of the message format. /// Used to identify the registered MM handlers that should be given the message. - header_guid: patina::BinaryGuid, + header_guid: BinaryGuid, /// The size of Data (in bytes) and does not include the size of the header. message_length: usize, } diff --git a/sdk/patina/src/management_mode/protocol/mm_comm_buffer_update.rs b/sdk/patina/src/management_mode/protocol/mm_comm_buffer_update.rs index 4e8ce0ea1..609669c70 100644 --- a/sdk/patina/src/management_mode/protocol/mm_comm_buffer_update.rs +++ b/sdk/patina/src/management_mode/protocol/mm_comm_buffer_update.rs @@ -10,7 +10,7 @@ //! SPDX-License-Identifier: Apache-2.0 //! -use patina::BinaryGuid; +use crate::BinaryGuid; use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout}; /// GUID for the MM Communication Buffer Update Protocol diff --git a/sdk/patina/src/management_mode/protocol/mm_supervisor_request.rs b/sdk/patina/src/management_mode/protocol/mm_supervisor_request.rs index c8d7bf242..443495cf3 100644 --- a/sdk/patina/src/management_mode/protocol/mm_supervisor_request.rs +++ b/sdk/patina/src/management_mode/protocol/mm_supervisor_request.rs @@ -17,7 +17,7 @@ //! //! SPDX-License-Identifier: Apache-2.0 -use patina::BinaryGuid; +use crate::BinaryGuid; use r_efi::efi; use zerocopy::FromBytes; From b279163c974e9cf4a479717dffc8b351c78aa1b4 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Fri, 20 Mar 2026 14:36:15 -0700 Subject: [PATCH 24/26] remove some junk --- components/patina_mm/Cargo.toml | 7 +++---- components/patina_performance/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/components/patina_mm/Cargo.toml b/components/patina_mm/Cargo.toml index 9c74fe9a3..a69d1da55 100644 --- a/components/patina_mm/Cargo.toml +++ b/components/patina_mm/Cargo.toml @@ -23,7 +23,7 @@ zerocopy-derive = { workspace = true } env_logger = { workspace = true } mockall = { workspace = true } patina = { workspace = true, features = ["mockall"] } -patina_dxe_core = { path = "../../patina_dxe_core" } +patina_dxe_core = { path = "../../patina_dxe_core"} [target.'cfg(target_arch="x86_64")'.dependencies] x86_64 = { workspace = true, features = [ @@ -31,7 +31,6 @@ x86_64 = { workspace = true, features = [ ] } [features] -doc = ['alloc'] +doc = [] mockall = ["dep:mockall", "std"] -std = ['alloc'] -alloc = [] +std = [] diff --git a/components/patina_performance/Cargo.toml b/components/patina_performance/Cargo.toml index 40479ea07..73f113f2e 100644 --- a/components/patina_performance/Cargo.toml +++ b/components/patina_performance/Cargo.toml @@ -17,7 +17,7 @@ uuid = { workspace = true } mu_rust_helpers = { workspace = true } patina = { workspace = true } -patina_mm = { workspace = true, features = ["alloc"] } +patina_mm = { workspace = true } zerocopy = { workspace = true } zerocopy-derive = { workspace = true } From dcc0415e50f5314e5fff5a11b14fbbccc8c38f45 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Fri, 20 Mar 2026 14:40:05 -0700 Subject: [PATCH 25/26] fmt? --- components/patina_mm/src/component/communicator.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/patina_mm/src/component/communicator.rs b/components/patina_mm/src/component/communicator.rs index 9496fe2a9..1768f604f 100644 --- a/components/patina_mm/src/component/communicator.rs +++ b/components/patina_mm/src/component/communicator.rs @@ -376,8 +376,10 @@ mod tests { }, config::{CommunicateBuffer, MmCommunicationConfiguration}, }; - use patina::component::{IntoComponent, Storage}; - use patina::management_mode::MmCommBufferStatus; + use patina::{ + component::{IntoComponent, Storage}, + management_mode::MmCommBufferStatus, + }; use core::{cell::RefCell, pin::Pin}; From bca160e54ef60847fbb7d8959792093dfdd59515 Mon Sep 17 00:00:00 2001 From: Kun Qin Date: Fri, 20 Mar 2026 14:40:47 -0700 Subject: [PATCH 26/26] fmt? --- components/patina_mm/src/config.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/components/patina_mm/src/config.rs b/components/patina_mm/src/config.rs index 2610c5c3f..144329e76 100644 --- a/components/patina_mm/src/config.rs +++ b/components/patina_mm/src/config.rs @@ -21,8 +21,11 @@ use alloc::vec::Vec; use core::{fmt, pin::Pin, ptr::NonNull}; -use patina::management_mode::{EfiMmCommunicateHeader, MmCommBufferStatus}; -use patina::{BinaryGuid, Guid, base::UEFI_PAGE_MASK}; +use patina::{ + BinaryGuid, Guid, + base::UEFI_PAGE_MASK, + management_mode::{EfiMmCommunicateHeader, MmCommBufferStatus}, +}; /// Management Mode (MM) Configuration ///