zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 2c24bf2f79af8d258956d3169e0c64ac8e71e51d (tree)
parent 60bb1d4e1c262ff36c18cefe974aa2f773483af4
Author: Andrew Kelley <andrew@ziglang.org>
Date:   Fri, 18 Feb 2022 14:16:30 -0500

Merge pull request #10604 from fifty-six/master

std/os/uefi: additional improvements/fixes
Diffstat:
Mlib/std/builtin.zig | 47++++++++++++++++++++++++++++++++++++++++++++++-
Mlib/std/os/uefi.zig | 14++++++++++++--
Mlib/std/os/uefi/protocols.zig | 142++++++++++++++++++++++++-------------------------------------------------------
Mlib/std/os/uefi/protocols/absolute_pointer_protocol.zig | 8++------
Mlib/std/os/uefi/protocols/device_path_protocol.zig | 440++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mlib/std/os/uefi/protocols/edid_override_protocol.zig | 9+++------
Mlib/std/os/uefi/protocols/hii.zig | 4++--
Mlib/std/os/uefi/protocols/simple_network_protocol.zig | 8++------
Mlib/std/os/uefi/protocols/simple_text_input_ex_protocol.zig | 4++--
Mlib/std/os/uefi/status.zig | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/std/os/uefi/tables.zig | 19+++++--------------
Mlib/std/os/uefi/tables/boot_services.zig | 135++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Mlib/std/os/uefi/tables/runtime_services.zig | 60++++++++++++++++++++++++++++++++++++++++++++++--------------
13 files changed, 663 insertions(+), 289 deletions(-)

diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig @@ -758,7 +758,52 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn std.os.abort(); }, .uefi => { - // TODO look into using the debug info and logging helpful messages + const uefi = std.os.uefi; + + const ExitData = struct { + pub fn create_exit_data(exit_msg: []const u8, exit_size: *usize) ![*:0]u16 { + // Need boot services for pool allocation + if (uefi.system_table.boot_services == null) { + return error.BootServicesUnavailable; + } + + // ExitData buffer must be allocated using boot_services.allocatePool + var utf16: []u16 = try uefi.raw_pool_allocator.alloc(u16, 256); + errdefer uefi.raw_pool_allocator.free(utf16); + + if (exit_msg.len > 255) { + return error.MessageTooLong; + } + + var fmt: [256]u8 = undefined; + var slice = try std.fmt.bufPrint(&fmt, "\r\nerr: {s}\r\n", .{exit_msg}); + + var len = try std.unicode.utf8ToUtf16Le(utf16, slice); + + utf16[len] = 0; + + exit_size.* = 256; + + return @ptrCast([*:0]u16, utf16.ptr); + } + }; + + var exit_size: usize = 0; + var exit_data = ExitData.create_exit_data(msg, &exit_size) catch null; + + if (exit_data) |data| { + if (uefi.system_table.std_err) |out| { + _ = out.setAttribute(uefi.protocols.SimpleTextOutputProtocol.red); + _ = out.outputString(data); + _ = out.setAttribute(uefi.protocols.SimpleTextOutputProtocol.white); + } + } + + if (uefi.system_table.boot_services) |bs| { + _ = bs.exit(uefi.handle, .Aborted, exit_size, exit_data); + } + + // Didn't have boot_services, just fallback to whatever. std.os.abort(); }, else => { diff --git a/lib/std/os/uefi.zig b/lib/std/os/uefi.zig @@ -23,6 +23,18 @@ pub var system_table: *tables.SystemTable = undefined; /// A handle to an event structure. pub const Event = *opaque {}; +pub const MacAddress = extern struct { + address: [32]u8, +}; + +pub const Ipv4Address = extern struct { + address: [4]u8, +}; + +pub const Ipv6Address = extern struct { + address: [16]u8, +}; + /// GUIDs must be align(8) pub const Guid = extern struct { time_low: u32, @@ -86,7 +98,6 @@ pub const Time = extern struct { /// 0 - 59 second: u8, - _pad1: u8, /// 0 - 999999999 nanosecond: u32, @@ -103,7 +114,6 @@ pub const Time = extern struct { /// If true, the time is affected by daylight savings time. adjust_daylight: bool, }, - _pad2: u8, /// Time is to be interpreted as local time pub const unspecified_timezone: i16 = 0x7ff; diff --git a/lib/std/os/uefi/protocols.zig b/lib/std/os/uefi/protocols.zig @@ -1,100 +1,44 @@ -pub const LoadedImageProtocol = @import("protocols/loaded_image_protocol.zig").LoadedImageProtocol; -pub const loaded_image_device_path_protocol_guid = @import("protocols/loaded_image_protocol.zig").loaded_image_device_path_protocol_guid; - -pub const AcpiDevicePath = @import("protocols/device_path_protocol.zig").AcpiDevicePath; -pub const BiosBootSpecificationDevicePath = @import("protocols/device_path_protocol.zig").BiosBootSpecificationDevicePath; -pub const DevicePath = @import("protocols/device_path_protocol.zig").DevicePath; -pub const DevicePathProtocol = @import("protocols/device_path_protocol.zig").DevicePathProtocol; -pub const DevicePathType = @import("protocols/device_path_protocol.zig").DevicePathType; -pub const EndDevicePath = @import("protocols/device_path_protocol.zig").EndDevicePath; -pub const HardwareDevicePath = @import("protocols/device_path_protocol.zig").HardwareDevicePath; -pub const MediaDevicePath = @import("protocols/device_path_protocol.zig").MediaDevicePath; -pub const MessagingDevicePath = @import("protocols/device_path_protocol.zig").MessagingDevicePath; - -pub const SimpleFileSystemProtocol = @import("protocols/simple_file_system_protocol.zig").SimpleFileSystemProtocol; -pub const FileProtocol = @import("protocols/file_protocol.zig").FileProtocol; -pub const FileInfo = @import("protocols/file_protocol.zig").FileInfo; -pub const FileSystemInfo = @import("protocols/file_protocol.zig").FileSystemInfo; - -pub const InputKey = @import("protocols/simple_text_input_ex_protocol.zig").InputKey; -pub const KeyData = @import("protocols/simple_text_input_ex_protocol.zig").KeyData; -pub const KeyState = @import("protocols/simple_text_input_ex_protocol.zig").KeyState; -pub const SimpleTextInputProtocol = @import("protocols/simple_text_input_protocol.zig").SimpleTextInputProtocol; -pub const SimpleTextInputExProtocol = @import("protocols/simple_text_input_ex_protocol.zig").SimpleTextInputExProtocol; - -pub const SimpleTextOutputMode = @import("protocols/simple_text_output_protocol.zig").SimpleTextOutputMode; -pub const SimpleTextOutputProtocol = @import("protocols/simple_text_output_protocol.zig").SimpleTextOutputProtocol; - -pub const SimplePointerMode = @import("protocols/simple_pointer_protocol.zig").SimplePointerMode; -pub const SimplePointerProtocol = @import("protocols/simple_pointer_protocol.zig").SimplePointerProtocol; -pub const SimplePointerState = @import("protocols/simple_pointer_protocol.zig").SimplePointerState; - -pub const AbsolutePointerMode = @import("protocols/absolute_pointer_protocol.zig").AbsolutePointerMode; -pub const AbsolutePointerProtocol = @import("protocols/absolute_pointer_protocol.zig").AbsolutePointerProtocol; -pub const AbsolutePointerState = @import("protocols/absolute_pointer_protocol.zig").AbsolutePointerState; - -pub const GraphicsOutputBltPixel = @import("protocols/graphics_output_protocol.zig").GraphicsOutputBltPixel; -pub const GraphicsOutputBltOperation = @import("protocols/graphics_output_protocol.zig").GraphicsOutputBltOperation; -pub const GraphicsOutputModeInformation = @import("protocols/graphics_output_protocol.zig").GraphicsOutputModeInformation; -pub const GraphicsOutputProtocol = @import("protocols/graphics_output_protocol.zig").GraphicsOutputProtocol; -pub const GraphicsOutputProtocolMode = @import("protocols/graphics_output_protocol.zig").GraphicsOutputProtocolMode; -pub const GraphicsPixelFormat = @import("protocols/graphics_output_protocol.zig").GraphicsPixelFormat; -pub const PixelBitmask = @import("protocols/graphics_output_protocol.zig").PixelBitmask; - -pub const EdidDiscoveredProtocol = @import("protocols/edid_discovered_protocol.zig").EdidDiscoveredProtocol; - -pub const EdidActiveProtocol = @import("protocols/edid_active_protocol.zig").EdidActiveProtocol; - -pub const EdidOverrideProtocol = @import("protocols/edid_override_protocol.zig").EdidOverrideProtocol; -pub const EdidOverrideProtocolAttributes = @import("protocols/edid_override_protocol.zig").EdidOverrideProtocolAttributes; - -pub const SimpleNetworkProtocol = @import("protocols/simple_network_protocol.zig").SimpleNetworkProtocol; -pub const MacAddress = @import("protocols/simple_network_protocol.zig").MacAddress; -pub const SimpleNetworkMode = @import("protocols/simple_network_protocol.zig").SimpleNetworkMode; -pub const SimpleNetworkReceiveFilter = @import("protocols/simple_network_protocol.zig").SimpleNetworkReceiveFilter; -pub const SimpleNetworkState = @import("protocols/simple_network_protocol.zig").SimpleNetworkState; -pub const NetworkStatistics = @import("protocols/simple_network_protocol.zig").NetworkStatistics; -pub const SimpleNetworkInterruptStatus = @import("protocols/simple_network_protocol.zig").SimpleNetworkInterruptStatus; - -pub const ManagedNetworkServiceBindingProtocol = @import("protocols/managed_network_service_binding_protocol.zig").ManagedNetworkServiceBindingProtocol; -pub const ManagedNetworkProtocol = @import("protocols/managed_network_protocol.zig").ManagedNetworkProtocol; -pub const ManagedNetworkConfigData = @import("protocols/managed_network_protocol.zig").ManagedNetworkConfigData; -pub const ManagedNetworkCompletionToken = @import("protocols/managed_network_protocol.zig").ManagedNetworkCompletionToken; -pub const ManagedNetworkReceiveData = @import("protocols/managed_network_protocol.zig").ManagedNetworkReceiveData; -pub const ManagedNetworkTransmitData = @import("protocols/managed_network_protocol.zig").ManagedNetworkTransmitData; -pub const ManagedNetworkFragmentData = @import("protocols/managed_network_protocol.zig").ManagedNetworkFragmentData; - -pub const Ip6ServiceBindingProtocol = @import("protocols/ip6_service_binding_protocol.zig").Ip6ServiceBindingProtocol; -pub const Ip6Protocol = @import("protocols/ip6_protocol.zig").Ip6Protocol; -pub const Ip6ModeData = @import("protocols/ip6_protocol.zig").Ip6ModeData; -pub const Ip6ConfigData = @import("protocols/ip6_protocol.zig").Ip6ConfigData; -pub const Ip6Address = @import("protocols/ip6_protocol.zig").Ip6Address; -pub const Ip6AddressInfo = @import("protocols/ip6_protocol.zig").Ip6AddressInfo; -pub const Ip6RouteTable = @import("protocols/ip6_protocol.zig").Ip6RouteTable; -pub const Ip6NeighborState = @import("protocols/ip6_protocol.zig").Ip6NeighborState; -pub const Ip6NeighborCache = @import("protocols/ip6_protocol.zig").Ip6NeighborCache; -pub const Ip6IcmpType = @import("protocols/ip6_protocol.zig").Ip6IcmpType; -pub const Ip6CompletionToken = @import("protocols/ip6_protocol.zig").Ip6CompletionToken; - -pub const Ip6ConfigProtocol = @import("protocols/ip6_config_protocol.zig").Ip6ConfigProtocol; -pub const Ip6ConfigDataType = @import("protocols/ip6_config_protocol.zig").Ip6ConfigDataType; - -pub const Udp6ServiceBindingProtocol = @import("protocols/udp6_service_binding_protocol.zig").Udp6ServiceBindingProtocol; -pub const Udp6Protocol = @import("protocols/udp6_protocol.zig").Udp6Protocol; -pub const Udp6ConfigData = @import("protocols/udp6_protocol.zig").Udp6ConfigData; -pub const Udp6CompletionToken = @import("protocols/udp6_protocol.zig").Udp6CompletionToken; -pub const Udp6ReceiveData = @import("protocols/udp6_protocol.zig").Udp6ReceiveData; -pub const Udp6TransmitData = @import("protocols/udp6_protocol.zig").Udp6TransmitData; -pub const Udp6SessionData = @import("protocols/udp6_protocol.zig").Udp6SessionData; -pub const Udp6FragmentData = @import("protocols/udp6_protocol.zig").Udp6FragmentData; - +// Misc +pub usingnamespace @import("protocols/loaded_image_protocol.zig"); +pub usingnamespace @import("protocols/device_path_protocol.zig"); +pub usingnamespace @import("protocols/rng_protocol.zig"); +pub usingnamespace @import("protocols/shell_parameters_protocol.zig"); + +// Files +pub usingnamespace @import("protocols/simple_file_system_protocol.zig"); +pub usingnamespace @import("protocols/file_protocol.zig"); + +// Text +pub usingnamespace @import("protocols/simple_text_input_protocol.zig"); +pub usingnamespace @import("protocols/simple_text_input_ex_protocol.zig"); +pub usingnamespace @import("protocols/simple_text_output_protocol.zig"); + +// Pointer +pub usingnamespace @import("protocols/simple_pointer_protocol.zig"); +pub usingnamespace @import("protocols/absolute_pointer_protocol.zig"); + +pub usingnamespace @import("protocols/graphics_output_protocol.zig"); + +// edid +pub usingnamespace @import("protocols/edid_discovered_protocol.zig"); +pub usingnamespace @import("protocols/edid_active_protocol.zig"); +pub usingnamespace @import("protocols/edid_override_protocol.zig"); + +// Network +pub usingnamespace @import("protocols/simple_network_protocol.zig"); +pub usingnamespace @import("protocols/managed_network_service_binding_protocol.zig"); +pub usingnamespace @import("protocols/managed_network_protocol.zig"); + +// ip6 +pub usingnamespace @import("protocols/ip6_service_binding_protocol.zig"); +pub usingnamespace @import("protocols/ip6_protocol.zig"); +pub usingnamespace @import("protocols/ip6_config_protocol.zig"); + +// udp6 +pub usingnamespace @import("protocols/udp6_service_binding_protocol.zig"); +pub usingnamespace @import("protocols/udp6_protocol.zig"); + +// hii pub const hii = @import("protocols/hii.zig"); -pub const HIIDatabaseProtocol = @import("protocols/hii_database_protocol.zig").HIIDatabaseProtocol; -pub const HIIPopupProtocol = @import("protocols/hii_popup_protocol.zig").HIIPopupProtocol; -pub const HIIPopupStyle = @import("protocols/hii_popup_protocol.zig").HIIPopupStyle; -pub const HIIPopupType = @import("protocols/hii_popup_protocol.zig").HIIPopupType; -pub const HIIPopupSelection = @import("protocols/hii_popup_protocol.zig").HIIPopupSelection; - -pub const RNGProtocol = @import("protocols/rng_protocol.zig").RNGProtocol; - -pub const ShellParametersProtocol = @import("protocols/shell_parameters_protocol.zig").ShellParametersProtocol; +pub usingnamespace @import("protocols/hii_database_protocol.zig"); +pub usingnamespace @import("protocols/hii_popup_protocol.zig"); diff --git a/lib/std/os/uefi/protocols/absolute_pointer_protocol.zig b/lib/std/os/uefi/protocols/absolute_pointer_protocol.zig @@ -40,9 +40,7 @@ pub const AbsolutePointerMode = extern struct { attributes: packed struct { supports_alt_active: bool, supports_pressure_as_z: bool, - _pad1: u6, - _pad2: u8, - _pad3: u16, + _pad: u30 = 0, }, }; @@ -53,8 +51,6 @@ pub const AbsolutePointerState = extern struct { active_buttons: packed struct { touch_active: bool, alt_active: bool, - _pad1: u6, - _pad2: u8, - _pad3: u16, + _pad: u30 = 0, }, }; diff --git a/lib/std/os/uefi/protocols/device_path_protocol.zig b/lib/std/os/uefi/protocols/device_path_protocol.zig @@ -72,63 +72,39 @@ pub const DevicePathProtocol = packed struct { } pub fn getDevicePath(self: *const DevicePathProtocol) ?DevicePath { - return switch (self.type) { - .Hardware => blk: { - const hardware: ?HardwareDevicePath = switch (@intToEnum(HardwareDevicePath.Subtype, self.subtype)) { - .Pci => .{ .Pci = @ptrCast(*const HardwareDevicePath.PciDevicePath, self) }, - .PcCard => .{ .PcCard = @ptrCast(*const HardwareDevicePath.PcCardDevicePath, self) }, - .MemoryMapped => .{ .MemoryMapped = @ptrCast(*const HardwareDevicePath.MemoryMappedDevicePath, self) }, - .Vendor => .{ .Vendor = @ptrCast(*const HardwareDevicePath.VendorDevicePath, self) }, - .Controller => .{ .Controller = @ptrCast(*const HardwareDevicePath.ControllerDevicePath, self) }, - .Bmc => .{ .Bmc = @ptrCast(*const HardwareDevicePath.BmcDevicePath, self) }, - _ => null, - }; - break :blk if (hardware) |h| .{ .Hardware = h } else null; - }, - .Acpi => blk: { - const acpi: ?AcpiDevicePath = switch (@intToEnum(AcpiDevicePath.Subtype, self.subtype)) { - else => null, // TODO - }; - break :blk if (acpi) |a| .{ .Acpi = a } else null; - }, - .Messaging => blk: { - const messaging: ?MessagingDevicePath = switch (@intToEnum(MessagingDevicePath.Subtype, self.subtype)) { - else => null, // TODO - }; - break :blk if (messaging) |m| .{ .Messaging = m } else null; - }, - .Media => blk: { - const media: ?MediaDevicePath = switch (@intToEnum(MediaDevicePath.Subtype, self.subtype)) { - .HardDrive => .{ .HardDrive = @ptrCast(*const MediaDevicePath.HardDriveDevicePath, self) }, - .Cdrom => .{ .Cdrom = @ptrCast(*const MediaDevicePath.CdromDevicePath, self) }, - .Vendor => .{ .Vendor = @ptrCast(*const MediaDevicePath.VendorDevicePath, self) }, - .FilePath => .{ .FilePath = @ptrCast(*const MediaDevicePath.FilePathDevicePath, self) }, - .MediaProtocol => .{ .MediaProtocol = @ptrCast(*const MediaDevicePath.MediaProtocolDevicePath, self) }, - .PiwgFirmwareFile => .{ .PiwgFirmwareFile = @ptrCast(*const MediaDevicePath.PiwgFirmwareFileDevicePath, self) }, - .PiwgFirmwareVolume => .{ .PiwgFirmwareVolume = @ptrCast(*const MediaDevicePath.PiwgFirmwareVolumeDevicePath, self) }, - .RelativeOffsetRange => .{ .RelativeOffsetRange = @ptrCast(*const MediaDevicePath.RelativeOffsetRangeDevicePath, self) }, - .RamDisk => .{ .RamDisk = @ptrCast(*const MediaDevicePath.RamDiskDevicePath, self) }, - _ => null, - }; - break :blk if (media) |m| .{ .Media = m } else null; - }, - .BiosBootSpecification => blk: { - const bbs: ?BiosBootSpecificationDevicePath = switch (@intToEnum(BiosBootSpecificationDevicePath.Subtype, self.subtype)) { - .BBS101 => .{ .BBS101 = @ptrCast(*const BiosBootSpecificationDevicePath.BBS101DevicePath, self) }, - _ => null, - }; - break :blk if (bbs) |b| .{ .BiosBootSpecification = b } else null; - }, - .End => blk: { - const end: ?EndDevicePath = switch (@intToEnum(EndDevicePath.Subtype, self.subtype)) { - .EndEntire => .{ .EndEntire = @ptrCast(*const EndDevicePath.EndEntireDevicePath, self) }, - .EndThisInstance => .{ .EndThisInstance = @ptrCast(*const EndDevicePath.EndThisInstanceDevicePath, self) }, - _ => null, - }; - break :blk if (end) |e| .{ .End = e } else null; - }, - _ => null, - }; + inline for (@typeInfo(DevicePath).Union.fields) |ufield| { + const enum_value = std.meta.stringToEnum(DevicePathType, ufield.name); + + // Got the associated union type for self.type, now + // we need to initialize it and its subtype + if (self.type == enum_value) { + var subtype = self.initSubtype(ufield.field_type); + + if (subtype) |sb| { + // e.g. return .{ .Hardware = .{ .Pci = @ptrCast(...) } } + return @unionInit(DevicePath, ufield.name, sb); + } + } + } + + return null; + } + + pub fn initSubtype(self: *const DevicePathProtocol, comptime TUnion: type) ?TUnion { + const type_info = @typeInfo(TUnion).Union; + const TTag = type_info.tag_type.?; + + inline for (type_info.fields) |subtype| { + // The tag names match the union names, so just grab that off the enum + const tag_val: u8 = @enumToInt(@field(TTag, subtype.name)); + + if (self.subtype == tag_val) { + // e.g. expr = .{ .Pci = @ptrCast(...) } + return @unionInit(TUnion, subtype.name, @ptrCast(subtype.field_type, self)); + } + } + + return null; } }; @@ -173,79 +149,113 @@ pub const HardwareDevicePath = union(Subtype) { type: DevicePathType, subtype: Subtype, length: u16, - // TODO + function: u8, + device: u8, }; pub const PcCardDevicePath = packed struct { type: DevicePathType, subtype: Subtype, length: u16, - // TODO + function_number: u8, }; pub const MemoryMappedDevicePath = packed struct { type: DevicePathType, subtype: Subtype, length: u16, - // TODO + memory_type: u32, + start_address: u64, + end_address: u64, }; pub const VendorDevicePath = packed struct { type: DevicePathType, subtype: Subtype, length: u16, - // TODO + vendor_guid: Guid, }; pub const ControllerDevicePath = packed struct { type: DevicePathType, subtype: Subtype, length: u16, - // TODO + controller_number: u32, }; pub const BmcDevicePath = packed struct { type: DevicePathType, subtype: Subtype, length: u16, - // TODO + interface_type: u8, + base_address: usize, }; }; pub const AcpiDevicePath = union(Subtype) { - Acpi: void, // TODO - ExpandedAcpi: void, // TODO - Adr: void, // TODO - Nvdimm: void, // TODO + Acpi: *const BaseAcpiDevicePath, + ExpandedAcpi: *const ExpandedAcpiDevicePath, + Adr: *const AdrDevicePath, pub const Subtype = enum(u8) { Acpi = 1, ExpandedAcpi = 2, Adr = 3, - Nvdimm = 4, _, }; + + pub const BaseAcpiDevicePath = packed struct { + type: DevicePathType, + subtype: Subtype, + length: u16, + hid: u32, + uid: u32, + }; + + pub const ExpandedAcpiDevicePath = packed struct { + type: DevicePathType, + subtype: Subtype, + length: u16, + hid: u32, + uid: u32, + cid: u32, + // variable length u16[*:0] strings + // hid_str, uid_str, cid_str + }; + + pub const AdrDevicePath = packed struct { + type: DevicePathType, + subtype: Subtype, + length: u16, + adr: u32, + // multiple adr entries can optionally follow + pub fn adrs(self: *const AdrDevicePath) []const u32 { + // self.length is a minimum of 8 with one adr which is size 4. + var entries = (self.length - 4) / @sizeOf(u32); + return @ptrCast([*]const u32, &self.adr)[0..entries]; + } + }; }; pub const MessagingDevicePath = union(Subtype) { - Atapi: void, // TODO - Scsi: void, // TODO - FibreChannel: void, // TODO - FibreChannelEx: void, // TODO - @"1394": void, // TODO - Usb: void, // TODO - Sata: void, // TODO - UsbWwid: void, // TODO - Lun: void, // TODO - UsbClass: void, // TODO - I2o: void, // TODO - MacAddress: void, // TODO - Ipv4: void, // TODO - Ipv6: void, // TODO - Vlan: void, // TODO - InfiniBand: void, // TODO - Uart: void, // TODO - Vendor: void, // TODO + Atapi: *const AtapiDevicePath, + Scsi: *const ScsiDevicePath, + FibreChannel: *const FibreChannelDevicePath, + FibreChannelEx: *const FibreChannelExDevicePath, + @"1394": *const F1394DevicePath, + Usb: *const UsbDevicePath, + Sata: *const SataDevicePath, + UsbWwid: *const UsbWwidDevicePath, + Lun: *const DeviceLogicalUnitDevicePath, + UsbClass: *const UsbClassDevicePath, + I2o: *const I2oDevicePath, + MacAddress: *const MacAddressDevicePath, + Ipv4: *const Ipv4DevicePath, + Ipv6: *const Ipv6DevicePath, + Vlan: *const VlanDevicePath, + InfiniBand: *const InfiniBandDevicePath, + Uart: *const UartDevicePath, + Vendor: *const VendorDefinedDevicePath, pub const Subtype = enum(u8) { Atapi = 1, @@ -268,6 +278,232 @@ pub const MessagingDevicePath = union(Subtype) { Vendor = 10, _, }; + + pub const AtapiDevicePath = packed struct { + const Role = enum(u8) { + Master = 0, + Slave = 1, + }; + + const Rank = enum(u8) { + Primary = 0, + Secondary = 1, + }; + + type: DevicePathType, + subtype: Subtype, + length: u16, + primary_secondary: Rank, + slave_master: Role, + logical_unit_number: u16, + }; + + pub const ScsiDevicePath = packed struct { + type: DevicePathType, + subtype: Subtype, + length: u16, + target_id: u16, + logical_unit_number: u16, + }; + + pub const FibreChannelDevicePath = packed struct { + type: DevicePathType, + subtype: Subtype, + length: u16, + reserved: u32, + world_wide_name: u64, + logical_unit_number: u64, + }; + + pub const FibreChannelExDevicePath = packed struct { + type: DevicePathType, + subtype: Subtype, + length: u16, + reserved: u32, + world_wide_name: [8]u8, + logical_unit_number: [8]u8, + }; + + pub const F1394DevicePath = packed struct { + type: DevicePathType, + subtype: Subtype, + length: u16, + reserved: u32, + guid: u64, + }; + + pub const UsbDevicePath = packed struct { + type: DevicePathType, + subtype: Subtype, + length: u16, + parent_port_number: u8, + interface_number: u8, + }; + + pub const SataDevicePath = packed struct { + type: DevicePathType, + subtype: Subtype, + length: u16, + hba_port_number: u16, + port_multiplier_port_number: u16, + logical_unit_number: u16, + }; + + pub const UsbWwidDevicePath = packed struct { + type: DevicePathType, + subtype: Subtype, + length: u16, + interface_number: u16, + device_vendor_id: u16, + device_product_id: u16, + + pub fn serial_number(self: *const UsbWwidDevicePath) []const u16 { + var serial_len = (self.length - @sizeOf(UsbWwidDevicePath)) / @sizeOf(u16); + return @ptrCast([*]u16, @ptrCast([*]u8, self) + @sizeOf(UsbWwidDevicePath))[0..serial_len]; + } + }; + + pub const DeviceLogicalUnitDevicePath = packed struct { + type: DevicePathType, + subtype: Subtype, + length: u16, + lun: u8, + }; + + pub const UsbClassDevicePath = packed struct { + type: DevicePathType, + subtype: Subtype, + length: u16, + vendor_id: u16, + product_id: u16, + device_class: u8, + device_subclass: u8, + device_protocol: u8, + }; + + pub const I2oDevicePath = packed struct { + type: DevicePathType, + subtype: Subtype, + length: u16, + tid: u32, + }; + + pub const MacAddressDevicePath = packed struct { + type: DevicePathType, + subtype: Subtype, + length: u16, + mac_address: uefi.MacAddress, + if_type: u8, + }; + + pub const Ipv4DevicePath = packed struct { + pub const IpType = enum(u8) { + Dhcp = 0, + Static = 1, + }; + + type: DevicePathType, + subtype: Subtype, + length: u16, + local_ip_address: uefi.Ipv4Address, + remote_ip_address: uefi.Ipv4Address, + local_port: u16, + remote_port: u16, + network_protocol: u16, + static_ip_address: IpType, + gateway_ip_address: u32, + subnet_mask: u32, + }; + + pub const Ipv6DevicePath = packed struct { + pub const Origin = enum(u8) { + Manual = 0, + AssignedStateless = 1, + AssignedStateful = 2, + }; + + type: DevicePathType, + subtype: Subtype, + length: u16, + local_ip_address: uefi.Ipv6Address, + remote_ip_address: uefi.Ipv6Address, + local_port: u16, + remote_port: u16, + protocol: u16, + ip_address_origin: Origin, + prefix_length: u8, + gateway_ip_address: uefi.Ipv6Address, + }; + + pub const VlanDevicePath = packed struct { + type: DevicePathType, + subtype: Subtype, + length: u16, + vlan_id: u16, + }; + + pub const InfiniBandDevicePath = packed struct { + pub const ResourceFlags = packed struct { + pub const ControllerType = enum(u1) { + Ioc = 0, + Service = 1, + }; + + ioc_or_service: ControllerType, + extend_boot_environment: bool, + console_protocol: bool, + storage_protocol: bool, + network_protocol: bool, + + // u1 + 4 * bool = 5 bits, we need a total of 32 bits + reserved: u27, + }; + + type: DevicePathType, + subtype: Subtype, + length: u16, + resource_flags: ResourceFlags, + port_gid: [16]u8, + service_id: u64, + target_port_id: u64, + device_id: u64, + }; + + pub const UartDevicePath = packed struct { + pub const Parity = enum(u8) { + Default = 0, + None = 1, + Even = 2, + Odd = 3, + Mark = 4, + Space = 5, + _, + }; + + pub const StopBits = enum(u8) { + Default = 0, + One = 1, + OneAndAHalf = 2, + Two = 3, + _, + }; + + type: DevicePathType, + subtype: Subtype, + length: u16, + reserved: u16, + baud_rate: u32, + data_bits: u8, + parity: Parity, + stop_bits: StopBits, + }; + + pub const VendorDefinedDevicePath = packed struct { + type: DevicePathType, + subtype: Subtype, + length: u16, + vendor_guid: Guid, + }; }; pub const MediaDevicePath = union(Subtype) { @@ -295,24 +531,44 @@ pub const MediaDevicePath = union(Subtype) { }; pub const HardDriveDevicePath = packed struct { + pub const Format = enum(u8) { + LegacyMbr = 0x01, + GuidPartitionTable = 0x02, + }; + + pub const SignatureType = enum(u8) { + NoSignature = 0x00, + /// "32-bit signature from address 0x1b8 of the type 0x01 MBR" + MbrSignature = 0x01, + GuidSignature = 0x02, + }; + type: DevicePathType, subtype: Subtype, length: u16, - // TODO + partition_number: u32, + partition_start: u64, + partition_size: u64, + partition_signature: [16]u8, + partition_format: Format, + signature_type: SignatureType, }; pub const CdromDevicePath = packed struct { type: DevicePathType, subtype: Subtype, length: u16, - // TODO + boot_entry: u32, + partition_start: u64, + partition_size: u64, }; pub const VendorDevicePath = packed struct { type: DevicePathType, subtype: Subtype, length: u16, - // TODO + guid: Guid, + // vendor-defined variable data }; pub const FilePathDevicePath = packed struct { @@ -329,19 +585,21 @@ pub const MediaDevicePath = union(Subtype) { type: DevicePathType, subtype: Subtype, length: u16, - // TODO + guid: Guid, }; pub const PiwgFirmwareFileDevicePath = packed struct { type: DevicePathType, subtype: Subtype, length: u16, + fv_filename: Guid, }; pub const PiwgFirmwareVolumeDevicePath = packed struct { type: DevicePathType, subtype: Subtype, length: u16, + fv_name: Guid, }; pub const RelativeOffsetRangeDevicePath = packed struct { @@ -359,7 +617,7 @@ pub const MediaDevicePath = union(Subtype) { length: u16, start: u64, end: u64, - disk_type: uefi.Guid, + disk_type: Guid, instance: u16, }; }; diff --git a/lib/std/os/uefi/protocols/edid_override_protocol.zig b/lib/std/os/uefi/protocols/edid_override_protocol.zig @@ -8,9 +8,8 @@ pub const EdidOverrideProtocol = extern struct { _get_edid: fn (*const EdidOverrideProtocol, Handle, *u32, *usize, *?[*]u8) callconv(.C) Status, /// Returns policy information and potentially a replacement EDID for the specified video output device. - /// attributes must be align(4) pub fn getEdid(self: *const EdidOverrideProtocol, handle: Handle, attributes: *EdidOverrideProtocolAttributes, edid_size: *usize, edid: *?[*]u8) Status { - return self._get_edid(self, handle, attributes, edid_size, edid); + return self._get_edid(self, handle, @ptrCast(*u32, attributes), edid_size, edid); } pub const guid align(8) = Guid{ @@ -24,9 +23,7 @@ pub const EdidOverrideProtocol = extern struct { }; pub const EdidOverrideProtocolAttributes = packed struct { - dont_override: bool, + dont_override: bool align(4), enable_hot_plug: bool, - _pad1: u6, - _pad2: u8, - _pad3: u16, + _pad: u30 = 0, }; diff --git a/lib/std/os/uefi/protocols/hii.zig b/lib/std/os/uefi/protocols/hii.zig @@ -48,7 +48,7 @@ pub const NarrowGlyph = extern struct { attributes: packed struct { non_spacing: bool, wide: bool, - _pad: u6, + _pad: u6 = 0, }, glyph_col_1: [19]u8, }; @@ -62,7 +62,7 @@ pub const WideGlyph = extern struct { }, glyph_col_1: [19]u8, glyph_col_2: [19]u8, - _pad: [3]u8, + _pad: [3]u8 = [_]u8{0} ** 3, }; pub const HIIStringPackage = extern struct { diff --git a/lib/std/os/uefi/protocols/simple_network_protocol.zig b/lib/std/os/uefi/protocols/simple_network_protocol.zig @@ -126,9 +126,7 @@ pub const SimpleNetworkReceiveFilter = packed struct { receive_broadcast: bool, receive_promiscuous: bool, receive_promiscuous_multicast: bool, - _pad1: u3 = undefined, - _pad2: u8 = undefined, - _pad3: u16 = undefined, + _pad: u27 = 0, }; pub const SimpleNetworkState = enum(u32) { @@ -171,7 +169,5 @@ pub const SimpleNetworkInterruptStatus = packed struct { transmit_interrupt: bool, command_interrupt: bool, software_interrupt: bool, - _pad1: u4, - _pad2: u8, - _pad3: u16, + _pad: u28 = 0, }; diff --git a/lib/std/os/uefi/protocols/simple_text_input_ex_protocol.zig b/lib/std/os/uefi/protocols/simple_text_input_ex_protocol.zig @@ -64,14 +64,14 @@ pub const KeyState = extern struct { left_logo_pressed: bool, menu_key_pressed: bool, sys_req_pressed: bool, - _pad1: u21, + _pad: u21 = 0, shift_state_valid: bool, }, key_toggle_state: packed struct { scroll_lock_active: bool, num_lock_active: bool, caps_lock_active: bool, - _pad1: u3, + _pad: u3 = 0, key_state_exposed: bool, toggle_state_valid: bool, }, diff --git a/lib/std/os/uefi/status.zig b/lib/std/os/uefi/status.zig @@ -1,3 +1,5 @@ +const testing = @import("std").testing; + const high_bit = 1 << @typeInfo(usize).Int.bits - 1; pub const Status = enum(usize) { @@ -139,4 +141,64 @@ pub const Status = enum(usize) { WarnResetRequired = 7, _, + + pub const EfiError = error{ + LoadError, + InvalidParameter, + Unsupported, + BadBufferSize, + BufferTooSmall, + NotReady, + DeviceError, + WriteProtected, + OutOfResources, + VolumeCorrupted, + VolumeFull, + NoMedia, + MediaChanged, + NotFound, + AccessDenied, + NoResponse, + NoMapping, + Timeout, + NotStarted, + AlreadyStarted, + Aborted, + IcmpError, + TftpError, + ProtocolError, + IncompatibleVersion, + SecurityViolation, + CrcError, + EndOfMedia, + EndOfFile, + InvalidLanguage, + CompromisedData, + IpAddressConflict, + HttpError, + NetworkUnreachable, + HostUnreachable, + ProtocolUnreachable, + PortUnreachable, + ConnectionFin, + ConnectionReset, + ConnectionRefused, + }; + + pub fn err(self: Status) EfiError!void { + inline for (@typeInfo(EfiError).ErrorSet.?) |efi_err| { + if (self == @field(Status, efi_err.name)) { + return @field(EfiError, efi_err.name); + } + } + // self is .Success or Warning + } }; + +test "status" { + var st: Status = .DeviceError; + try testing.expectError(error.DeviceError, st.err()); + + st = .Success; + try st.err(); +} diff --git a/lib/std/os/uefi/tables.zig b/lib/std/os/uefi/tables.zig @@ -1,14 +1,5 @@ -pub const AllocateType = @import("tables/boot_services.zig").AllocateType; -pub const BootServices = @import("tables/boot_services.zig").BootServices; -pub const ConfigurationTable = @import("tables/configuration_table.zig").ConfigurationTable; -pub const global_variable align(8) = @import("tables/runtime_services.zig").global_variable; -pub const LocateSearchType = @import("tables/boot_services.zig").LocateSearchType; -pub const MemoryDescriptor = @import("tables/boot_services.zig").MemoryDescriptor; -pub const MemoryType = @import("tables/boot_services.zig").MemoryType; -pub const OpenProtocolAttributes = @import("tables/boot_services.zig").OpenProtocolAttributes; -pub const ProtocolInformationEntry = @import("tables/boot_services.zig").ProtocolInformationEntry; -pub const ResetType = @import("tables/runtime_services.zig").ResetType; -pub const RuntimeServices = @import("tables/runtime_services.zig").RuntimeServices; -pub const SystemTable = @import("tables/system_table.zig").SystemTable; -pub const TableHeader = @import("tables/table_header.zig").TableHeader; -pub const TimerDelay = @import("tables/boot_services.zig").TimerDelay; +pub usingnamespace @import("tables/boot_services.zig"); +pub usingnamespace @import("tables/runtime_services.zig"); +pub usingnamespace @import("tables/configuration_table.zig"); +pub usingnamespace @import("tables/system_table.zig"); +pub usingnamespace @import("tables/table_header.zig"); diff --git a/lib/std/os/uefi/tables/boot_services.zig b/lib/std/os/uefi/tables/boot_services.zig @@ -21,120 +21,159 @@ pub const BootServices = extern struct { hdr: TableHeader, /// Raises a task's priority level and returns its previous level. - raiseTpl: fn (usize) callconv(.C) usize, + raiseTpl: fn (new_tpl: usize) callconv(.C) usize, /// Restores a task's priority level to its previous value. - restoreTpl: fn (usize) callconv(.C) void, + restoreTpl: fn (old_tpl: usize) callconv(.C) void, /// Allocates memory pages from the system. - allocatePages: fn (AllocateType, MemoryType, usize, *[*]align(4096) u8) callconv(.C) Status, + allocatePages: fn (alloc_type: AllocateType, mem_type: MemoryType, pages: usize, memory: *[*]align(4096) u8) callconv(.C) Status, /// Frees memory pages. - freePages: fn ([*]align(4096) u8, usize) callconv(.C) Status, + freePages: fn (memory: [*]align(4096) u8, pages: usize) callconv(.C) Status, /// Returns the current memory map. - getMemoryMap: fn (*usize, [*]MemoryDescriptor, *usize, *usize, *u32) callconv(.C) Status, + getMemoryMap: fn (mmap_size: *usize, mmap: [*]MemoryDescriptor, mapKey: *usize, descriptor_size: *usize, descriptor_version: *u32) callconv(.C) Status, /// Allocates pool memory. - allocatePool: fn (MemoryType, usize, *[*]align(8) u8) callconv(.C) Status, + allocatePool: fn (pool_type: MemoryType, size: usize, buffer: *[*]align(8) u8) callconv(.C) Status, /// Returns pool memory to the system. - freePool: fn ([*]align(8) u8) callconv(.C) Status, + freePool: fn (buffer: [*]align(8) u8) callconv(.C) Status, /// Creates an event. - createEvent: fn (u32, usize, ?fn (Event, ?*anyopaque) callconv(.C) void, ?*const anyopaque, *Event) callconv(.C) Status, + createEvent: fn (type: u32, notify_tpl: usize, notify_func: ?fn (Event, ?*anyopaque) callconv(.C) void, notifyCtx: ?*const anyopaque, event: *Event) callconv(.C) Status, /// Sets the type of timer and the trigger time for a timer event. - setTimer: fn (Event, TimerDelay, u64) callconv(.C) Status, + setTimer: fn (event: Event, type: TimerDelay, triggerTime: u64) callconv(.C) Status, /// Stops execution until an event is signaled. - waitForEvent: fn (usize, [*]const Event, *usize) callconv(.C) Status, + waitForEvent: fn (event_len: usize, events: [*]const Event, index: *usize) callconv(.C) Status, /// Signals an event. - signalEvent: fn (Event) callconv(.C) Status, + signalEvent: fn (event: Event) callconv(.C) Status, /// Closes an event. - closeEvent: fn (Event) callconv(.C) Status, + closeEvent: fn (event: Event) callconv(.C) Status, /// Checks whether an event is in the signaled state. - checkEvent: fn (Event) callconv(.C) Status, + checkEvent: fn (event: Event) callconv(.C) Status, - installProtocolInterface: Status, // TODO - reinstallProtocolInterface: Status, // TODO - uninstallProtocolInterface: Status, // TODO + /// 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: fn (handle: Handle, protocol: *align(8) const Guid, interface_type: EfiInterfaceType, interface: *anyopaque) callconv(.C) Status, + + /// Reinstalls a protocol interface on a device handle + reinstallProtocolInterface: fn (handle: Handle, protocol: *align(8) const Guid, old_interface: *anyopaque, new_interface: *anyopaque) callconv(.C) Status, + + /// Removes a protocol interface from a device handle. Usage of + /// uninstallMultipleProtocolInterfaces is recommended over this. + uninstallProtocolInterface: fn (handle: Handle, protocol: *align(8) const Guid, interface: *anyopaque) callconv(.C) Status, /// Queries a handle to determine if it supports a specified protocol. - handleProtocol: fn (Handle, *align(8) const Guid, *?*anyopaque) callconv(.C) Status, + handleProtocol: fn (handle: Handle, protocol: *align(8) const Guid, interface: *?*anyopaque) callconv(.C) Status, reserved: *anyopaque, - registerProtocolNotify: Status, // TODO + /// Creates an event that is to be signaled whenever an interface is installed for a specified protocol. + registerProtocolNotify: fn (protocol: *align(8) const Guid, event: Event, registration: **anyopaque) callconv(.C) Status, /// Returns an array of handles that support a specified protocol. - locateHandle: fn (LocateSearchType, ?*align(8) const Guid, ?*const anyopaque, *usize, [*]Handle) callconv(.C) Status, + locateHandle: fn (search_type: LocateSearchType, protocol: ?*align(8) const Guid, search_key: ?*const anyopaque, bufferSize: *usize, buffer: [*]Handle) callconv(.C) Status, /// Locates the handle to a device on the device path that supports the specified protocol - locateDevicePath: fn (*align(8) const Guid, **const DevicePathProtocol, *?Handle) callconv(.C) Status, - installConfigurationTable: Status, // TODO + locateDevicePath: fn (protocols: *align(8) const Guid, device_path: **const DevicePathProtocol, device: *?Handle) callconv(.C) Status, + + /// Adds, updates, or removes a configuration table entry from the EFI System Table. + installConfigurationTable: fn (guid: *align(8) const Guid, table: ?*anyopaque) callconv(.C) Status, /// Loads an EFI image into memory. - loadImage: fn (bool, Handle, ?*const DevicePathProtocol, ?[*]const u8, usize, *?Handle) callconv(.C) Status, + loadImage: fn (boot_policy: bool, parent_image_handle: Handle, device_path: ?*const DevicePathProtocol, source_buffer: ?[*]const u8, source_size: usize, imageHandle: *?Handle) callconv(.C) Status, /// Transfers control to a loaded image's entry point. - startImage: fn (Handle, ?*usize, ?*[*]u16) callconv(.C) Status, + startImage: fn (image_handle: Handle, exit_data_size: ?*usize, exit_data: ?*[*]u16) callconv(.C) Status, /// Terminates a loaded EFI image and returns control to boot services. - exit: fn (Handle, Status, usize, ?*const anyopaque) callconv(.C) Status, + exit: fn (image_handle: Handle, exit_status: Status, exit_data_size: usize, exit_data: ?*const anyopaque) callconv(.C) Status, /// Unloads an image. - unloadImage: fn (Handle) callconv(.C) Status, + unloadImage: fn (image_handle: Handle) callconv(.C) Status, /// Terminates all boot services. - exitBootServices: fn (Handle, usize) callconv(.C) Status, + exitBootServices: fn (image_handle: Handle, map_key: usize) callconv(.C) Status, /// Returns a monotonically increasing count for the platform. - getNextMonotonicCount: fn (*u64) callconv(.C) Status, + getNextMonotonicCount: fn (count: *u64) callconv(.C) Status, /// Induces a fine-grained stall. - stall: fn (usize) callconv(.C) Status, + stall: fn (microseconds: usize) callconv(.C) Status, /// Sets the system's watchdog timer. - setWatchdogTimer: fn (usize, u64, usize, ?[*]const u16) callconv(.C) Status, + setWatchdogTimer: fn (timeout: usize, watchdogCode: u64, data_size: usize, watchdog_data: ?[*]const u16) callconv(.C) Status, - connectController: Status, // TODO - disconnectController: Status, // TODO + /// Connects one or more drives to a controller. + connectController: fn (controller_handle: Handle, driver_image_handle: ?Handle, remaining_device_path: ?*DevicePathProtocol, recursive: bool) callconv(.C) Status, + + // Disconnects one or more drivers from a controller + disconnectController: fn (controller_handle: Handle, driver_image_handle: ?Handle, child_handle: ?Handle) callconv(.C) Status, /// Queries a handle to determine if it supports a specified protocol. - openProtocol: fn (Handle, *align(8) const Guid, *?*anyopaque, ?Handle, ?Handle, OpenProtocolAttributes) callconv(.C) Status, + openProtocol: fn (handle: Handle, protocol: *align(8) const Guid, interface: *?*anyopaque, agent_handle: ?Handle, controller_handle: ?Handle, attributes: OpenProtocolAttributes) callconv(.C) Status, /// Closes a protocol on a handle that was opened using openProtocol(). - closeProtocol: fn (Handle, *align(8) const Guid, Handle, ?Handle) callconv(.C) Status, + closeProtocol: fn (handle: Handle, protocol: *align(8) const Guid, agentHandle: Handle, controller_handle: ?Handle) callconv(.C) Status, /// Retrieves the list of agents that currently have a protocol interface opened. - openProtocolInformation: fn (Handle, *align(8) const Guid, *[*]ProtocolInformationEntry, *usize) callconv(.C) Status, + openProtocolInformation: fn (handle: Handle, protocol: *align(8) const Guid, entry_buffer: *[*]ProtocolInformationEntry, entry_count: *usize) callconv(.C) Status, /// Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated from pool. - protocolsPerHandle: fn (Handle, *[*]*align(8) const Guid, *usize) callconv(.C) Status, + protocolsPerHandle: fn (handle: Handle, protocol_buffer: *[*]*align(8) const Guid, protocol_buffer_count: *usize) callconv(.C) Status, /// Returns an array of handles that support the requested protocol in a buffer allocated from pool. - locateHandleBuffer: fn (LocateSearchType, ?*align(8) const Guid, ?*const anyopaque, *usize, *[*]Handle) callconv(.C) Status, + locateHandleBuffer: fn (search_type: LocateSearchType, protocol: ?*align(8) const Guid, search_key: ?*const anyopaque, num_handles: *usize, buffer: *[*]Handle) callconv(.C) Status, /// Returns the first protocol instance that matches the given protocol. - locateProtocol: fn (*align(8) const Guid, ?*const anyopaque, *?*anyopaque) callconv(.C) Status, + locateProtocol: fn (protocol: *align(8) const Guid, registration: ?*const anyopaque, interface: *?*anyopaque) callconv(.C) Status, + + /// Installs one or more protocol interfaces into the boot services environment + installMultipleProtocolInterfaces: fn (handle: *Handle, ...) callconv(.C) Status, - installMultipleProtocolInterfaces: Status, // TODO - uninstallMultipleProtocolInterfaces: Status, // TODO + /// Removes one or more protocol interfaces into the boot services environment + uninstallMultipleProtocolInterfaces: fn (handle: *Handle, ...) callconv(.C) Status, /// Computes and returns a 32-bit CRC for a data buffer. - calculateCrc32: fn ([*]const u8, usize, *u32) callconv(.C) Status, + calculateCrc32: fn (data: [*]const u8, data_size: usize, *u32) callconv(.C) Status, /// Copies the contents of one buffer to another buffer - copyMem: fn ([*]u8, [*]const u8, usize) callconv(.C) void, + copyMem: fn (dest: [*]u8, src: [*]const u8, len: usize) callconv(.C) void, /// Fills a buffer with a specified value - setMem: fn ([*]u8, usize, u8) callconv(.C) void, + setMem: fn (buffer: [*]u8, size: usize, value: u8) callconv(.C) void, + + /// Creates an event in a group. + createEventEx: fn (type: u32, notify_tpl: usize, notify_func: EfiEventNotify, notify_ctx: *const anyopaque, event_group: *align(8) const Guid, event: *Event) callconv(.C) Status, - createEventEx: Status, // TODO + /// 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!"); + + var ptr: ?*protocol = undefined; + + try self.openProtocol( + handle, + &protocol.guid, + @ptrCast(*?*anyopaque, &ptr), + // Invoking handle (loaded image) + uefi.handle, + // Control handle (null as not a driver) + null, + uefi.tables.OpenProtocolAttributes{ .by_handle_protocol = true }, + ).err(); + + return ptr.?; + } pub const signature: u64 = 0x56524553544f4f42; @@ -151,6 +190,8 @@ pub const BootServices = extern struct { pub const tpl_high_level: usize = 31; }; +pub const EfiEventNotify = fn (event: Event, ctx: *anyopaque) callconv(.C) void; + pub const TimerDelay = enum(u32) { TimerCancel, TimerPeriodic, @@ -219,9 +260,7 @@ pub const OpenProtocolAttributes = packed struct { by_child_controller: bool = false, by_driver: bool = false, exclusive: bool = false, - _pad1: u2 = undefined, - _pad2: u8 = undefined, - _pad3: u16 = undefined, + _pad: u26 = 0, }; pub const ProtocolInformationEntry = extern struct { @@ -231,6 +270,10 @@ pub const ProtocolInformationEntry = extern struct { open_count: u32, }; +pub const EfiInterfaceType = enum(u32) { + EfiNativeInterface, +}; + pub const AllocateType = enum(u32) { AllocateAnyPages, AllocateMaxAddress, diff --git a/lib/std/os/uefi/tables/runtime_services.zig b/lib/std/os/uefi/tables/runtime_services.zig @@ -18,39 +18,71 @@ pub const RuntimeServices = extern struct { hdr: TableHeader, /// Returns the current time and date information, and the time-keeping capabilities of the hardware platform. - getTime: fn (*uefi.Time, ?*TimeCapabilities) callconv(.C) Status, + getTime: fn (time: *uefi.Time, capabilities: ?*TimeCapabilities) callconv(.C) Status, - setTime: Status, // TODO - getWakeupTime: Status, // TODO - setWakeupTime: Status, // TODO + /// Sets the current local time and date information + setTime: fn (time: *uefi.Time) callconv(.C) Status, + + /// Returns the current wakeup alarm clock setting + getWakeupTime: fn (enabled: *bool, pending: *bool, time: *uefi.Time) callconv(.C) Status, + + /// Sets the system wakeup alarm clock time + setWakeupTime: fn (enable: *bool, time: ?*uefi.Time) callconv(.C) Status, /// Changes the runtime addressing mode of EFI firmware from physical to virtual. - setVirtualAddressMap: fn (usize, usize, u32, [*]MemoryDescriptor) callconv(.C) Status, + setVirtualAddressMap: fn (mmap_size: usize, descriptor_size: usize, descriptor_version: u32, virtual_map: [*]MemoryDescriptor) callconv(.C) Status, /// Determines the new virtual address that is to be used on subsequent memory accesses. - convertPointer: fn (usize, **anyopaque) callconv(.C) Status, + convertPointer: fn (debug_disposition: usize, address: **anyopaque) callconv(.C) Status, /// Returns the value of a variable. - getVariable: fn ([*:0]const u16, *align(8) const Guid, ?*u32, *usize, ?*anyopaque) callconv(.C) Status, + getVariable: fn (var_name: [*:0]const u16, vendor_guid: *align(8) const Guid, attributes: ?*u32, data_size: *usize, data: ?*anyopaque) callconv(.C) Status, /// Enumerates the current variable names. - getNextVariableName: fn (*usize, [*:0]u16, *align(8) Guid) callconv(.C) Status, + getNextVariableName: fn (var_name_size: *usize, var_name: [*:0]u16, vendor_guid: *align(8) Guid) callconv(.C) Status, /// Sets the value of a variable. - setVariable: fn ([*:0]const u16, *align(8) const Guid, u32, usize, *anyopaque) callconv(.C) Status, + setVariable: fn (var_name: [*:0]const u16, vendor_guid: *align(8) const Guid, attributes: u32, data_size: usize, data: *anyopaque) callconv(.C) Status, - getNextHighMonotonicCount: Status, // TODO + /// Return the next high 32 bits of the platform's monotonic counter + getNextHighMonotonicCount: fn (high_count: *u32) callconv(.C) Status, /// Resets the entire platform. - resetSystem: fn (ResetType, Status, usize, ?*const anyopaque) callconv(.C) noreturn, + resetSystem: fn (reset_type: ResetType, reset_status: Status, data_size: usize, reset_data: ?*const anyopaque) callconv(.C) 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: fn (capsule_header_array: **CapsuleHeader, capsule_count: usize, scatter_gather_list: EfiPhysicalAddress) callconv(.C) Status, - updateCapsule: Status, // TODO - queryCapsuleCapabilities: Status, // TODO - queryVariableInfo: Status, // TODO + /// Returns if the capsule can be supported via `updateCapsule` + queryCapsuleCapabilities: fn (capsule_header_array: **CapsuleHeader, capsule_count: usize, maximum_capsule_size: *usize, resetType: ResetType) callconv(.C) Status, + + /// Returns information about the EFI variables + queryVariableInfo: fn (attributes: *u32, maximum_variable_storage_size: *u64, remaining_variable_storage_size: *u64, maximum_variable_size: *u64) callconv(.C) Status, pub const signature: u64 = 0x56524553544e5552; }; +const EfiPhysicalAddress = u64; + +pub const CapsuleHeader = extern struct { + capsuleGuid: Guid align(8), + headerSize: u32, + flags: u32, + capsuleImageSize: u32, +}; + +pub const UefiCapsuleBlockDescriptor = extern struct { + length: u64, + address: union { + dataBlock: EfiPhysicalAddress, + continuationPointer: EfiPhysicalAddress, + }, +}; + pub const ResetType = enum(u32) { ResetCold, ResetWarm,