diff --git a/cspell.yml b/cspell.yml index 44edafb0e..2eed9e7d1 100644 --- a/cspell.yml +++ b/cspell.yml @@ -41,6 +41,7 @@ words: - armasm - autocfg - bitvec + - bootmgfw - bootx - bucketize - bumpalo diff --git a/docs/src/rfc/text/0000-patina-boot.md b/docs/src/rfc/text/0000-patina-boot.md new file mode 100644 index 000000000..c23fd3047 --- /dev/null +++ b/docs/src/rfc/text/0000-patina-boot.md @@ -0,0 +1,756 @@ +# RFC: Boot Orchestration + +This RFC proposes modular components for UEFI-compliant boot functionality in Patina firmware. + +Within the scope of this RFC, boot functionality includes console initialization, boot option discovery, +and boot orchestration as defined in UEFI Specification 2.11 Chapter 3 (Boot Manager). This RFC also +includes BDS phase event signaling (EndOfDxe and ReadyToBoot) as defined in the Platform Initialization +(PI) Specification. + +## Change Log + +- 2025-11-04: Initial RFC draft +- 2025-11-06: + - Rewritten with modular component architecture + - Added optional service dependencies for platform customization + - Added BDS phase event signaling (EndOfDxe, ReadyToBoot) +- 2025-12-04: + - Updated watchdog timer reference to UEFI Specification 2.11 Section 3.1.2 + - Added requirement to disable watchdog when boot option returns control +- 2025-12-09: + - Added component rationales and decomposition justification +- 2025-12-10: + - Fixed EndOfDxe timing: now signaled after PCIe enumeration AND GOP discovery complete + - Added Future Work section for Connect Controller Service + - Expanded ConsoleDiscovery prerequisites (PCI/USB bus enumeration requirements) + - Added custom orchestrator example +- 2025-12-12: + - Added BootOptionDiscovery component for full UEFI boot variable management + - Reframed RFC: UEFI-compliant boot as primary case, hardcoded paths as alternative for divergent platforms +- 2025-12-18: + - Added Unresolved Questions section for BDS phase dispatch mechanism +- 2026-01-14: + - Resolved BDS phase dispatch mechanism: dual integration paths (native Patina and legacy bridge) +- 2026-02-03: + - Added partial device path expansion support with `expand_device_path()` helper (#1280) + - `boot_from_device_path()` now handles both full and partial paths transparently +- 2026-02-10: + - Added Implementation Phases section defining Minimal Boot as first deliverable + - Minimal Boot specifies two boot flows: normal (primary/secondary fallback) and hotkey (direct to error on failure) + - Reordered Guide-Level Explanation to lead with Minimal Boot usage +- 2026-02-10: + - Added Implementation Phases section defining Minimal Boot as first deliverable + - Minimal Boot demonstrates patina_boot booting Windows with a shorter BDS phase + - Reordered Guide-Level Explanation to lead with Minimal Boot usage +- 2026-02-12: + - Refactored BootOrchestrator from concrete component to trait-based design + - Added `BootOrchestrator` trait, `BootDispatcher` component, `SimpleBootManager` reference impl + - Boot options passed directly to `SimpleBootManager::from_options()` instead of `Config` + - `BootDispatcher` is the Patina component gated by `Service` + - Platforms provide custom boot flows by implementing `BootOrchestrator` trait + +## Motivation + +Most Patina platforms require UEFI-compliant boot functionality: discovering boot options from `Boot####`/`BootOrder` +variables, managing console devices, and orchestrating the boot flow per UEFI Specification Chapter 3. This RFC +provides common components that implement full UEFI Boot Manager compliance. + +Some platforms may diverge from UEFI compliance (e.g., embedded systems with hardcoded boot paths). The modular +architecture supports this by allowing platforms to use individual components selectively or provide boot options +directly via configuration. + +## Technology Background + +The UEFI Boot Manager (UEFI Specification 2.11 Chapter 3) operates through UEFI variables (`Boot####`, `BootOrder`, +`ConIn`/`ConOut`/`ErrOut`) containing boot configuration and console device paths. Boot options use `EFI_LOAD_OPTION` +structures with device paths and descriptions. The BDS phase signals EndOfDxe after DXE completion and ReadyToBoot +before boot attempts to coordinate firmware initialization and security lockdown. + +## Goals + +1. Provide UEFI-compliant boot option discovery (`Boot####`/`BootOrder` variable management) +2. Provide foundational boot orchestration for executing boot options +3. Provide a common boot flow implementation suitable for most platforms +4. Support platform-specific boot flows through custom orchestration +5. Maintain modular architecture where components can be used, replaced, or omitted independently +6. Provide reusable library functions to minimize code duplication across platforms + +## Requirements + +This RFC implements specific elements from UEFI Specification 2.11 Chapter 3 (Boot Manager) and Platform +Initialization (PI) Specification Volume 2 (DXE/BDS phase). The following requirements define the scope +of boot functionality provided by these components. + +### UEFI Specification 2.11 Chapter 3 (Boot Manager) + +**Boot Option Discovery**: + +- Read and parse `Boot####` variables containing `EFI_LOAD_OPTION` structures +- Read `BootOrder` variable to determine boot attempt sequence +- Manage boot option list (add, remove, reorder boot options) +- Support boot option attributes (LOAD_OPTION_ACTIVE, LOAD_OPTION_HIDDEN, etc.) +- Expand partial device paths to full device paths by matching against discovered device topology + (e.g., hard drive media device paths containing only partition GUID/signature) + +**Console Variables**: + +- Discover console devices via GOP (graphics) and SimpleTextInput protocols +- Populate `ConIn`, `ConOut`, and `ErrOut` variables with console device paths + +**Boot Orchestration**: + +- Execute boot options from `BootOrder` sequence (or platform-provided configuration) +- Load boot images via `LoadImage()` service +- Start boot images via `StartImage()` service +- Enable 5-minute watchdog timer before `StartImage()` per Section 3.1.2 +- Disable watchdog timer when boot option returns control +- Handle boot failures and attempt next option in sequence +- Detect platform-configured hotkey to trigger alternative boot path (e.g., F12 for secondary boot) + +### PI Specification Volume 2 (DXE/BDS Phase) + +**BDS Phase Event Signaling**: + +- Signal `gEfiEndOfDxeEventGroupGuid` after device enumeration completes +- Signal `gEfiEventReadyToBootGuid` immediately before attempting first boot option +- Enable event notification to C-based PI drivers (MM, security) via EventServices + +**Driver Dispatch Coordination**: + +- Coordinate driver dispatch during device connection to ensure complete device topology enumeration +- Support interleaved connect-dispatch pattern: connect controllers, dispatch newly loaded drivers, repeat until stable + +### Component Integration + +**Patina Component Model**: + +- Integrate with Patina's component model using standard dependency injection patterns +- Enable platform orchestration that controls execution order and can skip or replace steps +- Support progressive customization from default behavior to full custom orchestration + +**Service Dependencies** (from RFC 0017): + +- `RuntimeVariableServices`: Read/write UEFI variables (boot options, console variables) +- `ImageServices`: Load and start boot images (`LoadImage()`, `StartImage()`) +- `TimingServices`: Configure watchdog timer +- `ProtocolServices`: Locate protocol handles, connect controllers, query device paths +- `DxeServices`: Orchestrate driver dispatch during connect-dispatch interleaving +- `EventServices`: Signal BDS phase events (`signal_event_group()` for event group GUIDs) + +*Note: This RFC uses `ProtocolServices::connect_controller()` for device connection. If future +components require additional connection abstractions (e.g., connection filtering, connection +policies), a dedicated `ConnectionService` could be introduced. For this RFC's scope, +`ProtocolServices` is sufficient.* + +**Customization Support**: + +- Default: Use `BootOptionDiscovery` for UEFI-compliant boot variable management +- Alternative: Accept boot options via `BootOptions` passed directly to `SimpleBootManager::from_options()` for platforms not requiring UEFI compliance +- Enable platforms to use common components as-is, compose selectively, or replace entirely +- Provide library functions for platforms implementing custom boot flows + +### Out of Scope + +The following UEFI/PI Boot Manager features are **not** included in this RFC: + +- Capsule processing and update capsule handling +- Boot menu UI and user interaction (boot timeout, option selection) +- Full hotkey variable management (`Key####` variables per UEFI spec) +- Language management (`PlatformLang`, `PlatformLangCodes`) +- Variable policy registration (`EDKII_VARIABLE_POLICY_PROTOCOL`) +- Hardware error record variables (`HwErr####`, `HwErrRecSupport`) +- OS indications (`OsIndications`, `OsIndicationsSupport`) +- Deferred image loading (`EFI_DEFERRED_IMAGE_LOAD_PROTOCOL`) +- Platform recovery options (`PlatformRecovery####`) +- Automatic boot device provisioning UI + +These features may be addressed in future RFCs as optional components or platform-specific extensions. + +### Future Work: Connect Controller Service + +This RFC uses `ProtocolServices::connect_controller()` (the UEFI protocol) for device enumeration. +This is sufficient for the initial implementation but does not allow native Patina components to +participate in the connect controller flow. + +A future RFC will define a `Service` abstraction that allows native Patina +components to participate in device enumeration and driver binding without implementing UEFI Driver +Model protocols. This would enable: + +- Native Patina bus drivers participating in device discovery +- Connection filtering and policy components +- Custom binding logic for platform-specific device handling + +Until that RFC is implemented, platforms requiring custom connect controller behavior must use +UEFI Driver Model protocols or implement custom orchestrators that call `connect_controller()` +directly with platform-specific logic. + +## Design Decision: BDS Phase Dispatch Mechanism + +The PI Specification (Section II-12.2) defines the BDS Architectural Protocol as the mechanism for +transferring control from DXE phase to BDS phase. This RFC adopts a Patina-native approach while +providing a bridge component for platforms with existing C-based BDS implementations. + +### Chosen Approach: Dual Integration Paths + +Patina provides two integration paths, allowing platforms to choose based on their needs: + +#### Path 1: Native Patina (BootDispatcher + BootOrchestrator trait) + +Boot orchestration uses a trait-based design. `BootOrchestrator` is a plain Rust trait defining the +boot flow interface. `BootDispatcher` is the Patina component gated by `Service` that +holds a `Box` and invokes it at BDS time. `SimpleBootManager` is the reference +implementation. + +```rust +/// Trait defining the boot orchestration interface. +pub trait BootOrchestrator: Send + Sync + 'static { + fn execute( + &self, + boot_services: &StandardBootServices, + runtime_services: &StandardRuntimeServices, + image_handle: efi::Handle, + ); +} + +/// Component that invokes the orchestrator at BDS time. +#[component] +impl BootDispatcher { + fn entry_point( + self, + _bds_phase: Service, // Gates dispatch until BDS time + boot_services: StandardBootServices, + runtime_services: StandardRuntimeServices, + image_handle: Option, + ) -> Result<()> { + let handle = *image_handle.ok_or(EfiError::InvalidParameter)?; + self.orchestrator.execute(&boot_services, &runtime_services, handle); + loop { core::hint::spin_loop(); } + } +} + +/// Reference implementation with configurable boot options. +impl BootOrchestrator for SimpleBootManager { + fn execute(&self, boot_services: &StandardBootServices, ...) { + connect_all(boot_services)?; + signal_bds_phase_entry(boot_services)?; + discover_console_devices(boot_services, runtime_services)?; + // Hotkey detection, ReadyToBoot signal, boot attempts... + } +} +``` + +*Benefits*: Trait enforces the contract at compile time. Plain Rust trait with `Box` dispatch — +no Patina service indirection needed since there is only one consumer (`BootDispatcher`). Platforms +swap boot orchestration by providing a different `BootOrchestrator` impl. Single component +registration: `BootDispatcher::new(impl BootOrchestrator)`. + +#### Path 2: Legacy/Hybrid (BdsArchProtocolBridge) + +For platforms with existing C-based BDS implementations (e.g., EDK II's `BdsDxe`), a minimal bridge +component calls the BDS Architectural Protocol. This enables incremental migration and keeps Patina +agnostic of what owns BDS. + +```rust +/// Minimal component that bridges to existing BDS arch protocol +#[component] +impl BdsArchProtocolBridge { + fn entry_point(self, protocol_services: Service) -> Result<()> { + let bds_protocol = protocol_services.locate_protocol::()?; + unsafe { ((*bds_protocol).entry)(bds_protocol) }; + Ok(()) + } +} +``` + +*Benefits*: Works with existing C-based BDS drivers, no DXE Core modification required, clean +migration path for platforms transitioning to native Patina boot. + +### Rationale + +The BDS Architectural Protocol is a *dispatch mechanism*, not a functional requirement. The PI spec +requires that BDS phase enumerate boot devices, signal events, and attempt boot options—requirements +about *what* happens, not *how* it's dispatched. + +Providing both paths: + +1. Allows native Patina platforms to use idiomatic component patterns +2. Supports platforms with existing C-based BDS investments +3. Keeps Patina decoupled from any specific BDS implementation +4. Enables gradual migration without forcing immediate rewrites + +C drivers that register for BDS events (EndOfDxe, ReadyToBoot) via `CreateEventEx()` continue to +work because both paths signal these events through EventServices. + +## Prior Art (Existing EDK II Implementation) + +EDK II implements boot functionality through `BdsDxe` (`MdeModulePkg/Universal/BdsDxe`), a monolithic +driver that combines console initialization, boot option processing, and platform integration in a single +component. Platform customization occurs through `PlatformBootManagerLib` callbacks: +`PlatformBootManagerBeforeConsole()`, `PlatformBootManagerAfterConsole()`, +`PlatformBootManagerWaitCallback()`, and `PlatformBootManagerUnableToBoot()`. + +Boot option management uses `UefiBootManagerLib`, which provides functions for parsing `EFI_LOAD_OPTION` +structures, enumerating boot options, and managing boot variables. Console device connection and boot +target discovery are hardcoded into the boot flow with limited platform control over execution order. + +This design influenced our component architecture by demonstrating the need for console initialization, +boot discovery, and orchestration as distinct responsibilities. However, the callback pattern limits +platform flexibility compared to platform-controlled orchestration. + +## Alternatives + +### Callback-Based Pattern (EDK II Approach) + +Single Boot Manager component with fixed execution flow and platform callback hooks (`before_console()`, +`after_console()`, etc.). Platforms customize behavior through callback traits. + +**Limitation**: Callbacks have fixed execution order. Platforms cannot skip steps, change ordering, or +implement custom control flow like network-before-console or interleaved fallbacks. + +### Monolithic Boot Manager Component + +Single comprehensive component handling console initialization, boot discovery, and orchestration with +configuration options. + +**Limitation**: Individual pieces cannot be replaced independently of the reference implementation. + +### Library-Only Approach + +Library functions only (`parse_boot_variables()`, `discover_console_devices()`, etc.) with no reference +components. Platforms implement orchestration. + +**Limitation**: Code duplication across platforms. Simple platforms implement significant boilerplate. +Higher adoption barrier. + +### Chosen Approach: Modular Components with Platform Orchestration + +Three components (`BootOptionDiscovery`, `ConsoleDiscovery`, `BootDispatcher`) that platforms use +as-is, compose selectively, or replace entirely. `BootDispatcher` invokes a `BootOrchestrator` trait +implementation at BDS time; platforms provide custom boot flows by implementing the trait. +UEFI-compliant platforms use `BootOptionDiscovery` for boot variable management; platforms +diverging from UEFI compliance can provide boot options directly to `SimpleBootManager::from_options()`. + +**Benefits**: Full UEFI compliance for most platforms. Custom orchestration via `BootOrchestrator` +trait (change order, skip steps, custom control flow). Independent component replacement. Platforms +carry only used code. Escape hatch for non-UEFI-compliant platforms via direct configuration. + +## Design Assumptions + +This RFC's architecture is based on the following design considerations: + +1. **Platform diversity**: Platforms range from simple embedded systems with fixed boot paths to complex + servers with network boot, remote attestation, and custom boot policies +2. **Customization requirement**: Platform-specific boot flows, connection policies, and orchestration + requirements necessitate composable components rather than monolithic implementations +3. **Progressive disclosure**: Architecture supports both simple use cases (single composite component) + and complex scenarios (individual component composition with custom orchestration) +4. **Scope**: This RFC covers boot option discovery and console initialization alongside boot + orchestration because all are UEFI Boot Manager responsibilities. BootOptionDiscovery is optional + for platforms diverging from UEFI compliance; ConsoleDiscovery is optional for headless systems + +## Implementation Phases + +This RFC is delivered in two phases. Phase 1 (Minimal Boot) provides a working demonstration of +patina_boot booting Windows with a shorter BDS phase. Phase 2 adds full UEFI Boot Manager compliance. +This phased approach validates the component architecture and delivers tangible value before investing +in the full specification. + +### Phase 1: Minimal Boot + +**Goal**: Demonstrate patina_boot replacing the C-based BDS driver to boot Windows on QEMU platforms, +with a faster BDS phase achieved by eliminating boot variable parsing overhead and using +platform-provided device paths directly. + +**Target Platforms**: QEMU Q35 (x64) and QEMU SBSA (AArch64) + +**Components Used**: + +- `BootDispatcher` with `SimpleBootManager` orchestrator (platform-provided device paths via + `BootOptions`) +- `ConsoleDiscovery` with handle-only discovery (locate GOP/SimpleTextInput handles; console + variable write is deferred to Phase 2) + +#### Boot Flows + +Minimal Boot defines two distinct boot flows selected at runtime based on hotkey state. Both flows +share the same device enumeration, event signaling, and error handling infrastructure. + +**Common Preamble** (runs before either flow): + +1. `connect_all()` — recursive connect until device topology stabilizes +2. `ConsoleDiscovery` — locate GOP and SimpleTextInput handles +3. Signal EndOfDxe — security components perform lockdown +4. Check hotkey — select which boot flow to execute + +**Flow 1: Normal Boot** (no hotkey detected) + +The platform configures two boot device paths: a primary and a secondary. The orchestrator attempts +them in order. If both fail, the error path is taken. + +```text +Signal ReadyToBoot + | + v +Try primary device path (LoadImage/StartImage with 5-min watchdog) + | +Success --> boot (never returns) + | +Failure + | + v +Try secondary device path (LoadImage/StartImage with 5-min watchdog) + | +Success --> boot (never returns) + | +Failure + | + v +Error path: call failure_handler (demo: show error screen) +``` + +**Flow 2: Hotkey Boot** (hotkey detected, e.g., F12) + +When the platform-configured hotkey is held during boot, the orchestrator switches to the hotkey +device list. This flow does **not** fall through to the normal boot devices — if the hotkey device +fails, the error path is taken directly. + +```text +Signal ReadyToBoot + | + v +Try hotkey device path (LoadImage/StartImage with 5-min watchdog) + | +Success --> boot (never returns) + | +Failure + | + v +Error path: call failure_handler (demo: show error screen) +``` + +**Error Path**: The `failure_handler` is a platform-provided callback. For the Minimal Boot +demonstration, this displays an error screen. Production platforms can implement recovery logic, +network boot fallback, or diagnostics as needed. + +#### Minimal Boot Configuration + +```rust +use patina_boot::component::{BootDispatcher, SimpleBootManager}; +use patina_boot::config::BootOptions; + +// In ComponentInfo::components(): +add.component(BootDispatcher::new(SimpleBootManager::from_options( + BootOptions::new() + .with_device(nvme_esp_device_path()) // Primary: NVMe EFI System Partition + .with_device(nvme_recovery_path()) // Secondary: NVMe recovery partition + .with_hotkey(0x16) // F12 + .with_hotkey_device(usb_device_path()) // Hotkey: boot from USB + .with_failure_handler(|| show_error_screen("All boot options exhausted")) +))); +``` + +#### What Minimal Boot Includes + +- Platform-provided boot device paths via `BootOptions` (no `Boot####`/`BootOrder` parsing) +- Recursive `connect_all()` for device enumeration (connects all handles until topology stabilizes) +- Console handle discovery (GOP and SimpleTextInput protocol location) +- BDS phase event signaling (EndOfDxe, ReadyToBoot) +- Boot image execution via `LoadImage()`/`StartImage()` with watchdog timer compliance +- Hotkey detection for alternate boot path (e.g., F12 for USB boot) +- Partial device path expansion (`expand_device_path()` for short-form device paths) +- Boot failure handling with platform-provided failure callback + +#### What Minimal Boot Defers to Phase 2 + +- `BootOptionDiscovery` component (`Boot####`/`BootOrder` variable parsing) +- Full `ConsoleDiscovery` (writing `ConIn`/`ConOut`/`ErrOut` UEFI variables) +- Connect-dispatch interleaving with `DxeServices` (driver dispatch coordination during connection) + +#### Why This Is Sufficient to Boot Windows + +Windows requires a valid boot image path (typically `\EFI\Microsoft\Boot\bootmgfw.efi` on the EFI +System Partition) and functioning console output. In the Minimal Boot configuration, the platform +provides the NVMe device path to the ESP directly via `BootOptions`, bypassing the need to +parse UEFI boot variables. Console output is available through GOP handles discovered during +`connect_all()`. The BDS phase events ensure that security components and other PI drivers receive +the expected notifications. + +#### Success Criteria + +1. patina_boot `BootDispatcher`/`SimpleBootManager` replaces the C-based BdsDxe driver on QEMU Q35 and SBSA +2. Windows boots successfully from NVMe via platform-provided device path +3. If primary NVMe path fails, secondary path is attempted before entering error path +4. Hotkey (F12) triggers alternate boot from USB; failure goes directly to error path +5. BDS phase completes faster than the equivalent C-based BdsDxe flow +6. EndOfDxe and ReadyToBoot events fire correctly, enabling PI driver compatibility + +### Phase 2: Full UEFI Boot Manager Compliance + +**Goal**: Add UEFI-compliant boot option discovery and full console variable management, enabling +platforms to use standard UEFI boot variables instead of hardcoded paths. + +**Additional Components**: + +- `BootOptionDiscovery`: Read `Boot####`/`BootOrder` variables, provide discovered options to the + `BootOrchestrator` implementation +- Full `ConsoleDiscovery`: Write `ConIn`/`ConOut`/`ErrOut` variables with multi-instance device paths +- Connect-dispatch interleaving: Coordinate with `DxeServices` to dispatch drivers discovered + during controller connection + +**Platform Integration** (Full UEFI Compliance): + +```rust +use patina_boot::component::{BootDispatcher, SimpleBootManager}; + +// BootOptionDiscovery provides boot options; SimpleBootManager consumes them. +// The BootOrchestrator trait allows swapping SimpleBootManager for a custom impl. +add.component(BootOptionDiscovery); +add.component(ConsoleDiscovery); +add.component(BootDispatcher::new(SimpleBootManager::default())); +``` + +Phase 2 builds on Phase 1 without modifying existing interfaces. The `BootOrchestrator` trait and +`BootDispatcher` component are unchanged — `SimpleBootManager` continues to execute boot options +whether sourced from `BootOptionDiscovery` or platform configuration. This validates the RFC's +modular architecture: components are additive, not replacement. + +## Rust Code Design + +### Component Architecture + +This RFC provides components and a trait that transition firmware from initialization to OS execution. +Each piece operates independently and can be replaced without modifying the others. + +**BootOrchestrator** (trait): Defines the boot orchestration interface. Platforms provide +implementations with custom boot flows. This is a plain Rust trait (not a Patina service) because +there is only one consumer (`BootDispatcher`) — service indirection would add complexity without +benefit. + +```rust +pub trait BootOrchestrator: Send + Sync + 'static { + fn execute( + &self, + boot_services: &StandardBootServices, + runtime_services: &StandardRuntimeServices, + image_handle: efi::Handle, + ); +} +``` + +**BootDispatcher** (component): The Patina component gated by `Service`. Holds a +`Box` and invokes it when dispatched at BDS time. Platforms register it with +their chosen orchestrator: `BootDispatcher::new(impl BootOrchestrator)`. + +**SimpleBootManager**: Reference implementation of `BootOrchestrator`. Constructed from `BootOptions` +via `SimpleBootManager::from_options(options)`. Implements the common boot flow (connect, signal +events, detect hotkey, boot from device paths, handle failure). + +*Rationale: The trait-based design enforces the boot orchestration contract at compile time. Platforms +swap boot behavior by providing a different `BootOrchestrator` impl to `BootDispatcher::new()`, +requiring only a single component registration. This follows the principle that a trait is better than +a service when there is only one consumer.* + +**BootOptionDiscovery** (component, Phase 2): Reads `Boot####` variables containing `EFI_LOAD_OPTION` +structures and `BootOrder` variable to build the boot option list. Depends on RuntimeVariableServices. + +*Rationale: Boot option discovery is a component because UEFI-compliant platforms need full boot +variable management, while platforms diverging from UEFI compliance can skip this component and +provide `BootOptions` directly to `SimpleBootManager`. Separating discovery from orchestration allows +this choice without affecting boot execution logic.* + +**ConsoleDiscovery** (component): Locates GOP and SimpleTextInput protocol handles, creates device +paths, and writes `ConIn`/`ConOut`/`ErrOut` variables. Depends on RuntimeVariableServices and +ProtocolServices. + +*Prerequisites:* + +- PCI bus enumeration must complete before GOP devices are discoverable (graphics controllers are + typically PCI devices) +- USB bus enumeration must complete before USB input devices are discoverable (keyboards, mice) +- When used with `SimpleBootManager`, these prerequisites are satisfied by the `connect_all()` call + that runs before console discovery +- Platforms using `ConsoleDiscovery` standalone must ensure bus enumeration completes first + +*Rationale: Console setup is a component because platforms may need custom console configuration +(serial-only, specific GOP preference, headless operation). As a component, platforms can replace +it entirely without modifying orchestration code.* + +**Common Boot Flow** (what `SimpleBootManager` implements): + +1. **Device enumeration**: Connect all handles recursively until topology stable +2. **Signal EndOfDxe**: Notify security components to perform lockdown +3. **Console discovery**: Locate GOP and input devices, populate ConIn/ConOut/ErrOut variables +4. **Hotkey detection**: Check for platform-configured hotkey; if pressed, use alternate boot options +5. **Signal ReadyToBoot**: Notify drivers that boot is imminent +6. **Execute boot options**: For each device path in `BootOptions`: + - Enable 5-minute watchdog timer + - Call `LoadImage()` / `StartImage()` + - Disable watchdog if boot returns control + - On failure, attempt next option +7. **Handle boot failure**: Call platform-provided failure handler if all options exhausted + +**BootOptions**: Configuration specifying boot options as device paths. `SimpleBootManager` receives +boot options via `BootOptions` at construction time. Any boot target expressible as a legal UEFI +device path is supported: storage devices, network boot, ramdisks, or platform-specific boot media. +Configuration also includes an optional hotkey and alternate boot options to use when the hotkey is +detected. + +Boot options are sourced in one of two ways: + +- **UEFI-compliant platforms (default, Phase 2)**: Use `BootOptionDiscovery` component, which reads + `Boot####`/`BootOrder` variables and provides the options to the orchestrator +- **Non-UEFI-compliant platforms**: Provide `BootOptions` directly to + `SimpleBootManager::from_options()`, bypassing `BootOptionDiscovery` + +### Driver Dispatch + +Connecting device controllers may expose firmware volumes containing additional drivers (e.g., PCI +option ROM drivers). `SimpleBootManager` handles connect-dispatch interleaving internally: connect +controllers, dispatch newly-loaded drivers, repeat until the topology stabilizes. + +Platforms needing custom enumeration (selective buses, specific ordering, minimal enumeration) can +implement a custom `BootOrchestrator`. Example with PCI-only enumeration: + +```rust +struct PciOnlyOrchestrator { /* config */ } + +impl BootOrchestrator for PciOnlyOrchestrator { + fn execute( + &self, + boot_services: &StandardBootServices, + runtime_services: &StandardRuntimeServices, + image_handle: efi::Handle, + ) { + // Selective: Connect only PCI roots (skip USB for headless system) + let pci_handles = boot_services.protocol().locate_handle_buffer( + HandleSearchType::ByProtocol(&PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID) + ).unwrap(); + + for handle in pci_handles { + boot_services.protocol().connect_controller(handle, true).unwrap(); + } + + // Continue with event signaling, boot execution... + } +} + +// Platform registration: +add.component(BootDispatcher::new(PciOnlyOrchestrator::new(/* config */))); +``` + +### Event Signaling + +`SimpleBootManager` (the reference `BootOrchestrator`) signals two required BDS phase events: + +- `EndOfDxe` - After device topology is stable (PCIe enumeration and GOP discovery complete). + Security components register for this event and perform lockdown. +- `ReadyToBoot` - Immediately before attempting first boot option + +EventServices (RFC 0017) bridges Patina components and C-based PI drivers. C drivers register via +`CreateEventEx()`, and Patina signals via `event_services.signal_event_group()`. + +### Library Module + +A library module provides helper functions for platforms implementing custom orchestration. These +functions allow platforms to build custom boot flows using the same underlying logic as common +components. + +**Available Functions:** + +- `boot_from_device_path()` - Load and start image with UEFI spec compliance (5-minute watchdog per + Section 3.1.2). Accepts both full and partial device paths, automatically expanding partial paths + before boot. +- `expand_device_path()` - Expand partial device paths (e.g., HD media paths with partition GUID) to + full device paths by matching against the current device topology. Returns full paths unchanged. +- `interleave_connect_and_dispatch()` - Orchestrate connect-dispatch loop for device enumeration +- `signal_bds_phase_entry()` - Signal EndOfDxe event +- `signal_ready_to_boot()` - Signal ReadyToBoot event + +`SimpleBootManager` uses these internally. Custom `BootOrchestrator` implementations use them directly. + +#### Device Path Expansion + +UEFI `Boot####` variables can contain partial (short-form) device paths that specify only a portion +of the full hardware path. For example, a hard drive boot option might contain only `HD(1,GPT,)` +without the preceding PCI path. These partial paths must be expanded by matching against the current +device topology before they can be used for booting. + +Partial paths are detected by examining the first device path node: + +- **Full paths** start with hardware/ACPI root nodes (`PciRoot`, `Acpi`) +- **Partial paths** start with media nodes (`HD`, `CDROM`), messaging nodes without root, or file paths + +Both `expand_device_path()` and `boot_from_device_path()` are provided to support different use cases: + +| Function | Use Case | +|----------------------------|------------------------------------------------------------------------------------------------------------------------------------------| +| `boot_from_device_path()` | Simple case: pass any device path and boot. Expansion happens transparently. | +| `expand_device_path()` | Advanced case: explicit control over expansion for caching, custom prioritization when multiple devices match, or pre-boot validation. | + +**Design rationale**: Providing both functions ensures the library remains composable and future-proof. +Most platforms just call `boot_from_device_path()` and it works transparently. Platforms needing +explicit control (e.g., caching resolved paths across retries, custom device selection logic) can +call `expand_device_path()` directly. + +```rust +// Simple: just boot, expansion handled internally +boot_from_device_path(&partial_path)?; + +// Advanced: expand first for caching/custom logic, then boot +let full_path = expand_device_path(&partial_path)?; +boot_from_device_path(&full_path)?; +``` + +## Guide-Level Explanation + +Platforms integrate boot functionality by adding components and configuration during DXE Core +initialization. The recommended starting point is Minimal Boot (Phase 1), which provides a working +boot flow with platform-provided device paths. + +### Minimal Boot (Phase 1) + +The simplest integration provides boot device paths directly. The platform knows its boot devices +ahead of time and configures primary, secondary, and hotkey paths: + +```rust +use patina_boot::component::{BootDispatcher, SimpleBootManager}; +use patina_boot::config::BootOptions; + +// In ComponentInfo::components(): +add.component(BootDispatcher::new(SimpleBootManager::from_options( + BootOptions::new() + .with_device(nvme_esp_path()) // Primary boot device + .with_device(nvme_recovery_path()) // Secondary (tried if primary fails) + .with_hotkey(0x16) // F12 + .with_hotkey_device(usb_device_path()) // Used when F12 is held + .with_failure_handler(|| show_error_screen("Boot failed")) +))); +``` + +This is sufficient to boot Windows. `SimpleBootManager` handles device enumeration, BDS event +signaling, hotkey detection, and boot execution automatically. `BootDispatcher` gates dispatch +until `Service` is available (after DXE dispatch completes). + +### UEFI-Compliant Usage (Phase 2) + +Platforms requiring full UEFI compliance add `BootOptionDiscovery` to read boot options from +`Boot####`/`BootOrder` variables instead of hardcoding device paths: + +```rust +use patina_boot::component::{BootDispatcher, SimpleBootManager}; + +// BootOptionDiscovery provides boot options; SimpleBootManager consumes them. +add.component(BootOptionDiscovery); +add.component(ConsoleDiscovery); +add.component(BootDispatcher::new(SimpleBootManager::default())); +``` + +`BootOptionDiscovery` reads `Boot####`/`BootOrder` variables and provides the boot option list to +`SimpleBootManager`. The `BootOrchestrator` trait and `BootDispatcher` component are unchanged — +`SimpleBootManager` executes boot options regardless of the source. + +### Custom Orchestration + +Platforms can implement the `BootOrchestrator` trait for specialized behavior and pass their +implementation to `BootDispatcher::new()`. See the Driver Dispatch section for an example custom +orchestrator with selective PCI-only enumeration. \ No newline at end of file