master
  1const std = @import("../std.zig");
  2const assert = std.debug.assert;
  3
  4/// A protocol is an interface identified by a GUID.
  5pub const protocol = @import("uefi/protocol.zig");
  6pub const DevicePath = @import("uefi/device_path.zig").DevicePath;
  7pub const hii = @import("uefi/hii.zig");
  8
  9/// Status codes returned by EFI interfaces
 10pub const Status = @import("uefi/status.zig").Status;
 11pub const Error = UnexpectedError || Status.Error;
 12pub const tables = @import("uefi/tables.zig");
 13
 14/// The memory type to allocate when using the pool.
 15/// Defaults to `.loader_data`, the default data allocation type
 16/// used by UEFI applications to allocate pool memory.
 17pub var efi_pool_memory_type: tables.MemoryType = .loader_data;
 18pub const pool_allocator = @import("uefi/pool_allocator.zig").pool_allocator;
 19pub const raw_pool_allocator = @import("uefi/pool_allocator.zig").raw_pool_allocator;
 20
 21/// The EFI image's handle that is passed to its entry point.
 22pub var handle: Handle = undefined;
 23
 24/// A pointer to the EFI System Table that is passed to the EFI image's entry point.
 25pub var system_table: *tables.SystemTable = undefined;
 26
 27/// UEFI's memory interfaces exclusively act on 4096-byte pages.
 28pub const Page = [4096]u8;
 29
 30/// A handle to an event structure.
 31pub const Event = *opaque {};
 32
 33pub const EventRegistration = *const opaque {};
 34
 35pub const EventType = packed struct(u32) {
 36    lo_context: u8 = 0,
 37    /// If an event of this type is not already in the signaled state, then
 38    /// the event’s NotificationFunction will be queued at the event’s NotifyTpl
 39    /// whenever the event is being waited on via EFI_BOOT_SERVICES.WaitForEvent()
 40    /// or EFI_BOOT_SERVICES.CheckEvent() .
 41    wait: bool = false,
 42    /// The event’s NotifyFunction is queued whenever the event is signaled.
 43    signal: bool = false,
 44    hi_context: u20 = 0,
 45    /// The event is allocated from runtime memory. If an event is to be signaled
 46    /// after the call to EFI_BOOT_SERVICES.ExitBootServices() the event’s data
 47    /// structure and notification function need to be allocated from runtime
 48    /// memory.
 49    runtime: bool = false,
 50    timer: bool = false,
 51
 52    /// This event should not be combined with any other event types. This event
 53    /// type is functionally equivalent to the EFI_EVENT_GROUP_EXIT_BOOT_SERVICES
 54    /// event group.
 55    pub const signal_exit_boot_services: EventType = .{
 56        .signal = true,
 57        .lo_context = 1,
 58    };
 59
 60    /// The event is to be notified by the system when SetVirtualAddressMap()
 61    /// is performed. This event type is a composite of EVT_NOTIFY_SIGNAL,
 62    /// EVT_RUNTIME, and EVT_RUNTIME_CONTEXT and should not be combined with
 63    /// any other event types.
 64    pub const signal_virtual_address_change: EventType = .{
 65        .runtime = true,
 66        .hi_context = 0x20000,
 67        .signal = true,
 68        .lo_context = 2,
 69    };
 70};
 71
 72/// The calling convention used for all external functions part of the UEFI API.
 73pub const cc: std.builtin.CallingConvention = switch (@import("builtin").target.cpu.arch) {
 74    .x86_64 => .{ .x86_64_win = .{} },
 75    else => .c,
 76};
 77
 78pub const MacAddress = extern struct {
 79    address: [32]u8,
 80};
 81
 82pub const Ipv4Address = extern struct {
 83    address: [4]u8,
 84};
 85
 86pub const Ipv6Address = extern struct {
 87    address: [16]u8,
 88};
 89
 90pub const IpAddress = extern union {
 91    v4: Ipv4Address,
 92    v6: Ipv6Address,
 93};
 94
 95/// GUIDs are align(8) unless otherwise specified.
 96pub const Guid = extern struct {
 97    comptime {
 98        std.debug.assert(std.mem.Alignment.of(Guid) == .@"8");
 99    }
100
101    time_low: u32 align(8),
102    time_mid: u16,
103    time_high_and_version: u16,
104    clock_seq_high_and_reserved: u8,
105    clock_seq_low: u8,
106    node: [6]u8,
107
108    /// Format GUID into hexadecimal lowercase xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
109    pub fn format(self: Guid, writer: *std.Io.Writer) std.Io.Writer.Error!void {
110        const time_low = @byteSwap(self.time_low);
111        const time_mid = @byteSwap(self.time_mid);
112        const time_high_and_version = @byteSwap(self.time_high_and_version);
113
114        return writer.print("{x:0>8}-{x:0>4}-{x:0>4}-{x:0>2}{x:0>2}-{x:0>12}", .{
115            std.mem.asBytes(&time_low),
116            std.mem.asBytes(&time_mid),
117            std.mem.asBytes(&time_high_and_version),
118            std.mem.asBytes(&self.clock_seq_high_and_reserved),
119            std.mem.asBytes(&self.clock_seq_low),
120            std.mem.asBytes(&self.node),
121        });
122    }
123
124    pub fn eql(a: Guid, b: Guid) bool {
125        return a.time_low == b.time_low and
126            a.time_mid == b.time_mid and
127            a.time_high_and_version == b.time_high_and_version and
128            a.clock_seq_high_and_reserved == b.clock_seq_high_and_reserved and
129            a.clock_seq_low == b.clock_seq_low and
130            std.mem.eql(u8, &a.node, &b.node);
131    }
132};
133
134/// An EFI Handle represents a collection of related interfaces.
135pub const Handle = *opaque {};
136
137/// This structure represents time information.
138pub const Time = extern struct {
139    /// 1900 - 9999
140    year: u16,
141
142    /// 1 - 12
143    month: u8,
144
145    /// 1 - 31
146    day: u8,
147
148    /// 0 - 23
149    hour: u8,
150
151    /// 0 - 59
152    minute: u8,
153
154    /// 0 - 59
155    second: u8,
156
157    _pad1: u8,
158
159    /// 0 - 999999999
160    nanosecond: u32,
161
162    /// The time's offset in minutes from UTC.
163    /// Allowed values are -1440 to 1440 or unspecified_timezone
164    timezone: i16,
165    daylight: packed struct(u8) {
166        /// If true, the time has been adjusted for daylight savings time.
167        in_daylight: bool,
168
169        /// If true, the time is affected by daylight savings time.
170        adjust_daylight: bool,
171
172        _: u6,
173    },
174
175    _pad2: u8,
176
177    comptime {
178        std.debug.assert(@sizeOf(Time) == 16);
179    }
180
181    /// Time is to be interpreted as local time
182    pub const unspecified_timezone: i16 = 0x7ff;
183
184    fn daysInYear(year: u16, max_month: u4) u9 {
185        var days: u9 = 0;
186        var month: u4 = 0;
187        while (month < max_month) : (month += 1) {
188            days += std.time.epoch.getDaysInMonth(year, @enumFromInt(month + 1));
189        }
190        return days;
191    }
192
193    pub fn toEpoch(self: std.os.uefi.Time) u64 {
194        var year: u16 = 0;
195        var days: u32 = 0;
196
197        while (year < (self.year - 1971)) : (year += 1) {
198            days += daysInYear(year + 1970, 12);
199        }
200
201        days += daysInYear(self.year, @as(u4, @intCast(self.month)) - 1) + self.day;
202        const hours: u64 = self.hour + (days * 24);
203        const minutes: u64 = self.minute + (hours * 60);
204        const seconds: u64 = self.second + (minutes * std.time.s_per_min);
205        return self.nanosecond + (seconds * std.time.ns_per_s);
206    }
207};
208
209/// Capabilities of the clock device
210pub const TimeCapabilities = extern struct {
211    /// Resolution in Hz
212    resolution: u32,
213
214    /// Accuracy in an error rate of 1e-6 parts per million.
215    accuracy: u32,
216
217    /// If true, a time set operation clears the device's time below the resolution level.
218    sets_to_zero: bool,
219};
220
221/// File Handle as specified in the EFI Shell Spec
222pub const FileHandle = *opaque {};
223
224test "GUID formatting" {
225    const bytes = [_]u8{ 137, 60, 203, 50, 128, 128, 124, 66, 186, 19, 80, 73, 135, 59, 194, 135 };
226    const guid: Guid = @bitCast(bytes);
227
228    const str = try std.fmt.allocPrint(std.testing.allocator, "{}", .{guid});
229    defer std.testing.allocator.free(str);
230
231    try std.testing.expect(std.mem.eql(u8, str, "32cb3c89-8080-427c-ba13-5049873bc287"));
232}
233
234test {
235    _ = tables;
236    _ = protocol;
237}
238
239pub const UnexpectedError = error{Unexpected};
240
241pub fn unexpectedStatus(status: Status) UnexpectedError {
242    // TODO: debug printing the encountered error? maybe handle warnings?
243    _ = status;
244    return error.Unexpected;
245}