diff --git a/components/patina_mm/src/component/communicator.rs b/components/patina_mm/src/component/communicator.rs index e6f7646e8..1768f604f 100644 --- a/components/patina_mm/src/component/communicator.rs +++ b/components/patina_mm/src/component/communicator.rs @@ -16,7 +16,7 @@ mod comm_buffer_update; use crate::{ - config::{CommunicateBuffer, EfiMmCommunicateHeader, MmCommunicationConfiguration}, + config::{CommunicateBuffer, MmCommunicationConfiguration}, service::SwMmiTrigger, }; use patina::{ @@ -26,8 +26,9 @@ use patina::{ Storage, component, service::{IntoService, Service}, }, + management_mode::EfiMmCommunicateHeader, }; -extern crate alloc; + use alloc::{boxed::Box, vec::Vec}; use core::{ @@ -373,14 +374,16 @@ mod tests { communicator::{MmCommunicator, MockMmExecutor}, sw_mmi_manager::SwMmiManager, }, - config::{CommunicateBuffer, MmCommBufferStatus, MmCommunicationConfiguration}, + config::{CommunicateBuffer, MmCommunicationConfiguration}, + }; + use patina::{ + component::{IntoComponent, Storage}, + management_mode::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..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,20 +10,16 @@ //! //! 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; 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 +285,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 958dbf420..144329e76 100644 --- a/components/patina_mm/src/config.rs +++ b/components/patina_mm/src/config.rs @@ -18,51 +18,14 @@ //! //! SPDX-License-Identifier: Apache-2.0 //! -extern crate alloc; 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 patina::{ + BinaryGuid, Guid, + base::UEFI_PAGE_MASK, + management_mode::{EfiMmCommunicateHeader, MmCommBufferStatus}, +}; /// Management Mode (MM) Configuration /// @@ -119,70 +82,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..e90a80f09 100644 --- a/components/patina_mm/src/lib.rs +++ b/components/patina_mm/src/lib.rs @@ -6,7 +6,8 @@ #![cfg_attr(all(not(feature = "std"), not(test), not(feature = "mockall")), no_std)] #![feature(coverage_attribute)] +extern crate alloc; + pub mod component; pub mod config; -pub mod protocol; pub mod service; 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..d9011a868 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,16 @@ 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. pub mod mm_supv { - /// Supervisor signature bytes - pub const SIGNATURE: [u8; 4] = [b'M', b'S', b'U', b'P']; - - /// Communication protocol revision - pub const REVISION: u32 = 1; - - /// 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 - 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..ea21b709a 100644 --- a/components/patina_mm/tests/patina_mm_integration/common/handlers.rs +++ b/components/patina_mm/tests/patina_mm_integration/common/handlers.rs @@ -17,11 +17,16 @@ //! 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}; -use zerocopy::{FromBytes, IntoBytes}; -use zerocopy_derive::*; +pub use zerocopy::IntoBytes; + +// Import shared protocol types from patina_mm +pub use patina::management_mode::protocol::mm_supervisor_request::{ + MmSupervisorRequestHeader, MmSupervisorVersionInfo, REVISION, RequestType, ResponseType, SIGNATURE, +}; /// 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 @@ -180,9 +127,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::requests::VERSION_INFO, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::VersionInfo as u32, reserved: 0, result: 0, // Success }; @@ -190,12 +137,12 @@ 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(); - 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) @@ -203,9 +150,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::requests::FETCH_POLICY, + signature: SIGNATURE, + revision: REVISION, + request: 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()); @@ -222,9 +169,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::requests::COMM_UPDATE, + signature: SIGNATURE, + revision: REVISION, + request: 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()); @@ -242,9 +189,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::requests::UNBLOCK_MEM, + signature: SIGNATURE, + revision: REVISION, + request: 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,58 +220,57 @@ 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 { + if request_header.signature != SIGNATURE { return Err(MmHandlerError::InvalidInput(format!( "Invalid signature: 0x{:08X}, expected 0x{:08X}", - request_header.signature, - mm_supv::REQUEST_SIGNATURE + request_header.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 + request_header.revision, REVISION ))); } // Process based on request type - match request_header.request { - mm_supv::requests::VERSION_INFO => { + match RequestType::try_from(request_header.request) { + Ok(RequestType::VersionInfo) => { log::debug!(target: "supervisor_handler", "Processing get info request"); self.handle_get_info_request() } - mm_supv::requests::FETCH_POLICY => { + Ok(RequestType::FetchPolicy) => { log::debug!(target: "supervisor_handler", "Processing fetch policy request"); self.handle_get_capabilities_request() } - mm_supv::requests::COMM_UPDATE => { + Ok(RequestType::CommUpdate) => { log::debug!(target: "supervisor_handler", "Processing comm update request"); self.handle_comm_update_request() } - mm_supv::requests::UNBLOCK_MEM => { + Ok(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 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: efi::Status::from(ResponseType::InvalidRequest).as_usize() as u64, // Error }; 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 +428,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/framework/core_functionality_tests.rs b/components/patina_mm/tests/patina_mm_integration/framework/core_functionality_tests.rs index 27336ddf5..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,17 +9,16 @@ //! //! SPDX-License-Identifier: Apache-2.0 -use patina::{BinaryGuid, Guid}; +use patina::{BinaryGuid, Guid, management_mode::EfiMmCommunicateHeader}; use patina_mm::{ component::communicator::{MmCommunication, MmCommunicator, MmExecutor, Status}, - config::{CommunicateBuffer, EfiMmCommunicateHeader}, + config::CommunicateBuffer, }; 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/component_integration_tests.rs b/components/patina_mm/tests/patina_mm_integration/mm_communicator/component_integration_tests.rs index e175f7b91..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,6 +16,7 @@ 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}, @@ -24,6 +25,8 @@ use patina_mm::{ use core::pin::Pin; +use r_efi::efi; + use crate::patina_mm_integration::common::*; #[test] @@ -156,14 +159,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), - revision: mm_supv::REVISION, - request: mm_supv::requests::VERSION_INFO, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::VersionInfo.into(), 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); @@ -181,10 +184,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::requests::VERSION_INFO, "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, efi::Status::SUCCESS.as_usize() as u64, "Response should indicate success"); // Parse version info from response let version_info_offset = core::mem::size_of::(); @@ -201,7 +204,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,15 +278,15 @@ fn test_real_component_multiple_handlers() { // Test MM supervisor handler let supervisor_request = MmSupervisorRequestHeader { - signature: u32::from_le_bytes(mm_supv::SIGNATURE), - revision: mm_supv::REVISION, - request: mm_supv::requests::FETCH_POLICY, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::FetchPolicy.into(), 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()); 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_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/mm_supervisor/communication_tests.rs b/components/patina_mm/tests/patina_mm_integration/mm_supervisor/communication_tests.rs index c4cb5bd3c..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,6 +15,8 @@ //! SPDX-License-Identifier: Apache-2.0 use crate::patina_mm_integration::common::*; +use patina::management_mode::protocol::mm_supervisor_request::{REVISION, RequestType, SIGNATURE}; +use r_efi::efi; #[test] fn test_mm_supervisor_version_request_integration() { @@ -25,14 +27,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), - revision: mm_supv::REVISION, - request: mm_supv::requests::VERSION_INFO, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::VersionInfo.into(), 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); @@ -51,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, mm_supv::responses::SUCCESS, "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::(); @@ -75,14 +77,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), - revision: mm_supv::REVISION, - request: mm_supv::requests::FETCH_POLICY, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::FetchPolicy.into(), 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); @@ -97,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, mm_supv::responses::SUCCESS, "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::(); @@ -124,14 +126,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), - revision: mm_supv::REVISION, + signature: SIGNATURE, + revision: 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); @@ -142,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, mm_supv::responses::ERROR, "Invalid request should return error"); + assert_eq!( + response_header.result, + efi::Status::INVALID_PARAMETER.as_usize() as u64, + "Invalid request should return error" + ); } #[test] @@ -153,13 +159,13 @@ 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::requests::VERSION_INFO, + revision: REVISION, + request: RequestType::VersionInfo.into(), 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 +213,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), - revision: mm_supv::REVISION, - request: mm_supv::requests::VERSION_INFO, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::VersionInfo.into(), 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 +235,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), - revision: mm_supv::REVISION, - request: mm_supv::requests::VERSION_INFO, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::VersionInfo.into(), 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 +273,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), - revision: mm_supv::REVISION, - request: mm_supv::requests::COMM_UPDATE, + signature: SIGNATURE, + revision: REVISION, + request: RequestType::CommUpdate.into(), 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,8 +295,8 @@ 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.result, mm_supv::responses::SUCCESS, "Comm update request should succeed"); + assert_eq!(response_header.request, RequestType::CommUpdate.into(), "Response should be for COMM_UPDATE request"); + 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::(); @@ -315,14 +321,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), - revision: mm_supv::REVISION, - request: mm_supv::requests::UNBLOCK_MEM, // This uses the constant! + signature: SIGNATURE, + revision: REVISION, + request: RequestType::UnblockMem.into(), 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,8 +343,8 @@ 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.result, mm_supv::responses::SUCCESS, "Unblock mem request should succeed"); + assert_eq!(response_header.request, RequestType::UnblockMem.into(), "Response should be for UNBLOCK_MEM request"); + 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::(); 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/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..deacb45c8 --- /dev/null +++ b/sdk/patina/src/management_mode.rs @@ -0,0 +1,21 @@ +//! 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; + +// 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 new file mode 100644 index 000000000..905a13535 --- /dev/null +++ b/sdk/patina/src/management_mode/comm_buffer_hob.rs @@ -0,0 +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 crate::{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: 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/protocol.rs b/sdk/patina/src/management_mode/protocol.rs similarity index 90% rename from components/patina_mm/src/protocol.rs rename to sdk/patina/src/management_mode/protocol.rs index cf73116f5..89493e062 100644 --- a/components/patina_mm/src/protocol.rs +++ b/sdk/patina/src/management_mode/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_comm_buffer_update.rs b/sdk/patina/src/management_mode/protocol/mm_comm_buffer_update.rs similarity index 98% 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 index 4e8ce0ea1..609669c70 100644 --- a/components/patina_mm/src/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 new file mode 100644 index 000000000..443495cf3 --- /dev/null +++ b/sdk/patina/src/management_mode/protocol/mm_supervisor_request.rs @@ -0,0 +1,221 @@ +//! 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 crate::BinaryGuid; +use r_efi::efi; +use zerocopy::FromBytes; + +/// 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; + +// 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 [`RequestType`] enum) +/// 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)] +#[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 [`RequestType`] enum). + pub request: u32, + /// Reserved for alignment, must be 0. + pub reserved: u32, + /// Result status. The value of this field follows the [`efi::Status`] definitions. + 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 { + Self::read_from_bytes(bytes.get(..Self::SIZE)?).ok() + } +} + +/// Response from MM Supervisor version info request. +/// +/// Returned as the payload following an [`MmSupervisorRequestHeader`] when the request +/// type is [`RequestType::VersionInfo`]. +/// +/// ## 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, + zerocopy_derive::FromBytes, + zerocopy_derive::IntoBytes, + zerocopy_derive::Immutable, + zerocopy_derive::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 { + Self::read_from_bytes(bytes.get(..Self::SIZE)?).ok() + } +} + +/// MM Supervisor request types. +/// +/// Each variant corresponds to a specific supervisor operation. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +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 { + /// 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 { + 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), + } + } +} + +impl From for u32 { + fn from(request_type: RequestType) -> Self { + request_type as u32 + } +} + +/// Standard MM Supervisor response types. +/// +/// Each variant corresponds to a specific response status that the supervisor can return. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ResponseType { + /// Error: Invalid request index. + InvalidRequest, + /// Error: Invalid data buffer. + InvalidDataBuffer, + /// Error: Communication buffer initialization failed. + 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::InvalidRequest => efi::Status::INVALID_PARAMETER, + ResponseType::InvalidDataBuffer => efi::Status::BUFFER_TOO_SMALL, + ResponseType::CommBufferInitError => efi::Status::DEVICE_ERROR, + } + } +} + +/// 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. + pub const SIZE: usize = core::mem::size_of::(); +}