mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
std.os.uefi.tables: ziggify boot and runtime services (#23441)
* 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>
This commit is contained in:
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -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();
|
||||
},
|
||||
|
||||
+49
-3
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+200
-28
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
return ptr.?;
|
||||
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 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 NotifyOpts = struct {
|
||||
tpl: TaskPriorityLevel = .application,
|
||||
function: ?*const fn (Event, ?*anyopaque) callconv(cc) void = null,
|
||||
context: ?*anyopaque = null,
|
||||
};
|
||||
|
||||
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 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..]);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
+3
-3
@@ -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);
|
||||
}
|
||||
|
||||
+2
-6
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user