|
| 1 | +//! UEFI RAM Disk Protocol bindings (UEFI 2.10 §13.16). |
| 2 | +//! |
| 3 | +//! Used to install a contiguous range of system memory as a virtual block device the system |
| 4 | +//! firmware can boot from. The SRE flow uses this to boot the recovery WIM after reading it |
| 5 | +//! out of the NVMe boot partition into RAM. |
| 6 | +//! |
| 7 | +//! ## License |
| 8 | +//! |
| 9 | +//! Copyright (c) Microsoft Corporation. |
| 10 | +//! |
| 11 | +//! SPDX-License-Identifier: Apache-2.0 |
| 12 | +//! |
| 13 | +use r_efi::efi; |
| 14 | + |
| 15 | +use crate::uefi_protocol::ProtocolInterface; |
| 16 | + |
| 17 | +/// Well-known `RamDiskType` GUID for a generic virtual disk. |
| 18 | +pub const RAM_DISK_VIRTUAL_DISK_GUID: efi::Guid = |
| 19 | + efi::Guid::from_fields(0x77ab535a, 0x45fc, 0x624b, 0x55, 0x60, &[0xf7, 0xb2, 0x81, 0xd1, 0xf9, 0x6e]); |
| 20 | + |
| 21 | +/// Well-known `RamDiskType` GUID for a virtual CD (ISO9660) image. |
| 22 | +pub const RAM_DISK_VIRTUAL_CD_GUID: efi::Guid = |
| 23 | + efi::Guid::from_fields(0x3d5abd30, 0x4175, 0x87ce, 0x6d, 0x64, &[0xd2, 0xad, 0xe5, 0x23, 0xc4, 0xbb]); |
| 24 | + |
| 25 | +/// Well-known `RamDiskType` GUID for a persistent virtual disk. |
| 26 | +pub const RAM_DISK_PERSISTENT_VIRTUAL_DISK_GUID: efi::Guid = |
| 27 | + efi::Guid::from_fields(0x5cea02c9, 0x4d07, 0x69d3, 0x26, 0x9f, &[0x44, 0x96, 0xfb, 0xe0, 0x96, 0xf9]); |
| 28 | + |
| 29 | +/// Well-known `RamDiskType` GUID for a persistent virtual CD. |
| 30 | +pub const RAM_DISK_PERSISTENT_VIRTUAL_CD_GUID: efi::Guid = |
| 31 | + efi::Guid::from_fields(0x08018188, 0x42cd, 0xbb48, 0x10, 0x0f, &[0x53, 0x87, 0xd5, 0x3d, 0xed, 0x3d]); |
| 32 | + |
| 33 | +/// FFI type for `EFI_RAM_DISK_REGISTER_RAMDISK`. |
| 34 | +/// |
| 35 | +/// Installs a `[ram_disk_base, ram_disk_base + ram_disk_size)` memory range as a RAM disk of |
| 36 | +/// type `ram_disk_type`. When `parent_device_path` is null, the protocol creates a virtual |
| 37 | +/// device-path root; otherwise the new RAM disk is appended under the supplied path. On |
| 38 | +/// success the resulting device path is written to `*device_path` (caller-owned, do not free |
| 39 | +/// before calling `Unregister`). |
| 40 | +pub type RegisterFn = extern "efiapi" fn( |
| 41 | + ram_disk_base: u64, |
| 42 | + ram_disk_size: u64, |
| 43 | + ram_disk_type: *mut efi::Guid, |
| 44 | + parent_device_path: *mut efi::protocols::device_path::Protocol, |
| 45 | + device_path: *mut *mut efi::protocols::device_path::Protocol, |
| 46 | +) -> efi::Status; |
| 47 | + |
| 48 | +/// FFI type for `EFI_RAM_DISK_UNREGISTER_RAMDISK`. |
| 49 | +/// |
| 50 | +/// Removes a previously-installed RAM disk identified by the device path returned from |
| 51 | +/// `Register`. The backing memory is **not** freed by this call — the caller owns its |
| 52 | +/// lifetime. |
| 53 | +pub type UnregisterFn = extern "efiapi" fn(device_path: *mut efi::protocols::device_path::Protocol) -> efi::Status; |
| 54 | + |
| 55 | +/// FFI binding for `EFI_RAM_DISK_PROTOCOL` per UEFI 2.10 §13.16. |
| 56 | +#[repr(C)] |
| 57 | +pub struct Protocol { |
| 58 | + pub register: RegisterFn, |
| 59 | + pub unregister: UnregisterFn, |
| 60 | +} |
| 61 | + |
| 62 | +// SAFETY: Layout matches the UEFI 2.10 §13.16 protocol struct (two efiapi function pointers). |
| 63 | +// PROTOCOL_GUID matches the UEFI-spec value (AB38A0DF-6873-44A9-87E6-D4EB56148449). |
| 64 | +unsafe impl ProtocolInterface for Protocol { |
| 65 | + const PROTOCOL_GUID: crate::BinaryGuid = crate::BinaryGuid::from_string("AB38A0DF-6873-44A9-87E6-D4EB56148449"); |
| 66 | +} |
| 67 | + |
| 68 | +#[cfg(test)] |
| 69 | +mod tests { |
| 70 | + use super::*; |
| 71 | + use crate::uefi_protocol::ProtocolInterface; |
| 72 | + |
| 73 | + #[test] |
| 74 | + fn protocol_guid_matches_uefi_spec() { |
| 75 | + // EFI_RAM_DISK_PROTOCOL_GUID per UEFI 2.10 §13.16. |
| 76 | + let expected = |
| 77 | + efi::Guid::from_fields(0xab38a0df, 0x6873, 0x44a9, 0x87, 0xe6, &[0xd4, 0xeb, 0x56, 0x14, 0x84, 0x49]); |
| 78 | + assert_eq!( |
| 79 | + *Protocol::PROTOCOL_GUID.0.as_bytes(), |
| 80 | + *expected.as_bytes(), |
| 81 | + "RAM Disk protocol GUID must match UEFI 2.10 §13.16" |
| 82 | + ); |
| 83 | + } |
| 84 | + |
| 85 | + #[test] |
| 86 | + fn ram_disk_type_guids_are_distinct() { |
| 87 | + let virtual_disk = *RAM_DISK_VIRTUAL_DISK_GUID.as_bytes(); |
| 88 | + let virtual_cd = *RAM_DISK_VIRTUAL_CD_GUID.as_bytes(); |
| 89 | + let persistent = *RAM_DISK_PERSISTENT_VIRTUAL_DISK_GUID.as_bytes(); |
| 90 | + let persistent_cd = *RAM_DISK_PERSISTENT_VIRTUAL_CD_GUID.as_bytes(); |
| 91 | + |
| 92 | + assert_ne!(virtual_disk, virtual_cd); |
| 93 | + assert_ne!(virtual_disk, persistent); |
| 94 | + assert_ne!(virtual_disk, persistent_cd); |
| 95 | + assert_ne!(virtual_cd, persistent); |
| 96 | + assert_ne!(virtual_cd, persistent_cd); |
| 97 | + assert_ne!(persistent, persistent_cd); |
| 98 | + } |
| 99 | +} |
0 commit comments