diff --git a/output.txt b/output.txt new file mode 100644 index 000000000..d830c1842 --- /dev/null +++ b/output.txt @@ -0,0 +1,1362 @@ +run_cmd: 'cargo build --target x86_64-unknown-uefi --package uefi-test-runner --features uefi-test-runner/debug_support,uefi-test-runner/pxe,uefi-test-runner/multi_processor --bins --examples' +qemu-system-x86_64 -nodefaults -device virtio-rng-pci -boot menu=on,splash-time=0 -machine q35 -smp 4 -m 256M -vga std --enable-kvm -device isa-debug-exit,iobase=0xf4,iosize=0x04 -drive if=pflash,format=raw,readonly=on,file=target/ovmf/x86_64/code.fd -drive if=pflash,format=raw,readonly=off,file=/tmp/.tmpd4UNQx/ovmf_vars -drive format=raw,file=fat:rw:target/x86_64-unknown-uefi/debug/esp -drive format=raw,file=/tmp/.tmpd4UNQx/test_disk.fat.img -serial pipe:/tmp/.tmpd4UNQx/serial -qmp pipe:/tmp/.tmpd4UNQx/qemu-monitor -nic user,model=e1000,net=192.168.17.0/24,tftp=uefi-test-runner/tftp/,bootfile=fake-boot-file +BdsDxe: loading Boot0001 "UEFI QEMU HARDDISK QM00001 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0) +BdsDxe: starting Boot0001 "UEFI QEMU HARDDISK QM00001 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0) +[ INFO]: uefi-test-runner/src/bin/shell_launcher.rs@080: launching the shell app +UEFI Interactive Shell v2.2 +EDK II +UEFI v2.70 (EDK II, 0x00010000) +Mapping table + FS0: Alias(s):HD0a65535a1:;BLK1: + PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1) + FS1: Alias(s):HD0b65535a1:;BLK3: + PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x1,0xFFFF,0x0)/HD(1,MBR,0xFFFFFFFF,0x1,0x4FFF) + BLK0: Alias(s): + PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0) + BLK2: Alias(s): + PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x1,0xFFFF,0x0) +[ INFO]: uefi-test-runner/src/main.rs@029: Firmware Vendor: EDK II +Testing print! macro with formatting: 0b10011011 Testing println! macro with formatting: 0b10011011 +[ INFO]: uefi-test-runner/src/main.rs@072: UEFI 2.7 +[ INFO]: uefi-test-runner/src/boot/mod.rs@015: Testing boot services +[ INFO]: uefi-test-runner/src/boot/memory.rs@006: Testing memory functions +[ INFO]: uefi-test-runner/src/boot/memory.rs@016: Allocating some pages of memory +[ INFO]: uefi-test-runner/src/boot/memory.rs@039: Allocating a vector through the `alloc` crate +[ INFO]: uefi-test-runner/src/boot/memory.rs@051: Allocating a structure with alignment to 0x100 +[ INFO]: uefi-test-runner/src/boot/memory.rs@061: Testing memory map functions +[ INFO]: uefi-test-runner/src/boot/misc.rs@011: Testing timer... +[ INFO]: uefi-test-runner/src/boot/misc.rs@013: Testing events... +[ INFO]: uefi-test-runner/src/boot/misc.rs@038: Inside the event callback +[ INFO]: uefi-test-runner/src/boot/misc.rs@051: Inside the event callback with context +[ INFO]: uefi-test-runner/src/boot/misc.rs@016: Testing watchdog... +[ INFO]: uefi-test-runner/src/boot/misc.rs@018: Testing protocol handler services... +[ INFO]: uefi-test-runner/src/boot/misc.rs@110: Installing TestProtocol +[ INFO]: uefi-test-runner/src/boot/misc.rs@090: Protocol was (re)installed and this function notified. +[ INFO]: uefi-test-runner/src/boot/misc.rs@123: Reinstalling TestProtocol +[ INFO]: uefi-test-runner/src/boot/misc.rs@090: Protocol was (re)installed and this function notified. +[ INFO]: uefi-test-runner/src/boot/misc.rs@139: Uninstalling TestProtocol +[ INFO]: uefi-test-runner/src/boot/mod.rs@023: Testing the `locate_handle_buffer` function +[ INFO]: uefi-test-runner/src/boot/mod.rs@054: Testing the `load_image` function +[DEBUG]: uefi-test-runner/src/boot/mod.rs@095: load_image with FromBuffer strategy works +[DEBUG]: uefi-test-runner/src/boot/mod.rs@114: load_image with FromFilePath strategy works +[ INFO]: uefi-test-runner/src/proto/mod.rs@007: Testing various protocols +[ INFO]: uefi-test-runner/src/proto/console/mod.rs@004: Testing console protocols +[ INFO]: uefi-test-runner/src/proto/console/stdout.rs@005: Running text output protocol test +[ INFO]: uefi-test-runner/src/proto/console/stdout.rs@029: UEFI standard output current mode: Some(OutputMode { index: 0, dims: (80, 25) }) +[ INFO]: uefi-test-runner/src/proto/console/stdout.rs@061: # uefi-rs test runner +[ INFO]: uefi-test-runner/src/proto/console/stdout.rs@065: Cursor visibility control unavailable +[ INFO]: uefi-test-runner/src/proto/console/stdout.rs@014: - Text mode #0: 25 rows by 80 columns +[ INFO]: uefi-test-runner/src/proto/console/stdout.rs@014: - Text mode #1: 31 rows by 100 columns +[ INFO]: uefi-test-runner/src/proto/console/serial.rs@050: Running serial protocol test +[ INFO]: uefi-test-runner/src/proto/console/gop.rs@007: Running graphics output protocol test +[ INFO]: uefi-test-runner/src/proto/console/pointer.rs@005: Running pointer protocol test +[ INFO]: uefi-test-runner/src/proto/console/pointer.rs@024: Pointer state has not changed since the last query +[ INFO]: uefi-test-runner/src/proto/mod.rs@052: Image handle has 3 protocols +[ INFO]: uefi-test-runner/src/proto/debug.rs@074: Running UEFI debug connection protocol test +[ INFO]: uefi-test-runner/src/proto/debug.rs@088: - Architecture: EBC +[ INFO]: uefi-test-runner/src/proto/debug.rs@089: - Maximum Processor Index: 0 +[ INFO]: uefi-test-runner/src/proto/debug.rs@096: Registering periodic callback +[ INFO]: uefi-test-runner/src/proto/debug.rs@100: Deregistering periodic callback +[ INFO]: uefi-test-runner/src/proto/debug.rs@105: Deregistering exception callback +[ INFO]: uefi-test-runner/src/proto/debug.rs@109: Registering exception callback +[ INFO]: uefi-test-runner/src/proto/debug.rs@159: Invalidating instruction cache +[ INFO]: uefi-test-runner/src/proto/debug.rs@012: Running UEFI debug port protocol test +[ INFO]: uefi-test-runner/src/proto/device_path.rs@010: Running device path protocol test +[ INFO]: uefi-test-runner/src/proto/device_path.rs@037: path: type=ACPI, subtype=DeviceSubType(1), length=12 +[ INFO]: uefi-test-runner/src/proto/device_path.rs@048: path name: PciRoot(0x0) +[ INFO]: uefi-test-runner/src/proto/device_path.rs@037: path: type=HARDWARE, subtype=DeviceSubType(1), length=6 +[ INFO]: uefi-test-runner/src/proto/device_path.rs@048: path name: Pci(0x1F,0x2) +[ INFO]: uefi-test-runner/src/proto/device_path.rs@037: path: type=MESSAGING, subtype=DeviceSubType(18), length=10 +[ INFO]: uefi-test-runner/src/proto/device_path.rs@048: path name: Sata(0x0,0xFFFF,0x0) +[ INFO]: uefi-test-runner/src/proto/device_path.rs@037: path: type=MEDIA, subtype=DeviceSubType(1), length=42 +[ INFO]: uefi-test-runner/src/proto/device_path.rs@048: path name: HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1) +[ INFO]: uefi-test-runner/src/proto/driver.rs@142: Running component name test +[ INFO]: uefi-test-runner/src/proto/loaded_image.rs@006: Running loaded image protocol test +[ INFO]: uefi-test-runner/src/proto/loaded_image.rs@013: LoadedImage options: Some([116, 0, 101, 0, 115, 0, 116, 0, 95, 0, 114, 0, 117, 0, 110, 0, 110, 0, 101, 0, 114, 0, 46, 0, 101, 0, 102, 0, 105, 0, 32, 0, 97, 0, 114, 0, 103, 0, 49, 0, 32, 0, 97, 0, 114, 0, 103, 0, 50, 0, 0, 0]) +[ INFO]: uefi-test-runner/src/proto/loaded_image.rs@016: LoadedImage image address: 0xdd7a000, image size: 733184 bytes +[ INFO]: uefi-test-runner/src/proto/media.rs@020: Testing existing directory +[ INFO]: uefi-test-runner/src/proto/media.rs@109: Testing existing file +[ INFO]: uefi-test-runner/src/proto/media.rs@123: Successfully read test_dir\test_input.txt +[ INFO]: uefi-test-runner/src/proto/media.rs@181: Testing file creation +[ INFO]: uefi-test-runner/src/proto/media.rs@203: Testing directory creation +[ INFO]: uefi-test-runner/src/proto/media.rs@354: MBR partition: MbrPartitionRecord { boot_indicator: 0, starting_chs: [0, 0, 0], os_type: MbrOsType(6), ending_chs: [0, 0, 0], starting_lba: 1, size_in_lba: 20479 } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file foo_dir\foo: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file \foo_dir\foo_cpy: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file foo_dir\foo_cpy2: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file foo_dir\foo_cpy: Error { status: NOT_FOUND, data: () } +[DEBUG]: uefi/src/fs/file_system/fs.rs@159: parent=foo_dir\1\2\3\4\5\6 +[DEBUG]: uefi/src/fs/file_system/fs.rs@159: parent=foo_dir\1\2\3\4\5 +[DEBUG]: uefi/src/fs/file_system/fs.rs@159: parent=foo_dir\1\2\3\4 +[DEBUG]: uefi/src/fs/file_system/fs.rs@159: parent=foo_dir\1\2\3 +[DEBUG]: uefi/src/fs/file_system/fs.rs@159: parent=foo_dir\1\2 +[DEBUG]: uefi/src/fs/file_system/fs.rs@159: parent=foo_dir\1 +[DEBUG]: uefi/src/fs/file_system/fs.rs@159: parent=foo_dir +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file foo_dir\1: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file foo_dir\1\2: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file foo_dir\1\2\3: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file foo_dir\1\2\3\4: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file foo_dir\1\2\3\4\5: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file foo_dir\1\2\3\4\5\6: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file foo_dir\1\2\3\4\5\6\7: Error { status: NOT_FOUND, data: () } +[DEBUG]: uefi/src/fs/file_system/fs.rs@159: parent=foo_dir\1\2\3\4\5\6\7 +[DEBUG]: uefi/src/fs/file_system/fs.rs@159: parent=foo_dir\1\2\3\4\5\6 +[DEBUG]: uefi/src/fs/file_system/fs.rs@159: parent=foo_dir\1\2\3\4\5 +[DEBUG]: uefi/src/fs/file_system/fs.rs@159: parent=foo_dir\1\2\3\4 +[DEBUG]: uefi/src/fs/file_system/fs.rs@159: parent=foo_dir\1\2\3 +[DEBUG]: uefi/src/fs/file_system/fs.rs@159: parent=foo_dir\1\2 +[DEBUG]: uefi/src/fs/file_system/fs.rs@159: parent=foo_dir\1 +[DEBUG]: uefi/src/fs/file_system/fs.rs@159: parent=foo_dir +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file foo_dir\1\2\3\4\5\6\7\8: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file foo_dir\1\2\3\4\5\6\7\8\foobar: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file foo_dir\1: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file file1: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file src: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file file1: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file file2: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file file2: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file file1: Error { status: NOT_FOUND, data: () } +[TRACE]: uefi/src/fs/file_system/fs.rs@424: Can't open file file2: Error { status: NOT_FOUND, data: () } +[ INFO]: uefi-test-runner/src/proto/media.rs@267: Testing raw disk I/O +[ INFO]: uefi-test-runner/src/proto/media.rs@286: Raw disk I/O succeeded +[ INFO]: uefi-test-runner/src/proto/media.rs@300: Testing raw disk I/O 2 +[ INFO]: uefi-test-runner/src/proto/media.rs@341: Raw disk I/O 2 succeeded +[ INFO]: uefi-test-runner/src/proto/network/mod.rs@004: Testing Network protocols +[ INFO]: uefi-test-runner/src/proto/network/pxe.rs@012: Testing The PXE base code protocol +[ INFO]: uefi-test-runner/src/proto/network/pxe.rs@020: Starting PXE Base Code + +>>Start PXE over IPv4 + Station IP address is 192.168.17.15 +[ INFO]: uefi-test-runner/src/proto/network/pxe.rs@037: Getting remote file size +[ INFO]: uefi-test-runner/src/proto/network/pxe.rs@043: Reading remote file +[ INFO]: uefi-test-runner/src/proto/network/pxe.rs@057: Writing UDP packet to example service +[ INFO]: uefi-test-runner/src/proto/network/pxe.rs@075: Reading UDP packet from example service +[ INFO]: uefi-test-runner/src/proto/network/pxe.rs@111: Stopping PXE Base Code +[ INFO]: uefi-test-runner/src/proto/network/snp.rs@007: Testing the simple network protocol +[ INFO]: uefi-test-runner/src/proto/network/snp.rs@091: Waiting for the transmit +[ INFO]: uefi-test-runner/src/proto/network/snp.rs@101: Waiting for the reception +[ INFO]: uefi-test-runner/src/proto/network/snp.rs@118: Stats: NetworkStats { rx_total_frames: 1, rx_good_frames: 1, rx_undersize_frames: 0, rx_oversize_frames: 0, rx_dropped_frames: 0, rx_unicast_frames: 0, rx_broadcast_frames: 0, rx_multicast_frames: 0, rx_crc_error_frames: 0, rx_total_bytes: 0, tx_total_frames: 1, tx_good_frames: 1, tx_undersize_frames: 0, tx_oversize_frames: 0, tx_dropped_frames: 0, tx_unicast_frames: 0, tx_broadcast_frames: 0, tx_multicast_frames: 0, tx_crc_error_frames: 0, tx_total_bytes: 0, collisions: 0, unsupported_protocol: 0, rx_duplicated_frames: 0, rx_decrypt_error_frames: 0, tx_error_frames: 0, tx_retry_frames: 0 } +[ INFO]: uefi-test-runner/src/proto/pi/mod.rs@004: Testing Platform Initialization protocols +[ INFO]: uefi-test-runner/src/proto/pi/mp.rs@019: Running UEFI multi-processor services protocol test +[ INFO]: uefi-test-runner/src/proto/pi/mp.rs@098: After proc_increment atomic: 0 +[ INFO]: uefi-test-runner/src/proto/pi/mp.rs@030: After startup all: 3 +[ INFO]: uefi-test-runner/src/proto/pi/mp.rs@032: After startup this: 6 +[ INFO]: uefi-test-runner/src/proto/pi/mp.rs@034: Enable/Disable: 6 +[ INFO]: uefi-test-runner/src/proto/pi/mp.rs@036: Boot Services Processor & who am i: 6 +[ INFO]: uefi-test-runner/src/proto/rng.rs@005: Running rng protocol test +[ INFO]: uefi-test-runner/src/proto/rng.rs@016: Supported rng algorithms : [ALGORITHM_RAW] +[ INFO]: uefi-test-runner/src/proto/rng.rs@023: Random buffer : [149, 11, 0, 24] +[ INFO]: uefi-test-runner/src/proto/shell_params.rs@008: Running loaded image protocol test +[ INFO]: uefi-test-runner/src/proto/string/mod.rs@004: Testing String protocols +[ INFO]: uefi-test-runner/src/proto/string/unicode_collation.rs@007: Testing the Unicode Collation protocol +[ INFO]: uefi-test-runner/src/proto/shim.rs@005: Running shim lock protocol test +[ INFO]: uefi-test-runner/src/proto/shim.rs@019: Shim lock protocol is not supported +[ INFO]: uefi-test-runner/src/main.rs@062: Boot handle count: 6 +[ INFO]: uefi-test-runner/src/runtime/mod.rs@004: Testing runtime services +[ INFO]: uefi-test-runner/src/runtime/vars.rs@014: Testing set_variable +[ INFO]: uefi-test-runner/src/runtime/vars.rs@018: Testing get_variable_size +[ INFO]: uefi-test-runner/src/runtime/vars.rs@024: Testing get_variable +[ INFO]: uefi-test-runner/src/runtime/vars.rs@032: Testing get_variable_boxed +[ INFO]: uefi-test-runner/src/runtime/vars.rs@039: Testing variable_keys +[ INFO]: uefi-test-runner/src/runtime/vars.rs@041: Found 56 variables +[ INFO]: uefi-test-runner/src/runtime/vars.rs@045: First variable: VariableKey { name: "OsIndicationsSupported", vendor: GLOBAL_VARIABLE } +[ INFO]: uefi-test-runner/src/runtime/vars.rs@048: Testing delete_variable() +[ INFO]: uefi-test-runner/src/runtime/vars.rs@060: Storage for non-volatile boot-services variables: VariableStorageInfo { maximum_variable_storage_size: 262044, remaining_variable_storage_size: 250480, maximum_variable_size: 33732 } +[ INFO]: uefi-test-runner/src/runtime/vars.rs@067: Storage for volatile runtime variables: VariableStorageInfo { maximum_variable_storage_size: 262116, remaining_variable_storage_size: 257308, maximum_variable_size: 33732 } +[ INFO]: uefi-test-runner/src/main.rs@161: Testing complete, shutting down... +[PANIC]: panicked at uefi/src/boot/mod.rs:192:9: +assertion `left == right` failed: this must be the only boot handle remaining + left: 7 + right: 1 +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active or are exiting +[PANIC]: panicked at uefi/src/table/boot.rs:938:9: +boot services are not active BdsDxe: loading Boot0001 "UEFI QEMU HARDDISK QM00001 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0) +BdsDxe: starting Boot0001 "UEFI QEMU HARDDISK QM00001 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0) +[ INFO]: uefi-test-runner/src/bin/shell_launcher.rs@080: launching the shell app +UEFI Interactive Shell v2.2 +EDK II +UEFI v2.70 (EDK II, 0x00010000) +Mapping table + FS0: Alias(s):HD0a65535a1:;BLK1: + PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1) + FS1: Alias(s):HD0b65535a1:;BLK3: + PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x1,0xFFFF,0x0)/HD(1,MBR,0xFFFFFFFF,0x1,0x4FFF) + BLK0: Alias(s): + PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0) + BLK2: Alias(s): + PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x1,0xFFFF,0x0) +[ INFO]: uefi-test-runner/src/main.rs@029: Firmware Vendor: EDK II +Testing print! macro with formatting: 0b10011011 Testing println! macro with formatting: 0b10011011 +[ INFO]: uefi-test-runner/src/main.rs@072: UEFI 2.7 +[ INFO]: uefi-test-runner/src/boot/mod.rs@015: Testing boot services +[ INFO]: uefi-test-runner/src/boot/memory.rs@006: Testing memory functions +[ INFO]: uefi-test-runner/src/boot/memory.rs@016: Allocating some pages of memory +[ INFO]: uefi-test-runner/src/boot/memory.rs@039: Allocating a vector through the `alloc` crate +[ INFO]: uefi-test-runner/src/boot/memory.rs@051: Allocating a structure with alignment to 0x100 +[ INFO]: uefi-test-runner/src/boot/memory.rs@061: Testing memory map functions +[ INFO]: uefi-test-runner/src/boot/misc.rs@011: Testing timer... +[ INFO]: uefi-test-runner/src/boot/misc.rs@013: Testing events... +[ INFO]: uefi-test-runner/src/boot/misc.rs@038: Inside the event callback +[ INFO]: uefi-test-runner/src/boot/misc.rs@051: Inside the event callback with context +[ INFO]: uefi-test-runner/src/boot/misc.rs@016: Testing watchdog... +[ INFO]: uefi-test-runner/src/boot/misc.rs@018: Testing protocol handler services... +[ INFO]: uefi-test-runner/src/boot/misc.rs@110: Installing TestProtocol +[ INFO]: uefi-test-runner/src/boot/misc.rs@090: Protocol was (re)installed and this function notified. +[ INFO]: uefi-test-runner/src/boot/misc.rs@123: Reinstalling TestProtocol +[ INFO]: uefi-test-runner/src/boot/misc.rs@090: Protocol was (re)installed and this function notified. +[ INFO]: uefi-test-runner/src/boot/misc.rs@139: Uninstalling TestProtocol +[ INFO]: uefi-test-runner/src/boot/mod.rs@023: Testing the `locate_handle_buffer` function +[ INFO]: uefi-test-runner/src/boot/mod.rs@054: Testing the `load_image` function +[DEBUG]: uefi-test-runner/src/boot/mod.rs@095: load_image with FromBuffer strategy works +[DEBUG]: uefi-test-runner/src/boot/mod.rs@114: load_image with FromFilePath strategy works +[ INFO]: uefi-test-runner/src/proto/mod.rs@007: Testing various protocols +[ INFO]: uefi-test-runner/src/proto/console/mod.rs@004: Testing console protocols +[ INFO]: uefi-test-runner/src/proto/console/stdout.rs@005: Running text output protocol test +[ INFO]: uefi-test-runner/src/proto/console/stdout.rs@029: UEFI standard output current mode: Some(OutputMode { index: 0, dims: (80, 25) }) +[ INFO]: uefi-test-runner/src/proto/console/stdout.rs@061: # uefi-rs test runner +[ INFO]: uefi-test-runner/src/proto/console/stdout.rs@065: Cursor visibility control unavailable +[ INFO]: uefi-test-runner/src/proto/console/stdout.rs@014: - Text mode #0: 25 rows by 80 columns +[ INFO]: uefi-test-runner/src/proto/console/stdout.rs@014: - Text mode #1: 31 rows by 100 columns +[ INFO]: uefi-test-runner/src/proto/console/serial.rs@050: Running serial protocol test +[ INFO]: uefi-test-runner/src/proto/console/gop.rs@007: Running graphics output protocol test +[ INFO]: uefi-test-runner/src/proto/console/pointer.rs@005: Running pointer protocol test +[ INFO]: uefi-test-runner/src/proto/console/pointer.rs@024: Pointer state has not changed since the last query +[ INFO]: uefi-test-runner/src/proto/mod.rs@052: Image handle has 3 protocols +[ INFO]: uefi-test-runner/src/proto/debug.rs@074: Running UEFI debug connection protocol test +[ INFO]: uefi-test-runner/src/proto/debug.rs@088: - Architecture: EBC +[ INFO]: uefi-test-runner/src/proto/debug.rs@089: - Maximum Processor Index: 0 +[ INFO]: uefi-test-runner/src/proto/debug.rs@096: Registering periodic callback +[ INFO]: uefi-test-runner/src/proto/debug.rs@100: Deregistering periodic callback +[ INFO]: uefi-test-runner/src/proto/debug.rs@105: Deregistering exception callback +[ INFO]: uefi-test-runner/src/proto/debug.rs@109: Registering exception callback +[ INFO]: uefi-test-runner/src/proto/debug.rs@159: Invalidating instruction cache +[ INFO]: uefi-test-runner/src/proto/debug.rs@012: Running UEFI debug port protocol test +[ INFO]: uefi-test-runner/src/proto/device_path.rs@010: Running device path protocol test +[ INFO]: uefi-test-runner/src/proto/device_path.rs@037: path: type=ACPI, subtype=DeviceSubType(1), length=12 +[ INFO]: uefi-test-runner/src/proto/device_path.rs@048: path name: PciRoot(0x0) +[ INFO]: uefi-test-runner/src/proto/device_path.rs@037: path: type=HARDWARE, subtype=DeviceSubType(1), length=6 +[ INFO]: uefi-test-runner/src/proto/device_path.rs@048: path name: Pci(0x1F,0x2) +[ INFO]: uefi-test-runner/src/proto/device_path.rs@037: path: type=MESSAGING, subtype=DeviceSubType(18), length=10 +[ INFO]: uefi-test-runner/src/proto/device_path.rs@048: path name: Sata(0x0,0xFFFF,0x0) +[ INFO]: uefi-test-runner/src/proto/device_path.rs@037: path: type=MEDIA, subtype=DeviceSubType(1), length=42 +[ INFO]: uefi-test-runner/src/proto/device_path.rs@048: path name: HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1) +[ INFO]: uefi-test-runner/src/proto/driver.rs@142: Running component name test +[ INFO]: uefi-test-runner/src/proto/loaded_image.rs@006: Running loaded image protocol test +[ INFO]: uefi-test-runner/src/proto/loaded_image.rs@013: LoadedImage options: Some([116, 0, 101, 0, 115, 0, 116, 0, 95, 0, 114, 0, 117, 0, 110, 0, 110, 0, 101, 0, 114, 0, 46, 0, 101, 0, 102, 0, 105, 0, 32, 0, 97, 0, 114, 0, 103, 0, 49, 0, 32, 0, 97, 0, 114, 0, 103, 0, 50, 0, 0, 0]) +[ INFO]: uefi-test-runner/src/proto/loaded_image.rs@016: LoadedImage image address: 0xdd7a000, image size: 733184 bytes +[PANIC]: panicked at uefi-test-runner/src/proto/media.rs:416:9: +assertion `left == right` failed + left: 10420224 + right: 10425344 diff --git a/uefi-macros/src/lib.rs b/uefi-macros/src/lib.rs index 971bf2c9f..1659db01c 100644 --- a/uefi-macros/src/lib.rs +++ b/uefi-macros/src/lib.rs @@ -209,6 +209,17 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { ); } + if let Some(ref system_table_ident) = system_table_ident { + f.block.stmts.insert( + 0, + parse_quote! { + unsafe { + #system_table_ident.set_global_system_table(); + } + }, + ); + } + let fn_ident = &f.sig.ident; // Get an iterator of the function inputs types. This is needed instead of // directly using `sig.inputs` because patterns you can use in fn items like diff --git a/uefi-test-runner/examples/shell_params.rs b/uefi-test-runner/examples/shell_params.rs index 1491fdf83..eb9beb092 100644 --- a/uefi-test-runner/examples/shell_params.rs +++ b/uefi-test-runner/examples/shell_params.rs @@ -6,7 +6,8 @@ use log::error; // ANCHOR: use -use uefi::{prelude::*, proto::shell_params::ShellParameters}; +use uefi::prelude::*; +use uefi::proto::shell_params::ShellParameters; use uefi_services::println; extern crate alloc; diff --git a/uefi-test-runner/src/main.rs b/uefi-test-runner/src/main.rs index 4392c735c..7938d2694 100644 --- a/uefi-test-runner/src/main.rs +++ b/uefi-test-runner/src/main.rs @@ -59,6 +59,8 @@ fn efi_main(image: Handle, mut st: SystemTable) -> Status { // probably want to test them after exit_boot_services. However, // exit_boot_services is currently called during shutdown. + log::info!("Boot handle count: {}", uefi::boot::check_count()); + runtime::test(st.runtime_services()); shutdown(st); diff --git a/uefi-test-runner/src/proto/console/gop.rs b/uefi-test-runner/src/proto/console/gop.rs index d0fd2946f..c8c80e2c1 100644 --- a/uefi-test-runner/src/proto/console/gop.rs +++ b/uefi-test-runner/src/proto/console/gop.rs @@ -22,7 +22,7 @@ pub unsafe fn test(image: Handle, bt: &BootServices) { ) .expect("failed to open Graphics Output Protocol"); - set_graphics_mode(gop, bt); + set_graphics_mode(gop); fill_color(gop); draw_fb(gop); @@ -33,10 +33,10 @@ pub unsafe fn test(image: Handle, bt: &BootServices) { } // Set a larger graphics mode. -fn set_graphics_mode(gop: &mut GraphicsOutput, bs: &BootServices) { +fn set_graphics_mode(gop: &mut GraphicsOutput) { // We know for sure QEMU has a 1024x768 mode. let mode = gop - .modes(bs) + .modes() .find(|mode| { let info = mode.info(); info.resolution() == (1024, 768) diff --git a/uefi-test-runner/src/proto/pi/mp.rs b/uefi-test-runner/src/proto/pi/mp.rs index f40fe5ea4..22978ab68 100644 --- a/uefi-test-runner/src/proto/pi/mp.rs +++ b/uefi-test-runner/src/proto/pi/mp.rs @@ -27,9 +27,16 @@ pub fn test(bt: &BootServices) { test_get_number_of_processors(mp_support); test_get_processor_info(mp_support); test_startup_all_aps(mp_support, bt); + log::info!("After startup all: {}", uefi::boot::check_count()); test_startup_this_ap(mp_support, bt); + log::info!("After startup this: {}", uefi::boot::check_count()); test_enable_disable_ap(mp_support); + log::info!("Enable/Disable: {}", uefi::boot::check_count()); test_switch_bsp_and_who_am_i(mp_support); + log::info!( + "Boot Services Processor & who am i: {}", + uefi::boot::check_count() + ); } fn test_get_number_of_processors(mps: &MpServices) { @@ -88,6 +95,8 @@ fn test_startup_all_aps(mps: &MpServices, bt: &BootServices) { .unwrap(); assert_eq!(counter.load(Ordering::Relaxed), NUM_CPUS - 1); + log::info!("After proc_increment atomic: {}", uefi::boot::check_count()); + // Make sure that timeout works let bt_ptr: *mut c_void = bt as *const _ as *mut _; let ret = mps.startup_all_aps( diff --git a/uefi/src/allocator.rs b/uefi/src/allocator.rs index cf9153373..69a7df3dd 100644 --- a/uefi/src/allocator.rs +++ b/uefi/src/allocator.rs @@ -2,60 +2,30 @@ //! //! If the `global_allocator` feature is enabled, the [`Allocator`] will be used //! as the global Rust allocator. -//! -//! # Usage -//! -//! Call the `init` function with a reference to the boot services table. -//! Failure to do so before calling a memory allocating function will panic. -//! -//! Call the `exit_boot_services` function before exiting UEFI boot services. -//! Failure to do so will turn subsequent allocation into undefined behaviour. use core::alloc::{GlobalAlloc, Layout}; -use core::ptr::{self, NonNull}; +use core::ptr; +use crate::boot::{allocate_pool, free_pool, image_handle, open_protocol_exclusive}; use crate::proto::loaded_image::LoadedImage; use crate::table::boot::{BootServices, MemoryType}; -/// Reference to the boot services table, used to call the pool memory allocation functions. -/// -/// The inner pointer is only safe to dereference if UEFI boot services have not been -/// exited by the host application yet. -static mut BOOT_SERVICES: Option> = None; - /// The memory type used for pool memory allocations. /// TODO: Use OnceCell when stablilized. static mut MEMORY_TYPE: MemoryType = MemoryType::LOADER_DATA; /// Initializes the allocator. -/// -/// # Safety -/// -/// This function is unsafe because you _must_ make sure that exit_boot_services -/// will be called when UEFI boot services will be exited. -pub unsafe fn init(boot_services: &BootServices) { - BOOT_SERVICES = NonNull::new(boot_services as *const _ as *mut _); - - if let Ok(loaded_image) = - boot_services.open_protocol_exclusive::(boot_services.image_handle()) - { - MEMORY_TYPE = loaded_image.data_type() +pub fn init(_boot_services: &BootServices) { + if let Ok(loaded_image) = open_protocol_exclusive::(image_handle()) { + unsafe { MEMORY_TYPE = loaded_image.data_type() } } } -/// Access the boot services -fn boot_services() -> NonNull { - unsafe { BOOT_SERVICES.expect("Boot services are unavailable or have been exited") } -} - /// Notify the allocator library that boot services are not safe to call anymore /// -/// You must arrange for this function to be called on exit from UEFI boot services -pub fn exit_boot_services() { - unsafe { - BOOT_SERVICES = None; - } -} +/// No longer needs to be called. +#[deprecated] +pub fn exit_boot_services() {} /// Allocator which uses the UEFI pool allocation functions. /// @@ -64,7 +34,7 @@ pub fn exit_boot_services() { pub struct Allocator; unsafe impl GlobalAlloc for Allocator { - /// Allocate memory using [`BootServices::allocate_pool`]. The allocation is + /// Allocate memory using [`allocate_pool`]. The allocation is /// of type [`MemoryType::LOADER_DATA`] for UEFI applications, [`MemoryType::BOOT_SERVICES_DATA`] /// for UEFI boot drivers and [`MemoryType::RUNTIME_SERVICES_DATA`] for UEFI runtime drivers. unsafe fn alloc(&self, layout: Layout) -> *mut u8 { @@ -76,10 +46,7 @@ unsafe impl GlobalAlloc for Allocator { // only guaranteed to provide eight-byte alignment. Allocate extra // space so that we can return an appropriately-aligned pointer // within the allocation. - let full_alloc_ptr = if let Ok(ptr) = boot_services() - .as_ref() - .allocate_pool(MEMORY_TYPE, size + align) - { + let full_alloc_ptr = if let Ok(ptr) = allocate_pool(MEMORY_TYPE, size + align) { ptr } else { return ptr::null_mut(); @@ -108,21 +75,18 @@ unsafe impl GlobalAlloc for Allocator { // The requested alignment is less than or equal to eight, and // `allocate_pool` always provides eight-byte alignment, so we can // use `allocate_pool` directly. - boot_services() - .as_ref() - .allocate_pool(MEMORY_TYPE, size) - .unwrap_or(ptr::null_mut()) + allocate_pool(MEMORY_TYPE, size).unwrap_or(ptr::null_mut()) } } - /// Deallocate memory using [`BootServices::free_pool`]. + /// Deallocate memory using [`free_pool`]. unsafe fn dealloc(&self, mut ptr: *mut u8, layout: Layout) { if layout.align() > 8 { // Retrieve the pointer to the full allocation that was packed right // before the aligned allocation in `alloc`. ptr = (ptr as *const *mut u8).sub(1).read(); } - boot_services().as_ref().free_pool(ptr).unwrap(); + free_pool(ptr).unwrap(); } } diff --git a/uefi/src/boot/mod.rs b/uefi/src/boot/mod.rs new file mode 100644 index 000000000..b7b018164 --- /dev/null +++ b/uefi/src/boot/mod.rs @@ -0,0 +1,2255 @@ +//! UEFI services available during boot. +//! +//! There are two ways to call all boot services except [`exit_boot_services`]. +//! - Utilize a [`BootHandle`], which can be acquired by calling [`acquire_boot_handle`] +//! or cloning an existing [`BootHandle`]. +//! - Utilize a function, which are all avialable through this module. + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; +use core::cell::UnsafeCell; +use core::ffi::c_void; +use core::mem::{self, MaybeUninit}; +use core::ops::{Deref, DerefMut}; +use core::ptr::{self, NonNull}; +use core::slice; +use core::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering}; + +use uefi_raw::table::boot::{EventType, MemoryType, Tpl}; +use uefi_raw::{PhysicalAddress, Status}; +use uguid::Guid; + +use crate::proto::device_path::DevicePath; +use crate::proto::media::fs::SimpleFileSystem; +use crate::proto::{Protocol, ProtocolPointer}; +use crate::system::system_table; +use crate::table::boot::{ + AllocateType, EventNotifyFn, LoadImageSource, MemoryMap, MemoryMapKey, MemoryMapSize, + OpenProtocolAttributes, OpenProtocolParams, SearchType, TimerTrigger, +}; +use crate::{Char16, Event, Handle, Result}; + +use self::raw::{ + allocate_pages_raw, allocate_pool_raw, check_event_raw, close_event_raw, + connect_controller_raw, create_event_ex_raw, create_event_raw, disconnect_controller_raw, + exit_boot_services_raw, exit_raw, free_pages_raw, free_pool_raw, get_handle_for_protocol_raw, + get_image_file_system_raw, install_configuration_table_raw, install_protocol_interface_raw, + load_image_raw, locate_device_path_raw, locate_handle_buffer_raw, locate_handle_raw, + memory_map_raw, memory_map_size_raw, open_protocol_exclusive_raw, open_protocol_raw, + protocols_per_handle_raw, raise_tpl_raw, register_protocol_notify_raw, + reinstall_protocol_interface_raw, set_timer_raw, set_watchdog_timer_raw, signal_event_raw, + stall_raw, start_image_raw, test_protocol_raw, uninstall_protocol_interface_raw, + unload_image_raw, wait_for_event_raw, +}; + +mod raw; + +static IMAGE_HANDLE: AtomicPtr = AtomicPtr::new(ptr::null_mut()); + +/// The reference counter for [`BootHandle`]s, which allows safe exiting from +/// boot services using a global design. +static BOOT_HANDLE_COUNT: AtomicUsize = AtomicUsize::new(0); + +/// Set to true when [`exit_boot_services`] is called. +/// +/// This causes all calls to [`acquire_boot_handle`] to fail, +/// but clone [`BootHandle`]s is still allowed. +static EXITING_BOOT: AtomicBool = AtomicBool::new(false); + +pub(crate) fn boot_services_maybe_null() -> *mut uefi_raw::table::boot::BootServices { + let system_table = unsafe { system_table().as_ref() }; + + system_table.boot_services +} + +pub(crate) fn boot_services() -> NonNull { + NonNull::new(boot_services_maybe_null()).expect("boot services are not active") +} + +/// Returns whether boot services have exited yet. +pub fn exited_boot_services() -> bool { + EXITING_BOOT.load(Ordering::Relaxed) +} + +/// Returns a boot handle. +#[track_caller] +pub fn acquire_boot_handle() -> BootHandle { + BOOT_HANDLE_COUNT.fetch_add(1, Ordering::Relaxed); + + if EXITING_BOOT.load(Ordering::Relaxed) { + BOOT_HANDLE_COUNT.fetch_sub(1, Ordering::Relaxed); + panic!("boot services are not active or are exiting"); + } + + BootHandle(boot_services()) +} + +/// Returns the number of [`BootHandle`]s currently existing. +pub fn check_count() -> usize { + BOOT_HANDLE_COUNT.load(Ordering::Relaxed) +} + +/// Updates the global image [`Handle`]. +/// +/// This is called automatically in the `main` entry point as part of +/// [`uefi_macros::entry`]. It should not be called at any other point in time, +/// unless the executable does not use [`uefi_macros::entry`], in which case it +/// should be called once before calling other `boot` functions. +/// +/// # Safety +/// +/// This function should be only called as described above, and the `image_handle` +/// must be a valid image [`Handle`]. Then the safety guarantees of +/// [`open_protocol_exclusive`] will be correct. +pub unsafe fn set_image_handle(image_handle: Handle) { + IMAGE_HANDLE.store(image_handle.as_ptr(), Ordering::Relaxed) +} + +/// Get the [`Handle`] of the currently-executing image. +pub fn image_handle() -> Handle { + // SAFETY: + // If this pointer is not null, then by the invariants of `set_image_handle`, + // the value loaded from `IMAGE_HANDLE` is a valid handle. + unsafe { + Handle::from_ptr(IMAGE_HANDLE.load(Ordering::Relaxed)) + .expect("set_image_handle has not been called") + } +} + +/// A handle to all of the boot services. +/// +/// # Accessing `BootServices` +/// +/// A [`BootHandle`] can only be obtained by calling [`acquire_boot_handle`] +/// or cloning an existing [`BootHandle`]. +#[derive(Debug)] +#[repr(transparent)] +pub struct BootHandle(NonNull); + +impl BootHandle { + /// Get the [`Handle`] of the currently-executing image. + pub fn image_handle(&self) -> Handle { + image_handle() + } + + /// Update the global image [`Handle`]. + /// + /// This is called automatically in the `main` entry point as part + /// of [`uefi_macros::entry`]. It should not be called at any other + /// point in time, unless the executable does not use + /// [`uefi_macros::entry`], in which case it should be called once + /// before calling other `BootServices` functions. + /// + /// # Safety + /// + /// This function should only be called as described above, + /// and the `image_handle` must be a valid image [`Handle`]. Then + /// safety guarantees of [`BootServices::open_protocol_exclusive`] + /// rely on the global image handle being correct. + pub unsafe fn set_image_handle(&self, image_handle: Handle) { + set_image_handle(image_handle) + } + + /// Raises a task's priority level and returns its previous level. + /// + /// The effect of calling [`raise_tpl`] with a [`Tpl`] that is below the current + /// one (which, sadly, cannot be queried) is undefined by the UEFI spec, + /// which also warns against remaining at high [`Tpl`]s for a long time. + /// + /// This function outputs an RAII guard that will automatically restore the + /// original [`Tpl`] when dropped. + /// + /// # Safety + /// + /// Raising a task's priority level can affect other running tasks and + /// critical processes run by UEFI. The highest priority level is the + /// most dangerous, since it disables interrupts. + #[must_use] + pub unsafe fn raise_tpl(&self, tpl: Tpl) -> TplGuard { + raise_tpl_raw(MaybeBootRef::Ref(self), tpl) + } + + /// Exits the UEFI boot services + /// + /// This unsafe method is meant to be an implementation detail of the safe + /// `SystemTable::exit_boot_services()` method, which is why it is not + /// public. + /// + /// Everything that is explained in the documentation of the high-level + /// `SystemTable` method is also true here, except that this function + /// is one-shot (no automatic retry) and does not prevent you from shooting + /// yourself in the foot by calling invalid boot services after a failure. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.ExitBootServices()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + pub(crate) unsafe fn exit_boot_services(self, image: Handle, mmap_key: MemoryMapKey) -> Result { + EXITING_BOOT.store(true, Ordering::Relaxed); + + self.stall(100_000); + + assert_eq!( + BOOT_HANDLE_COUNT.load(Ordering::Relaxed), + 1, + "this must be the only boot handle remaining" + ); + + exit_boot_services_raw(&self, image, mmap_key) + } + + /// Allocates memory pages from the system. + /// + /// UEFI OS loaders should allocate memory of the type `LoaderData`. An `u64` + /// is returned even on 32-bit platforms because some hardware configurations + /// like Intel PAE enable 64-bit physical addressing on a 32-bit processor. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.AllocatePages()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::OUT_OF_RESOURCES`] + /// * [`uefi::Status::INVALID_PARAMETER`] + /// * [`uefi::Status::NOT_FOUND`] + pub fn allocate_pages( + &self, + ty: AllocateType, + mem_ty: MemoryType, + count: usize, + ) -> Result { + allocate_pages_raw(self, ty, mem_ty, count) + } + + /// Frees memory pages allocated by UEFI. + /// + /// # Safety + /// + /// The caller must ensure that no references into the allocation remain, + /// and that the memory at the allocation is not used after it is freed. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.FreePages()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::NOT_FOUND`] + /// * [`uefi::Status::INVALID_PARAMETER`] + pub unsafe fn free_pages(&self, addr: PhysicalAddress, count: usize) -> Result { + free_pages_raw(self, addr, count) + } + + /// Returns struct which contains the size of a single memory descriptor + /// as well as the size of the current memory map. + /// + /// Note that the size of the memory map can increase any time an allocation happens, + /// so when creating a buffer to put the memory map into, it's recommended to allocate a few extra + /// elements worth of space above the size of the current memory map. + #[must_use] + pub fn memory_map_size(&self) -> MemoryMapSize { + memory_map_size_raw(self) + } + + /// Retrieves the current memory map. + /// + /// The allocated buffer should be big enough to contain the memory map, + /// and a way of estimating how big it should be is by calling `memory_map_size`. + /// + /// The buffer must be aligned like a `MemoryDescriptor`. + /// + /// The returned key is a unique identifier of the current configuration of memory. + /// Any allocations or such will change the memory map's key. + /// + /// If you want to store the resulting memory map without having to keep + /// the buffer around, you can use `.copied().collect()` on the iterator. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.GetMemoryMap()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::BUFFER_TOO_SMALL`] + /// * [`uefi::Status::INVALID_PARAMETER`] + pub fn memory_map<'buf>(&self, buffer: &'buf mut [u8]) -> Result> { + memory_map_raw(self, buffer) + } + + /// Allocates from a memory pool. The pointer will be 8-byte aligned. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.AllocatePool()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::OUT_OF_RESOURCES`] + /// * [`uefi::Status::INVALID_PARAMETER`] + pub fn allocate_pool(&self, mem_ty: MemoryType, size: usize) -> Result<*mut u8> { + allocate_pool_raw(self, mem_ty, size) + } + + /// Frees memory allocated from a pool. + /// + /// # Safety + /// + /// The caller must ensure that no references into the allocation remain, + /// and that the memory at the allocation is not used after it is freed. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.FreePool()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + pub unsafe fn free_pool(&self, addr: *mut u8) -> Result { + free_pool_raw(self, addr) + } + + /// Creates an event + /// + /// This function creates a new event of the specified type and returns it. + /// + /// Events are created in a "waiting" state, and may switch to a "signaled" + /// state. If the event type has flag `NotifySignal` set, this will result in + /// a callback for the event being immediately enqueued at the `notify_tpl` + /// priority level. If the event type has flag `NotifyWait`, the notification + /// will be delivered next time `wait_for_event` or `check_event` is called. + /// In both cases, a `notify_fn` callback must be specified. + /// + /// # Safety + /// + /// This function is unsafe because callbacks must handle exit from boot + /// services correctly. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.CreateEvent()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + /// * [`uefi::Status::OUT_OF_RESOURCES`] + pub unsafe fn create_event( + &self, + event_ty: EventType, + notify_tpl: Tpl, + notify_fn: Option, + notify_ctx: Option>, + ) -> Result { + create_event_raw(self, event_ty, notify_tpl, notify_fn, notify_ctx) + } + + /// Creates a new `Event` of type `event_type`. The event's notification function, context, + /// and task priority are specified by `notify_fn`, `notify_ctx`, and `notify_tpl`, respectively. + /// The `Event` will be added to the group of `Event`s identified by `event_group`. + /// + /// If no group is specified by `event_group`, this function behaves as if the same parameters + /// had been passed to `create_event()`. + /// + /// Event groups are collections of events identified by a shared `Guid` where, when one member + /// event is signaled, all other events are signaled and their individual notification actions + /// are taken. All events are guaranteed to be signaled before the first notification action is + /// taken. All notification functions will be executed in the order specified by their `Tpl`. + /// + /// A single event can only be part of a single event group. An event may be removed from an + /// event group by using `close_event()`. + /// + /// The `EventType` of an event uses the same values as `create_event()`, except that + /// `EventType::SIGNAL_EXIT_BOOT_SERVICES` and `EventType::SIGNAL_VIRTUAL_ADDRESS_CHANGE` + /// are not valid. + /// + /// If `event_type` has `EventType::NOTIFY_SIGNAL` or `EventType::NOTIFY_WAIT`, then `notify_fn` + /// mus be `Some` and `notify_tpl` must be a valid task priority level, otherwise these parameters + /// are ignored. + /// + /// More than one event of type `EventType::TIMER` may be part of a single event group. However, + /// there is no mechanism for determining which of the timers was signaled. + /// + /// This operation is only supported starting with UEFI 2.0; earlier + /// versions will fail with [`Status::UNSUPPORTED`]. + /// + /// # Safety + /// + /// The caller must ensure they are passing a valid `Guid` as `event_group`, if applicable. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.CreateEventEx()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + /// * [`uefi::Status::OUT_OF_RESOURCES`] + pub unsafe fn create_event_ex( + &self, + event_type: EventType, + notify_tpl: Tpl, + notify_fn: Option, + notify_ctx: Option>, + event_group: Option>, + ) -> Result { + create_event_ex_raw( + self, + event_type, + notify_tpl, + notify_fn, + notify_ctx, + event_group, + ) + } + + /// Sets the trigger for `EventType::TIMER` event. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.SetTimer()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + pub fn set_timer(&self, event: &Event, trigger_time: TimerTrigger) -> Result { + set_timer_raw(self, event, trigger_time) + } + + /// Stops execution until an event is signaled. + /// + /// This function must be called at priority level `Tpl::APPLICATION`. If an + /// attempt is made to call it at any other priority level, an `Unsupported` + /// error is returned. + /// + /// The input `Event` slice is repeatedly iterated from first to last until + /// an event is signaled or an error is detected. The following checks are + /// performed on each event: + /// + /// * If an event is of type `NotifySignal`, then an `InvalidParameter` + /// error is returned with the index of the event that caused the failure. + /// * If an event is in the signaled state, the signaled state is cleared + /// and the index of the event that was signaled is returned. + /// * If an event is not in the signaled state but does have a notification + /// function, the notification function is queued at the event's + /// notification task priority level. If the execution of the event's + /// notification function causes the event to be signaled, then the + /// signaled state is cleared and the index of the event that was signaled + /// is returned. + /// + /// To wait for a specified time, a timer event must be included in the + /// Event slice. + /// + /// To check if an event is signaled without waiting, an already signaled + /// event can be used as the last event in the slice being checked, or the + /// check_event() interface may be used. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.WaitForEvent()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + /// * [`uefi::Status::UNSUPPORTED`] + pub fn wait_for_event(&self, events: &mut [Event]) -> Result> { + wait_for_event_raw(self, events) + } + + /// Place 'event' in the signaled stated. If 'event' is already in the signaled state, + /// then nothing further occurs and `Status::SUCCESS` is returned. If `event` is of type + /// `EventType::NOTIFY_SIGNAL`, then the event's notification function is scheduled to + /// be invoked at the event's notification task priority level. + /// + /// This function may be invoked from any task priority level. + /// + /// If `event` is part of an event group, then all of the events in the event group are + /// also signaled and their notification functions are scheduled. + /// + /// When signaling an event group, it is possible to create an event in the group, signal + /// it, and then close the event to remove it from the group. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.SignalEvent()` in the UEFI Specification for more details. + /// + /// Currently, (as of UEFI Spec v2.9) this only returns `EFI_SUCCESS`. + pub fn signal_event(&self, event: &Event) -> Result { + signal_event_raw(self, event) + } + + /// Removes `event` from any event group to which it belongs and closes it. If `event` was + /// registered with `register_protocol_notify()`, then the corresponding registration will + /// be removed. It is safe to call this function within the corresponding notify function. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.CloseEvent()` in the UEFI Specification for more details. + /// + /// Note: The UEFI Specification v2.9 states that this may only return `EFI_SUCCESS`, but, + /// at least for application based on EDK2 (such as OVMF), it may also return `EFI_INVALID_PARAMETER`. + /// To be safe, ensure that error codes are handled properly. + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + pub fn close_event(&self, event: Event) -> Result { + close_event_raw(self, event) + } + + /// Checks to see if an event is signaled, without blocking execution to wait for it. + /// + /// The returned value will be `true` if the event is in the signaled state, + /// otherwise `false` is returned. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.CheckEvent()` in the UEFI Specification for more details. + /// + /// Note: Instead of returning the `EFI_NOT_READY` error, as listed in the UEFI + /// Specification, this function will return `false`. + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + pub fn check_event(&self, event: Event) -> Result { + check_event_raw(self, event) + } + + /// Installs a protocol interface on a device handle. If the inner `Option` in `handle` is `None`, + /// one will be created and added to the list of handles in the system and then returned. + /// + /// When a protocol interface is installed, firmware will call all functions that have registered + /// to wait for that interface to be installed. + /// + /// # Safety + /// + /// The caller is responsible for ensuring that they pass a valid `Guid` for `protocol`. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.InstallProtocolInterface()` in the UEFI Specification for + /// more details. + /// + /// * [`uefi::Status::OUT_OF_RESOURCES`] + /// * [`uefi::Status::INVALID_PARAMETER`] + pub unsafe fn install_protocol_interface( + &self, + handle: Option, + protocol: &Guid, + interface: *mut c_void, + ) -> Result { + install_protocol_interface_raw(self, handle, protocol, interface) + } + + /// Reinstalls a protocol interface on a device handle. `old_interface` is replaced with `new_interface`. + /// These interfaces may be the same, in which case the registered protocol notifies occur for the handle + /// without replacing the interface. + /// + /// As with `install_protocol_interface`, any process that has registered to wait for the installation of + /// the interface is notified. + /// + /// # Safety + /// + /// The caller is responsible for ensuring that there are no references to the `old_interface` that is being + /// removed. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.ReinstallProtocolInterface()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::NOT_FOUND`] + /// * [`uefi::Status::ACCESS_DENIED`] + /// * [`uefi::Status::INVALID_PARAMETER`] + pub unsafe fn reinstall_protocol_interface( + &self, + handle: Handle, + protocol: &Guid, + old_interface: *mut c_void, + new_interface: *mut c_void, + ) -> Result<()> { + reinstall_protocol_interface_raw(self, handle, protocol, old_interface, new_interface) + } + + /// Removes a protocol interface from a device handle. + /// + /// # Safety + /// + /// The caller is responsible for ensuring that there are no references to a protocol interface + /// that has been removed. Some protocols may not be able to be removed as there is no information + /// available regarding the references. This includes Console I/O, Block I/O, Disk I/o, and handles + /// to device protocols. + /// + /// The caller is responsible for ensuring that they pass a valid `Guid` for `protocol`. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.UninstallProtocolInterface()` in the UEFI Specification for + /// more details. + /// + /// * [`uefi::Status::NOT_FOUND`] + /// * [`uefi::Status::ACCESS_DENIED`] + /// * [`uefi::Status::INVALID_PARAMETER`] + pub unsafe fn uninstall_protocol_interface( + &self, + handle: Handle, + protocol: &Guid, + interface: *mut c_void, + ) -> Result<()> { + uninstall_protocol_interface_raw(self, handle, protocol, interface) + } + + /// Registers `event` to be signalled whenever a protocol interface is registered for + /// `protocol` by `install_protocol_interface()` or `reinstall_protocol_interface()`. + /// + /// Once `event` has been signalled, `BootServices::locate_handle()` can be used to identify + /// the newly (re)installed handles that support `protocol`. The returned `SearchKey` on success + /// corresponds to the `search_key` parameter in `locate_handle()`. + /// + /// Events can be unregistered from protocol interface notification by calling `close_event()`. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.RegisterProtocolNotify()` in the UEFI Specification for + /// more details. + /// + /// * [`uefi::Status::OUT_OF_RESOURCES`] + /// * [`uefi::Status::INVALID_PARAMETER`] + pub fn register_protocol_notify<'guid>( + &self, + protocol: &'guid Guid, + event: Event, + ) -> Result<(Event, SearchType<'guid>)> { + register_protocol_notify_raw(self, protocol, event) + } + + /// Enumerates all handles installed on the system which match a certain query. + /// + /// You should first call this function with `None` for the output buffer, + /// in order to retrieve the length of the buffer you need to allocate. + /// + /// The next call will fill the buffer with the requested data. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.LocateHandle()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::NOT_FOUND`] + /// * [`uefi::Status::BUFFER_TOO_SMALL`] + /// * [`uefi::Status::INVALID_PARAMETER`] + pub fn locate_handle( + &self, + search_ty: SearchType, + output: Option<&mut [MaybeUninit]>, + ) -> Result { + locate_handle_raw(self, search_ty, output) + } + + /// Locates the handle to a device on the device path that supports the specified protocol. + /// + /// The `device_path` is updated to point at the remaining part of the [`DevicePath`] after + /// the part that matched the protocol. For example, it can be used with a device path + /// that contains a file path to strip off the file system portion of the device path, + /// leaving the file path and handle to the file system driver needed to access the file. + /// + /// If the first node of `device_path` matches the + /// protocol, the `device_path` is advanced to the device path terminator node. If `device_path` + /// is a multi-instance device path, the function will operate on the first instance. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.LocateDevicePath()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::NOT_FOUND`] + /// * [`uefi::Status::INVALID_PARAMETER`] + pub fn locate_device_path( + &self, + device_path: &mut &DevicePath, + ) -> Result { + locate_device_path_raw::

(self, device_path) + } + + /// Find an arbitrary handle that supports a particular + /// [`Protocol`]. Returns [`NOT_FOUND`] if no handles support the + /// protocol. + /// + /// This method is a convenient wrapper around + /// [`BootServices::locate_handle_buffer`] for getting just one + /// handle. This is useful when you don't care which handle the + /// protocol is opened on. For example, [`DevicePathToText`] isn't + /// tied to a particular device, so only a single handle is expected + /// to exist. + /// + /// [`NOT_FOUND`]: Status::NOT_FOUND + /// [`DevicePathToText`]: uefi::proto::device_path::text::DevicePathToText + /// + /// # Example + /// + /// ``` + /// use uefi::proto::device_path::text::DevicePathToText; + /// use uefi::table::boot::{BootServices, OpenProtocolAttributes, OpenProtocolParams}; + /// use uefi::Handle; + /// # use uefi::Result; + /// + /// # fn get_fake_val() -> T { todo!() } + /// # fn test() -> Result { + /// # let boot_services: &BootServices = get_fake_val(); + /// # let image_handle: Handle = get_fake_val(); + /// let handle = boot_services.get_handle_for_protocol::()?; + /// let device_path_to_text = boot_services.open_protocol_exclusive::(handle)?; + /// # Ok(()) + /// # } + /// ``` + /// + /// # Errors + /// + /// Returns [`NOT_FOUND`] if no handles support the requested protocol. + pub fn get_handle_for_protocol(&self) -> Result { + get_handle_for_protocol_raw::

(self) + } + + /// Load an EFI image into memory and return a [`Handle`] to the image. + /// + /// There are two ways to load the image: by copying raw image data + /// from a source buffer, or by loading the image via the + /// [`SimpleFileSystem`] protocol. See [`LoadImageSource`] for more + /// details of the `source` parameter. + /// + /// The `parent_image_handle` is used to initialize the + /// `parent_handle` field of the [`LoadedImage`] protocol for the + /// image. + /// + /// If the image is successfully loaded, a [`Handle`] supporting the + /// [`LoadedImage`] and [`LoadedImageDevicePath`] protocols is + /// returned. The image can be started with [`start_image`] or + /// unloaded with [`unload_image`]. + /// + /// [`LoadedImageDevicePath`]: crate::proto::device_path::LoadedImageDevicePath + /// [`start_image`]: BootServices::start_image + /// [`unload_image`]: BootServices::unload_image + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.LoadImage()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::NOT_FOUND`] + /// * [`uefi::Status::INVALID_PARAMETER`] + /// * [`uefi::Status::UNSUPPORTED`] + /// * [`uefi::Status::OUT_OF_RESOURCES`] + /// * [`uefi::Status::LOAD_ERROR`] + /// * [`uefi::Status::DEVICE_ERROR`] + /// * [`uefi::Status::ACCESS_DENIED`] + /// * [`uefi::Status::SECURITY_VIOLATION`] + pub fn load_image( + &self, + parent_image_handle: Handle, + source: LoadImageSource, + ) -> uefi::Result { + load_image_raw(self, parent_image_handle, source) + } + + /// Unload an EFI image. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.UnloadImage()` in the UEFI Specification for more details. + /// + /// As this function can return an error code from the unloaded image, any error type + /// can be returned by this function. + /// + /// The following error codes can also be returned while unloading an image: + /// + /// * [`uefi::Status::UNSUPPORTED`] + /// * [`uefi::Status::INVALID_PARAMETER`] + pub fn unload_image(&self, image_handle: Handle) -> Result { + unload_image_raw(self, image_handle) + } + + /// Transfer control to a loaded image's entry point. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.StartImage()` in the UEFI Specification for more details. + /// + /// As this function can return an error code from the started image, any error type + /// can be returned by this function. + /// + /// The following error code can also be returned while starting an image: + /// + /// * [`uefi::Status::UNSUPPORTED`] + pub fn start_image(&self, image_handle: Handle) -> Result { + start_image_raw(self, image_handle) + } + + /// Exits the UEFI application and returns control to the UEFI component + /// that started the UEFI application. + /// + /// # Safety + /// + /// This function is unsafe because it is up to the caller to ensure that + /// all resources allocated by the application is freed before invoking + /// exit and returning control to the UEFI component that started the UEFI + /// application. + pub unsafe fn exit( + &self, + image_handle: Handle, + exit_status: Status, + exit_data_size: usize, + exit_data: *mut Char16, + ) -> ! { + exit_raw(self, image_handle, exit_status, exit_data_size, exit_data) + } + + /// Stalls the processor for an amount of time. + /// + /// The time is in microseconds. + pub fn stall(&self, time: usize) { + stall_raw(self, time) + } + + /// Adds, updates, or removes a configuration table entry + /// from the EFI System Table. + /// + /// # Safety + /// + /// This relies on `table_ptr` being allocated in the + /// pool of type [`uefi::table::boot::MemoryType::RUNTIME_SERVICES_DATA`] + /// according to the specification. + /// Other memory types such as + /// [`uefi::table::boot::MemoryType::ACPI_RECLAIM`] + /// can be considered. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.InstallConfigurationTable()` in the UEFI + /// Specification for more details. + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + /// * [`uefi::Status::NOT_FOUND`] + /// * [`uefi::Status::OUT_OF_RESOURCES`] + pub unsafe fn install_configuration_table( + &self, + guid_entry: &Guid, + table_ptr: *const c_void, + ) -> Result { + install_configuration_table_raw(self, guid_entry, table_ptr) + } + + /// Set the watchdog timer. + /// + /// UEFI will start a 5-minute countdown after an UEFI image is loaded. + /// The image must either successfully load an OS and call `ExitBootServices` + /// in that time, or disable the watchdog. + /// + /// Otherwise, the firmware will log the event using the provided numeric + /// code and data, then reset the system. + /// + /// This function allows you to change the watchdog timer's timeout to a + /// certain amount of seconds or to disable the watchdog entirely. It also + /// allows you to change what will be logged when the timer expires. + /// + /// The watchdog codes from 0 to 0xffff (65535) are reserved for internal + /// firmware use. Higher values can be used freely by applications. + /// + /// If provided, the watchdog data must be a null-terminated string + /// optionally followed by other binary data. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.SetWatchdogTimer()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + /// * [`uefi::Status::UNSUPPORTED`] + /// * [`uefi::Status::DEVICE_ERROR`] + pub fn set_watchdog_timer( + &self, + timeout: usize, + watchdog_code: u64, + data: Option<&mut [u16]>, + ) -> Result { + set_watchdog_timer_raw(self, timeout, watchdog_code, data) + } + + /// Connect one or more drivers to a controller. + /// + /// Usually one disconnects and then reconnects certain drivers + /// to make them rescan some state that changed, e.g. reconnecting + /// a `BlockIO` handle after your app changed the partitions somehow. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.ConnectController()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + /// * [`uefi::Status::NOT_FOUND`] + /// * [`uefi::Status::SECURITY_VIOLATION`] + pub fn connect_controller( + &self, + controller: Handle, + driver_image: Option, + remaining_device_path: Option<&DevicePath>, + recursive: bool, + ) -> Result { + connect_controller_raw( + self, + controller, + driver_image, + remaining_device_path, + recursive, + ) + } + + /// Disconnect one or more drivers from a controller. + /// + /// See [`connect_controller`][Self::connect_controller]. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.DisconnectController()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + /// * [`uefi::Status::OUT_OF_RESOURCES`] + /// * [`uefi::Status::DEVICE_ERROR`] + pub fn disconnect_controller( + &self, + controller: Handle, + driver_image: Option, + child: Option, + ) -> Result { + disconnect_controller_raw(self, controller, driver_image, child) + } + + /// Open a protocol interface for a handle. + /// + /// See also [`open_protocol_exclusive`], which provides a safe + /// subset of this functionality. + /// + /// This function attempts to get the protocol implementation of a + /// handle, based on the protocol GUID. It is recommended that all + /// new drivers and applications use [`open_protocol_exclusive`] or + /// [`open_protocol`]. + /// + /// See [`OpenProtocolParams`] and [`OpenProtocolAttributes`] for + /// details of the input parameters. + /// + /// If successful, a [`ScopedProtocol`] is returned that will + /// automatically close the protocol interface when dropped. + /// + /// UEFI protocols are neither thread-safe nor reentrant, but the firmware + /// provides no mechanism to protect against concurrent usage. Such + /// protections must be implemented by user-level code, for example via a + /// global `HashSet`. + /// + /// # Safety + /// + /// This function is unsafe because it can be used to open a + /// protocol in ways that don't get tracked by the UEFI + /// implementation. This could allow the protocol to be removed from + /// a handle, or for the handle to be deleted entirely, while a + /// reference to the protocol is still active. The caller is + /// responsible for ensuring that the handle and protocol remain + /// valid until the `ScopedProtocol` is dropped. + /// + /// [`open_protocol`]: BootServices::open_protocol + /// [`open_protocol_exclusive`]: BootServices::open_protocol_exclusive + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.OpenProtocol()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + /// * [`uefi::Status::UNSUPPORTED`] + /// * [`uefi::Status::ACCESS_DENIED`] + /// * [`uefi::Status::ALREADY_STARTED`] + pub unsafe fn open_protocol( + &self, + params: OpenProtocolParams, + attributes: OpenProtocolAttributes, + ) -> Result> { + open_protocol_raw(MaybeBootRef::Ref(self), params, attributes) + } + + /// Open a protocol interface for a handle in exclusive mode. + /// + /// If successful, a [`ScopedProtocol`] is returned that will + /// automatically close the protocol interface when dropped. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.OpenProtocol()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + /// * [`uefi::Status::UNSUPPORTED`] + /// * [`uefi::Status::ACCESS_DENIED`] + /// * [`uefi::Status::ALREADY_STARTED`] + pub fn open_protocol_exclusive( + &self, + handle: Handle, + ) -> Result> { + open_protocol_exclusive_raw(MaybeBootRef::Ref(self), handle) + } + + /// Test whether a handle supports a protocol. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.OpenProtocol()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + /// * [`uefi::Status::UNSUPPORTED`] + /// * [`uefi::Status::ACCESS_DENIED`] + /// * [`uefi::Status::ALREADY_STARTED`] + pub fn test_protocol( + &self, + params: OpenProtocolParams, + ) -> Result<()> { + test_protocol_raw::

(self, params) + } + + /// Get the list of protocol interface [`Guids`][Guid] that are installed + /// on a [`Handle`]. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.ProtocolsPerHandle()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + /// * [`uefi::Status::OUT_OF_RESOURCES`] + pub fn protocols_per_handle(&self, handle: Handle) -> Result { + protocols_per_handle_raw(MaybeBootRef::Ref(self), handle) + } + + /// Returns an array of handles that support the requested protocol in a buffer allocated from + /// pool. + /// + /// # Errors + /// + /// See section `EFI_BOOT_SERVICES.LocateHandleBuffer()` in the UEFI Specification for more details. + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + /// * [`uefi::Status::NOT_FOUND`] + /// * [`uefi::Status::OUT_OF_RESOURCES`] + pub fn locate_handle_buffer(&self, search_ty: SearchType) -> Result { + locate_handle_buffer_raw(MaybeBootRef::Ref(self), search_ty) + } + + /// Retrieves a [`SimpleFileSystem`] protocol associated with the device the given + /// image was loaded from. + /// + /// # Errors + /// + /// This function can return errors from [`open_protocol_exclusive`] and + /// [`locate_device_path`]. See those functions for more details. + /// + /// [`open_protocol_exclusive`]: Self::open_protocol_exclusive + /// [`locate_device_path`]: Self::locate_device_path + /// + /// * [`uefi::Status::INVALID_PARAMETER`] + /// * [`uefi::Status::UNSUPPORTED`] + /// * [`uefi::Status::ACCESS_DENIED`] + /// * [`uefi::Status::ALREADY_STARTED`] + /// * [`uefi::Status::NOT_FOUND`] + pub fn get_image_file_system( + &self, + image_handle: Handle, + ) -> Result> { + get_image_file_system_raw(MaybeBootRef::Ref(self), image_handle) + } + + #[cfg(feature = "alloc")] + /// Returns all the handles implementing a certain protocol. + /// + /// # Errors + /// + /// All errors come from calls to [`locate_handle`]. + /// + /// [`locate_handle`]: Self::locate_handle + pub fn find_handles(&self) -> Result> { + use self::raw::find_handles_raw; + + find_handles_raw::

(self) + } +} + +impl Clone for BootHandle { + fn clone(&self) -> Self { + let count = BOOT_HANDLE_COUNT.fetch_add(1, Ordering::Relaxed); + + if count > usize::MAX / 2 { + BOOT_HANDLE_COUNT.fetch_sub(1, Ordering::Relaxed); + panic!("boot handle reference counter grew too large"); + } + + BootHandle(self.0) + } +} + +impl Drop for BootHandle { + fn drop(&mut self) { + let count = BOOT_HANDLE_COUNT.fetch_sub(1, Ordering::Relaxed); + assert!(count > 0, "corrupted boot handle counter"); + } +} + +/// Raises a task's priority level and returns its previous level. +/// +/// The effect of calling [`raise_tpl`] with a [`Tpl`] that is below the current +/// one (which, sadly, cannot be queried) is undefined by the UEFI spec, +/// which also warns against remaining at high [`Tpl`]s for a long time. +/// +/// This function outputs an RAII guard that will automatically restore the +/// original [`Tpl`] when dropped. +/// +/// # Safety +/// +/// Raising a task's priority level can affect other running tasks and +/// critical processes run by UEFI. The highest priority level is the +/// most dangerous, since it disables interrupts. +#[must_use] +pub unsafe fn raise_tpl(tpl: Tpl) -> TplGuard<'static> { + let boot_handle = acquire_boot_handle(); + + raise_tpl_raw(MaybeBootRef::Value(boot_handle), tpl) +} + +/// Allocates memory pages from the system. +/// +/// UEFI OS loaders should allocate memory of the type `LoaderData`. An `u64` +/// is returned even on 32-bit platforms because some hardware configurations +/// like Intel PAE enable 64-bit physical addressing on a 32-bit processor. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.AllocatePages()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::OUT_OF_RESOURCES`] +/// * [`uefi::Status::INVALID_PARAMETER`] +/// * [`uefi::Status::NOT_FOUND`] +pub fn allocate_pages( + ty: AllocateType, + mem_ty: MemoryType, + count: usize, +) -> Result { + let boot_handle = acquire_boot_handle(); + + allocate_pages_raw(&boot_handle, ty, mem_ty, count) +} + +/// Frees memory pages allocated by UEFI. +/// +/// # Safety +/// +/// The caller must ensure that no references into the allocation remain, +/// and that the memory at the allocation is not used after it is freed. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.FreePages()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::NOT_FOUND`] +/// * [`uefi::Status::INVALID_PARAMETER`] +pub unsafe fn free_pages(addr: PhysicalAddress, count: usize) -> Result { + let boot_handle = acquire_boot_handle(); + + free_pages_raw(&boot_handle, addr, count) +} + +/// Returns struct which contains the size of a single memory descriptor +/// as well as the size of the current memory map. +/// +/// Note that the size of the memory map can increase any time an allocation happens, +/// so when creating a buffer to put the memory map into, it's recommended to allocate a few extra +/// elements worth of space above the size of the current memory map. +#[must_use] +pub fn memory_map_size() -> MemoryMapSize { + let boot_handle = acquire_boot_handle(); + + memory_map_size_raw(&boot_handle) +} + +/// Retrieves the current memory map. +/// +/// The allocated buffer should be big enough to contain the memory map, +/// and a way of estimating how big it should be is by calling `memory_map_size`. +/// +/// The buffer must be aligned like a `MemoryDescriptor`. +/// +/// The returned key is a unique identifier of the current configuration of memory. +/// Any allocations or such will change the memory map's key. +/// +/// If you want to store the resulting memory map without having to keep +/// the buffer around, you can use `.copied().collect()` on the iterator. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.GetMemoryMap()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::BUFFER_TOO_SMALL`] +/// * [`uefi::Status::INVALID_PARAMETER`] +pub fn memory_map(buffer: &mut [u8]) -> Result { + let boot_handle = acquire_boot_handle(); + + memory_map_raw(&boot_handle, buffer) +} + +/// Allocates from a memory pool. The pointer will be 8-byte aligned. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.AllocatePool()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::OUT_OF_RESOURCES`] +/// * [`uefi::Status::INVALID_PARAMETER`] +pub fn allocate_pool(mem_ty: MemoryType, size: usize) -> Result<*mut u8> { + let boot_handle = acquire_boot_handle(); + + allocate_pool_raw(&boot_handle, mem_ty, size) +} + +/// Frees memory allocated from a pool. +/// +/// # Safety +/// +/// The caller must ensure that no references into the allocation remain, +/// and that the memory at the allocation is not used after it is freed. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.FreePool()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::INVALID_PARAMETER`] +pub unsafe fn free_pool(addr: *mut u8) -> Result { + let boot_handle = acquire_boot_handle(); + + free_pool_raw(&boot_handle, addr) +} + +/// Creates an event +/// +/// This function creates a new event of the specified type and returns it. +/// +/// Events are created in a "waiting" state, and may switch to a "signaled" +/// state. If the event type has flag `NotifySignal` set, this will result in +/// a callback for the event being immediately enqueued at the `notify_tpl` +/// priority level. If the event type has flag `NotifyWait`, the notification +/// will be delivered next time `wait_for_event` or `check_event` is called. +/// In both cases, a `notify_fn` callback must be specified. +/// +/// # Safety +/// +/// This function is unsafe because callbacks must handle exit from boot +/// services correctly. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.CreateEvent()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::INVALID_PARAMETER`] +/// * [`uefi::Status::OUT_OF_RESOURCES`] +pub unsafe fn create_event( + event_ty: EventType, + notify_tpl: Tpl, + notify_fn: Option, + notify_ctx: Option>, +) -> Result { + let boot_handle = acquire_boot_handle(); + + create_event_raw(&boot_handle, event_ty, notify_tpl, notify_fn, notify_ctx) +} + +/// Creates a new `Event` of type `event_type`. The event's notification function, context, +/// and task priority are specified by `notify_fn`, `notify_ctx`, and `notify_tpl`, respectively. +/// The `Event` will be added to the group of `Event`s identified by `event_group`. +/// +/// If no group is specified by `event_group`, this function behaves as if the same parameters +/// had been passed to `create_event()`. +/// +/// Event groups are collections of events identified by a shared `Guid` where, when one member +/// event is signaled, all other events are signaled and their individual notification actions +/// are taken. All events are guaranteed to be signaled before the first notification action is +/// taken. All notification functions will be executed in the order specified by their `Tpl`. +/// +/// A single event can only be part of a single event group. An event may be removed from an +/// event group by using `close_event()`. +/// +/// The `EventType` of an event uses the same values as `create_event()`, except that +/// `EventType::SIGNAL_EXIT_BOOT_SERVICES` and `EventType::SIGNAL_VIRTUAL_ADDRESS_CHANGE` +/// are not valid. +/// +/// If `event_type` has `EventType::NOTIFY_SIGNAL` or `EventType::NOTIFY_WAIT`, then `notify_fn` +/// mus be `Some` and `notify_tpl` must be a valid task priority level, otherwise these parameters +/// are ignored. +/// +/// More than one event of type `EventType::TIMER` may be part of a single event group. However, +/// there is no mechanism for determining which of the timers was signaled. +/// +/// This operation is only supported starting with UEFI 2.0; earlier +/// versions will fail with [`Status::UNSUPPORTED`]. +/// +/// # Safety +/// +/// The caller must ensure they are passing a valid `Guid` as `event_group`, if applicable. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.CreateEventEx()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::INVALID_PARAMETER`] +/// * [`uefi::Status::OUT_OF_RESOURCES`] +pub unsafe fn create_event_ex( + event_type: EventType, + notify_tpl: Tpl, + notify_fn: Option, + notify_ctx: Option>, + event_group: Option>, +) -> Result { + let boot_handle = acquire_boot_handle(); + + create_event_ex_raw( + &boot_handle, + event_type, + notify_tpl, + notify_fn, + notify_ctx, + event_group, + ) +} + +/// Sets the trigger for `EventType::TIMER` event. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.SetTimer()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::INVALID_PARAMETER`] +pub fn set_timer(event: &Event, trigger_time: TimerTrigger) -> Result { + let boot_handle = acquire_boot_handle(); + + set_timer_raw(&boot_handle, event, trigger_time) +} + +/// Stops execution until an event is signaled. +/// +/// This function must be called at priority level `Tpl::APPLICATION`. If an +/// attempt is made to call it at any other priority level, an `Unsupported` +/// error is returned. +/// +/// The input `Event` slice is repeatedly iterated from first to last until +/// an event is signaled or an error is detected. The following checks are +/// performed on each event: +/// +/// * If an event is of type `NotifySignal`, then an `InvalidParameter` +/// error is returned with the index of the event that caused the failure. +/// * If an event is in the signaled state, the signaled state is cleared +/// and the index of the event that was signaled is returned. +/// * If an event is not in the signaled state but does have a notification +/// function, the notification function is queued at the event's +/// notification task priority level. If the execution of the event's +/// notification function causes the event to be signaled, then the +/// signaled state is cleared and the index of the event that was signaled +/// is returned. +/// +/// To wait for a specified time, a timer event must be included in the +/// Event slice. +/// +/// To check if an event is signaled without waiting, an already signaled +/// event can be used as the last event in the slice being checked, or the +/// check_event() interface may be used. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.WaitForEvent()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::INVALID_PARAMETER`] +/// * [`uefi::Status::UNSUPPORTED`] +pub fn wait_for_event(events: &mut [Event]) -> Result> { + let boot_handle = acquire_boot_handle(); + + wait_for_event_raw(&boot_handle, events) +} + +/// Place 'event' in the signaled stated. If 'event' is already in the signaled state, +/// then nothing further occurs and `Status::SUCCESS` is returned. If `event` is of type +/// `EventType::NOTIFY_SIGNAL`, then the event's notification function is scheduled to +/// be invoked at the event's notification task priority level. +/// +/// This function may be invoked from any task priority level. +/// +/// If `event` is part of an event group, then all of the events in the event group are +/// also signaled and their notification functions are scheduled. +/// +/// When signaling an event group, it is possible to create an event in the group, signal +/// it, and then close the event to remove it from the group. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.SignalEvent()` in the UEFI Specification for more details. +/// +/// Currently, (as of UEFI Spec v2.9) this only returns `EFI_SUCCESS`. +pub fn signal_event(event: &Event) -> Result { + let boot_handle = acquire_boot_handle(); + + signal_event_raw(&boot_handle, event) +} + +/// Removes `event` from any event group to which it belongs and closes it. If `event` was +/// registered with `register_protocol_notify()`, then the corresponding registration will +/// be removed. It is safe to call this function within the corresponding notify function. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.CloseEvent()` in the UEFI Specification for more details. +/// +/// Note: The UEFI Specification v2.9 states that this may only return `EFI_SUCCESS`, but, +/// at least for application based on EDK2 (such as OVMF), it may also return `EFI_INVALID_PARAMETER`. +/// To be safe, ensure that error codes are handled properly. +/// +/// * [`uefi::Status::INVALID_PARAMETER`] +pub fn close_event(event: Event) -> Result { + let boot_handle = acquire_boot_handle(); + + close_event_raw(&boot_handle, event) +} + +/// Checks to see if an event is signaled, without blocking execution to wait for it. +/// +/// The returned value will be `true` if the event is in the signaled state, +/// otherwise `false` is returned. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.CheckEvent()` in the UEFI Specification for more details. +/// +/// Note: Instead of returning the `EFI_NOT_READY` error, as listed in the UEFI +/// Specification, this function will return `false`. +/// +/// * [`uefi::Status::INVALID_PARAMETER`] +pub fn check_event(event: Event) -> Result { + let boot_handle = acquire_boot_handle(); + + check_event_raw(&boot_handle, event) +} + +/// Installs a protocol interface on a device handle. If the inner `Option` in `handle` is `None`, +/// one will be created and added to the list of handles in the system and then returned. +/// +/// When a protocol interface is installed, firmware will call all functions that have registered +/// to wait for that interface to be installed. +/// +/// # Safety +/// +/// The caller is responsible for ensuring that they pass a valid `Guid` for `protocol`. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.InstallProtocolInterface()` in the UEFI Specification for +/// more details. +/// +/// * [`uefi::Status::OUT_OF_RESOURCES`] +/// * [`uefi::Status::INVALID_PARAMETER`] +pub unsafe fn install_protocol_interface( + handle: Option, + protocol: &Guid, + interface: *mut c_void, +) -> Result { + let boot_handle = acquire_boot_handle(); + + install_protocol_interface_raw(&boot_handle, handle, protocol, interface) +} + +/// Reinstalls a protocol interface on a device handle. `old_interface` is replaced with `new_interface`. +/// These interfaces may be the same, in which case the registered protocol notifies occur for the handle +/// without replacing the interface. +/// +/// As with `install_protocol_interface`, any process that has registered to wait for the installation of +/// the interface is notified. +/// +/// # Safety +/// +/// The caller is responsible for ensuring that there are no references to the `old_interface` that is being +/// removed. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.ReinstallProtocolInterface()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::NOT_FOUND`] +/// * [`uefi::Status::ACCESS_DENIED`] +/// * [`uefi::Status::INVALID_PARAMETER`] +pub unsafe fn reinstall_protocol_interface( + handle: Handle, + protocol: &Guid, + old_interface: *mut c_void, + new_interface: *mut c_void, +) -> Result<()> { + let boot_handle = acquire_boot_handle(); + + reinstall_protocol_interface_raw(&boot_handle, handle, protocol, old_interface, new_interface) +} + +/// Removes a protocol interface from a device handle. +/// +/// # Safety +/// +/// The caller is responsible for ensuring that there are no references to a protocol interface +/// that has been removed. Some protocols may not be able to be removed as there is no information +/// available regarding the references. This includes Console I/O, Block I/O, Disk I/o, and handles +/// to device protocols. +/// +/// The caller is responsible for ensuring that they pass a valid `Guid` for `protocol`. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.UninstallProtocolInterface()` in the UEFI Specification for +/// more details. +/// +/// * [`uefi::Status::NOT_FOUND`] +/// * [`uefi::Status::ACCESS_DENIED`] +/// * [`uefi::Status::INVALID_PARAMETER`] +pub unsafe fn uninstall_protocol_interface( + handle: Handle, + protocol: &Guid, + interface: *mut c_void, +) -> Result<()> { + let boot_handle = acquire_boot_handle(); + + uninstall_protocol_interface_raw(&boot_handle, handle, protocol, interface) +} + +/// Registers `event` to be signalled whenever a protocol interface is registered for +/// `protocol` by `install_protocol_interface()` or `reinstall_protocol_interface()`. +/// +/// Once `event` has been signalled, `BootServices::locate_handle()` can be used to identify +/// the newly (re)installed handles that support `protocol`. The returned `SearchKey` on success +/// corresponds to the `search_key` parameter in `locate_handle()`. +/// +/// Events can be unregistered from protocol interface notification by calling `close_event()`. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.RegisterProtocolNotify()` in the UEFI Specification for +/// more details. +/// +/// * [`uefi::Status::OUT_OF_RESOURCES`] +/// * [`uefi::Status::INVALID_PARAMETER`] +pub fn register_protocol_notify(protocol: &Guid, event: Event) -> Result<(Event, SearchType)> { + let boot_handle = acquire_boot_handle(); + + register_protocol_notify_raw(&boot_handle, protocol, event) +} + +/// Enumerates all handles installed on the system which match a certain query. +/// +/// You should first call this function with `None` for the output buffer, +/// in order to retrieve the length of the buffer you need to allocate. +/// +/// The next call will fill the buffer with the requested data. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.LocateHandle()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::NOT_FOUND`] +/// * [`uefi::Status::BUFFER_TOO_SMALL`] +/// * [`uefi::Status::INVALID_PARAMETER`] +pub fn locate_handle( + search_ty: SearchType, + output: Option<&mut [MaybeUninit]>, +) -> Result { + let boot_handle = acquire_boot_handle(); + + locate_handle_raw(&boot_handle, search_ty, output) +} + +/// Locates the handle to a device on the device path that supports the specified protocol. +/// +/// The `device_path` is updated to point at the remaining part of the [`DevicePath`] after +/// the part that matched the protocol. For example, it can be used with a device path +/// that contains a file path to strip off the file system portion of the device path, +/// leaving the file path and handle to the file system driver needed to access the file. +/// +/// If the first node of `device_path` matches the +/// protocol, the `device_path` is advanced to the device path terminator node. If `device_path` +/// is a multi-instance device path, the function will operate on the first instance. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.LocateDevicePath()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::NOT_FOUND`] +/// * [`uefi::Status::INVALID_PARAMETER`] +pub fn locate_device_path( + device_path: &mut &DevicePath, +) -> Result { + let boot_handle = acquire_boot_handle(); + + locate_device_path_raw::

(&boot_handle, device_path) +} + +/// Find an arbitrary handle that supports a particular +/// [`Protocol`]. Returns [`NOT_FOUND`] if no handles support the +/// protocol. +/// +/// This method is a convenient wrapper around +/// [`BootServices::locate_handle_buffer`] for getting just one +/// handle. This is useful when you don't care which handle the +/// protocol is opened on. For example, [`DevicePathToText`] isn't +/// tied to a particular device, so only a single handle is expected +/// to exist. +/// +/// [`NOT_FOUND`]: Status::NOT_FOUND +/// [`DevicePathToText`]: uefi::proto::device_path::text::DevicePathToText +/// +/// # Example +/// +/// ``` +/// use uefi::proto::device_path::text::DevicePathToText; +/// use uefi::table::boot::{BootServices, OpenProtocolAttributes, OpenProtocolParams}; +/// use uefi::Handle; +/// # use uefi::Result; +/// +/// # fn get_fake_val() -> T { todo!() } +/// # fn test() -> Result { +/// # let boot_services: &BootServices = get_fake_val(); +/// # let image_handle: Handle = get_fake_val(); +/// let handle = boot_services.get_handle_for_protocol::()?; +/// let device_path_to_text = boot_services.open_protocol_exclusive::(handle)?; +/// # Ok(()) +/// # } +/// ``` +/// +/// # Errors +/// +/// Returns [`NOT_FOUND`] if no handles support the requested protocol. +pub fn get_handle_for_protocol() -> Result { + let boot_handle = acquire_boot_handle(); + + get_handle_for_protocol_raw::

(&boot_handle) +} + +/// Load an EFI image into memory and return a [`Handle`] to the image. +/// +/// There are two ways to load the image: by copying raw image data +/// from a source buffer, or by loading the image via the +/// [`SimpleFileSystem`] protocol. See [`LoadImageSource`] for more +/// details of the `source` parameter. +/// +/// The `parent_image_handle` is used to initialize the +/// `parent_handle` field of the [`LoadedImage`] protocol for the +/// image. +/// +/// If the image is successfully loaded, a [`Handle`] supporting the +/// [`LoadedImage`] and [`LoadedImageDevicePath`] protocols is +/// returned. The image can be started with [`start_image`] or +/// unloaded with [`unload_image`]. +/// +/// [`LoadedImageDevicePath`]: crate::proto::device_path::LoadedImageDevicePath +/// [`start_image`]: BootServices::start_image +/// [`unload_image`]: BootServices::unload_image +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.LoadImage()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::NOT_FOUND`] +/// * [`uefi::Status::INVALID_PARAMETER`] +/// * [`uefi::Status::UNSUPPORTED`] +/// * [`uefi::Status::OUT_OF_RESOURCES`] +/// * [`uefi::Status::LOAD_ERROR`] +/// * [`uefi::Status::DEVICE_ERROR`] +/// * [`uefi::Status::ACCESS_DENIED`] +/// * [`uefi::Status::SECURITY_VIOLATION`] +pub fn load_image(parent_image_handle: Handle, source: LoadImageSource) -> uefi::Result { + let boot_handle = acquire_boot_handle(); + + load_image_raw(&boot_handle, parent_image_handle, source) +} + +/// Unload an EFI image. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.UnloadImage()` in the UEFI Specification for more details. +/// +/// As this function can return an error code from the unloaded image, any error type +/// can be returned by this function. +/// +/// The following error codes can also be returned while unloading an image: +/// +/// * [`uefi::Status::UNSUPPORTED`] +/// * [`uefi::Status::INVALID_PARAMETER`] +pub fn unload_image(image_handle: Handle) -> Result { + let boot_handle = acquire_boot_handle(); + + unload_image_raw(&boot_handle, image_handle) +} + +/// Transfer control to a loaded image's entry point. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.StartImage()` in the UEFI Specification for more details. +/// +/// As this function can return an error code from the started image, any error type +/// can be returned by this function. +/// +/// The following error code can also be returned while starting an image: +/// +/// * [`uefi::Status::UNSUPPORTED`] +pub fn start_image(image_handle: Handle) -> Result { + let boot_handle = acquire_boot_handle(); + + start_image_raw(&boot_handle, image_handle) +} + +/// Exits the UEFI application and returns control to the UEFI component +/// that started the UEFI application. +/// +/// # Safety +/// +/// This function is unsafe because it is up to the caller to ensure that +/// all resources allocated by the application is freed before invoking +/// exit and returning control to the UEFI component that started the UEFI +/// application. +pub unsafe fn exit( + image_handle: Handle, + exit_status: Status, + exit_data_size: usize, + exit_data: *mut Char16, +) -> ! { + let boot_handle = acquire_boot_handle(); + + exit_raw( + &boot_handle, + image_handle, + exit_status, + exit_data_size, + exit_data, + ) +} + +/// Stalls the processor for an amount of time. +/// +/// The time is in microseconds. +#[track_caller] +pub fn stall(time: usize) { + let boot_handle = acquire_boot_handle(); + + stall_raw(&boot_handle, time) +} + +/// Adds, updates, or removes a configuration table entry +/// from the EFI System Table. +/// +/// # Safety +/// +/// This relies on `table_ptr` being allocated in the +/// pool of type [`uefi::table::boot::MemoryType::RUNTIME_SERVICES_DATA`] +/// according to the specification. +/// Other memory types such as +/// [`uefi::table::boot::MemoryType::ACPI_RECLAIM`] +/// can be considered. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.InstallConfigurationTable()` in the UEFI +/// Specification for more details. +/// +/// * [`uefi::Status::INVALID_PARAMETER`] +/// * [`uefi::Status::NOT_FOUND`] +/// * [`uefi::Status::OUT_OF_RESOURCES`] +pub unsafe fn install_configuration_table(guid_entry: &Guid, table_ptr: *const c_void) -> Result { + let boot_handle = acquire_boot_handle(); + + install_configuration_table_raw(&boot_handle, guid_entry, table_ptr) +} + +/// Set the watchdog timer. +/// +/// UEFI will start a 5-minute countdown after an UEFI image is loaded. +/// The image must either successfully load an OS and call `ExitBootServices` +/// in that time, or disable the watchdog. +/// +/// Otherwise, the firmware will log the event using the provided numeric +/// code and data, then reset the system. +/// +/// This function allows you to change the watchdog timer's timeout to a +/// certain amount of seconds or to disable the watchdog entirely. It also +/// allows you to change what will be logged when the timer expires. +/// +/// The watchdog codes from 0 to 0xffff (65535) are reserved for internal +/// firmware use. Higher values can be used freely by applications. +/// +/// If provided, the watchdog data must be a null-terminated string +/// optionally followed by other binary data. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.SetWatchdogTimer()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::INVALID_PARAMETER`] +/// * [`uefi::Status::UNSUPPORTED`] +/// * [`uefi::Status::DEVICE_ERROR`] +pub fn set_watchdog_timer(timeout: usize, watchdog_code: u64, data: Option<&mut [u16]>) -> Result { + let boot_handle = acquire_boot_handle(); + + set_watchdog_timer_raw(&boot_handle, timeout, watchdog_code, data) +} + +/// Connect one or more drivers to a controller. +/// +/// Usually one disconnects and then reconnects certain drivers +/// to make them rescan some state that changed, e.g. reconnecting +/// a `BlockIO` handle after your app changed the partitions somehow. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.ConnectController()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::INVALID_PARAMETER`] +/// * [`uefi::Status::NOT_FOUND`] +/// * [`uefi::Status::SECURITY_VIOLATION`] +pub fn connect_controller( + controller: Handle, + driver_image: Option, + remaining_device_path: Option<&DevicePath>, + recursive: bool, +) -> Result { + let boot_handle = acquire_boot_handle(); + + connect_controller_raw( + &boot_handle, + controller, + driver_image, + remaining_device_path, + recursive, + ) +} + +/// Disconnect one or more drivers from a controller. +/// +/// See [`connect_controller`][Self::connect_controller]. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.DisconnectController()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::INVALID_PARAMETER`] +/// * [`uefi::Status::OUT_OF_RESOURCES`] +/// * [`uefi::Status::DEVICE_ERROR`] +pub fn disconnect_controller( + controller: Handle, + driver_image: Option, + child: Option, +) -> Result { + let boot_handle = acquire_boot_handle(); + + disconnect_controller_raw(&boot_handle, controller, driver_image, child) +} + +/// Open a protocol interface for a handle. +/// +/// See also [`open_protocol_exclusive`], which provides a safe +/// subset of this functionality. +/// +/// This function attempts to get the protocol implementation of a +/// handle, based on the protocol GUID. It is recommended that all +/// new drivers and applications use [`open_protocol_exclusive`] or +/// [`open_protocol`]. +/// +/// See [`OpenProtocolParams`] and [`OpenProtocolAttributes`] for +/// details of the input parameters. +/// +/// If successful, a [`ScopedProtocol`] is returned that will +/// automatically close the protocol interface when dropped. +/// +/// UEFI protocols are neither thread-safe nor reentrant, but the firmware +/// provides no mechanism to protect against concurrent usage. Such +/// protections must be implemented by user-level code, for example via a +/// global `HashSet`. +/// +/// # Safety +/// +/// This function is unsafe because it can be used to open a +/// protocol in ways that don't get tracked by the UEFI +/// implementation. This could allow the protocol to be removed from +/// a handle, or for the handle to be deleted entirely, while a +/// reference to the protocol is still active. The caller is +/// responsible for ensuring that the handle and protocol remain +/// valid until the `ScopedProtocol` is dropped. +/// +/// [`open_protocol`]: BootServices::open_protocol +/// [`open_protocol_exclusive`]: BootServices::open_protocol_exclusive +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.OpenProtocol()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::INVALID_PARAMETER`] +/// * [`uefi::Status::UNSUPPORTED`] +/// * [`uefi::Status::ACCESS_DENIED`] +/// * [`uefi::Status::ALREADY_STARTED`] +pub unsafe fn open_protocol( + params: OpenProtocolParams, + attributes: OpenProtocolAttributes, +) -> Result> { + let boot_handle = acquire_boot_handle(); + + open_protocol_raw(MaybeBootRef::Value(boot_handle), params, attributes) +} + +/// Open a protocol interface for a handle in exclusive mode. +/// +/// If successful, a [`ScopedProtocol`] is returned that will +/// automatically close the protocol interface when dropped. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.OpenProtocol()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::INVALID_PARAMETER`] +/// * [`uefi::Status::UNSUPPORTED`] +/// * [`uefi::Status::ACCESS_DENIED`] +/// * [`uefi::Status::ALREADY_STARTED`] +pub fn open_protocol_exclusive( + handle: Handle, +) -> Result> { + let boot_handle = acquire_boot_handle(); + + open_protocol_exclusive_raw(MaybeBootRef::Value(boot_handle), handle) +} + +/// Test whether a handle supports a protocol. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.OpenProtocol()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::INVALID_PARAMETER`] +/// * [`uefi::Status::UNSUPPORTED`] +/// * [`uefi::Status::ACCESS_DENIED`] +/// * [`uefi::Status::ALREADY_STARTED`] +pub fn test_protocol(params: OpenProtocolParams) -> Result<()> { + let boot_handle = acquire_boot_handle(); + + test_protocol_raw::

(&boot_handle, params) +} + +/// Get the list of protocol interface [`Guids`][Guid] that are installed +/// on a [`Handle`]. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.ProtocolsPerHandle()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::INVALID_PARAMETER`] +/// * [`uefi::Status::OUT_OF_RESOURCES`] +pub fn protocols_per_handle(handle: Handle) -> Result> { + let boot_handle = acquire_boot_handle(); + + protocols_per_handle_raw(MaybeBootRef::Value(boot_handle), handle) +} + +/// Returns an array of handles that support the requested protocol in a buffer allocated from +/// pool. +/// +/// # Errors +/// +/// See section `EFI_BOOT_SERVICES.LocateHandleBuffer()` in the UEFI Specification for more details. +/// +/// * [`uefi::Status::INVALID_PARAMETER`] +/// * [`uefi::Status::NOT_FOUND`] +/// * [`uefi::Status::OUT_OF_RESOURCES`] +pub fn locate_handle_buffer(search_ty: SearchType) -> Result { + let boot_handle = acquire_boot_handle(); + + locate_handle_buffer_raw(MaybeBootRef::Value(boot_handle), search_ty) +} + +/// Retrieves a [`SimpleFileSystem`] protocol associated with the device the given +/// image was loaded from. +/// +/// # Errors +/// +/// This function can return errors from [`open_protocol_exclusive`] and +/// [`locate_device_path`]. See those functions for more details. +/// +/// [`open_protocol_exclusive`]: Self::open_protocol_exclusive +/// [`locate_device_path`]: Self::locate_device_path +/// +/// * [`uefi::Status::INVALID_PARAMETER`] +/// * [`uefi::Status::UNSUPPORTED`] +/// * [`uefi::Status::ACCESS_DENIED`] +/// * [`uefi::Status::ALREADY_STARTED`] +/// * [`uefi::Status::NOT_FOUND`] +pub fn get_image_file_system( + image_handle: Handle, +) -> Result> { + let boot_handle = acquire_boot_handle(); + + get_image_file_system_raw(MaybeBootRef::Value(boot_handle), image_handle) +} + +#[cfg(feature = "alloc")] +/// Returns all the handles implementing a certain protocol. +/// +/// # Errors +/// +/// All errors come from calls to [`locate_handle`]. +/// +/// [`locate_handle`]: Self::locate_handle +pub fn find_handles() -> Result> { + use self::raw::find_handles_raw; + let boot_handle = acquire_boot_handle(); + + find_handles_raw::

(&boot_handle) +} + +/// RAII guard for task priority level changes +/// +/// Will automatically restore the former task priority level when dropped. +#[derive(Debug)] +pub struct TplGuard<'boot> { + old_tpl: Tpl, + boot_handle: MaybeBootRef<'boot>, +} + +impl<'boot> TplGuard<'boot> { + /// Converts potentially scoped [`TplGuard`] into a `'static` [`TplGuard`]. + #[must_use] + pub fn make_static(self) -> TplGuard<'static> { + let old_tpl = self.old_tpl; + + let boot_handle = match self.boot_handle { + MaybeBootRef::Ref(boot_ref) => boot_ref.clone(), + MaybeBootRef::Value(ref boot_handle) => BootHandle(boot_handle.0), + }; + + mem::forget(self); + + TplGuard { + old_tpl, + boot_handle: MaybeBootRef::Value(boot_handle), + } + } +} + +impl Drop for TplGuard<'_> { + fn drop(&mut self) { + let boot_services = self.boot_handle.0; + + unsafe { + (boot_services.as_ref().restore_tpl)(self.old_tpl); + } + } +} + +/// An open protocol interface. Automatically closes the protocol +/// interface on drop. +/// +/// Most protocols have interface data associated with them. `ScopedProtocol` +/// implements [`Deref`] and [`DerefMut`] to access this data. A few protocols +/// (such as [`DevicePath`] and [`LoadedImageDevicePath`]) may be installed with +/// null interface data, in which case [`Deref`] and [`DerefMut`] will +/// panic. The [`get`] and [`get_mut`] methods may be used to access the +/// optional interface data without panicking. +/// +/// See also the [`BootServices`] documentation for details of how to open a +/// protocol and why [`UnsafeCell`] is used. +/// +/// [`LoadedImageDevicePath`]: crate::proto::device_path::LoadedImageDevicePath +/// [`get`]: ScopedProtocol::get +/// [`get_mut`]: ScopedProtocol::get_mut +#[derive(Debug)] +pub struct ScopedProtocol<'a, P: Protocol + ?Sized + 'static> { + /// The protocol interface. + interface: Option<&'static UnsafeCell

>, + + open_params: OpenProtocolParams, + boot_handle: MaybeBootRef<'a>, +} + +impl<'a, P: Protocol + ?Sized> ScopedProtocol<'a, P> { + /// Get the protocol interface data, or `None` if the open protocol's + /// interface is null. + #[must_use] + pub fn get(&self) -> Option<&'a P> { + self.interface.map(|p| unsafe { &*p.get() }) + } + + /// Get the protocol interface data, or `None` if the open protocol's + /// interface is null. + #[must_use] + pub fn get_mut(&self) -> Option<&'a mut P> { + self.interface.map(|p| unsafe { &mut *p.get() }) + } + + /// Converts potentially scoped [`ScopedProtocol`] into a `'static` [`ScopedProtocol`]. + #[must_use] + pub fn make_static(self) -> ScopedProtocol<'static, P> { + let interface = self.interface; + let open_params = self.open_params; + + let boot_handle = match self.boot_handle { + MaybeBootRef::Ref(boot_ref) => boot_ref.clone(), + MaybeBootRef::Value(ref boot_handle) => BootHandle(boot_handle.0), + }; + + mem::forget(self); + + ScopedProtocol { + interface, + open_params, + boot_handle: MaybeBootRef::Value(boot_handle), + } + } +} + +impl<'a, P: Protocol + ?Sized> Drop for ScopedProtocol<'a, P> { + fn drop(&mut self) { + let status = unsafe { + (self.boot_handle.0.as_ref().close_protocol)( + self.open_params.handle.as_ptr(), + &P::GUID, + self.open_params.agent.as_ptr(), + Handle::opt_to_ptr(self.open_params.controller), + ) + }; + // All of the error cases for close_protocol boil down to + // calling it with a different set of parameters than what was + // passed to open_protocol. The public API prevents such errors, + // and the error can't be propagated out of drop anyway, so just + // assert success. + assert_eq!(status, Status::SUCCESS); + } +} + +impl<'a, P: Protocol + ?Sized> Deref for ScopedProtocol<'a, P> { + type Target = P; + + #[track_caller] + fn deref(&self) -> &Self::Target { + unsafe { &*self.interface.unwrap().get() } + } +} + +impl<'a, P: Protocol + ?Sized> DerefMut for ScopedProtocol<'a, P> { + #[track_caller] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.interface.unwrap().get() } + } +} + +/// Protocol interface [`Guids`][Guid] that are installed on a [`Handle`] as +/// returned by [`BootServices::protocols_per_handle`]. +#[derive(Debug)] +pub struct ProtocolsPerHandle<'a> { + protocols: *mut &'static Guid, + count: usize, + + // The pointer returned by `protocols_per_handle` has to be free'd with + // `free_pool`, so keep a reference to boot services for that purpose. + boot_handle: MaybeBootRef<'a>, +} + +impl<'a> Drop for ProtocolsPerHandle<'a> { + fn drop(&mut self) { + // Ignore the result, we can't do anything about an error here. + let _ = unsafe { self.boot_handle.free_pool(self.protocols.cast::()) }; + } +} + +impl<'a> Deref for ProtocolsPerHandle<'a> { + type Target = [&'a Guid]; + + fn deref(&self) -> &Self::Target { + unsafe { slice::from_raw_parts(self.protocols, self.count) } + } +} + +impl<'a> ProtocolsPerHandle<'a> { + /// Get the protocol interface [`Guids`][Guid] that are installed on the + /// [`Handle`]. + #[allow(clippy::missing_const_for_fn)] // Required until we bump the MSRV. + #[deprecated = "use Deref instead"] + #[must_use] + pub fn protocols<'b>(&'b self) -> &'b [&'a Guid] { + // convert raw pointer to slice here so that we can get + // appropriate lifetime of the slice. + unsafe { slice::from_raw_parts(self.protocols, self.count) } + } + + /// Converts potentially scoped [`ProtocolsPerHandle`] into a `'static` [`ProtocolsPerHandle`]. + #[must_use] + pub fn make_static(self) -> ProtocolsPerHandle<'static> { + let protocols = self.protocols; + let count = self.count; + + let boot_handle = match self.boot_handle { + MaybeBootRef::Ref(boot_ref) => boot_ref.clone(), + MaybeBootRef::Value(ref boot_handle) => BootHandle(boot_handle.0), + }; + + mem::forget(self); + + ProtocolsPerHandle { + protocols, + count, + boot_handle: MaybeBootRef::Value(boot_handle), + } + } +} + +/// A buffer that contains an array of [`Handles`][Handle] that support the +/// requested protocol. Returned by [`BootServices::locate_handle_buffer`]. +#[derive(Debug)] +pub struct HandleBuffer<'a> { + count: usize, + buffer: *mut Handle, + + // The pointer returned by `locate_handle_buffer` has to be freed with + // `free_pool`, so keep a reference to boot services for that purpose. + boot_handle: MaybeBootRef<'a>, +} + +impl<'a> Drop for HandleBuffer<'a> { + fn drop(&mut self) { + // Ignore the result, we can't do anything about an error here. + let _ = unsafe { self.boot_handle.free_pool(self.buffer.cast::()) }; + } +} + +impl<'a> Deref for HandleBuffer<'a> { + type Target = [Handle]; + + fn deref(&self) -> &Self::Target { + unsafe { slice::from_raw_parts(self.buffer, self.count) } + } +} + +impl<'a> HandleBuffer<'a> { + /// Get an array of [`Handles`][Handle] that support the requested protocol. + #[allow(clippy::missing_const_for_fn)] // Required until we bump the MSRV. + #[deprecated = "use Deref instead"] + #[must_use] + pub fn handles(&self) -> &[Handle] { + // convert raw pointer to slice here so that we can get + // appropriate lifetime of the slice. + unsafe { slice::from_raw_parts(self.buffer, self.count) } + } + + /// Converts potentially scoped [`HandleBuffer`] into a `'static` [`HandleBuffer`]. + #[must_use] + pub fn make_static(self) -> HandleBuffer<'static> { + let count = self.count; + let buffer = self.buffer; + + let boot_handle = match self.boot_handle { + MaybeBootRef::Ref(boot_ref) => boot_ref.clone(), + MaybeBootRef::Value(ref boot_handle) => BootHandle(boot_handle.0), + }; + + mem::forget(self); + + HandleBuffer { + buffer, + count, + boot_handle: MaybeBootRef::Value(boot_handle), + } + } +} + +#[derive(Debug)] +enum MaybeBootRef<'boot> { + Ref(&'boot BootHandle), + Value(BootHandle), +} + +impl Deref for MaybeBootRef<'_> { + type Target = BootHandle; + + fn deref(&self) -> &Self::Target { + match *self { + MaybeBootRef::Ref(reference) => reference, + MaybeBootRef::Value(ref value) => value, + } + } +} diff --git a/uefi/src/boot/raw.rs b/uefi/src/boot/raw.rs new file mode 100644 index 000000000..6fb027701 --- /dev/null +++ b/uefi/src/boot/raw.rs @@ -0,0 +1,720 @@ +#[cfg(feature = "alloc")] +use alloc::vec::Vec; +use core::cell::UnsafeCell; +use core::ffi::c_void; +use core::mem::{self, MaybeUninit}; +use core::ops::Deref; +use core::ptr::{self, NonNull}; +use core::slice; + +use uefi_raw::table::boot::{EventType, InterfaceType, MemoryDescriptor, MemoryType, Tpl}; +use uefi_raw::table::Revision; +use uefi_raw::{PhysicalAddress, Status}; +use uguid::Guid; + +use crate::data_types::Align; +use crate::proto::device_path::DevicePath; +use crate::proto::loaded_image::LoadedImage; +use crate::proto::media::fs::SimpleFileSystem; +use crate::proto::ProtocolPointer; +use crate::table::boot::{ + AllocateType, EventNotifyFn, LoadImageSource, MemoryMap, MemoryMapKey, MemoryMapSize, + OpenProtocolAttributes, OpenProtocolParams, ProtocolSearchKey, SearchType, TimerTrigger, +}; +use crate::util::opt_nonnull_to_ptr; +use crate::{Char16, Error, Event, Handle, Result, StatusExt}; + +use super::{ + image_handle, BootHandle, HandleBuffer, MaybeBootRef, ProtocolsPerHandle, ScopedProtocol, + TplGuard, +}; + +pub(super) unsafe fn raise_tpl_raw(boot_handle: MaybeBootRef, tpl: Tpl) -> TplGuard { + let boot_services = unsafe { boot_handle.0.as_ref() }; + + let old_tpl = unsafe { (boot_services.raise_tpl)(tpl) }; + + TplGuard { + old_tpl, + boot_handle, + } +} + +pub(super) fn allocate_pages_raw( + boot_handle: &BootHandle, + ty: AllocateType, + mem_ty: MemoryType, + count: usize, +) -> Result { + let (ty, mut addr) = match ty { + AllocateType::AnyPages => (0, 0), + AllocateType::MaxAddress(addr) => (1, addr), + AllocateType::Address(addr) => (2, addr), + }; + + unsafe { (boot_handle.0.as_ref().allocate_pages)(ty, mem_ty, count, &mut addr) } + .to_result_with_val(|| addr) +} + +pub(super) unsafe fn free_pages_raw( + boot_handle: &BootHandle, + addr: PhysicalAddress, + count: usize, +) -> Result { + unsafe { ((*boot_handle.0.as_ptr()).free_pages)(addr, count) }.to_result() +} + +pub(super) fn memory_map_size_raw(boot_handle: &BootHandle) -> MemoryMapSize { + let mut map_size = 0; + let mut map_key = MemoryMapKey(0); + let mut entry_size = 0; + let mut entry_version = 0; + + let status = unsafe { + ((boot_handle.0.as_ref()).get_memory_map)( + &mut map_size, + ptr::null_mut(), + &mut map_key.0, + &mut entry_size, + &mut entry_version, + ) + }; + assert_eq!(status, Status::BUFFER_TOO_SMALL); + + MemoryMapSize { + entry_size, + map_size, + } +} + +pub(super) fn memory_map_raw<'buf>( + boot_handle: &BootHandle, + buffer: &'buf mut [u8], +) -> Result> { + let mut map_size = buffer.len(); + MemoryDescriptor::assert_aligned(buffer); + let map_buffer = buffer.as_mut_ptr().cast::(); + let mut map_key = MemoryMapKey(0); + let mut entry_size = 0; + let mut entry_version = 0; + + assert_eq!( + (map_buffer as usize) % mem::align_of::(), + 0, + "Memory map buffers must be aligned like a MemoryDescriptor" + ); + + unsafe { + ((boot_handle.0.as_ref()).get_memory_map)( + &mut map_size, + map_buffer, + &mut map_key.0, + &mut entry_size, + &mut entry_version, + ) + } + .to_result_with_val(move || { + let len = map_size / entry_size; + + MemoryMap { + key: map_key, + buf: buffer, + entry_size, + len, + } + }) +} + +pub(super) fn allocate_pool_raw( + boot_handle: &BootHandle, + mem_ty: MemoryType, + size: usize, +) -> Result<*mut u8> { + let mut buffer = ptr::null_mut(); + unsafe { ((boot_handle.0.as_ref()).allocate_pool)(mem_ty, size, &mut buffer) } + .to_result_with_val(|| buffer) +} + +pub(super) unsafe fn free_pool_raw(boot_handle: &BootHandle, addr: *mut u8) -> Result { + unsafe { (boot_handle.0.as_ref().free_pool)(addr) }.to_result() +} + +pub(super) unsafe fn create_event_raw( + boot_handle: &BootHandle, + event_ty: EventType, + notify_tpl: Tpl, + notify_fn: Option, + notify_ctx: Option>, +) -> Result { + let mut event = ptr::null_mut(); + + let notify_ctx = opt_nonnull_to_ptr(notify_ctx); + + // Safety: the argument types of the function pointers are defined + // differently, but are compatible and can be safely transmuted. + let notify_fn: Option = mem::transmute(notify_fn); + + // Now we're ready to call UEFI + (boot_handle.0.as_ref().create_event)(event_ty, notify_tpl, notify_fn, notify_ctx, &mut event) + .to_result_with_val( + // OK to unwrap: event is non-null for Status::SUCCESS. + || Event::from_ptr(event).unwrap(), + ) +} + +pub(super) unsafe fn create_event_ex_raw( + boot_handle: &BootHandle, + event_type: EventType, + notify_tpl: Tpl, + notify_fn: Option, + notify_ctx: Option>, + event_group: Option>, +) -> Result { + if boot_handle.0.as_ref().header.revision < Revision::EFI_2_00 { + return Err(Status::UNSUPPORTED.into()); + } + + let mut event = ptr::null_mut(); + + // Safety: the argument types of the function pointers are defined + // differently, but are compatible and can be safely transmuted. + let notify_fn: Option = mem::transmute(notify_fn); + + (boot_handle.0.as_ref().create_event_ex)( + event_type, + notify_tpl, + notify_fn, + opt_nonnull_to_ptr(notify_ctx), + opt_nonnull_to_ptr(event_group), + &mut event, + ) + .to_result_with_val( + // OK to unwrap: event is non-null for Status::SUCCESS. + || Event::from_ptr(event).unwrap(), + ) +} + +pub(super) fn set_timer_raw( + boot_handle: &BootHandle, + event: &Event, + trigger_time: TimerTrigger, +) -> Result { + let (ty, time) = match trigger_time { + TimerTrigger::Cancel => (0, 0), + TimerTrigger::Periodic(hundreds_ns) => (1, hundreds_ns), + TimerTrigger::Relative(hundreds_ns) => (2, hundreds_ns), + }; + unsafe { (boot_handle.0.as_ref().set_timer)(event.as_ptr(), ty, time) }.to_result() +} + +pub(super) fn wait_for_event_raw( + boot_handle: &BootHandle, + events: &mut [Event], +) -> Result> { + let number_of_events = events.len(); + let events: *mut uefi_raw::Event = events.as_mut_ptr().cast(); + + let mut index = 0; + unsafe { (boot_handle.0.as_ref().wait_for_event)(number_of_events, events, &mut index) } + .to_result_with( + || index, + |s| { + if s == Status::INVALID_PARAMETER { + Some(index) + } else { + None + } + }, + ) +} + +pub(super) fn signal_event_raw(boot_handle: &BootHandle, event: &Event) -> Result { + // Safety: cloning this event should be safe, as we're directly passing it to firmware + // and not keeping the clone around. + unsafe { (boot_handle.0.as_ref().signal_event)(event.as_ptr()).to_result() } +} + +pub(super) fn close_event_raw(boot_handle: &BootHandle, event: Event) -> Result { + unsafe { (boot_handle.0.as_ref().close_event)(event.as_ptr()).to_result() } +} + +pub(super) fn check_event_raw(boot_handle: &BootHandle, event: Event) -> Result { + let status = unsafe { (boot_handle.0.as_ref().check_event)(event.as_ptr()) }; + match status { + Status::SUCCESS => Ok(true), + Status::NOT_READY => Ok(false), + _ => Err(status.into()), + } +} + +pub(super) unsafe fn install_protocol_interface_raw( + boot_handle: &BootHandle, + handle: Option, + protocol: &Guid, + interface: *mut c_void, +) -> Result { + let mut handle = Handle::opt_to_ptr(handle); + ((boot_handle.0.as_ref().install_protocol_interface)( + &mut handle, + protocol, + InterfaceType::NATIVE_INTERFACE, + interface, + )) + .to_result_with_val(|| Handle::from_ptr(handle).unwrap()) +} + +pub(super) unsafe fn reinstall_protocol_interface_raw( + boot_handle: &BootHandle, + handle: Handle, + protocol: &Guid, + old_interface: *mut c_void, + new_interface: *mut c_void, +) -> Result<()> { + (boot_handle.0.as_ref().reinstall_protocol_interface)( + handle.as_ptr(), + protocol, + old_interface, + new_interface, + ) + .to_result() +} + +pub(super) unsafe fn uninstall_protocol_interface_raw( + boot_handle: &BootHandle, + handle: Handle, + protocol: &Guid, + interface: *mut c_void, +) -> Result<()> { + (boot_handle.0.as_ref().uninstall_protocol_interface)(handle.as_ptr(), protocol, interface) + .to_result() +} + +pub fn register_protocol_notify_raw<'guid>( + boot_handle: &BootHandle, + protocol: &'guid Guid, + event: Event, +) -> Result<(Event, SearchType<'guid>)> { + let mut key = ptr::null(); + // Safety: we clone `event` a couple times, but there will be only one left once we return. + unsafe { (boot_handle.0.as_ref().register_protocol_notify)(protocol, event.as_ptr(), &mut key) } + // Safety: as long as this call is successful, `key` will be valid. + .to_result_with_val(|| unsafe { + ( + event.unsafe_clone(), + // OK to unwrap: key is non-null for Status::SUCCESS. + SearchType::ByRegisterNotify(ProtocolSearchKey( + NonNull::new(key.cast_mut()).unwrap(), + )), + ) + }) +} + +pub(super) fn locate_handle_raw( + boot_handle: &BootHandle, + search_ty: SearchType, + output: Option<&mut [MaybeUninit]>, +) -> Result { + let handle_size = mem::size_of::(); + + const NULL_BUFFER: *mut MaybeUninit = ptr::null_mut(); + + let (mut buffer_size, buffer) = match output { + Some(buffer) => (buffer.len() * handle_size, buffer.as_mut_ptr()), + None => (0, NULL_BUFFER), + }; + + // Obtain the needed data from the parameters. + let (ty, guid, key) = match search_ty { + SearchType::AllHandles => (0, ptr::null(), ptr::null()), + SearchType::ByRegisterNotify(registration) => { + (1, ptr::null(), registration.0.as_ptr().cast_const()) + } + SearchType::ByProtocol(guid) => (2, guid as *const Guid, ptr::null()), + }; + + let status = unsafe { + (boot_handle.0.as_ref().locate_handle)(ty, guid, key, &mut buffer_size, buffer.cast()) + }; + + // Must convert the returned size (in bytes) to length (number of elements). + let buffer_len = buffer_size / handle_size; + + match (buffer, status) { + (NULL_BUFFER, Status::BUFFER_TOO_SMALL) => Ok(buffer_len), + (_, other_status) => other_status.to_result_with_val(|| buffer_len), + } +} + +pub(super) fn locate_device_path_raw( + boot_handle: &BootHandle, + device_path: &mut &DevicePath, +) -> Result { + let mut handle = ptr::null_mut(); + let mut device_path_ptr: *const uefi_raw::protocol::device_path::DevicePathProtocol = + device_path.as_ffi_ptr().cast(); + unsafe { + (boot_handle.0.as_ref().locate_device_path)(&P::GUID, &mut device_path_ptr, &mut handle) + .to_result_with_val(|| { + *device_path = DevicePath::from_ffi_ptr(device_path_ptr.cast()); + // OK to unwrap: handle is non-null for Status::SUCCESS. + Handle::from_ptr(handle).unwrap() + }) + } +} + +pub(super) fn get_handle_for_protocol_raw( + boot_handle: &BootHandle, +) -> Result { + // Delegate to a non-generic function to potentially reduce code size. + get_handle_for_protocol_impl(boot_handle, &P::GUID) +} + +fn get_handle_for_protocol_impl(boot_handle: &BootHandle, guid: &Guid) -> Result { + locate_handle_buffer_raw(MaybeBootRef::Ref(boot_handle), SearchType::ByProtocol(guid))? + .first() + .cloned() + .ok_or_else(|| Status::NOT_FOUND.into()) +} + +pub(super) fn load_image_raw( + boot_handle: &BootHandle, + parent_image_handle: Handle, + source: LoadImageSource, +) -> uefi::Result { + let boot_policy; + let device_path; + let source_buffer; + let source_size; + match source { + LoadImageSource::FromBuffer { buffer, file_path } => { + // Boot policy is ignored when loading from source buffer. + boot_policy = 0; + + device_path = file_path.map(|p| p.as_ffi_ptr()).unwrap_or(ptr::null()); + source_buffer = buffer.as_ptr(); + source_size = buffer.len(); + } + LoadImageSource::FromDevicePath { + device_path: file_path, + from_boot_manager, + } => { + boot_policy = u8::from(from_boot_manager); + device_path = file_path.as_ffi_ptr(); + source_buffer = ptr::null(); + source_size = 0; + } + }; + + let mut image_handle = ptr::null_mut(); + unsafe { + (boot_handle.0.as_ref().load_image)( + boot_policy, + parent_image_handle.as_ptr(), + device_path.cast(), + source_buffer, + source_size, + &mut image_handle, + ) + .to_result_with_val( + // OK to unwrap: image handle is non-null for Status::SUCCESS. + || Handle::from_ptr(image_handle).unwrap(), + ) + } +} + +pub(super) fn unload_image_raw(boot_handle: &BootHandle, image_handle: Handle) -> Result { + unsafe { (boot_handle.0.as_ref().unload_image)(image_handle.as_ptr()) }.to_result() +} + +pub(super) fn start_image_raw(boot_handle: &BootHandle, image_handle: Handle) -> Result { + unsafe { + // TODO: implement returning exit data to the caller. + let mut exit_data_size: usize = 0; + let mut exit_data: *mut u16 = ptr::null_mut(); + (boot_handle.0.as_ref().start_image)( + image_handle.as_ptr(), + &mut exit_data_size, + &mut exit_data, + ) + .to_result() + } +} + +pub(super) unsafe fn exit_raw( + boot_handle: &BootHandle, + image_handle: Handle, + exit_status: Status, + exit_data_size: usize, + exit_data: *mut Char16, +) -> ! { + (boot_handle.0.as_ref().exit)( + image_handle.as_ptr(), + exit_status, + exit_data_size, + exit_data.cast(), + ) +} + +pub(super) unsafe fn exit_boot_services_raw( + boot_handle: &BootHandle, + image: Handle, + mmap_key: MemoryMapKey, +) -> Result { + (boot_handle.0.as_ref().exit_boot_services)(image.as_ptr(), mmap_key.0).to_result() +} + +pub(super) fn stall_raw(boot_handle: &BootHandle, time: usize) { + assert_eq!( + unsafe { (boot_handle.0.as_ref().stall)(time) }, + Status::SUCCESS + ); +} + +pub(super) unsafe fn install_configuration_table_raw( + boot_handle: &BootHandle, + guid_entry: &Guid, + table_ptr: *const c_void, +) -> Result { + (boot_handle.0.as_ref().install_configuration_table)(guid_entry, table_ptr).to_result() +} + +pub(super) fn set_watchdog_timer_raw( + boot_handle: &BootHandle, + timeout: usize, + watchdog_code: u64, + data: Option<&mut [u16]>, +) -> Result { + assert!( + watchdog_code > 0xffff, + "Invalid use of a reserved firmware watchdog code" + ); + + let (data_len, data) = data + .map(|d| { + assert!( + d.contains(&0), + "Watchdog data must start with a null-terminated string" + ); + (d.len(), d.as_mut_ptr()) + }) + .unwrap_or((0, ptr::null_mut())); + + unsafe { (boot_handle.0.as_ref().set_watchdog_timer)(timeout, watchdog_code, data_len, data) } + .to_result() +} + +pub(super) fn connect_controller_raw( + boot_handle: &BootHandle, + controller: Handle, + driver_image: Option, + remaining_device_path: Option<&DevicePath>, + recursive: bool, +) -> Result { + unsafe { + (boot_handle.0.as_ref().connect_controller)( + controller.as_ptr(), + Handle::opt_to_ptr(driver_image), + remaining_device_path + .map(|dp| dp.as_ffi_ptr()) + .unwrap_or(ptr::null()) + .cast(), + recursive, + ) + } + .to_result_with_err(|_| ()) +} + +pub(super) fn disconnect_controller_raw( + boot_handle: &BootHandle, + controller: Handle, + driver_image: Option, + child: Option, +) -> Result { + unsafe { + (boot_handle.0.as_ref().disconnect_controller)( + controller.as_ptr(), + Handle::opt_to_ptr(driver_image), + Handle::opt_to_ptr(child), + ) + } + .to_result_with_err(|_| ()) +} + +pub(super) unsafe fn open_protocol_raw( + boot_handle: MaybeBootRef, + params: OpenProtocolParams, + attributes: OpenProtocolAttributes, +) -> Result> { + let mut interface = ptr::null_mut(); + (boot_handle.0.as_ref().open_protocol)( + params.handle.as_ptr(), + &P::GUID, + &mut interface, + params.agent.as_ptr(), + Handle::opt_to_ptr(params.controller), + attributes as u32, + ) + .to_result_with_val(|| { + let interface = (!interface.is_null()).then(|| { + let interface = P::mut_ptr_from_ffi(interface) as *const UnsafeCell

; + &*interface + }); + + ScopedProtocol { + interface, + open_params: params, + boot_handle, + } + }) +} + +pub(super) fn open_protocol_exclusive_raw( + boot_handle: MaybeBootRef, + handle: Handle, +) -> Result> { + // Safety: opening in exclusive mode with the correct agent + // handle set ensures that the protocol cannot be modified or + // removed while it is open, so this usage is safe. + unsafe { + open_protocol_raw::

( + boot_handle, + OpenProtocolParams { + handle, + agent: image_handle(), + controller: None, + }, + OpenProtocolAttributes::Exclusive, + ) + } +} + +pub(super) fn test_protocol_raw( + boot_handle: &BootHandle, + params: OpenProtocolParams, +) -> Result<()> { + const TEST_PROTOCOL: u32 = 0x04; + let mut interface = ptr::null_mut(); + unsafe { + (boot_handle.0.as_ref().open_protocol)( + params.handle.as_ptr(), + &P::GUID, + &mut interface, + params.agent.as_ptr(), + Handle::opt_to_ptr(params.controller), + TEST_PROTOCOL, + ) + } + .to_result_with_val(|| ()) +} + +pub(super) fn protocols_per_handle_raw( + boot_handle: MaybeBootRef, + handle: Handle, +) -> Result { + let mut protocols = ptr::null_mut(); + let mut count = 0; + + let mut status = unsafe { + (boot_handle.0.as_ref().protocols_per_handle)(handle.as_ptr(), &mut protocols, &mut count) + }; + + if !status.is_error() { + // Ensure that protocols isn't null, and that none of the GUIDs + // returned are null. + if protocols.is_null() { + status = Status::OUT_OF_RESOURCES; + } else { + let protocols: &[*const Guid] = unsafe { slice::from_raw_parts(protocols, count) }; + if protocols.iter().any(|ptr| ptr.is_null()) { + status = Status::OUT_OF_RESOURCES; + } + } + } + + status.to_result_with_val(|| ProtocolsPerHandle { + protocols: protocols.cast::<&Guid>(), + count, + boot_handle, + }) +} + +pub(super) fn locate_handle_buffer_raw<'boof>( + boot_handle: MaybeBootRef<'boof>, + search_ty: SearchType, +) -> Result> { + let mut num_handles: usize = 0; + let mut buffer: *mut uefi_raw::Handle = ptr::null_mut(); + + // Obtain the needed data from the parameters. + let (ty, guid, key) = match search_ty { + SearchType::AllHandles => (0, ptr::null(), ptr::null()), + SearchType::ByRegisterNotify(registration) => { + (1, ptr::null(), registration.0.as_ptr().cast_const()) + } + SearchType::ByProtocol(guid) => (2, guid as *const _, ptr::null()), + }; + + unsafe { + (boot_handle.0.as_ref().locate_handle_buffer)(ty, guid, key, &mut num_handles, &mut buffer) + } + .to_result_with_val(|| HandleBuffer { + boot_handle, + count: num_handles, + buffer: buffer.cast(), + }) +} + +pub(super) fn get_image_file_system_raw( + boot_handle: MaybeBootRef, + image_handle: Handle, +) -> Result> { + let raw_boot_handle: &BootHandle = boot_handle.deref(); + + let loaded_image = open_protocol_exclusive_raw::( + MaybeBootRef::Ref(raw_boot_handle), + image_handle, + )?; + + let device_handle = loaded_image + .device() + .ok_or(Error::new(Status::UNSUPPORTED, ()))?; + + let device_path = open_protocol_exclusive_raw::( + MaybeBootRef::Ref(raw_boot_handle), + device_handle, + )?; + + let device_handle = + locate_device_path_raw::(raw_boot_handle, &mut &*device_path)?; + + drop(loaded_image); + drop(device_path); + + open_protocol_exclusive_raw(boot_handle, device_handle) +} + +#[cfg(feature = "alloc")] +pub(super) fn find_handles_raw( + boot_handle: &BootHandle, +) -> Result> { + // Search by protocol. + let search_type = SearchType::from_proto::

(); + + // Determine how much we need to allocate. + let buffer_size = locate_handle_raw(boot_handle, search_type, None)?; + + // Allocate a large enough buffer without pointless initialization. + let mut handles = Vec::with_capacity(buffer_size); + let buffer = handles.spare_capacity_mut(); + + // Perform the search. + let buffer_size = locate_handle_raw(boot_handle, search_type, Some(buffer))?; + + // Mark the returned number of elements as initialized. + unsafe { + handles.set_len(buffer_size); + } + + // Emit output, with warnings + Ok(handles) +} diff --git a/uefi/src/lib.rs b/uefi/src/lib.rs index f8fa31f62..287966635 100644 --- a/uefi/src/lib.rs +++ b/uefi/src/lib.rs @@ -114,6 +114,10 @@ pub mod prelude; pub mod allocator; +pub mod boot; +pub mod runtime; +pub mod system; + #[cfg(feature = "logger")] pub mod logger; diff --git a/uefi/src/proto/console/gop.rs b/uefi/src/proto/console/gop.rs index 351dc0c89..64d5a75d7 100644 --- a/uefi/src/proto/console/gop.rs +++ b/uefi/src/proto/console/gop.rs @@ -50,7 +50,7 @@ //! You will have to implement your own double buffering if you want to //! avoid tearing with animations. -use crate::prelude::BootServices; +use crate::boot::free_pool; use crate::proto::unsafe_protocol; use crate::util::usize_from_u32; use crate::{Result, StatusExt}; @@ -76,7 +76,7 @@ pub struct GraphicsOutput(GraphicsOutputProtocol); impl GraphicsOutput { /// Returns information for an available graphics mode that the graphics /// device and the set of active video output devices supports. - pub fn query_mode(&self, index: u32, bs: &BootServices) -> Result { + pub fn query_mode(&self, index: u32) -> Result { let mut info_sz = 0; let mut info_heap_ptr = ptr::null(); // query_mode allocates a buffer and stores the heap ptr in the provided @@ -90,7 +90,7 @@ impl GraphicsOutput { // User has no benefit from propagating this error. If this // fails, it is an error of the UEFI implementation. - unsafe { bs.free_pool(info_heap_ptr) }.expect("buffer should be deallocatable"); + unsafe { free_pool(info_heap_ptr) }.expect("buffer should be deallocatable"); Mode { index, @@ -102,10 +102,9 @@ impl GraphicsOutput { /// Returns information about all available graphics modes. #[must_use] - pub fn modes<'a>(&'a self, bs: &'a BootServices) -> ModeIter { + pub fn modes<'a>(&'a self) -> ModeIter { ModeIter { gop: self, - bs, current: 0, max: self.mode().max_mode, } @@ -410,7 +409,6 @@ impl ModeInfo { /// Iterator for [`Mode`]s of the [`GraphicsOutput`] protocol. pub struct ModeIter<'gop> { gop: &'gop GraphicsOutput, - bs: &'gop BootServices, current: u32, max: u32, } @@ -421,7 +419,7 @@ impl<'gop> Iterator for ModeIter<'gop> { fn next(&mut self) -> Option { let index = self.current; if index < self.max { - let m = self.gop.query_mode(index, self.bs); + let m = self.gop.query_mode(index); self.current += 1; m.ok().or_else(|| self.next()) diff --git a/uefi/src/proto/console/serial.rs b/uefi/src/proto/console/serial.rs index 59e8658e4..de52944de 100644 --- a/uefi/src/proto/console/serial.rs +++ b/uefi/src/proto/console/serial.rs @@ -5,8 +5,9 @@ use crate::{Result, StatusExt}; use core::fmt::Write; use uefi_raw::protocol::console::serial::SerialIoProtocol; -pub use uefi_raw::protocol::console::serial::SerialIoMode as IoMode; -pub use uefi_raw::protocol::console::serial::{ControlBits, Parity, StopBits}; +pub use uefi_raw::protocol::console::serial::{ + ControlBits, Parity, SerialIoMode as IoMode, StopBits, +}; /// Provides access to a serial I/O device. /// diff --git a/uefi/src/proto/pi/mp.rs b/uefi/src/proto/pi/mp.rs index 50f0e2e8e..8fcfde94c 100644 --- a/uefi/src/proto/pi/mp.rs +++ b/uefi/src/proto/pi/mp.rs @@ -11,8 +11,9 @@ //! * dispatching user-provided function to APs //! * maintaining MP-related processor status +use crate::data_types::Event; use crate::proto::unsafe_protocol; -use crate::{data_types::Event, Result, Status, StatusExt}; +use crate::{Result, Status, StatusExt}; use bitflags::bitflags; use core::ffi::c_void; use core::ptr; diff --git a/uefi/src/runtime.rs b/uefi/src/runtime.rs new file mode 100644 index 000000000..9e2815689 --- /dev/null +++ b/uefi/src/runtime.rs @@ -0,0 +1,368 @@ +//! UEFI services available at runtime, even after the OS boots. +//! +//! All of these functions are unsafe because UEFI runtime services require +//! an elaborate CPU configuration which may not be preserved by OS loaders. +//! See the "Calling Conventions" chapter of the UEFI specification for details. + +#[cfg(feature = "alloc")] +use alloc::{boxed::Box, vec::Vec}; +use core::mem::MaybeUninit; +use core::ptr::{self, NonNull}; + +use uefi_raw::table::boot::MemoryDescriptor; +use uefi_raw::table::runtime::{ResetType, TimeCapabilities, VariableAttributes, VariableVendor}; +use uefi_raw::table::Revision; +use uefi_raw::Status; + +use crate::system::{set_system_table, system_table}; +#[cfg(feature = "alloc")] +use crate::table::runtime::VariableKey; +use crate::table::runtime::{Time, VariableStorageInfo}; +use crate::{CStr16, Error, Result, StatusExt}; + +pub(crate) fn runtime_table() -> NonNull { + let runtime = unsafe { system_table().as_ref().runtime_services }; + + NonNull::new(runtime).expect("runtime table doesn't exist") +} + +/// Query the current time and date information +/// +/// # Safety +/// +/// This is unsafe because UEFI runtime services require an elaborate +/// CPU configuration which may not be preserved by OS loaders. See the +/// "Calling Conventions" chapter of the UEFI specification for details. +pub unsafe fn get_time() -> Result