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 return writer.print("{x:0>8}-{x:0>4}-{x:0>4}-{x:0>2}{x:0>2}-{x}", .{
111 self.time_low,
112 self.time_mid,
113 self.time_high_and_version,
114 self.clock_seq_high_and_reserved,
115 self.clock_seq_low,
116 self.node,
117 });
118 }
119
120 pub fn eql(a: Guid, b: Guid) bool {
121 return a.time_low == b.time_low and
122 a.time_mid == b.time_mid and
123 a.time_high_and_version == b.time_high_and_version and
124 a.clock_seq_high_and_reserved == b.clock_seq_high_and_reserved and
125 a.clock_seq_low == b.clock_seq_low and
126 std.mem.eql(u8, &a.node, &b.node);
127 }
128};
129
130/// An EFI Handle represents a collection of related interfaces.
131pub const Handle = *opaque {};
132
133/// This structure represents time information.
134pub const Time = extern struct {
135 /// 1900 - 9999
136 year: u16,
137
138 /// 1 - 12
139 month: u8,
140
141 /// 1 - 31
142 day: u8,
143
144 /// 0 - 23
145 hour: u8,
146
147 /// 0 - 59
148 minute: u8,
149
150 /// 0 - 59
151 second: u8,
152
153 _pad1: u8,
154
155 /// 0 - 999999999
156 nanosecond: u32,
157
158 /// The time's offset in minutes from UTC.
159 /// Allowed values are -1440 to 1440 or unspecified_timezone
160 timezone: i16,
161 daylight: packed struct(u8) {
162 /// If true, the time has been adjusted for daylight savings time.
163 in_daylight: bool,
164
165 /// If true, the time is affected by daylight savings time.
166 adjust_daylight: bool,
167
168 _: u6,
169 },
170
171 _pad2: u8,
172
173 comptime {
174 std.debug.assert(@sizeOf(Time) == 16);
175 }
176
177 /// Time is to be interpreted as local time
178 pub const unspecified_timezone: i16 = 0x7ff;
179
180 fn daysInYear(year: u16, max_month: u4) u9 {
181 var days: u9 = 0;
182 var month: u4 = 0;
183 while (month < max_month) : (month += 1) {
184 days += std.time.epoch.getDaysInMonth(year, @fromBackingInt(@intCast(month + 1)));
185 }
186 return days;
187 }
188
189 pub fn toEpoch(self: std.os.uefi.Time) u64 {
190 var year: u16 = 0;
191 var days: u32 = 0;
192
193 while (year < (self.year - 1971)) : (year += 1) {
194 days += daysInYear(year + 1970, 12);
195 }
196
197 days += daysInYear(self.year, @as(u4, @intCast(self.month)) - 1) + self.day;
198 const hours: u64 = self.hour + (days * 24);
199 const minutes: u64 = self.minute + (hours * 60);
200 const seconds: u64 = self.second + (minutes * std.time.s_per_min);
201 return self.nanosecond + (seconds * std.time.ns_per_s);
202 }
203};
204
205/// Capabilities of the clock device
206pub const TimeCapabilities = extern struct {
207 /// Resolution in Hz
208 resolution: u32,
209
210 /// Accuracy in an error rate of 1e-6 parts per million.
211 accuracy: u32,
212
213 /// If true, a time set operation clears the device's time below the resolution level.
214 sets_to_zero: bool,
215};
216
217/// File Handle as specified in the EFI Shell Spec
218pub const FileHandle = *opaque {};
219
220test "GUID formatting" {
221 const bytes: [16]u8 = .{ 137, 60, 203, 50, 128, 128, 124, 66, 186, 19, 80, 73, 135, 59, 194, 135 };
222 const guid: Guid = @bitCast(bytes);
223
224 const str = try std.fmt.allocPrint(std.testing.allocator, "{f}", .{guid});
225 defer std.testing.allocator.free(str);
226
227 try std.testing.expectEqualStrings(str, "32cb3c89-8080-427c-ba13-5049873bc287");
228}
229
230test {
231 _ = tables;
232 _ = protocol;
233}
234
235pub const UnexpectedError = error{Unexpected};
236
237pub fn unexpectedStatus(status: Status) UnexpectedError {
238 // TODO: debug printing the encountered error? maybe handle warnings?
239 _ = status;
240 return error.Unexpected;
241}