feature. See also
. The project being documented here (as the example) is the Zig library itself.
File
Code
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;
pub const BootServices = extern struct {
hdr: TableHeader,
raiseTpl: *const fn (new_tpl: TaskPriorityLevel) callconv(cc) TaskPriorityLevel,
restoreTpl: *const fn (old_tpl: TaskPriorityLevel) callconv(cc) void,
_allocatePages: *const fn (alloc_type: AllocateType, mem_type: MemoryType, pages: usize, memory: *[*]align(4096) Page) callconv(cc) Status,
_freePages: *const fn (memory: [*]align(4096) Page, pages: usize) 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,
_allocatePool: *const fn (pool_type: MemoryType, size: usize, buffer: *[*]align(8) u8) callconv(cc) Status,
_freePool: *const fn (buffer: [*]align(8) u8) 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,
_setTimer: *const fn (event: Event, type: TimerDelay, trigger_time: u64) callconv(cc) Status,
_waitForEvent: *const fn (event_len: usize, events: [*]const Event, index: *usize) callconv(cc) Status,
_signalEvent: *const fn (event: Event) callconv(cc) Status,
_closeEvent: *const fn (event: Event) callconv(cc) Status,
_checkEvent: *const fn (event: Event) callconv(cc) Status,
_installProtocolInterface: *const fn (handle: Handle, protocol: *const Guid, interface_type: InterfaceType, interface: *anyopaque) callconv(cc) Status,
_reinstallProtocolInterface: *const fn (handle: Handle, protocol: *const Guid, old_interface: *anyopaque, new_interface: *anyopaque) callconv(cc) Status,
_uninstallProtocolInterface: *const fn (handle: Handle, protocol: *const Guid, interface: *anyopaque) callconv(cc) Status,
_handleProtocol: *const fn (handle: Handle, protocol: *const Guid, interface: *?*anyopaque) callconv(cc) Status,
_reserved: *anyopaque,
_registerProtocolNotify: *const fn (protocol: *const Guid, event: Event, registration: *EventRegistration) callconv(cc) Status,
_locateHandle: *const fn (search_type: LocateSearchType, protocol: ?*const Guid, search_key: ?*const anyopaque, buffer_size: *usize, buffer: ?[*]Handle) callconv(cc) Status,
_locateDevicePath: *const fn (protocols: *const Guid, device_path: **const DevicePathProtocol, device: *?Handle) callconv(cc) Status,
_installConfigurationTable: *const fn (guid: *const Guid, table: ?*anyopaque) 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,
_startImage: *const fn (image_handle: Handle, exit_data_size: ?*usize, exit_data: ?*[*]u16) 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,
_unloadImage: *const fn (image_handle: Handle) callconv(cc) Status,
_exitBootServices: *const fn (image_handle: Handle, map_key: MemoryMapKey) callconv(cc) Status,
_getNextMonotonicCount: *const fn (count: *u64) callconv(cc) Status,
_stall: *const fn (microseconds: usize) callconv(cc) Status,
_setWatchdogTimer: *const fn (timeout: usize, watchdog_code: u64, data_size: usize, watchdog_data: ?[*]const u16) callconv(cc) Status,
_connectController: *const fn (controller_handle: Handle, driver_image_handle: ?[*:null]?Handle, remaining_device_path: ?*const DevicePathProtocol, recursive: bool) callconv(cc) Status,
_disconnectController: *const fn (controller_handle: Handle, driver_image_handle: ?Handle, child_handle: ?Handle) callconv(cc) Status,
_openProtocol: *const fn (handle: Handle, protocol: *const Guid, interface: ?*?*anyopaque, agent_handle: ?Handle, controller_handle: ?Handle, attributes: OpenProtocolAttributes) callconv(cc) Status,
_closeProtocol: *const fn (handle: Handle, protocol: *const Guid, agent_handle: Handle, controller_handle: ?Handle) callconv(cc) Status,
_openProtocolInformation: *const fn (handle: Handle, protocol: *const Guid, entry_buffer: *[*]ProtocolInformationEntry, entry_count: *usize) callconv(cc) Status,
_protocolsPerHandle: *const fn (handle: Handle, protocol_buffer: *[*]*const Guid, protocol_buffer_count: *usize) callconv(cc) Status,
_locateHandleBuffer: *const fn (search_type: LocateSearchType, protocol: ?*const Guid, search_key: ?*const anyopaque, num_handles: *usize, buffer: *[*]Handle) callconv(cc) Status,
_locateProtocol: *const fn (protocol: *const Guid, registration: ?EventRegistration, interface: *?*const anyopaque) callconv(cc) Status,
_installMultipleProtocolInterfaces: *const fn (handle: *?Handle, ...) callconv(cc) Status,
_uninstallMultipleProtocolInterfaces: *const fn (handle: Handle, ...) callconv(cc) Status,
_calculateCrc32: *const fn (data: [*]const u8, data_size: usize, *u32) callconv(cc) Status,
_copyMem: *const fn (dest: [*]u8, src: [*]const u8, len: usize) callconv(cc) void,
_setMem: *const fn (buffer: [*]u8, size: usize, value: u8) callconv(cc) void,
_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;
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,
};
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),
}
}
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),
}
}
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),
}
}
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),
}
}
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),
}
}
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),
}
}
pub fn installProtocolInterface(
self: *BootServices,
handle: ?Handle,
interface: anytype,
) InstallProtocolInterfacesError!Handle {
return self.installProtocolInterfaces(handle, .{
interface,
});
}
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),
}
}
pub fn uninstallProtocolInterface(
self: *BootServices,
handle: Handle,
interface: anytype,
) UninstallProtocolInterfacesError!void {
return self.uninstallProtocolInterfaces(handle, .{
interface,
});
}
pub fn handleProtocol(
self: *BootServices,
Protocol: type,
handle: Handle,
) HandleProtocolError!?*Protocol {
// 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),
}
}
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,
)) {
// This is because it can/should only return success when a valid buffer is
// passed with a non zero size, which is not the case.
// Thus this status is considered unreachable and will return error.Unexpected
// .success => unreachable,
.buffer_too_small => return @divExact(len, @sizeOf(uefi.Handle)),
.not_found => return 0,
// as per the most recent UEFI spec 2.10A, therefore this branch is
// considered unreachable and will return error.Unexpected instead
// .invalid_parameter => unreachable
else => |status| return uefi.unexpectedStatus(status),
}
}
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),
}
}
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],
};
}
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),
}
}
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),
}
}
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),
}
}
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),
}
}
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),
}
}
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;
result[result.len - 1] = null;
comptime 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.field_names.len * 2 + 2]type = undefined;
tuple_types[0] = HandleType;
tuple_types[tuple_types.len - 1] = ?*const Guid;
var idx = 1;
while (idx < tuple_types.len - 1) : (idx += 2) {
tuple_types[idx] = *const Guid;
tuple_types[idx + 1] = *const anyopaque;
}
return @Tuple(tuple_types[0..]);
}