mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 22:04:21 +00:00
* std.os.uefi.tables: ziggify boot and runtime services
* avoid T{} syntax
Co-authored-by: linusg <mail@linusgroh.de>
* misc fixes
* work
* self-review quickfixes
* dont make MemoryMapSlice generic
* more review fixes, work
* more work
* more work
* review fixes
* update boot/runtime services references throughout codebase
* self-review fixes
* couple of fixes i forgot to commit earlier
* fixes from integrating in my own project
* fixes from refAllDeclsRecursive
* Apply suggestions from code review
Co-authored-by: truemedian <truemedian@gmail.com>
* more fixes from review
* fixes from project integration
* make natural alignment of Guid align-8
* EventRegistration is a new opaque type
* fix getNextHighMonotonicCount
* fix locateProtocol
* fix exit
* partly revert 7372d65
* oops exit data_len is num of bytes
* fixes from project integration
* MapInfo consistency, MemoryType update per review
* turn EventRegistration back into a pointer
* forgot to finish updating MemoryType methods
* fix IntFittingRange calls
* set uefi.Page nat alignment
* Back out "set uefi.Page nat alignment"
This backs out commit cdd9bd6f7f5fb763f994b8fbe3e1a1c2996a2393.
* get rid of some error.NotFound-s
* fix .exit call in panic
* review comments, add format method
* fix resetSystem data alignment
* oops, didnt do a final refAllDeclsRecursive i guess
* review comments
* writergate update MemoryType.format
* fix rename
---------
Co-authored-by: linusg <mail@linusgroh.de>
Co-authored-by: truemedian <truemedian@gmail.com>
1277 lines
46 KiB
Zig
1277 lines
46 KiB
Zig
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.
|
||
///
|
||
/// Boot Services must not be used after exitBootServices has been called. The only exception is
|
||
/// getMemoryMap, which may be used after the first unsuccessful call to exitBootServices.
|
||
/// After successfully calling exitBootServices, system_table.console_in_handle, system_table.con_in,
|
||
/// system_table.console_out_handle, system_table.con_out, system_table.standard_error_handle,
|
||
/// system_table.std_err, and system_table.boot_services should be set to null. After setting these
|
||
/// attributes to null, system_table.hdr.crc32 must be recomputed.
|
||
///
|
||
/// As the boot_services table may grow with new UEFI versions, it is important to check hdr.header_size.
|
||
pub const BootServices = extern struct {
|
||
hdr: TableHeader,
|
||
|
||
/// Raises a task's priority level and returns its previous level.
|
||
raiseTpl: *const fn (new_tpl: TaskPriorityLevel) callconv(cc) TaskPriorityLevel,
|
||
|
||
/// Restores a task's priority level to its previous value.
|
||
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) Page) callconv(cc) Status,
|
||
|
||
/// Frees memory pages.
|
||
_freePages: *const fn (memory: [*]align(4096) Page, pages: usize) callconv(cc) Status,
|
||
|
||
/// Returns the current memory map.
|
||
_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,
|
||
|
||
/// Returns pool memory to the system.
|
||
_freePool: *const fn (buffer: [*]align(8) u8) callconv(cc) Status,
|
||
|
||
/// Creates an event.
|
||
_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,
|
||
|
||
/// Stops execution until an event is signaled.
|
||
_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,
|
||
|
||
/// Closes an event.
|
||
_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,
|
||
|
||
/// 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: *const Guid, interface_type: InterfaceType, interface: *anyopaque) callconv(cc) Status,
|
||
|
||
/// Reinstalls a protocol interface on a device handle
|
||
_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: *const Guid, interface: *anyopaque) callconv(cc) Status,
|
||
|
||
/// Queries a handle to determine if it supports a specified protocol.
|
||
_handleProtocol: *const fn (handle: Handle, protocol: *const Guid, interface: *?*anyopaque) callconv(cc) Status,
|
||
|
||
_reserved: *anyopaque,
|
||
|
||
/// Creates an event that is to be signaled whenever an interface is installed for a specified protocol.
|
||
_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: ?*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: *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: *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,
|
||
|
||
/// 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,
|
||
|
||
/// 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: ?[*]align(2) const u8) callconv(cc) Status,
|
||
|
||
/// Unloads an image.
|
||
_unloadImage: *const fn (image_handle: Handle) callconv(cc) Status,
|
||
|
||
/// Terminates all boot services.
|
||
_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,
|
||
|
||
/// Induces a fine-grained stall.
|
||
_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,
|
||
|
||
/// Connects one or more drives to a controller.
|
||
_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,
|
||
|
||
/// Queries a handle to determine if it supports a specified protocol.
|
||
_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: *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: *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: *[*]*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: ?*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: *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,
|
||
|
||
/// 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,
|
||
|
||
/// Computes and returns a 32-bit CRC for a data buffer.
|
||
_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,
|
||
|
||
/// Fills a buffer with a specified value
|
||
_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: *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
|
||
///
|
||
/// 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));
|
||
|
||
const agent_handle: ?Handle, const controller_handle: ?Handle = switch (attributes) {
|
||
inline else => |arg| .{ arg.agent, arg.controller },
|
||
};
|
||
|
||
var ptr: ?*Protocol = undefined;
|
||
|
||
switch (self._openProtocol(
|
||
handle,
|
||
&Protocol.guid,
|
||
@as(*?*anyopaque, @ptrCast(&ptr)),
|
||
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);
|
||
|
||
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 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..]);
|
||
}
|