|
| 1 | +# Patina MM Supervisor Core |
| 2 | + |
| 3 | +A pure Rust implementation of the MM Supervisor Core for standalone MM mode environments. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +This crate provides the core functionality for the MM (Management Mode) Supervisor in a standalone MM environment. It is designed to run on x64 systems where: |
| 8 | + |
| 9 | +- Page tables are already set up by the pre-MM phase |
| 10 | +- All images are loaded and ready to execute |
| 11 | +- The BSP (Bootstrap Processor) orchestrates incoming requests |
| 12 | +- APs (Application Processors) wait in a holding pen, checking a mailbox for work |
| 13 | + |
| 14 | +## Memory Model |
| 15 | + |
| 16 | +The core can be instantiated as a `static` with no runtime allocation required for core data structures. |
| 17 | + |
| 18 | +## Building a PE/COFF Binary |
| 19 | + |
| 20 | +### Prerequisites |
| 21 | + |
| 22 | +1. Install the Rust UEFI target: |
| 23 | + ```bash |
| 24 | + rustup target add x86_64-unknown-uefi |
| 25 | + ``` |
| 26 | + |
| 27 | +2. Ensure you have the nightly toolchain (required for `#![feature(...)]`): |
| 28 | + ```bash |
| 29 | + rustup override set nightly |
| 30 | + ``` |
| 31 | + |
| 32 | +### Build Command |
| 33 | + |
| 34 | +Build the example MM Supervisor binary: |
| 35 | + |
| 36 | +```bash |
| 37 | +cargo build --release --target x86_64-unknown-uefi --bin example_mm_supervisor |
| 38 | +``` |
| 39 | + |
| 40 | +The output PE/COFF binary will be at: |
| 41 | +``` |
| 42 | +target/x86_64-unknown-uefi/release/example_mm_supervisor.efi |
| 43 | +``` |
| 44 | + |
| 45 | +### Entry Point |
| 46 | + |
| 47 | +The MM Supervisor exports `MmSupervisorMain` as its entry point, matching the EDK2 convention: |
| 48 | + |
| 49 | +```rust |
| 50 | +#[unsafe(export_name = "MmSupervisorMain")] |
| 51 | +pub extern "efiapi" fn mm_supervisor_main(hob_list: *const c_void) -> ! { |
| 52 | + SUPERVISOR.entry_point(hob_list) |
| 53 | +} |
| 54 | +``` |
| 55 | + |
| 56 | +The MM IPL (Initial Program Loader) calls this entry point on **all processors** after: |
| 57 | +1. Loading the supervisor image into MMRAM |
| 58 | +2. Setting up page tables |
| 59 | +3. Constructing the HOB list with MMRAM ranges |
| 60 | + |
| 61 | +## Architecture |
| 62 | + |
| 63 | +### Entry Point Model |
| 64 | + |
| 65 | +The entry point is executed on all cores simultaneously: |
| 66 | + |
| 67 | +1. **BSP (Bootstrap Processor)**: |
| 68 | + - First CPU to arrive (determined by atomic counter) |
| 69 | + - Performs one-time initialization |
| 70 | + - Sets up the request handling infrastructure |
| 71 | + - Enters the main request serving loop |
| 72 | + |
| 73 | +2. **APs (Application Processors)**: |
| 74 | + - All other CPUs |
| 75 | + - Wait for BSP initialization to complete |
| 76 | + - Enter a holding pen and poll mailboxes for commands |
| 77 | + |
| 78 | +### Mailbox System |
| 79 | + |
| 80 | +The mailbox system provides inter-processor communication: |
| 81 | + |
| 82 | +- Each AP has a dedicated mailbox (cache-line aligned to avoid false sharing) |
| 83 | +- BSP sends commands to APs via mailboxes |
| 84 | +- APs respond with results through the same mailbox |
| 85 | +- Supports synchronization primitives for coordinated operations |
| 86 | + |
| 87 | +## Usage |
| 88 | + |
| 89 | +### Basic Platform Implementation |
| 90 | + |
| 91 | +```rust |
| 92 | +#![no_std] |
| 93 | +#![no_main] |
| 94 | + |
| 95 | +use core::{ffi::c_void, panic::PanicInfo}; |
| 96 | +use patina_mm_supervisor_core::*; |
| 97 | + |
| 98 | +struct MyPlatform; |
| 99 | + |
| 100 | +impl CpuInfo for MyPlatform { |
| 101 | + fn ap_poll_timeout_us() -> u64 { 1000 } |
| 102 | +} |
| 103 | + |
| 104 | + |
| 105 | + |
| 106 | +// Static instance - no heap allocation required |
| 107 | +static SUPERVISOR: MmSupervisorCore<MyPlatform> = MmSupervisorCore::new(); |
| 108 | + |
| 109 | +#[panic_handler] |
| 110 | +fn panic(_info: &PanicInfo) -> ! { |
| 111 | + loop { core::hint::spin_loop(); } |
| 112 | +} |
| 113 | + |
| 114 | +#[unsafe(export_name = "MmSupervisorMain")] |
| 115 | +pub extern "efiapi" fn mm_supervisor_main(hob_list: *const c_void) -> ! { |
| 116 | + SUPERVISOR.entry_point(hob_list) |
| 117 | +} |
| 118 | +``` |
| 119 | + |
| 120 | +### Registering Request Handlers |
| 121 | + |
| 122 | +Handlers must be defined as static references: |
| 123 | + |
| 124 | +```rust |
| 125 | +use patina_mm_supervisor_core::*; |
| 126 | + |
| 127 | +struct MyHandler; |
| 128 | + |
| 129 | +impl RequestHandler for MyHandler { |
| 130 | + fn guid(&self) -> r_efi::efi::Guid { |
| 131 | + // Your handler's GUID |
| 132 | + r_efi::efi::Guid::from_fields(0x12345678, 0x1234, 0x5678, 0x12, 0x34, &[0; 6]) |
| 133 | + } |
| 134 | + |
| 135 | + fn handle(&self, context: &mut RequestContext) -> RequestResult { |
| 136 | + // Handle the request |
| 137 | + RequestResult::Success |
| 138 | + } |
| 139 | + |
| 140 | + fn name(&self) -> &'static str { |
| 141 | + "MyHandler" |
| 142 | + } |
| 143 | +} |
| 144 | + |
| 145 | +static MY_HANDLER: MyHandler = MyHandler; |
| 146 | + |
| 147 | +// Register before calling entry_point, or during BSP initialization |
| 148 | +SUPERVISOR.register_handler(&MY_HANDLER); |
| 149 | +``` |
| 150 | + |
| 151 | +### Integration with MM IPL |
| 152 | + |
| 153 | +The MM IPL (from EDK2/MmSupervisorPkg) loads this binary and calls the entry point. The HOB list passed contains: |
| 154 | + |
| 155 | +- `gEfiMmPeiMmramMemoryReserveGuid` - MMRAM ranges |
| 156 | +- `gMmCommBufferHobGuid` - Communication buffer information |
| 157 | +- `gMmCommonRegionHobGuid` - Common memory regions |
| 158 | +- FV HOBs for MM driver firmware volumes |
| 159 | + |
| 160 | +## Example Binary |
| 161 | + |
| 162 | +See [bin/example_mm_supervisor.rs](bin/example_mm_supervisor.rs) for a complete example platform implementation. |
| 163 | + |
| 164 | +## License |
| 165 | + |
| 166 | +Copyright (c) Microsoft Corporation. |
| 167 | + |
| 168 | +SPDX-License-Identifier: Apache-2.0 |
0 commit comments