Skip to content

Commit a834ca0

Browse files
committed
[user] user module changes
1 parent edc5cca commit a834ca0

12 files changed

Lines changed: 3458 additions & 0 deletions

File tree

patina_mm_user_core/Cargo.toml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
[package]
2+
name = "patina_mm_user_core"
3+
version.workspace = true
4+
repository.workspace = true
5+
license.workspace = true
6+
edition.workspace = true
7+
readme = "README.md"
8+
description = "A pure Rust implementation of the MM User Core for standalone MM mode environments."
9+
10+
# Metadata to tell docs.rs how to build the documentation when uploading
11+
[package.metadata.docs.rs]
12+
features = ["doc"]
13+
14+
# Example binary showing how to build a PE/COFF MM User Core
15+
[[bin]]
16+
name = "example_mm_user"
17+
path = "bin/example_mm_user.rs"
18+
19+
[dependencies]
20+
goblin = { workspace = true, features = ["pe32", "pe64"] }
21+
log = { workspace = true }
22+
patina = { workspace = true }
23+
patina_internal_depex = { workspace = true }
24+
patina_internal_mm_alloc = { workspace = true }
25+
patina_internal_mm_common = { workspace = true }
26+
patina_adv_logger = { workspace = true }
27+
r-efi = { workspace = true }
28+
spin = { workspace = true }
29+
uuid = { workspace = true }
30+
31+
[dev-dependencies]
32+
mockall = { workspace = true }
33+
serial_test = { workspace = true }
34+
35+
[features]
36+
default = []
37+
std = []
38+
doc = []

patina_mm_user_core/README.md

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
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
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//! Example MM User Core Binary
2+
//!
3+
//! This is an example platform binary that demonstrates how to build a PE/COFF
4+
//! MM User Core using the `patina_mm_user_core` crate. It follows the same pattern
5+
//! as `q35_dxe_core.rs` for the DXE Core.
6+
//!
7+
//! ## Building
8+
//!
9+
//! Build with cargo for the UEFI target:
10+
//! ```bash
11+
//! cargo build --release --target x86_64-unknown-uefi --bin example_mm_user
12+
//! ```
13+
//!
14+
//! ## Entry Point
15+
//!
16+
//! The MM User Core is invoked by the MM Supervisor Core via `invoke_demoted_routine`
17+
//! after being loaded into MMRAM. The supervisor passes three arguments:
18+
//! - `arg1`: Command type (StartUserCore, UserRequest, UserApProcedure)
19+
//! - `arg2`: Command-specific data pointer (HOB list for init, buffer for requests)
20+
//! - `arg3`: Command-specific auxiliary data
21+
//!
22+
//! ## License
23+
//!
24+
//! Copyright (c) Microsoft Corporation.
25+
//!
26+
//! SPDX-License-Identifier: Apache-2.0
27+
//!
28+
#![cfg(all(target_os = "uefi", target_arch = "x86_64"))]
29+
#![no_std]
30+
#![no_main]
31+
32+
use core::panic::PanicInfo;
33+
use core::sync::atomic::AtomicBool;
34+
use core::ffi::c_void;
35+
use patina::{log::Format, serial::uart::Uart16550};
36+
use patina_adv_logger::logger::AdvancedLogger;
37+
use patina_internal_mm_common::UserCommandType;
38+
use patina_mm_user_core::MmUserCore;
39+
40+
// =============================================================================
41+
// Static Core Instance
42+
// =============================================================================
43+
44+
/// Flag indicating that advanced logger initialization is complete.
45+
static ADV_LOGGER_INIT_COMPLETE: AtomicBool = AtomicBool::new(false);
46+
47+
/// The static MM User Core instance.
48+
static USER_CORE: MmUserCore = MmUserCore::new();
49+
50+
static LOGGER: AdvancedLogger<Uart16550> = AdvancedLogger::new(
51+
Format::Standard,
52+
&[
53+
("goblin", log::LevelFilter::Off),
54+
("allocations", log::LevelFilter::Off),
55+
("efi_memory_map", log::LevelFilter::Off),
56+
("mm_comm", log::LevelFilter::Off),
57+
("sw_mmi", log::LevelFilter::Off),
58+
("patina_performance", log::LevelFilter::Off),
59+
],
60+
log::LevelFilter::Info,
61+
Uart16550::Io { base: 0x402 },
62+
);
63+
64+
65+
// =============================================================================
66+
// Panic Handler
67+
// =============================================================================
68+
69+
#[panic_handler]
70+
fn panic(_info: &PanicInfo) -> ! {
71+
loop {}
72+
}
73+
74+
// =============================================================================
75+
// Entry Point
76+
// =============================================================================
77+
78+
/// The entry point for the MM User Core binary.
79+
///
80+
/// Called by the MM Supervisor via `invoke_demoted_routine` with three arguments:
81+
/// - `arg1`: Command type (0 = StartUserCore, 1 = UserRequest, 2 = UserApProcedure)
82+
/// - `arg2`: Command-specific data (HOB list pointer for init, buffer pointer for requests)
83+
/// - `arg3`: Command-specific auxiliary data (0 for init, context size for requests)
84+
///
85+
/// Returns 0 (`EFI_SUCCESS`) on success, or a non-zero EFI status code on failure.
86+
#[cfg_attr(target_os = "uefi", unsafe(export_name = "user_core_main"))]
87+
pub extern "efiapi" fn mm_user_main(op_code: u64, arg1: u64, arg2: u64) -> u64 {
88+
89+
// Initialize the advanced logger on the first CPU to arrive (BSP)
90+
if !ADV_LOGGER_INIT_COMPLETE.swap(true, core::sync::atomic::Ordering::SeqCst) {
91+
// If this is our first time here, it better be that the op_code being MmUserRequestTypeInit
92+
if op_code != UserCommandType::StartUserCore as u64 {
93+
// This means the BSP didn't send the expected init command first, which is a problem.
94+
// Log an error and return failure.
95+
panic!("MM User Core received non-init command before initialization: op_code = {}", op_code);
96+
}
97+
98+
log::set_logger(&LOGGER).map(|()| log::set_max_level(log::LevelFilter::Trace)).unwrap();
99+
// SAFETY: The physical_hob_list pointer is considered valid at this point as it's provided by the core
100+
// to the entry point.
101+
unsafe {
102+
LOGGER.init(arg1 as *const c_void).unwrap();
103+
}
104+
}
105+
106+
USER_CORE.entry_point_worker(op_code, arg1, arg2)
107+
}

0 commit comments

Comments
 (0)