mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
535 lines
18 KiB
Zig
535 lines
18 KiB
Zig
const std = @import("std");
|
|
const uefi = std.os.uefi;
|
|
const Guid = uefi.Guid;
|
|
const TableHeader = uefi.tables.TableHeader;
|
|
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.
|
|
///
|
|
/// As the runtime_services table may grow with new UEFI versions, it is important to check hdr.header_size.
|
|
///
|
|
/// Some functions may not be supported. Check the RuntimeServicesSupported variable using getVariable.
|
|
/// getVariable is one of the functions that may not be supported.
|
|
///
|
|
/// Some functions may not be called while other functions are running.
|
|
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: *Time, capabilities: ?*TimeCapabilities) callconv(cc) Status,
|
|
|
|
/// Sets the current local time and date information
|
|
_setTime: *const fn (time: *const Time) callconv(cc) Status,
|
|
|
|
/// Returns the current wakeup alarm clock setting
|
|
_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: ?*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: [*]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: DebugDisposition, address: *?*anyopaque) callconv(cc) Status,
|
|
|
|
/// Returns the value of a variable.
|
|
_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]const u16, vendor_guid: *Guid) callconv(cc) Status,
|
|
|
|
/// Sets the value of a variable.
|
|
_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,
|
|
|
|
/// Resets the entire platform.
|
|
_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: [*]*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: [*]*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: 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| @ptrCast(@alignCast(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;
|
|
};
|