Commit 5b4e982169
Changed files (10)
lib/std/os/uefi/tables/boot_services.zig
@@ -1,21 +1,31 @@
const std = @import("std");
const uefi = std.os.uefi;
const Event = uefi.Event;
+const EventRegistration = uefi.EventRegistration;
const Guid = uefi.Guid;
const Handle = uefi.Handle;
+const Page = uefi.Page;
+const Pages = uefi.Pages;
const Status = uefi.Status;
const TableHeader = uefi.tables.TableHeader;
const DevicePathProtocol = uefi.protocol.DevicePath;
+const AllocateLocation = uefi.tables.AllocateLocation;
const AllocateType = uefi.tables.AllocateType;
const MemoryType = uefi.tables.MemoryType;
const MemoryDescriptor = uefi.tables.MemoryDescriptor;
+const MemoryMapKey = uefi.tables.MemoryMapKey;
+const MemoryMapInfo = uefi.tables.MemoryMapInfo;
+const MemoryMapSlice = uefi.tables.MemoryMapSlice;
const TimerDelay = uefi.tables.TimerDelay;
const InterfaceType = uefi.tables.InterfaceType;
+const LocateSearch = uefi.tables.LocateSearch;
const LocateSearchType = uefi.tables.LocateSearchType;
+const OpenProtocolArgs = uefi.tables.OpenProtocolArgs;
const OpenProtocolAttributes = uefi.tables.OpenProtocolAttributes;
const ProtocolInformationEntry = uefi.tables.ProtocolInformationEntry;
const EventNotify = uefi.tables.EventNotify;
const cc = uefi.cc;
+const Error = Status.Error;
/// Boot services are services provided by the system's firmware until the operating system takes
/// over control over the hardware by calling exitBootServices.
@@ -32,173 +42,1236 @@ pub const BootServices = extern struct {
hdr: TableHeader,
/// Raises a task's priority level and returns its previous level.
- raiseTpl: *const fn (new_tpl: usize) callconv(cc) usize,
+ raiseTpl: *const fn (new_tpl: TaskPriorityLevel) callconv(cc) TaskPriorityLevel,
/// Restores a task's priority level to its previous value.
- restoreTpl: *const fn (old_tpl: usize) callconv(cc) void,
+ restoreTpl: *const fn (old_tpl: TaskPriorityLevel) callconv(cc) void,
/// Allocates memory pages from the system.
- allocatePages: *const fn (alloc_type: AllocateType, mem_type: MemoryType, pages: usize, memory: *[*]align(4096) u8) callconv(cc) Status,
+ _allocatePages: *const fn (alloc_type: AllocateType, mem_type: MemoryType, pages: usize, memory: *[*]align(4096) Page) callconv(cc) Status,
/// Frees memory pages.
- freePages: *const fn (memory: [*]align(4096) u8, pages: usize) callconv(cc) Status,
+ _freePages: *const fn (memory: [*]align(4096) Page, pages: usize) callconv(cc) Status,
/// Returns the current memory map.
- getMemoryMap: *const fn (mmap_size: *usize, mmap: ?[*]MemoryDescriptor, map_key: *usize, descriptor_size: *usize, descriptor_version: *u32) callconv(cc) Status,
+ _getMemoryMap: *const fn (mmap_size: *usize, mmap: ?[*]align(@alignOf(MemoryDescriptor)) u8, map_key: *MemoryMapKey, descriptor_size: *usize, descriptor_version: *u32) callconv(cc) Status,
/// Allocates pool memory.
- allocatePool: *const fn (pool_type: MemoryType, size: usize, buffer: *[*]align(8) u8) callconv(cc) Status,
+ _allocatePool: *const fn (pool_type: MemoryType, size: usize, buffer: *[*]align(8) u8) callconv(cc) Status,
/// Returns pool memory to the system.
- freePool: *const fn (buffer: [*]align(8) u8) callconv(cc) Status,
+ _freePool: *const fn (buffer: [*]align(8) u8) callconv(cc) Status,
/// Creates an event.
- createEvent: *const fn (type: u32, notify_tpl: usize, notify_func: ?*const fn (Event, ?*anyopaque) callconv(cc) void, notify_ctx: ?*const anyopaque, event: *Event) callconv(cc) Status,
+ _createEvent: *const fn (type: u32, notify_tpl: TaskPriorityLevel, notify_func: ?*const fn (Event, ?*anyopaque) callconv(cc) void, notify_ctx: ?*anyopaque, event: *Event) callconv(cc) Status,
/// Sets the type of timer and the trigger time for a timer event.
- setTimer: *const fn (event: Event, type: TimerDelay, trigger_time: u64) callconv(cc) Status,
+ _setTimer: *const fn (event: Event, type: TimerDelay, trigger_time: u64) callconv(cc) Status,
/// Stops execution until an event is signaled.
- waitForEvent: *const fn (event_len: usize, events: [*]const Event, index: *usize) callconv(cc) Status,
+ _waitForEvent: *const fn (event_len: usize, events: [*]const Event, index: *usize) callconv(cc) Status,
/// Signals an event.
- signalEvent: *const fn (event: Event) callconv(cc) Status,
+ _signalEvent: *const fn (event: Event) callconv(cc) Status,
/// Closes an event.
- closeEvent: *const fn (event: Event) callconv(cc) Status,
+ _closeEvent: *const fn (event: Event) callconv(cc) Status,
/// Checks whether an event is in the signaled state.
- checkEvent: *const fn (event: Event) callconv(cc) Status,
+ _checkEvent: *const fn (event: Event) callconv(cc) Status,
/// Installs a protocol interface on a device handle. If the handle does not exist, it is created
/// and added to the list of handles in the system. installMultipleProtocolInterfaces()
/// performs more error checking than installProtocolInterface(), so its use is recommended over this.
- installProtocolInterface: *const fn (handle: Handle, protocol: *align(8) const Guid, interface_type: InterfaceType, interface: *anyopaque) callconv(cc) Status,
+ _installProtocolInterface: *const fn (handle: Handle, protocol: *const Guid, interface_type: InterfaceType, interface: *anyopaque) callconv(cc) Status,
/// Reinstalls a protocol interface on a device handle
- reinstallProtocolInterface: *const fn (handle: Handle, protocol: *align(8) const Guid, old_interface: *anyopaque, new_interface: *anyopaque) callconv(cc) Status,
+ _reinstallProtocolInterface: *const fn (handle: Handle, protocol: *const Guid, old_interface: *anyopaque, new_interface: *anyopaque) callconv(cc) Status,
/// Removes a protocol interface from a device handle. Usage of
/// uninstallMultipleProtocolInterfaces is recommended over this.
- uninstallProtocolInterface: *const fn (handle: Handle, protocol: *align(8) const Guid, interface: *anyopaque) callconv(cc) Status,
+ _uninstallProtocolInterface: *const fn (handle: Handle, protocol: *const Guid, interface: *anyopaque) callconv(cc) Status,
/// Queries a handle to determine if it supports a specified protocol.
- handleProtocol: *const fn (handle: Handle, protocol: *align(8) const Guid, interface: *?*anyopaque) callconv(cc) Status,
+ _handleProtocol: *const fn (handle: Handle, protocol: *const Guid, interface: *?*anyopaque) callconv(cc) Status,
- reserved: *anyopaque,
+ _reserved: *anyopaque,
/// Creates an event that is to be signaled whenever an interface is installed for a specified protocol.
- registerProtocolNotify: *const fn (protocol: *align(8) const Guid, event: Event, registration: **anyopaque) callconv(cc) Status,
+ _registerProtocolNotify: *const fn (protocol: *const Guid, event: Event, registration: *EventRegistration) callconv(cc) Status,
/// Returns an array of handles that support a specified protocol.
- locateHandle: *const fn (search_type: LocateSearchType, protocol: ?*align(8) const Guid, search_key: ?*const anyopaque, buffer_size: *usize, buffer: [*]Handle) callconv(cc) Status,
+ _locateHandle: *const fn (search_type: LocateSearchType, protocol: ?*const Guid, search_key: ?*const anyopaque, buffer_size: *usize, buffer: ?[*]Handle) callconv(cc) Status,
/// Locates the handle to a device on the device path that supports the specified protocol
- locateDevicePath: *const fn (protocols: *align(8) const Guid, device_path: **const DevicePathProtocol, device: *?Handle) callconv(cc) Status,
+ _locateDevicePath: *const fn (protocols: *const Guid, device_path: **const DevicePathProtocol, device: *?Handle) callconv(cc) Status,
/// Adds, updates, or removes a configuration table entry from the EFI System Table.
- installConfigurationTable: *const fn (guid: *align(8) const Guid, table: ?*anyopaque) callconv(cc) Status,
+ _installConfigurationTable: *const fn (guid: *const Guid, table: ?*anyopaque) callconv(cc) Status,
/// Loads an EFI image into memory.
- loadImage: *const fn (boot_policy: bool, parent_image_handle: Handle, device_path: ?*const DevicePathProtocol, source_buffer: ?[*]const u8, source_size: usize, image_handle: *?Handle) callconv(cc) Status,
+ _loadImage: *const fn (boot_policy: bool, parent_image_handle: Handle, device_path: ?*const DevicePathProtocol, source_buffer: ?[*]const u8, source_size: usize, image_handle: *Handle) callconv(cc) Status,
/// Transfers control to a loaded image's entry point.
- startImage: *const fn (image_handle: Handle, exit_data_size: ?*usize, exit_data: ?*[*]u16) callconv(cc) Status,
+ _startImage: *const fn (image_handle: Handle, exit_data_size: ?*usize, exit_data: ?*[*]u16) callconv(cc) Status,
/// Terminates a loaded EFI image and returns control to boot services.
- exit: *const fn (image_handle: Handle, exit_status: Status, exit_data_size: usize, exit_data: ?*const anyopaque) callconv(cc) Status,
+ _exit: *const fn (image_handle: Handle, exit_status: Status, exit_data_size: usize, exit_data: ?[*]align(2) const u8) callconv(cc) Status,
/// Unloads an image.
- unloadImage: *const fn (image_handle: Handle) callconv(cc) Status,
+ _unloadImage: *const fn (image_handle: Handle) callconv(cc) Status,
/// Terminates all boot services.
- exitBootServices: *const fn (image_handle: Handle, map_key: usize) callconv(cc) Status,
+ _exitBootServices: *const fn (image_handle: Handle, map_key: MemoryMapKey) callconv(cc) Status,
/// Returns a monotonically increasing count for the platform.
- getNextMonotonicCount: *const fn (count: *u64) callconv(cc) Status,
+ _getNextMonotonicCount: *const fn (count: *u64) callconv(cc) Status,
/// Induces a fine-grained stall.
- stall: *const fn (microseconds: usize) callconv(cc) Status,
+ _stall: *const fn (microseconds: usize) callconv(cc) Status,
/// Sets the system's watchdog timer.
- setWatchdogTimer: *const fn (timeout: usize, watchdog_code: u64, data_size: usize, watchdog_data: ?[*]const u16) callconv(cc) Status,
+ _setWatchdogTimer: *const fn (timeout: usize, watchdog_code: u64, data_size: usize, watchdog_data: ?[*]const u16) callconv(cc) Status,
/// Connects one or more drives to a controller.
- connectController: *const fn (controller_handle: Handle, driver_image_handle: ?Handle, remaining_device_path: ?*DevicePathProtocol, recursive: bool) callconv(cc) Status,
+ _connectController: *const fn (controller_handle: Handle, driver_image_handle: ?[*:null]?Handle, remaining_device_path: ?*const DevicePathProtocol, recursive: bool) callconv(cc) Status,
// Disconnects one or more drivers from a controller
- disconnectController: *const fn (controller_handle: Handle, driver_image_handle: ?Handle, child_handle: ?Handle) callconv(cc) Status,
+ _disconnectController: *const fn (controller_handle: Handle, driver_image_handle: ?Handle, child_handle: ?Handle) callconv(cc) Status,
/// Queries a handle to determine if it supports a specified protocol.
- openProtocol: *const fn (handle: Handle, protocol: *align(8) const Guid, interface: *?*anyopaque, agent_handle: ?Handle, controller_handle: ?Handle, attributes: OpenProtocolAttributes) callconv(cc) Status,
+ _openProtocol: *const fn (handle: Handle, protocol: *const Guid, interface: ?*?*anyopaque, agent_handle: ?Handle, controller_handle: ?Handle, attributes: OpenProtocolAttributes) callconv(cc) Status,
/// Closes a protocol on a handle that was opened using openProtocol().
- closeProtocol: *const fn (handle: Handle, protocol: *align(8) const Guid, agent_handle: Handle, controller_handle: ?Handle) callconv(cc) Status,
+ _closeProtocol: *const fn (handle: Handle, protocol: *const Guid, agent_handle: Handle, controller_handle: ?Handle) callconv(cc) Status,
/// Retrieves the list of agents that currently have a protocol interface opened.
- openProtocolInformation: *const fn (handle: Handle, protocol: *align(8) const Guid, entry_buffer: *[*]ProtocolInformationEntry, entry_count: *usize) callconv(cc) Status,
+ _openProtocolInformation: *const fn (handle: Handle, protocol: *const Guid, entry_buffer: *[*]ProtocolInformationEntry, entry_count: *usize) callconv(cc) Status,
/// Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated from pool.
- protocolsPerHandle: *const fn (handle: Handle, protocol_buffer: *[*]*align(8) const Guid, protocol_buffer_count: *usize) callconv(cc) Status,
+ _protocolsPerHandle: *const fn (handle: Handle, protocol_buffer: *[*]*const Guid, protocol_buffer_count: *usize) callconv(cc) Status,
/// Returns an array of handles that support the requested protocol in a buffer allocated from pool.
- locateHandleBuffer: *const fn (search_type: LocateSearchType, protocol: ?*align(8) const Guid, search_key: ?*const anyopaque, num_handles: *usize, buffer: *[*]Handle) callconv(cc) Status,
+ _locateHandleBuffer: *const fn (search_type: LocateSearchType, protocol: ?*const Guid, search_key: ?*const anyopaque, num_handles: *usize, buffer: *[*]Handle) callconv(cc) Status,
/// Returns the first protocol instance that matches the given protocol.
- locateProtocol: *const fn (protocol: *align(8) const Guid, registration: ?*const anyopaque, interface: *?*anyopaque) callconv(cc) Status,
+ _locateProtocol: *const fn (protocol: *const Guid, registration: ?EventRegistration, interface: *?*const anyopaque) callconv(cc) Status,
/// Installs one or more protocol interfaces into the boot services environment
// TODO: use callconv(cc) instead once that works
- installMultipleProtocolInterfaces: *const fn (handle: *Handle, ...) callconv(.c) Status,
+ _installMultipleProtocolInterfaces: *const fn (handle: *Handle, ...) callconv(.c) Status,
/// Removes one or more protocol interfaces into the boot services environment
// TODO: use callconv(cc) instead once that works
- uninstallMultipleProtocolInterfaces: *const fn (handle: *Handle, ...) callconv(.c) Status,
+ _uninstallMultipleProtocolInterfaces: *const fn (handle: *Handle, ...) callconv(.c) Status,
/// Computes and returns a 32-bit CRC for a data buffer.
- calculateCrc32: *const fn (data: [*]const u8, data_size: usize, *u32) callconv(cc) Status,
+ _calculateCrc32: *const fn (data: [*]const u8, data_size: usize, *u32) callconv(cc) Status,
/// Copies the contents of one buffer to another buffer
- copyMem: *const fn (dest: [*]u8, src: [*]const u8, len: usize) callconv(cc) void,
+ _copyMem: *const fn (dest: [*]u8, src: [*]const u8, len: usize) callconv(cc) void,
/// Fills a buffer with a specified value
- setMem: *const fn (buffer: [*]u8, size: usize, value: u8) callconv(cc) void,
+ _setMem: *const fn (buffer: [*]u8, size: usize, value: u8) callconv(cc) void,
/// Creates an event in a group.
- createEventEx: *const fn (type: u32, notify_tpl: usize, notify_func: EventNotify, notify_ctx: *const anyopaque, event_group: *align(8) const Guid, event: *Event) callconv(cc) Status,
+ _createEventEx: *const fn (type: u32, notify_tpl: usize, notify_func: EventNotify, notify_ctx: *const anyopaque, event_group: *const Guid, event: *Event) callconv(cc) Status,
+
+ pub const AllocatePagesError = uefi.UnexpectedError || error{
+ OutOfResources,
+ InvalidParameter,
+ NotFound,
+ };
+
+ pub const FreePagesError = uefi.UnexpectedError || error{
+ NotFound,
+ InvalidParameter,
+ };
+
+ pub const GetMemoryMapError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ BufferTooSmall,
+ };
+
+ pub const AllocatePoolError = uefi.UnexpectedError || error{
+ OutOfResources,
+ InvalidParameter,
+ };
+
+ pub const FreePoolError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ };
+
+ pub const CreateEventError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ OutOfResources,
+ };
+
+ pub const SetTimerError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ };
+
+ pub const WaitForEventError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ Unsupported,
+ };
+
+ pub const CheckEventError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ };
+
+ pub const ReinstallProtocolInterfaceError = uefi.UnexpectedError || error{
+ NotFound,
+ AccessDenied,
+ InvalidParameter,
+ };
+
+ pub const HandleProtocolError = uefi.UnexpectedError || error{
+ Unsupported,
+ };
+
+ pub const RegisterProtocolNotifyError = uefi.UnexpectedError || error{
+ OutOfResources,
+ InvalidParameter,
+ };
+
+ pub const NumHandlesError = uefi.UnexpectedError || error{
+ OutOfResources,
+ };
+
+ pub const LocateHandleError = uefi.UnexpectedError || error{
+ BufferTooSmall,
+ InvalidParameter,
+ };
+
+ pub const LocateDevicePathError = uefi.UnexpectedError || error{
+ NotFound,
+ InvalidParameter,
+ };
+
+ pub const InstallConfigurationTableError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ OutOfResources,
+ };
+
+ pub const UninstallConfigurationTableError = InstallConfigurationTableError || error{
+ NotFound,
+ };
+
+ pub const LoadImageError = uefi.UnexpectedError || error{
+ NotFound,
+ InvalidParameter,
+ Unsupported,
+ OutOfResources,
+ LoadError,
+ DeviceError,
+ AccessDenied,
+ SecurityViolation,
+ };
+
+ pub const StartImageError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ SecurityViolation,
+ };
+
+ pub const ExitError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ };
+
+ pub const ExitBootServicesError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ };
+
+ pub const GetNextMonotonicCountError = uefi.UnexpectedError || error{
+ DeviceError,
+ InvalidParameter,
+ };
+
+ pub const SetWatchdogTimerError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ Unsupported,
+ DeviceError,
+ };
+
+ pub const ConnectControllerError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ NotFound,
+ SecurityViolation,
+ };
+
+ pub const DisconnectControllerError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ OutOfResources,
+ DeviceError,
+ };
+
+ pub const OpenProtocolError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ Unsupported,
+ AccessDenied,
+ AlreadyStarted,
+ };
+
+ pub const CloseProtocolError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ NotFound,
+ };
+
+ pub const OpenProtocolInformationError = uefi.UnexpectedError || error{
+ OutOfResources,
+ };
+
+ pub const ProtocolsPerHandleError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ OutOfResources,
+ };
+
+ pub const LocateHandleBufferError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ OutOfResources,
+ };
+
+ pub const LocateProtocolError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ };
+
+ pub const InstallProtocolInterfacesError = uefi.UnexpectedError || error{
+ AlreadyStarted,
+ OutOfResources,
+ InvalidParameter,
+ };
+
+ pub const UninstallProtocolInterfacesError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ };
+
+ pub const CalculateCrc32Error = uefi.UnexpectedError || error{
+ InvalidParameter,
+ };
+
+ /// Allocates pages of memory.
+ ///
+ /// This function scans the memory map to locate free pages. When it finds a
+ /// physically contiguous block of pages that is large enough and also satisfies
+ /// the allocation requirements of `alloc_type`, it changes the memory map to
+ /// indicate that the pages are now of type `mem_type`.
+ ///
+ /// In general, UEFI OS loaders and UEFI applications should allocate memory
+ /// (and pool) of type `.loader_data`. UEFI boot service drivers must allocate
+ /// memory (and pool) of type `.boot_services_data`. UREFI runtime drivers
+ /// should allocate memory (and pool) of type `.runtime_services_data`
+ /// (although such allocation can only be made during boot services time).
+ ///
+ /// Allocation requests of `.allocate_any_pages` allocate any available range
+ /// of pages that satisfies the request.
+ ///
+ /// Allocation requests of `.allocate_max_address` allocate any available range
+ /// of pages whose uppermost address is less than or equal to the address
+ /// pointed to by the input.
+ ///
+ /// Allocation requests of `.allocate_address` allocate pages at the address
+ /// pointed to by the input.
+ pub fn allocatePages(
+ self: *BootServices,
+ location: AllocateLocation,
+ mem_type: MemoryType,
+ pages: usize,
+ ) AllocatePagesError![]align(4096) Page {
+ var ptr: [*]align(4096) Page = switch (location) {
+ .any => undefined,
+ .address, .max_address => |ptr| ptr,
+ };
+
+ switch (self._allocatePages(
+ std.meta.activeTag(location),
+ mem_type,
+ pages,
+ &ptr,
+ )) {
+ .success => return ptr[0..pages],
+ .out_of_resources => return error.OutOfResources,
+ .invalid_parameter => return error.InvalidParameter,
+ .not_found => return error.NotFound,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn freePages(self: *BootServices, pages: []align(4096) Page) FreePagesError!void {
+ switch (self._freePages(pages.ptr, pages.len)) {
+ .success => {},
+ .not_found => return error.NotFound,
+ .invalid_parameter => return error.InvalidParameter,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn getMemoryMapInfo(self: *const BootServices) uefi.UnexpectedError!MemoryMapInfo {
+ var info: MemoryMapInfo = undefined;
+ info.len = 0;
+
+ switch (self._getMemoryMap(
+ &info.len,
+ null,
+ &info.key,
+ &info.descriptor_size,
+ &info.descriptor_version,
+ )) {
+ .success, .buffer_too_small => {
+ info.len = @divExact(info.len, info.descriptor_size);
+ return info;
+ },
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn getMemoryMap(
+ self: *const BootServices,
+ buffer: []align(@alignOf(MemoryDescriptor)) u8,
+ ) GetMemoryMapError!MemoryMapSlice {
+ var info: MemoryMapInfo = undefined;
+ info.len = buffer.len;
+
+ switch (self._getMemoryMap(
+ &info.len,
+ buffer.ptr,
+ &info.key,
+ &info.descriptor_size,
+ &info.descriptor_version,
+ )) {
+ .success => {
+ info.len = @divExact(info.len, info.descriptor_size);
+ return .{ .info = info, .ptr = buffer.ptr };
+ },
+ .buffer_too_small => return error.BufferTooSmall,
+ .invalid_parameter => return error.InvalidParameter,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ /// Allocates a memory region of `size` bytes from memory of type `pool_type`
+ /// and returns the allocated memory. Allocates pages from `.conventional_memory`
+ /// as needed to grow the requested pool type.
+ pub fn allocatePool(
+ self: *BootServices,
+ pool_type: MemoryType,
+ size: usize,
+ ) AllocatePoolError![]align(8) u8 {
+ var ptr: [*]align(8) u8 = undefined;
+
+ switch (self._allocatePool(pool_type, size, &ptr)) {
+ .success => return ptr[0..size],
+ .out_of_resources => return error.OutOfResources,
+ .invalid_parameter => return error.InvalidParameter,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn freePool(self: *BootServices, ptr: [*]align(8) u8) FreePoolError!void {
+ switch (self._freePool(ptr)) {
+ .success => {},
+ .invalid_parameter => return error.InvalidParameter,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn createEvent(
+ self: *BootServices,
+ event_type: uefi.EventType,
+ notify_opts: NotifyOpts,
+ ) CreateEventError!Event {
+ var evt: Event = undefined;
+
+ switch (self._createEvent(
+ @bitCast(event_type),
+ notify_opts.tpl,
+ notify_opts.function,
+ notify_opts.context,
+ &evt,
+ )) {
+ .success => return evt,
+ .invalid_parameter => return error.InvalidParameter,
+ .out_of_resources => return error.OutOfResources,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ /// Cancels any previous time trigger setting for the event, and sets a new
+ /// trigger timer for the event.
+ ///
+ /// Returns `error.InvalidParameter` if the event is not a timer event.
+ pub fn setTimer(
+ self: *BootServices,
+ event: Event,
+ @"type": TimerDelay,
+ trigger_time: u64,
+ ) SetTimerError!void {
+ switch (self._setTimer(event, @"type", trigger_time)) {
+ .success => {},
+ .invalid_parameter => return error.InvalidParameter,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ /// Returns the event that was signaled, along with its index in the slice.
+ pub fn waitForEvent(
+ self: *BootServices,
+ events: []const Event,
+ ) WaitForEventError!struct { *const Event, usize } {
+ var idx: usize = undefined;
+ switch (self._waitForEvent(events.len, events.ptr, &idx)) {
+ .success => return .{ &events[idx], idx },
+ .invalid_parameter => return error.InvalidParameter,
+ .unsupported => return error.Unsupported,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ /// If `event` is `EventType.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 the supplied Event is a 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.
+ pub fn signalEvent(self: *BootServices, event: Event) uefi.UnexpectedError!void {
+ switch (self._signalEvent(event)) {
+ .success => {},
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn closeEvent(self: *BootServices, event: Event) uefi.UnexpectedError!void {
+ switch (self._closeEvent(event)) {
+ .success => {},
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ /// Checks to see whether an event is signaled.
+ ///
+ /// The underlying function is equivalent to this pseudo-code:
+ /// ```
+ /// if (event.type.signal)
+ /// return error.InvalidParameter;
+ ///
+ /// if (event.signaled) {
+ /// event.signaled = false;
+ /// return true;
+ /// }
+ ///
+ /// const notify = event.notification_function orelse return false;
+ /// notify();
+ ///
+ /// if (event.signaled) {
+ /// event.signaled = false;
+ /// return true;
+ /// }
+ ///
+ /// return false;
+ /// ```
+ pub fn checkEvent(self: *BootServices, event: Event) CheckEventError!bool {
+ switch (self._checkEvent(event)) {
+ .success => return true,
+ .not_ready => return false,
+ .invalid_parameter => return error.InvalidParameter,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ /// See `installProtocolInterfaces`.
+ ///
+ /// Does not call `self._installProtocolInterface`, because
+ /// `self._installMultipleProtocolInterfaces` performs more error checks.
+ pub fn installProtocolInterface(
+ self: *BootServices,
+ handle: ?Handle,
+ interface: anytype,
+ ) InstallProtocolInterfacesError!Handle {
+ return self.installProtocolInterfaces(handle, .{
+ interface,
+ });
+ }
+
+ /// Reinstalls a protocol interface on a device handle.
+ ///
+ /// `new` may be the same as `old`. If it is, the registered protocol notifications
+ /// occur for the handle without replacing the interface on the handle.
+ ///
+ /// Any process that has registered to wait for the installation of the interface
+ /// is notified.
+ ///
+ /// The caller is responsible for ensuring that there are no references to `old`
+ /// if it is being removed.
+ pub fn reinstallProtocolInterface(
+ self: *BootServices,
+ handle: Handle,
+ Protocol: type,
+ old: ?*const Protocol,
+ new: ?*const Protocol,
+ ) ReinstallProtocolInterfaceError!void {
+ if (!@hasDecl(Protocol, "guid"))
+ @compileError("protocol is missing guid");
+
+ switch (self._reinstallProtocolInterface(
+ handle,
+ &Protocol.guid,
+ old,
+ new,
+ )) {
+ .success => {},
+ .not_found => return error.NotFound,
+ .access_denied => return error.AccessDenied,
+ .invalid_parameter => return error.InvalidParameter,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ /// See `uninstallProtocolInterfaces`.
+ ///
+ /// Does not call `self._uninstallProtocolInterface`, because
+ /// `self._uninstallMultipleProtocolInterfaces` performs more error checks.
+ pub fn uninstallProtocolInterface(
+ self: *BootServices,
+ handle: Handle,
+ interface: anytype,
+ ) UninstallProtocolInterfacesError!void {
+ return self.uninstallProtocolInterfaces(handle, .{
+ interface,
+ });
+ }
+
+ /// Returns a pointer to the `Protocol` interface if it's supported by the
+ /// handle.
+ ///
+ /// Note that UEFI implementations are no longer required to implement this
+ /// function, so it's implemented using `openProtocol` instead.
+ pub fn handleProtocol(
+ self: *BootServices,
+ Protocol: type,
+ handle: Handle,
+ ) HandleProtocolError!?*Protocol {
+ // per https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-handleprotocol
+ // handleProtocol is basically `openProtocol` where:
+ // 1. agent_handle is `uefi.handle` (aka handle passed to `EfiMain`)
+ // 2. controller_handle is `null`
+ // 3. attributes is `EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL`
+
+ return self.openProtocol(
+ Protocol,
+ handle,
+ .{ .by_handle_protocol = .{ .agent = uefi.handle } },
+ ) catch |err| switch (err) {
+ error.AlreadyStarted => return uefi.unexpectedStatus(.already_started),
+ error.AccessDenied => return uefi.unexpectedStatus(.access_denied),
+ error.InvalidParameter => return uefi.unexpectedStatus(.invalid_parameter),
+ else => return @errorCast(err),
+ };
+ }
+
+ pub fn registerProtocolNotify(
+ self: *BootServices,
+ Protocol: type,
+ event: Event,
+ ) RegisterProtocolNotifyError!EventRegistration {
+ if (!@hasDecl(Protocol, "guid"))
+ @compileError("Protocol is missing guid");
+
+ var registration: EventRegistration = undefined;
+ switch (self._registerProtocolNotify(
+ &Protocol.guid,
+ event,
+ ®istration,
+ )) {
+ .success => return registration,
+ .out_of_resources => return error.OutOfResources,
+ .invalid_parameter => return error.InvalidParameter,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ /// Returns the number of handles that match the given search criteria.
+ pub fn locateHandleLen(self: *const BootServices, search: LocateSearch) NumHandlesError!usize {
+ var len: usize = 0;
+ switch (self._locateHandle(
+ std.meta.activeTag(search),
+ if (search == .by_protocol) search.by_protocol else null,
+ if (search == .by_register_notify) search.by_register_notify else null,
+ &len,
+ null,
+ )) {
+ .success => return @divExact(len, @sizeOf(Handle)),
+ .out_of_resources => return error.OutOfResources,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ /// To determine the necessary size of `buffer`, call `locateHandleLen` first.
+ pub fn locateHandle(
+ self: *BootServices,
+ search: LocateSearch,
+ buffer: []Handle,
+ ) LocateHandleError![]Handle {
+ var len: usize = @sizeOf(Handle) * buffer.len;
+ switch (self._locateHandle(
+ std.meta.activeTag(search),
+ if (search == .by_protocol) search.by_protocol else null,
+ if (search == .by_register_notify) search.by_register_notify else null,
+ &len,
+ buffer.ptr,
+ )) {
+ .success => return buffer[0..@divExact(len, @sizeOf(Handle))],
+ .not_found => return buffer[0..0],
+ .buffer_too_small => return error.BufferTooSmall,
+ .invalid_parameter => return error.InvalidParameter,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ /// Locates all devices on `device_path` that support `Protocol`. Once the closest
+ /// match to `device_path` is found, it returns the unmatched device path and handle.
+ pub fn locateDevicePath(
+ self: *const BootServices,
+ device_path: *const DevicePathProtocol,
+ Protocol: type,
+ ) LocateHandleError!?struct { *const DevicePathProtocol, Handle } {
+ if (!@hasDecl(Protocol, "guid"))
+ @compileError("Protocol is missing guid");
+
+ var dev_path = device_path;
+ var device: ?Handle = undefined;
+ switch (self._locateDevicePath(
+ &Protocol.guid,
+ &dev_path,
+ &device,
+ )) {
+ .success => return .{ dev_path, device.? },
+ .not_found => return null,
+ .invalid_parameter => return error.InvalidParameter,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn installConfigurationTable(
+ self: *BootServices,
+ guid: *const Guid,
+ table: *anyopaque,
+ ) InstallConfigurationTableError!void {
+ switch (self._installConfigurationTable(
+ guid,
+ table,
+ )) {
+ .success => {},
+ .invalid_parameter => return error.InvalidParameter,
+ .out_of_resources => return error.OutOfResources,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn uninstallConfigurationTable(
+ self: *BootServices,
+ guid: *const Guid,
+ ) UninstallConfigurationTableError!void {
+ switch (self._installConfigurationTable(
+ guid,
+ null,
+ )) {
+ .success => {},
+ .not_found => return error.NotFound,
+ .invalid_parameter => return error.InvalidParameter,
+ .out_of_resources => return error.OutOfResources,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub const LoadImageSource = union(enum) {
+ buffer: []const u8,
+ device_path: *const DevicePathProtocol,
+ };
+
+ pub fn loadImage(
+ self: *BootServices,
+ boot_policy: bool,
+ parent_image: Handle,
+ source: LoadImageSource,
+ ) LoadImageError!Handle {
+ var handle: Handle = undefined;
+
+ switch (self._loadImage(
+ boot_policy,
+ parent_image,
+ if (source == .device_path) source.device_path else null,
+ if (source == .buffer) source.buffer.ptr else null,
+ if (source == .buffer) source.buffer.len else 0,
+ &handle,
+ )) {
+ .success => return handle,
+ .not_found => return error.NotFound,
+ .invalid_parameter => return error.InvalidParameter,
+ .unsupported => return error.Unsupported,
+ .out_of_resources => return error.OutOfResources,
+ .load_error => return error.LoadError,
+ .device_error => return error.DeviceError,
+ .access_denied => return error.AccessDenied,
+ .security_violation => return error.SecurityViolation,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn startImage(self: *BootServices, image: Handle) StartImageError!ImageExitData {
+ var exit_data_size: usize = undefined;
+ var exit_data: [*]u16 = undefined;
+
+ const exit_code = switch (self._startImage(
+ image,
+ &exit_data_size,
+ &exit_data,
+ )) {
+ .invalid_parameter => return error.InvalidParameter,
+ .security_violation => return error.SecurityViolation,
+ else => |exit_code| exit_code,
+ };
+
+ if (exit_data_size == 0) return .{
+ .code = exit_code,
+ .description = null,
+ .data = null,
+ };
+
+ const description_ptr: [*:0]const u16 = @ptrCast(exit_data);
+ const description = std.mem.sliceTo(description_ptr, 0);
+
+ return ImageExitData{
+ .code = exit_code,
+ .description = description,
+ .data = exit_data[description.len + 1 .. exit_data_size],
+ };
+ }
+
+ /// `message` must be allocated using `allocatePool`.
+ pub fn exit(
+ self: *BootServices,
+ handle: Handle,
+ status: Status,
+ message: ?[:0]const u16,
+ ) ExitError!void {
+ switch (self._exit(
+ handle,
+ status,
+ if (message) |msg| (2 * msg.len) + 1 else 0,
+ if (message) |msg| @ptrCast(msg.ptr) else null,
+ )) {
+ .success => {},
+ .invalid_parameter => return error.InvalidParameter,
+ else => |exit_status| return uefi.unexpectedStatus(exit_status),
+ }
+ }
+
+ /// `message` should be a null-terminated u16 string followed by binary data
+ /// allocated using `allocatePool`.
+ pub fn exitWithData(
+ self: *BootServices,
+ handle: Handle,
+ status: Status,
+ data: []align(2) const u8,
+ ) ExitError!void {
+ switch (self._exit(handle, status, data.len, data.ptr)) {
+ .success => {},
+ .invalid_parameter => return error.InvalidParameter,
+ else => |exit_status| return uefi.unexpectedStatus(exit_status),
+ }
+ }
+
+ /// The result is the exit code of the unload handler. Any error codes are
+ /// `try/catch`-able, leaving only success and warning codes as the result.
+ pub fn unloadImage(
+ self: *BootServices,
+ image: Handle,
+ ) Status.Error!Status {
+ const status = self._unloadImage(image);
+ try status.err();
+ return status;
+ }
+
+ pub fn exitBootServices(
+ self: *BootServices,
+ image: Handle,
+ map_key: MemoryMapKey,
+ ) ExitBootServicesError!void {
+ switch (self._exitBootServices(image, map_key)) {
+ .success => {},
+ .invalid_parameter => return error.InvalidParameter,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn getNextMonotonicCount(
+ self: *const BootServices,
+ count: *u64,
+ ) GetNextMonotonicCountError!void {
+ switch (self._getNextMonotonicCount(count)) {
+ .success => {},
+ .device_error => return error.DeviceError,
+ .invalid_parameter => return error.InvalidParameter,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn stall(self: *const BootServices, microseconds: usize) uefi.UnexpectedError!void {
+ switch (self._stall(microseconds)) {
+ .success => {},
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn setWatchdogTimer(
+ self: *BootServices,
+ timeout: usize,
+ watchdog_code: u64,
+ data: ?[]const u16,
+ ) SetWatchdogTimerError!void {
+ switch (self._setWatchdogTimer(
+ timeout,
+ watchdog_code,
+ if (data) |d| d.len else 0,
+ if (data) |d| d.ptr else null,
+ )) {
+ .success => {},
+ .invalid_parameter => return error.InvalidParameter,
+ .unsupported => return error.Unsupported,
+ .device_error => return error.DeviceError,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ /// `driver_image` should be a null-terminated ordered list of handles.
+ pub fn connectController(
+ self: *BootServices,
+ controller: Handle,
+ driver_image: ?[*:null]?Handle,
+ remaining_device_path: ?*const DevicePathProtocol,
+ recursive: bool,
+ ) ConnectControllerError!void {
+ switch (self._connectController(
+ controller,
+ driver_image,
+ remaining_device_path,
+ recursive,
+ )) {
+ .success => {},
+ .invalid_parameter => return error.InvalidParameter,
+ .not_found => return error.NotFound,
+ .security_violation => return error.SecurityViolation,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn disconnectController(
+ self: *BootServices,
+ controller: Handle,
+ driver_image: ?Handle,
+ child: ?Handle,
+ ) DisconnectControllerError!void {
+ switch (self._disconnectController(
+ controller,
+ driver_image,
+ child,
+ )) {
+ .success => {},
+ .invalid_parameter => return error.InvalidParameter,
+ .out_of_resources => return error.OutOfResources,
+ .device_error => return error.DeviceError,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
/// Opens a protocol with a structure as the loaded image for a UEFI application
- pub fn openProtocolSt(self: *BootServices, comptime protocol: type, handle: Handle) !*protocol {
- if (!@hasDecl(protocol, "guid"))
- @compileError("Protocol is missing guid!");
+ ///
+ /// If `flag` is `.test_protocol`, then the only valid return value is `null`,
+ /// and `Status.unsupported` is returned. Otherwise, if `_openProtocol` returns
+ /// `Status.unsupported`, then `null` is returned.
+ pub fn openProtocol(
+ self: *BootServices,
+ Protocol: type,
+ handle: Handle,
+ attributes: OpenProtocolArgs,
+ ) OpenProtocolError!?*Protocol {
+ if (!@hasDecl(Protocol, "guid"))
+ @compileError("Protocol is missing guid: " ++ @typeName(Protocol));
- var ptr: ?*protocol = undefined;
+ const agent_handle: ?Handle, const controller_handle: ?Handle = switch (attributes) {
+ inline else => |arg| .{ arg.agent, arg.controller },
+ };
- try self.openProtocol(
+ var ptr: ?*Protocol = undefined;
+
+ switch (self._openProtocol(
handle,
- &protocol.guid,
+ &Protocol.guid,
@as(*?*anyopaque, @ptrCast(&ptr)),
- // Invoking handle (loaded image)
- uefi.handle,
- // Control handle (null as not a driver)
- null,
- uefi.tables.OpenProtocolAttributes{ .by_handle_protocol = true },
- ).err();
+ agent_handle,
+ controller_handle,
+ std.meta.activeTag(attributes),
+ )) {
+ .success => return if (attributes == .test_protocol) null else ptr,
+ .unsupported => return if (attributes == .test_protocol) error.Unsupported else null,
+ .access_denied => return error.AccessDenied,
+ .already_started => return error.AlreadyStarted,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn closeProtocol(
+ self: *BootServices,
+ handle: Handle,
+ Protocol: type,
+ agent: Handle,
+ controller: ?Handle,
+ ) CloseProtocolError!void {
+ if (!@hasDecl(Protocol, "guid"))
+ @compileError("protocol is missing guid: " ++ @typeName(Protocol));
+
+ switch (self._closeProtocol(
+ handle,
+ &Protocol.guid,
+ agent,
+ controller,
+ )) {
+ .success => {},
+ .invalid_parameter => return error.InvalidParameter,
+ .not_found => return error.NotFound,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn openProtocolInformation(
+ self: *const BootServices,
+ handle: Handle,
+ Protocol: type,
+ ) OpenProtocolInformationError!?[]ProtocolInformationEntry {
+ var entries: [*]ProtocolInformationEntry = undefined;
+ var len: usize = undefined;
+
+ switch (self._openProtocolInformation(
+ handle,
+ &Protocol.guid,
+ &entries,
+ &len,
+ )) {
+ .success => return entries[0..len],
+ .not_found => return null,
+ .out_of_resources => return error.OutOfResources,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn protocolsPerHandle(
+ self: *const BootServices,
+ handle: Handle,
+ ) ProtocolsPerHandleError![]*const Guid {
+ var guids: [*]*const Guid = undefined;
+ var len: usize = undefined;
+
+ switch (self._protocolsPerHandle(
+ handle,
+ &guids,
+ &len,
+ )) {
+ .success => return guids[0..len],
+ .invalid_parameter => return error.InvalidParameter,
+ .out_of_resources => return error.OutOfResources,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn locateHandleBuffer(
+ self: *const BootServices,
+ search: LocateSearch,
+ ) LocateHandleBufferError!?[]Handle {
+ var handles: [*]Handle = undefined;
+ var len: usize = undefined;
+
+ switch (self._locateHandleBuffer(
+ std.meta.activeTag(search),
+ if (search == .by_protocol) search.by_protocol else null,
+ if (search == .by_register_notify) search.by_register_notify else null,
+ &len,
+ &handles,
+ )) {
+ .success => return handles[0..len],
+ .invalid_parameter => return error.InvalidParameter,
+ .not_found => return null,
+ .out_of_resources => return error.OutOfResources,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn locateProtocol(
+ self: *const BootServices,
+ Protocol: type,
+ registration: ?EventRegistration,
+ ) LocateProtocolError!?*Protocol {
+ var interface: *Protocol = undefined;
+
+ switch (self._locateProtocol(
+ &Protocol.guid,
+ registration,
+ @ptrCast(&interface),
+ )) {
+ .success => return interface,
+ .not_found => return null,
+ .invalid_parameter => return error.InvalidParameter,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ /// Installs a set of protocol interfaces into the boot services environment.
+ ///
+ /// This function's final argument should be a tuple of pointers to protocol
+ /// interfaces. For example:
+ ///
+ /// ```
+ /// const handle = try boot_services.installProtocolInterfaces(null, .{
+ /// &my_interface_1,
+ /// &my_interface_2,
+ /// });
+ /// ```
+ ///
+ /// The underlying function accepts a vararg list of pairs of Guid pointers
+ /// and opaque pointers to the interface. To provide a guid, the interface
+ /// types should declare a `guid` constant like so:
+ ///
+ /// ```
+ /// pub const guid: uefi.Guid = .{ ... };
+ /// ```
+ ///
+ /// See `std.os.uefi.protocol` for examples of protocol type definitions.
+ pub fn installProtocolInterfaces(
+ self: *BootServices,
+ handle: ?Handle,
+ interfaces: anytype,
+ ) InstallProtocolInterfacesError!Handle {
+ var hdl: ?Handle = handle;
+ const args_tuple = protocolInterfaces(&hdl, interfaces);
+
+ switch (@call(
+ .auto,
+ self._installMultipleProtocolInterfaces,
+ args_tuple,
+ )) {
+ .success => return hdl.?,
+ .already_started => return error.AlreadyStarted,
+ .out_of_resources => return error.OutOfResources,
+ .invalid_parameter => return error.InvalidParameter,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn uninstallProtocolInterfaces(
+ self: *BootServices,
+ handle: Handle,
+ interfaces: anytype,
+ ) UninstallProtocolInterfacesError!void {
+ const args_tuple = protocolInterfaces(handle, interfaces);
- return ptr.?;
+ switch (@call(
+ .auto,
+ self._uninstallMultipleProtocolInterfaces,
+ args_tuple,
+ )) {
+ .success => {},
+ .invalid_parameter => return error.InvalidParameter,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn calculateCrc32(
+ self: *const BootServices,
+ data: []const u8,
+ ) CalculateCrc32Error!u32 {
+ var value: u32 = undefined;
+ switch (self._calculateCrc32(data.ptr, data.len, &value)) {
+ .success => return value,
+ .invalid_parameter => return error.InvalidParameter,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
}
pub const signature: u64 = 0x56524553544f4f42;
- pub const event_timer: u32 = 0x80000000;
- pub const event_runtime: u32 = 0x40000000;
- pub const event_notify_wait: u32 = 0x00000100;
- pub const event_notify_signal: u32 = 0x00000200;
- pub const event_signal_exit_boot_services: u32 = 0x00000201;
- pub const event_signal_virtual_address_change: u32 = 0x00000202;
-
- pub const tpl_application: usize = 4;
- pub const tpl_callback: usize = 8;
- pub const tpl_notify: usize = 16;
- pub const tpl_high_level: usize = 31;
+ pub const NotifyOpts = struct {
+ tpl: TaskPriorityLevel = .application,
+ function: ?*const fn (Event, ?*anyopaque) callconv(cc) void = null,
+ context: ?*anyopaque = null,
+ };
+
+ pub const TaskPriorityLevel = enum(usize) {
+ application = 4,
+ callback = 8,
+ notify = 16,
+ high_level = 31,
+ _,
+ };
+
+ pub const ImageExitData = struct {
+ code: Status,
+ description: ?[:0]const u16,
+ data: ?[]const u16,
+ };
};
+
+fn protocolInterfaces(
+ handle_arg: anytype,
+ interfaces: anytype,
+) ProtocolInterfaces(@TypeOf(handle_arg), @TypeOf(interfaces)) {
+ var result: ProtocolInterfaces(
+ @TypeOf(handle_arg),
+ @TypeOf(interfaces),
+ ) = undefined;
+ result[0] = handle_arg;
+
+ var idx: usize = 1;
+ inline for (interfaces) |interface| {
+ const InterfacePtr = @TypeOf(interface);
+ const Interface = switch (@typeInfo(InterfacePtr)) {
+ .pointer => |pointer| pointer.child,
+ else => @compileError("expected tuple of '*const Protocol', got " ++ @typeName(InterfacePtr)),
+ };
+
+ if (!@hasDecl(Interface, "guid"))
+ @compileError("protocol interface '" ++ @typeName(Interface) ++
+ "' does not declare a 'const guid: uefi.Guid'.");
+
+ switch (@typeInfo(Interface)) {
+ .@"struct" => |struct_info| if (struct_info.layout != .@"extern")
+ @compileLog("protocol interface '" ++ @typeName(Interface) ++
+ "' is not extern - this is likely a mistake"),
+ else => @compileError("protocol interface must be a struct, got " ++ @typeName(Interface)),
+ }
+
+ result[idx] = &Interface.guid;
+ result[idx + 1] = @ptrCast(interface);
+ idx += 2;
+ }
+
+ return result;
+}
+
+fn ProtocolInterfaces(HandleType: type, Interfaces: type) type {
+ const interfaces_type_info = @typeInfo(Interfaces);
+ if (interfaces_type_info != .@"struct" or !interfaces_type_info.@"struct".is_tuple)
+ @compileError("expected tuple of protocol interfaces, got " ++ @typeName(Interfaces));
+ const interfaces_info = interfaces_type_info.@"struct";
+
+ var tuple_types: [interfaces_info.fields.len * 2 + 1]type = undefined;
+ tuple_types[0] = HandleType;
+ var idx = 1;
+ while (idx < tuple_types.len) : (idx += 2) {
+ tuple_types[idx] = *const Guid;
+ tuple_types[idx + 1] = *const anyopaque;
+ }
+
+ return std.meta.Tuple(tuple_types[0..]);
+}
lib/std/os/uefi/tables/configuration_table.zig
@@ -5,7 +5,7 @@ pub const ConfigurationTable = extern struct {
vendor_guid: Guid,
vendor_table: *anyopaque,
- pub const acpi_20_table_guid align(8) = Guid{
+ pub const acpi_20_table_guid: Guid = .{
.time_low = 0x8868e871,
.time_mid = 0xe4f1,
.time_high_and_version = 0x11d3,
@@ -13,7 +13,7 @@ pub const ConfigurationTable = extern struct {
.clock_seq_low = 0x22,
.node = [_]u8{ 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81 },
};
- pub const acpi_10_table_guid align(8) = Guid{
+ pub const acpi_10_table_guid: Guid = .{
.time_low = 0xeb9d2d30,
.time_mid = 0x2d88,
.time_high_and_version = 0x11d3,
@@ -21,7 +21,7 @@ pub const ConfigurationTable = extern struct {
.clock_seq_low = 0x16,
.node = [_]u8{ 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d },
};
- pub const sal_system_table_guid align(8) = Guid{
+ pub const sal_system_table_guid: Guid = .{
.time_low = 0xeb9d2d32,
.time_mid = 0x2d88,
.time_high_and_version = 0x113d,
@@ -29,7 +29,7 @@ pub const ConfigurationTable = extern struct {
.clock_seq_low = 0x16,
.node = [_]u8{ 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d },
};
- pub const smbios_table_guid align(8) = Guid{
+ pub const smbios_table_guid: Guid = .{
.time_low = 0xeb9d2d31,
.time_mid = 0x2d88,
.time_high_and_version = 0x11d3,
@@ -37,7 +37,7 @@ pub const ConfigurationTable = extern struct {
.clock_seq_low = 0x16,
.node = [_]u8{ 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d },
};
- pub const smbios3_table_guid align(8) = Guid{
+ pub const smbios3_table_guid: Guid = .{
.time_low = 0xf2fd1544,
.time_mid = 0x9794,
.time_high_and_version = 0x4a2c,
@@ -45,7 +45,7 @@ pub const ConfigurationTable = extern struct {
.clock_seq_low = 0x2e,
.node = [_]u8{ 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94 },
};
- pub const mps_table_guid align(8) = Guid{
+ pub const mps_table_guid: Guid = .{
.time_low = 0xeb9d2d2f,
.time_mid = 0x2d88,
.time_high_and_version = 0x11d3,
@@ -53,7 +53,7 @@ pub const ConfigurationTable = extern struct {
.clock_seq_low = 0x16,
.node = [_]u8{ 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d },
};
- pub const json_config_data_table_guid align(8) = Guid{
+ pub const json_config_data_table_guid: Guid = .{
.time_low = 0x87367f87,
.time_mid = 0x1119,
.time_high_and_version = 0x41ce,
@@ -61,7 +61,7 @@ pub const ConfigurationTable = extern struct {
.clock_seq_low = 0xec,
.node = [_]u8{ 0x8b, 0xe0, 0x11, 0x1f, 0x55, 0x8a },
};
- pub const json_capsule_data_table_guid align(8) = Guid{
+ pub const json_capsule_data_table_guid: Guid = .{
.time_low = 0x35e7a725,
.time_mid = 0x8dd2,
.time_high_and_version = 0x4cac,
@@ -69,7 +69,7 @@ pub const ConfigurationTable = extern struct {
.clock_seq_low = 0x11,
.node = [_]u8{ 0x33, 0xcd, 0xa8, 0x10, 0x90, 0x56 },
};
- pub const json_capsule_result_table_guid align(8) = Guid{
+ pub const json_capsule_result_table_guid: Guid = .{
.time_low = 0xdbc461c3,
.time_mid = 0xb3de,
.time_high_and_version = 0x422a,
lib/std/os/uefi/tables/runtime_services.zig
@@ -6,10 +6,12 @@ const Time = uefi.Time;
const TimeCapabilities = uefi.TimeCapabilities;
const Status = uefi.Status;
const MemoryDescriptor = uefi.tables.MemoryDescriptor;
+const MemoryMapSlice = uefi.tables.MemoryMapSlice;
const ResetType = uefi.tables.ResetType;
const CapsuleHeader = uefi.tables.CapsuleHeader;
const PhysicalAddress = uefi.tables.PhysicalAddress;
const cc = uefi.cc;
+const Error = Status.Error;
/// Runtime services are provided by the firmware before and after exitBootServices has been called.
///
@@ -23,50 +25,511 @@ pub const RuntimeServices = extern struct {
hdr: TableHeader,
/// Returns the current time and date information, and the time-keeping capabilities of the hardware platform.
- getTime: *const fn (time: *uefi.Time, capabilities: ?*TimeCapabilities) callconv(cc) Status,
+ _getTime: *const fn (time: *Time, capabilities: ?*TimeCapabilities) callconv(cc) Status,
/// Sets the current local time and date information
- setTime: *const fn (time: *uefi.Time) callconv(cc) Status,
+ _setTime: *const fn (time: *const Time) callconv(cc) Status,
/// Returns the current wakeup alarm clock setting
- getWakeupTime: *const fn (enabled: *bool, pending: *bool, time: *uefi.Time) callconv(cc) Status,
+ _getWakeupTime: *const fn (enabled: *bool, pending: *bool, time: *Time) callconv(cc) Status,
/// Sets the system wakeup alarm clock time
- setWakeupTime: *const fn (enable: *bool, time: ?*uefi.Time) callconv(cc) Status,
+ _setWakeupTime: *const fn (enable: bool, time: ?*const Time) callconv(cc) Status,
/// Changes the runtime addressing mode of EFI firmware from physical to virtual.
- setVirtualAddressMap: *const fn (mmap_size: usize, descriptor_size: usize, descriptor_version: u32, virtual_map: [*]MemoryDescriptor) callconv(cc) Status,
+ _setVirtualAddressMap: *const fn (mmap_size: usize, descriptor_size: usize, descriptor_version: u32, virtual_map: [*]align(@alignOf(MemoryDescriptor)) u8) callconv(cc) Status,
/// Determines the new virtual address that is to be used on subsequent memory accesses.
- convertPointer: *const fn (debug_disposition: usize, address: **anyopaque) callconv(cc) Status,
+ _convertPointer: *const fn (debug_disposition: DebugDisposition, address: *?*anyopaque) callconv(cc) Status,
/// Returns the value of a variable.
- getVariable: *const fn (var_name: [*:0]const u16, vendor_guid: *align(8) const Guid, attributes: ?*u32, data_size: *usize, data: ?*anyopaque) callconv(cc) Status,
+ _getVariable: *const fn (var_name: [*:0]const u16, vendor_guid: *const Guid, attributes: ?*VariableAttributes, data_size: *usize, data: ?*anyopaque) callconv(cc) Status,
/// Enumerates the current variable names.
- getNextVariableName: *const fn (var_name_size: *usize, var_name: [*:0]u16, vendor_guid: *align(8) Guid) callconv(cc) Status,
+ _getNextVariableName: *const fn (var_name_size: *usize, var_name: ?[*:0]const u16, vendor_guid: *Guid) callconv(cc) Status,
/// Sets the value of a variable.
- setVariable: *const fn (var_name: [*:0]const u16, vendor_guid: *align(8) const Guid, attributes: u32, data_size: usize, data: *anyopaque) callconv(cc) Status,
+ _setVariable: *const fn (var_name: [*:0]const u16, vendor_guid: *const Guid, attributes: VariableAttributes, data_size: usize, data: [*]const u8) callconv(cc) Status,
/// Return the next high 32 bits of the platform's monotonic counter
- getNextHighMonotonicCount: *const fn (high_count: *u32) callconv(cc) Status,
+ _getNextHighMonotonicCount: *const fn (high_count: *u32) callconv(cc) Status,
/// Resets the entire platform.
- resetSystem: *const fn (reset_type: ResetType, reset_status: Status, data_size: usize, reset_data: ?*const anyopaque) callconv(cc) noreturn,
+ _resetSystem: *const fn (reset_type: ResetType, reset_status: Status, data_size: usize, reset_data: ?[*]const u16) callconv(cc) noreturn,
/// Passes capsules to the firmware with both virtual and physical mapping.
/// Depending on the intended consumption, the firmware may process the capsule immediately.
/// If the payload should persist across a system reset, the reset value returned from
/// `queryCapsuleCapabilities` must be passed into resetSystem and will cause the capsule
/// to be processed by the firmware as part of the reset process.
- updateCapsule: *const fn (capsule_header_array: **CapsuleHeader, capsule_count: usize, scatter_gather_list: PhysicalAddress) callconv(cc) Status,
+ _updateCapsule: *const fn (capsule_header_array: [*]*const CapsuleHeader, capsule_count: usize, scatter_gather_list: PhysicalAddress) callconv(cc) Status,
/// Returns if the capsule can be supported via `updateCapsule`
- queryCapsuleCapabilities: *const fn (capsule_header_array: **CapsuleHeader, capsule_count: usize, maximum_capsule_size: *usize, reset_type: ResetType) callconv(cc) Status,
+ _queryCapsuleCapabilities: *const fn (capsule_header_array: [*]*const CapsuleHeader, capsule_count: usize, maximum_capsule_size: *usize, reset_type: *ResetType) callconv(cc) Status,
/// Returns information about the EFI variables
- queryVariableInfo: *const fn (attributes: *u32, maximum_variable_storage_size: *u64, remaining_variable_storage_size: *u64, maximum_variable_size: *u64) callconv(cc) Status,
+ _queryVariableInfo: *const fn (attributes: VariableAttributes, maximum_variable_storage_size: *u64, remaining_variable_storage_size: *u64, maximum_variable_size: *u64) callconv(cc) Status,
+
+ pub const GetTimeError = uefi.UnexpectedError || error{
+ DeviceError,
+ Unsupported,
+ };
+
+ pub const SetTimeError = uefi.UnexpectedError || error{
+ DeviceError,
+ Unsupported,
+ };
+
+ pub const GetWakeupTimeError = uefi.UnexpectedError || error{
+ DeviceError,
+ Unsupported,
+ };
+
+ pub const SetWakeupTimeError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ DeviceError,
+ Unsupported,
+ };
+
+ pub const SetVirtualAddressMapError = uefi.UnexpectedError || error{
+ Unsupported,
+ NoMapping,
+ NotFound,
+ };
+
+ pub const ConvertPointerError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ Unsupported,
+ };
+
+ pub const GetVariableSizeError = uefi.UnexpectedError || error{
+ DeviceError,
+ Unsupported,
+ };
+
+ pub const GetVariableError = GetVariableSizeError || error{
+ BufferTooSmall,
+ };
+
+ pub const SetVariableError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ OutOfResources,
+ DeviceError,
+ WriteProtected,
+ SecurityViolation,
+ NotFound,
+ Unsupported,
+ };
+
+ pub const GetNextHighMonotonicCountError = uefi.UnexpectedError || error{
+ DeviceError,
+ Unsupported,
+ };
+
+ pub const UpdateCapsuleError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ DeviceError,
+ Unsupported,
+ OutOfResources,
+ };
+
+ pub const QueryCapsuleCapabilitiesError = uefi.UnexpectedError || error{
+ Unsupported,
+ OutOfResources,
+ };
+
+ pub const QueryVariableInfoError = uefi.UnexpectedError || error{
+ InvalidParameter,
+ Unsupported,
+ };
+
+ /// Returns the current time and the time capabilities of the platform.
+ pub fn getTime(
+ self: *const RuntimeServices,
+ ) GetTimeError!struct { Time, TimeCapabilities } {
+ var time: Time = undefined;
+ var capabilities: TimeCapabilities = undefined;
+
+ switch (self._getTime(&time, &capabilities)) {
+ .success => return .{ time, capabilities },
+ .device_error => return error.DeviceError,
+ .unsupported => return error.Unsupported,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn setTime(self: *RuntimeServices, time: *const Time) SetTimeError!void {
+ switch (self._setTime(time)) {
+ .success => {},
+ .device_error => return error.DeviceError,
+ .unsupported => return error.Unsupported,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub const GetWakeupTime = struct {
+ enabled: bool,
+ pending: bool,
+ time: Time,
+ };
+
+ pub fn getWakeupTime(
+ self: *const RuntimeServices,
+ ) GetWakeupTimeError!GetWakeupTime {
+ var result: GetWakeupTime = undefined;
+ switch (self._getWakeupTime(
+ &result.enabled,
+ &result.pending,
+ &result.time,
+ )) {
+ .success => return result,
+ .device_error => return error.DeviceError,
+ .unsupported => return error.Unsupported,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub const SetWakeupTime = union(enum) {
+ enabled: *const Time,
+ disabled,
+ };
+
+ pub fn setWakeupTime(
+ self: *RuntimeServices,
+ set: SetWakeupTime,
+ ) SetWakeupTimeError!void {
+ switch (self._setWakeupTime(
+ set != .disabled,
+ if (set == .enabled) set.enabled else null,
+ )) {
+ .success => {},
+ .invalid_parameter => return error.InvalidParameter,
+ .device_error => return error.DeviceError,
+ .unsupported => return error.Unsupported,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn setVirtualAddressMap(
+ self: *RuntimeServices,
+ map: MemoryMapSlice,
+ ) SetVirtualAddressMapError!void {
+ switch (self._setVirtualAddressMap(
+ map.info.len * map.info.descriptor_size,
+ map.info.descriptor_size,
+ map.info.descriptor_version,
+ @ptrCast(map.ptr),
+ )) {
+ .success => {},
+ .unsupported => return error.Unsupported,
+ .no_mapping => return error.NoMapping,
+ .not_found => return error.NotFound,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn convertPointer(
+ self: *const RuntimeServices,
+ comptime disposition: DebugDisposition,
+ cvt: @FieldType(PointerConversion, @tagName(disposition)),
+ ) ConvertPointerError!?@FieldType(PointerConversion, @tagName(disposition)) {
+ var pointer = cvt;
+
+ switch (self._convertPointer(disposition, @ptrCast(&pointer))) {
+ .success => return pointer,
+ .not_found => return null,
+ .invalid_parameter => return error.InvalidParameter,
+ .unsupported => return error.Unsupported,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ /// Returns the length of the variable's data and its attributes.
+ pub fn getVariableSize(
+ self: *const RuntimeServices,
+ name: [*:0]const u16,
+ guid: *const Guid,
+ ) GetVariableSizeError!?struct { usize, VariableAttributes } {
+ var size: usize = 0;
+ var attrs: VariableAttributes = undefined;
+
+ switch (self._getVariable(
+ name,
+ guid,
+ &attrs,
+ &size,
+ null,
+ )) {
+ .buffer_too_small => return .{ size, attrs },
+ .not_found => return null,
+ .device_error => return error.DeviceError,
+ .unsupported => return error.Unsupported,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ /// To determine the minimum necessary buffer size for the variable, call
+ /// `getVariableSize` first.
+ pub fn getVariable(
+ self: *const RuntimeServices,
+ name: [*:0]const u16,
+ guid: *const Guid,
+ buffer: []u8,
+ ) GetVariableError!?struct { []u8, VariableAttributes } {
+ var attrs: VariableAttributes = undefined;
+ var len = buffer.len;
+
+ switch (self._getVariable(
+ name,
+ guid,
+ &attrs,
+ &len,
+ buffer.ptr,
+ )) {
+ .success => return .{ buffer[0..len], attrs },
+ .not_found => return null,
+ .buffer_too_small => return error.BufferTooSmall,
+ .device_error => return error.DeviceError,
+ .unsupported => return error.Unsupported,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn variableNameIterator(
+ self: *const RuntimeServices,
+ buffer: []u16,
+ ) VariableNameIterator {
+ buffer[0] = 0;
+ return .{
+ .services = self,
+ .buffer = buffer,
+ .guid = undefined,
+ };
+ }
+
+ pub fn setVariable(
+ self: *RuntimeServices,
+ name: [*:0]const u16,
+ guid: *const Guid,
+ attributes: VariableAttributes,
+ data: []const u8,
+ ) SetVariableError!void {
+ switch (self._setVariable(
+ name,
+ guid,
+ attributes,
+ data.len,
+ data.ptr,
+ )) {
+ .success => {},
+ .invalid_parameter => return error.InvalidParameter,
+ .out_of_resources => return error.OutOfResources,
+ .device_error => return error.DeviceError,
+ .write_protected => return error.WriteProtected,
+ .security_violation => return error.SecurityViolation,
+ .not_found => return error.NotFound,
+ .unsupported => return error.Unsupported,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn getNextHighMonotonicCount(self: *const RuntimeServices) GetNextHighMonotonicCountError!u32 {
+ var cnt: u32 = undefined;
+ switch (self._getNextHighMonotonicCount(&cnt)) {
+ .success => return cnt,
+ .device_error => return error.DeviceError,
+ .unsupported => return error.Unsupported,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn resetSystem(
+ self: *RuntimeServices,
+ reset_type: ResetType,
+ reset_status: Status,
+ data: ?[]align(2) const u8,
+ ) noreturn {
+ self._resetSystem(
+ reset_type,
+ reset_status,
+ if (data) |d| d.len else 0,
+ if (data) |d| @alignCast(@ptrCast(d.ptr)) else null,
+ );
+ }
+
+ pub fn updateCapsule(
+ self: *RuntimeServices,
+ capsules: []*const CapsuleHeader,
+ scatter_gather_list: PhysicalAddress,
+ ) UpdateCapsuleError!void {
+ switch (self._updateCapsule(
+ capsules.ptr,
+ capsules.len,
+ scatter_gather_list,
+ )) {
+ .success => {},
+ .invalid_parameter => return error.InvalidParameter,
+ .device_error => return error.DeviceError,
+ .unsupported => return error.Unsupported,
+ .out_of_resources => return error.OutOfResources,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn queryCapsuleCapabilities(
+ self: *const RuntimeServices,
+ capsules: []*const CapsuleHeader,
+ ) QueryCapsuleCapabilitiesError!struct { u64, ResetType } {
+ var max_capsule_size: u64 = undefined;
+ var reset_type: ResetType = undefined;
+
+ switch (self._queryCapsuleCapabilities(
+ capsules.ptr,
+ capsules.len,
+ &max_capsule_size,
+ &reset_type,
+ )) {
+ .success => return .{ max_capsule_size, reset_type },
+ .unsupported => return error.Unsupported,
+ .out_of_resources => return error.OutOfResources,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub fn queryVariableInfo(
+ self: *const RuntimeServices,
+ // Note: .append_write is ignored
+ attributes: VariableAttributes,
+ ) QueryVariableInfoError!VariableInfo {
+ var res: VariableInfo = undefined;
+
+ switch (self._queryVariableInfo(
+ attributes,
+ &res.max_variable_storage_size,
+ &res.remaining_variable_storage_size,
+ &res.max_variable_size,
+ )) {
+ .success => return res,
+ .invalid_parameter => return error.InvalidParameter,
+ .unsupported => return error.Unsupported,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ pub const DebugDisposition = enum(usize) {
+ const Bits = packed struct(usize) {
+ optional_ptr: bool = false,
+ _pad: std.meta.Int(.unsigned, @bitSizeOf(usize) - 1) = 0,
+ };
+
+ pointer = @bitCast(Bits{}),
+ optional = @bitCast(Bits{ .optional_ptr = true }),
+ _,
+ };
+
+ pub const PointerConversion = union(DebugDisposition) {
+ pointer: *anyopaque,
+ optional: ?*anyopaque,
+ };
+
+ pub const VariableAttributes = packed struct(u32) {
+ non_volatile: bool = false,
+ bootservice_access: bool = false,
+ runtime_access: bool = false,
+ hardware_error_record: bool = false,
+ /// Note: deprecated and should be considered reserved.
+ authenticated_write_access: bool = false,
+ time_based_authenticated_write_access: bool = false,
+ append_write: bool = false,
+ /// Indicates that the variable payload begins with a EFI_VARIABLE_AUTHENTICATION_3
+ /// structure, and potentially more structures as indicated by fields of
+ /// this structure.
+ enhanced_authenticated_access: bool = false,
+ _pad: u24 = 0,
+ };
+
+ pub const VariableAuthentication3 = extern struct {
+ version: u8 = 1,
+ type: Type,
+ metadata_size: u32,
+ flags: Flags,
+
+ pub fn payloadConst(self: *const VariableAuthentication3) []const u8 {
+ return @constCast(self).payload();
+ }
+
+ pub fn payload(self: *VariableAuthentication3) []u8 {
+ var ptr: [*]u8 = @ptrCast(self);
+ return ptr[@sizeOf(VariableAuthentication3)..self.metadata_size];
+ }
+
+ pub const Flags = packed struct(u32) {
+ update_cert: bool = false,
+ _pad: u31 = 0,
+ };
+
+ pub const Type = enum(u8) {
+ timestamp = 1,
+ nonce = 2,
+ _,
+ };
+ };
+
+ pub const VariableInfo = struct {
+ max_variable_storage_size: u64,
+ remaining_variable_storage_size: u64,
+ max_variable_size: u64,
+ };
+
+ pub const VariableNameIterator = struct {
+ pub const NextSizeError = uefi.UnexpectedError || error{
+ DeviceError,
+ Unsupported,
+ };
+
+ pub const IterateVariableNameError = NextSizeError || error{
+ BufferTooSmall,
+ };
+
+ services: *const RuntimeServices,
+ buffer: []u16,
+ guid: Guid,
+
+ pub fn nextSize(self: *VariableNameIterator) NextSizeError!?usize {
+ var len: usize = 0;
+ switch (self.services._getNextVariableName(
+ &len,
+ null,
+ &self.guid,
+ )) {
+ .buffer_too_small => return len,
+ .not_found => return null,
+ .device_error => return error.DeviceError,
+ .unsupported => return error.Unsupported,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+
+ /// Call `nextSize` to get the length of the next variable name and check
+ /// if `buffer` is large enough to hold the name.
+ pub fn next(
+ self: *VariableNameIterator,
+ ) IterateVariableNameError!?[:0]const u16 {
+ var len = self.buffer.len;
+ switch (self.services._getNextVariableName(
+ &len,
+ @ptrCast(self.buffer.ptr),
+ &self.guid,
+ )) {
+ .success => return self.buffer[0 .. len - 1 :0],
+ .not_found => return null,
+ .buffer_too_small => return error.BufferTooSmall,
+ .device_error => return error.DeviceError,
+ .unsupported => return error.Unsupported,
+ else => |status| return uefi.unexpectedStatus(status),
+ }
+ }
+ };
pub const signature: u64 = 0x56524553544e5552;
};
lib/std/os/uefi/pool_allocator.zig
@@ -28,14 +28,16 @@ const UefiPoolAllocator = struct {
const full_len = metadata_len + len;
- var unaligned_ptr: [*]align(8) u8 = undefined;
- if (uefi.system_table.boot_services.?.allocatePool(uefi.efi_pool_memory_type, full_len, &unaligned_ptr) != .success) return null;
+ const unaligned_slice = uefi.system_table.boot_services.?.allocatePool(
+ uefi.efi_pool_memory_type,
+ full_len,
+ ) catch return null;
- const unaligned_addr = @intFromPtr(unaligned_ptr);
+ const unaligned_addr = @intFromPtr(unaligned_slice.ptr);
const aligned_addr = mem.alignForward(usize, unaligned_addr + @sizeOf(usize), ptr_align);
- const aligned_ptr = unaligned_ptr + (aligned_addr - unaligned_addr);
- getHeader(aligned_ptr).* = unaligned_ptr;
+ const aligned_ptr = unaligned_slice.ptr + (aligned_addr - unaligned_addr);
+ getHeader(aligned_ptr).* = unaligned_slice.ptr;
return aligned_ptr;
}
@@ -76,7 +78,7 @@ const UefiPoolAllocator = struct {
) void {
_ = alignment;
_ = ret_addr;
- _ = uefi.system_table.boot_services.?.freePool(getHeader(buf.ptr).*);
+ uefi.system_table.boot_services.?.freePool(getHeader(buf.ptr).*) catch unreachable;
}
};
@@ -117,10 +119,12 @@ fn uefi_alloc(
std.debug.assert(@intFromEnum(alignment) <= 3);
- var ptr: [*]align(8) u8 = undefined;
- if (uefi.system_table.boot_services.?.allocatePool(uefi.efi_pool_memory_type, len, &ptr) != .success) return null;
+ const slice = uefi.system_table.boot_services.?.allocatePool(
+ uefi.efi_pool_memory_type,
+ len,
+ ) catch return null;
- return ptr;
+ return slice.ptr;
}
fn uefi_resize(
@@ -161,5 +165,5 @@ fn uefi_free(
) void {
_ = alignment;
_ = ret_addr;
- _ = uefi.system_table.boot_services.?.freePool(@alignCast(buf.ptr));
+ uefi.system_table.boot_services.?.freePool(@alignCast(buf.ptr)) catch unreachable;
}
lib/std/os/uefi/tables.zig
@@ -1,3 +1,12 @@
+const std = @import("std");
+const uefi = std.os.uefi;
+const Handle = uefi.Handle;
+const Event = uefi.Event;
+const Guid = uefi.Guid;
+const cc = uefi.cc;
+const math = std.math;
+const assert = std.debug.assert;
+
pub const BootServices = @import("tables/boot_services.zig").BootServices;
pub const RuntimeServices = @import("tables/runtime_services.zig").RuntimeServices;
pub const ConfigurationTable = @import("tables/configuration_table.zig").ConfigurationTable;
@@ -7,29 +16,90 @@ pub const TableHeader = @import("tables/table_header.zig").TableHeader;
pub const EventNotify = *const fn (event: Event, ctx: *anyopaque) callconv(cc) void;
pub const TimerDelay = enum(u32) {
- timer_cancel,
- timer_periodic,
- timer_relative,
+ cancel,
+ periodic,
+ relative,
};
pub const MemoryType = enum(u32) {
+ pub const Oem = math.IntFittingRange(
+ 0,
+ @intFromEnum(MemoryType.oem_end) - @intFromEnum(MemoryType.oem_start),
+ );
+ pub const Vendor = math.IntFittingRange(
+ 0,
+ @intFromEnum(MemoryType.vendor_end) - @intFromEnum(MemoryType.vendor_start),
+ );
+
+ /// can only be allocated using .allocate_any_pages mode unless you are explicitly targeting an interface that states otherwise
reserved_memory_type,
loader_code,
loader_data,
boot_services_code,
boot_services_data,
+ /// can only be allocated using .allocate_any_pages mode unless you are explicitly targeting an interface that states otherwise
runtime_services_code,
+ /// can only be allocated using .allocate_any_pages mode unless you are explicitly targeting an interface that states otherwise
runtime_services_data,
conventional_memory,
unusable_memory,
+ /// can only be allocated using .allocate_any_pages mode unless you are explicitly targeting an interface that states otherwise
acpi_reclaim_memory,
+ /// can only be allocated using .allocate_any_pages mode unless you are explicitly targeting an interface that states otherwise
acpi_memory_nvs,
memory_mapped_io,
memory_mapped_io_port_space,
pal_code,
persistent_memory,
+ unaccepted_memory,
max_memory_type,
+ invalid_start,
+ invalid_end = 0x6FFFFFFF,
+ /// MemoryType values in the range 0x70000000..0x7FFFFFFF are reserved for OEM use.
+ oem_start = 0x70000000,
+ oem_end = 0x7FFFFFFF,
+ /// MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI
+ /// OS loaders that are provided by operating system vendors.
+ vendor_start = 0x80000000,
+ vendor_end = 0xFFFFFFFF,
_,
+
+ pub fn fromOem(value: Oem) MemoryType {
+ const oem_start = @intFromEnum(MemoryType.oem_start);
+ return @enumFromInt(oem_start + value);
+ }
+
+ pub fn toOem(memtype: MemoryType) ?Oem {
+ const as_int = @intFromEnum(memtype);
+ const oem_start = @intFromEnum(MemoryType.oem_start);
+ if (as_int < oem_start) return null;
+ if (as_int > @intFromEnum(MemoryType.oem_end)) return null;
+ return @truncate(as_int - oem_start);
+ }
+
+ pub fn fromVendor(value: Vendor) MemoryType {
+ const vendor_start = @intFromEnum(MemoryType.vendor_start);
+ return @enumFromInt(vendor_start + value);
+ }
+
+ pub fn toVendor(memtype: MemoryType) ?Vendor {
+ const as_int = @intFromEnum(memtype);
+ const vendor_start = @intFromEnum(MemoryType.vendor_start);
+ if (as_int < @intFromEnum(MemoryType.vendor_end)) return null;
+ if (as_int > @intFromEnum(MemoryType.vendor_end)) return null;
+ return @truncate(as_int - vendor_start);
+ }
+
+ pub fn format(self: MemoryType, w: *std.io.Writer) std.io.WriteError!void {
+ if (self.toOem()) |oemval|
+ try w.print("OEM({X})", .{oemval})
+ else if (self.toVendor()) |vendorval|
+ try w.print("Vendor({X})", .{vendorval})
+ else if (std.enums.tagName(MemoryType, self)) |name|
+ try w.print("{s}", .{name})
+ else
+ try w.print("INVALID({X})", .{@intFromEnum(self)});
+ }
};
pub const MemoryDescriptorAttribute = packed struct(u64) {
@@ -51,6 +121,8 @@ pub const MemoryDescriptorAttribute = packed struct(u64) {
memory_runtime: bool,
};
+pub const MemoryMapKey = enum(usize) { _ };
+
pub const MemoryDescriptor = extern struct {
type: MemoryType,
physical_start: u64,
@@ -59,20 +131,121 @@ pub const MemoryDescriptor = extern struct {
attribute: MemoryDescriptorAttribute,
};
+pub const MemoryMapInfo = struct {
+ key: MemoryMapKey,
+ descriptor_size: usize,
+ descriptor_version: u32,
+ /// The number of descriptors in the map.
+ len: usize,
+};
+
+pub const MemoryMapSlice = struct {
+ info: MemoryMapInfo,
+ ptr: [*]align(@alignOf(MemoryDescriptor)) u8,
+
+ pub fn iterator(self: MemoryMapSlice) MemoryDescriptorIterator {
+ return .{ .ctx = self };
+ }
+
+ pub fn get(self: MemoryMapSlice, index: usize) ?*MemoryDescriptor {
+ if (index >= self.info.len) return null;
+ return self.getUnchecked(index);
+ }
+
+ pub fn getUnchecked(self: MemoryMapSlice, index: usize) *MemoryDescriptor {
+ const offset: usize = index * self.info.descriptor_size;
+ return @alignCast(@ptrCast(self.ptr[offset..]));
+ }
+};
+
+pub const MemoryDescriptorIterator = struct {
+ ctx: MemoryMapSlice,
+ index: usize = 0,
+
+ pub fn next(self: *MemoryDescriptorIterator) ?*MemoryDescriptor {
+ const md = self.ctx.get(self.index) orelse return null;
+ self.index += 1;
+ return md;
+ }
+};
+
pub const LocateSearchType = enum(u32) {
all_handles,
by_register_notify,
by_protocol,
};
-pub const OpenProtocolAttributes = packed struct(u32) {
- by_handle_protocol: bool = false,
- get_protocol: bool = false,
- test_protocol: bool = false,
- by_child_controller: bool = false,
- by_driver: bool = false,
- exclusive: bool = false,
- reserved: u26 = 0,
+pub const LocateSearch = union(LocateSearchType) {
+ all_handles,
+ by_register_notify: uefi.EventRegistration,
+ by_protocol: *const Guid,
+};
+
+pub const OpenProtocolAttributes = enum(u32) {
+ pub const Bits = packed struct(u32) {
+ by_handle_protocol: bool = false,
+ get_protocol: bool = false,
+ test_protocol: bool = false,
+ by_child_controller: bool = false,
+ by_driver: bool = false,
+ exclusive: bool = false,
+ reserved: u26 = 0,
+ };
+
+ by_handle_protocol = @bitCast(Bits{ .by_handle_protocol = true }),
+ get_protocol = @bitCast(Bits{ .get_protocol = true }),
+ test_protocol = @bitCast(Bits{ .test_protocol = true }),
+ by_child_controller = @bitCast(Bits{ .by_child_controller = true }),
+ by_driver = @bitCast(Bits{ .by_driver = true }),
+ by_driver_exclusive = @bitCast(Bits{ .by_driver = true, .exclusive = true }),
+ exclusive = @bitCast(Bits{ .exclusive = true }),
+ _,
+
+ pub fn fromBits(bits: Bits) OpenProtocolAttributes {
+ return @bitCast(bits);
+ }
+
+ pub fn toBits(self: OpenProtocolAttributes) Bits {
+ return @bitCast(self);
+ }
+};
+
+pub const OpenProtocolArgs = union(OpenProtocolAttributes) {
+ /// Used in the implementation of `handleProtocol`.
+ by_handle_protocol: struct { agent: ?Handle = null, controller: ?Handle = null },
+ /// Used by a driver to get a protocol interface from a handle. Care must be
+ /// taken when using this open mode because the driver that opens a protocol
+ /// interface in this manner will not be informed if the protocol interface
+ /// is uninstalled or reinstalled. The caller is also not required to close
+ /// the protocol interface with `closeProtocol`.
+ get_protocol: struct { agent: ?Handle = null, controller: ?Handle = null },
+ /// Used by a driver to test for the existence of a protocol interface on a
+ /// handle. The caller only use the return status code. The caller is also
+ /// not required to close the protocol interface with `closeProtocol`.
+ test_protocol: struct { agent: ?Handle = null, controller: ?Handle = null },
+ /// Used by bus drivers to show that a protocol interface is being used by one
+ /// of the child controllers of a bus. This information is used by
+ /// `BootServices.connectController` to recursively connect all child controllers
+ /// and by `BootServices.disconnectController` to get the list of child
+ /// controllers that a bus driver created.
+ by_child_controller: struct { agent: Handle, controller: Handle },
+ /// Used by a driver to gain access to a protocol interface. When this mode
+ /// is used, the driver’s Stop() function will be called by
+ /// `BootServices.disconnectController` if the protocol interface is reinstalled
+ /// or uninstalled. Once a protocol interface is opened by a driver with this
+ /// attribute, no other drivers will be allowed to open the same protocol interface
+ /// with the `.by_driver` attribute.
+ by_driver: struct { agent: Handle, controller: Handle },
+ /// Used by a driver to gain exclusive access to a protocol interface. If any
+ /// other drivers have the protocol interface opened with an attribute of
+ /// `.by_driver`, then an attempt will be made to remove them with
+ /// `BootServices.disconnectController`.
+ by_driver_exclusive: struct { agent: Handle, controller: Handle },
+ /// Used by applications to gain exclusive access to a protocol interface. If
+ /// any drivers have the protocol interface opened with an attribute of
+ /// `.by_driver`, then an attempt will be made to remove them by calling the
+ /// driver’s Stop() function.
+ exclusive: struct { agent: Handle, controller: ?Handle = null },
};
pub const ProtocolInformationEntry = extern struct {
@@ -83,19 +256,25 @@ pub const ProtocolInformationEntry = extern struct {
};
pub const InterfaceType = enum(u32) {
- efi_native_interface,
+ native,
+};
+
+pub const AllocateLocation = union(AllocateType) {
+ any,
+ max_address: [*]align(4096) uefi.Page,
+ address: [*]align(4096) uefi.Page,
};
pub const AllocateType = enum(u32) {
- allocate_any_pages,
- allocate_max_address,
- allocate_address,
+ any,
+ max_address,
+ address,
};
pub const PhysicalAddress = u64;
pub const CapsuleHeader = extern struct {
- capsule_guid: Guid align(8),
+ capsule_guid: Guid,
header_size: u32,
flags: u32,
capsule_image_size: u32,
@@ -110,13 +289,13 @@ pub const UefiCapsuleBlockDescriptor = extern struct {
};
pub const ResetType = enum(u32) {
- reset_cold,
- reset_warm,
- reset_shutdown,
- reset_platform_specific,
+ cold,
+ warm,
+ shutdown,
+ platform_specific,
};
-pub const global_variable align(8) = Guid{
+pub const global_variable = Guid{
.time_low = 0x8be4df61,
.time_mid = 0x93ca,
.time_high_and_version = 0x11d2,
@@ -128,10 +307,3 @@ pub const global_variable align(8) = Guid{
test {
std.testing.refAllDeclsRecursive(@This());
}
-
-const std = @import("std");
-const uefi = std.os.uefi;
-const Handle = uefi.Handle;
-const Event = uefi.Event;
-const Guid = uefi.Guid;
-const cc = uefi.cc;
lib/std/os/uefi.zig
@@ -24,9 +24,51 @@ pub var handle: Handle = undefined;
/// A pointer to the EFI System Table that is passed to the EFI image's entry point.
pub var system_table: *tables.SystemTable = undefined;
+/// UEFI's memory interfaces exclusively act on 4096-byte pages.
+pub const Page = [4096]u8;
+
/// A handle to an event structure.
pub const Event = *opaque {};
+pub const EventRegistration = *const opaque {};
+
+pub const EventType = packed struct(u32) {
+ lo_context: u8 = 0,
+ /// If an event of this type is not already in the signaled state, then
+ /// the event’s NotificationFunction will be queued at the event’s NotifyTpl
+ /// whenever the event is being waited on via EFI_BOOT_SERVICES.WaitForEvent()
+ /// or EFI_BOOT_SERVICES.CheckEvent() .
+ wait: bool = false,
+ /// The event’s NotifyFunction is queued whenever the event is signaled.
+ signal: bool = false,
+ hi_context: u20 = 0,
+ /// The event is allocated from runtime memory. If an event is to be signaled
+ /// after the call to EFI_BOOT_SERVICES.ExitBootServices() the event’s data
+ /// structure and notification function need to be allocated from runtime
+ /// memory.
+ runtime: bool = false,
+ timer: bool = false,
+
+ /// This event should not be combined with any other event types. This event
+ /// type is functionally equivalent to the EFI_EVENT_GROUP_EXIT_BOOT_SERVICES
+ /// event group.
+ pub const signal_exit_boot_services: EventType = .{
+ .signal = true,
+ .lo_context = 1,
+ };
+
+ /// The event is to be notified by the system when SetVirtualAddressMap()
+ /// is performed. This event type is a composite of EVT_NOTIFY_SIGNAL,
+ /// EVT_RUNTIME, and EVT_RUNTIME_CONTEXT and should not be combined with
+ /// any other event types.
+ pub const signal_virtual_address_change: EventType = .{
+ .runtime = true,
+ .hi_context = 0x20000,
+ .signal = true,
+ .lo_context = 2,
+ };
+};
+
/// The calling convention used for all external functions part of the UEFI API.
pub const cc: std.builtin.CallingConvention = switch (@import("builtin").target.cpu.arch) {
.x86_64 => .{ .x86_64_win = .{} },
@@ -52,7 +94,11 @@ pub const IpAddress = extern union {
/// GUIDs are align(8) unless otherwise specified.
pub const Guid = extern struct {
- time_low: u32,
+ comptime {
+ std.debug.assert(std.mem.Alignment.of(Guid) == .@"8");
+ }
+
+ time_low: u32 align(8),
time_mid: u16,
time_high_and_version: u16,
clock_seq_high_and_reserved: u8,
@@ -60,7 +106,7 @@ pub const Guid = extern struct {
node: [6]u8,
/// Format GUID into hexadecimal lowercase xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
- pub fn format(self: @This(), writer: *std.io.Writer) std.io.Writer.Error!void {
+ pub fn format(self: Guid, writer: *std.io.Writer) std.io.Writer.Error!void {
const time_low = @byteSwap(self.time_low);
const time_mid = @byteSwap(self.time_mid);
const time_high_and_version = @byteSwap(self.time_high_and_version);
@@ -75,7 +121,7 @@ pub const Guid = extern struct {
});
}
- pub fn eql(a: std.os.uefi.Guid, b: std.os.uefi.Guid) bool {
+ pub fn eql(a: Guid, b: Guid) bool {
return a.time_low == b.time_low and
a.time_mid == b.time_mid and
a.time_high_and_version == b.time_high_and_version and
lib/std/debug.zig
@@ -654,9 +654,8 @@ pub fn defaultPanic(
if (uefi.system_table.boot_services) |bs| {
// ExitData buffer must be allocated using boot_services.allocatePool (spec: page 220)
- const exit_data: []u16 = uefi.raw_pool_allocator.alloc(u16, exit_msg.len + 1) catch @trap();
- @memcpy(exit_data, exit_msg[0..exit_data.len]); // Includes null terminator.
- _ = bs.exit(uefi.handle, .aborted, exit_data.len, exit_data.ptr);
+ const exit_data = uefi.raw_pool_allocator.dupeZ(u16, exit_msg) catch @trap();
+ bs.exit(uefi.handle, .aborted, exit_data) catch {};
}
@trap();
},
lib/std/posix.zig
@@ -772,12 +772,12 @@ pub fn exit(status: u8) noreturn {
if (native_os == .uefi) {
const uefi = std.os.uefi;
// exit() is only available if exitBootServices() has not been called yet.
- // This call to exit should not fail, so we don't care about its return value.
+ // This call to exit should not fail, so we catch-ignore errors.
if (uefi.system_table.boot_services) |bs| {
- _ = bs.exit(uefi.handle, @enumFromInt(status), 0, null);
+ bs.exit(uefi.handle, @enumFromInt(status), null) catch {};
}
// If we can't exit, reboot the system instead.
- uefi.system_table.runtime_services.resetSystem(.reset_cold, @enumFromInt(status), 0, null);
+ uefi.system_table.runtime_services.resetSystem(.cold, @enumFromInt(status), null);
}
system.exit(status);
}
lib/std/Thread.zig
@@ -58,7 +58,7 @@ pub fn sleep(nanoseconds: u64) void {
const boot_services = std.os.uefi.system_table.boot_services.?;
const us_from_ns = nanoseconds / std.time.ns_per_us;
const us = math.cast(usize, us_from_ns) orelse math.maxInt(usize);
- _ = boot_services.stall(us);
+ boot_services.stall(us) catch unreachable;
return;
}
lib/std/time.zig
@@ -56,9 +56,7 @@ pub fn nanoTimestamp() i128 {
return ns;
},
.uefi => {
- var value: std.os.uefi.Time = undefined;
- const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);
- assert(status == .success);
+ const value, _ = std.os.uefi.system_table.runtime_services.getTime() catch return 0;
return value.toEpoch();
},
else => {
@@ -141,9 +139,7 @@ pub const Instant = struct {
return .{ .timestamp = ns };
},
.uefi => {
- var value: std.os.uefi.Time = undefined;
- const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);
- if (status != .success) return error.Unsupported;
+ const value, _ = std.os.uefi.system_table.runtime_services.getTime() catch return error.Unsupported;
return .{ .timestamp = value.toEpoch() };
},
// On darwin, use UPTIME_RAW instead of MONOTONIC as it ticks while