| 1 | const std = @import("std"); |
| 2 | const uefi = std.os.uefi; |
| 3 | const Event = uefi.Event; |
| 4 | const EventRegistration = uefi.EventRegistration; |
| 5 | const Guid = uefi.Guid; |
| 6 | const Handle = uefi.Handle; |
| 7 | const Page = uefi.Page; |
| 8 | const Pages = uefi.Pages; |
| 9 | const Status = uefi.Status; |
| 10 | const TableHeader = uefi.tables.TableHeader; |
| 11 | const DevicePathProtocol = uefi.protocol.DevicePath; |
| 12 | const AllocateLocation = uefi.tables.AllocateLocation; |
| 13 | const AllocateType = uefi.tables.AllocateType; |
| 14 | const MemoryType = uefi.tables.MemoryType; |
| 15 | const MemoryDescriptor = uefi.tables.MemoryDescriptor; |
| 16 | const MemoryMapKey = uefi.tables.MemoryMapKey; |
| 17 | const MemoryMapInfo = uefi.tables.MemoryMapInfo; |
| 18 | const MemoryMapSlice = uefi.tables.MemoryMapSlice; |
| 19 | const TimerDelay = uefi.tables.TimerDelay; |
| 20 | const InterfaceType = uefi.tables.InterfaceType; |
| 21 | const LocateSearch = uefi.tables.LocateSearch; |
| 22 | const LocateSearchType = uefi.tables.LocateSearchType; |
| 23 | const OpenProtocolArgs = uefi.tables.OpenProtocolArgs; |
| 24 | const OpenProtocolAttributes = uefi.tables.OpenProtocolAttributes; |
| 25 | const ProtocolInformationEntry = uefi.tables.ProtocolInformationEntry; |
| 26 | const EventNotify = uefi.tables.EventNotify; |
| 27 | const cc = uefi.cc; |
| 28 | const Error = Status.Error; |
| 29 | |
| 30 | /// Boot services are services provided by the system's firmware until the operating system takes |
| 31 | /// over control over the hardware by calling exitBootServices. |
| 32 | /// |
| 33 | /// Boot Services must not be used after exitBootServices has been called. The only exception is |
| 34 | /// getMemoryMap, which may be used after the first unsuccessful call to exitBootServices. |
| 35 | /// After successfully calling exitBootServices, system_table.console_in_handle, system_table.con_in, |
| 36 | /// system_table.console_out_handle, system_table.con_out, system_table.standard_error_handle, |
| 37 | /// system_table.std_err, and system_table.boot_services should be set to null. After setting these |
| 38 | /// attributes to null, system_table.hdr.crc32 must be recomputed. |
| 39 | /// |
| 40 | /// As the boot_services table may grow with new UEFI versions, it is important to check hdr.header_size. |
| 41 | pub const BootServices = extern struct { |
| 42 | hdr: TableHeader, |
| 43 | |
| 44 | /// Raises a task's priority level and returns its previous level. |
| 45 | raiseTpl: *const fn (new_tpl: TaskPriorityLevel) callconv(cc) TaskPriorityLevel, |
| 46 | |
| 47 | /// Restores a task's priority level to its previous value. |
| 48 | restoreTpl: *const fn (old_tpl: TaskPriorityLevel) callconv(cc) void, |
| 49 | |
| 50 | /// Allocates memory pages from the system. |
| 51 | _allocatePages: *const fn (alloc_type: AllocateType, mem_type: MemoryType, pages: usize, memory: *[*]align(4096) Page) callconv(cc) Status, |
| 52 | |
| 53 | /// Frees memory pages. |
| 54 | _freePages: *const fn (memory: [*]align(4096) Page, pages: usize) callconv(cc) Status, |
| 55 | |
| 56 | /// Returns the current memory map. |
| 57 | _getMemoryMap: *const fn (mmap_size: *usize, mmap: ?[*]align(@alignOf(MemoryDescriptor)) u8, map_key: *MemoryMapKey, descriptor_size: *usize, descriptor_version: *u32) callconv(cc) Status, |
| 58 | |
| 59 | /// Allocates pool memory. |
| 60 | _allocatePool: *const fn (pool_type: MemoryType, size: usize, buffer: *[*]align(8) u8) callconv(cc) Status, |
| 61 | |
| 62 | /// Returns pool memory to the system. |
| 63 | _freePool: *const fn (buffer: [*]align(8) u8) callconv(cc) Status, |
| 64 | |
| 65 | /// Creates an event. |
| 66 | _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, |
| 67 | |
| 68 | /// Sets the type of timer and the trigger time for a timer event. |
| 69 | _setTimer: *const fn (event: Event, type: TimerDelay, trigger_time: u64) callconv(cc) Status, |
| 70 | |
| 71 | /// Stops execution until an event is signaled. |
| 72 | _waitForEvent: *const fn (event_len: usize, events: [*]const Event, index: *usize) callconv(cc) Status, |
| 73 | |
| 74 | /// Signals an event. |
| 75 | _signalEvent: *const fn (event: Event) callconv(cc) Status, |
| 76 | |
| 77 | /// Closes an event. |
| 78 | _closeEvent: *const fn (event: Event) callconv(cc) Status, |
| 79 | |
| 80 | /// Checks whether an event is in the signaled state. |
| 81 | _checkEvent: *const fn (event: Event) callconv(cc) Status, |
| 82 | |
| 83 | /// Installs a protocol interface on a device handle. If the handle does not exist, it is created |
| 84 | /// and added to the list of handles in the system. installMultipleProtocolInterfaces() |
| 85 | /// performs more error checking than installProtocolInterface(), so its use is recommended over this. |
| 86 | _installProtocolInterface: *const fn (handle: Handle, protocol: *const Guid, interface_type: InterfaceType, interface: *anyopaque) callconv(cc) Status, |
| 87 | |
| 88 | /// Reinstalls a protocol interface on a device handle |
| 89 | _reinstallProtocolInterface: *const fn (handle: Handle, protocol: *const Guid, old_interface: *anyopaque, new_interface: *anyopaque) callconv(cc) Status, |
| 90 | |
| 91 | /// Removes a protocol interface from a device handle. Usage of |
| 92 | /// uninstallMultipleProtocolInterfaces is recommended over this. |
| 93 | _uninstallProtocolInterface: *const fn (handle: Handle, protocol: *const Guid, interface: *anyopaque) callconv(cc) Status, |
| 94 | |
| 95 | /// Queries a handle to determine if it supports a specified protocol. |
| 96 | _handleProtocol: *const fn (handle: Handle, protocol: *const Guid, interface: *?*anyopaque) callconv(cc) Status, |
| 97 | |
| 98 | _reserved: *anyopaque, |
| 99 | |
| 100 | /// Creates an event that is to be signaled whenever an interface is installed for a specified protocol. |
| 101 | _registerProtocolNotify: *const fn (protocol: *const Guid, event: Event, registration: *EventRegistration) callconv(cc) Status, |
| 102 | |
| 103 | /// Returns an array of handles that support a specified protocol. |
| 104 | _locateHandle: *const fn (search_type: LocateSearchType, protocol: ?*const Guid, search_key: ?*const anyopaque, buffer_size: *usize, buffer: ?[*]Handle) callconv(cc) Status, |
| 105 | |
| 106 | /// Locates the handle to a device on the device path that supports the specified protocol |
| 107 | _locateDevicePath: *const fn (protocols: *const Guid, device_path: **const DevicePathProtocol, device: *?Handle) callconv(cc) Status, |
| 108 | |
| 109 | /// Adds, updates, or removes a configuration table entry from the EFI System Table. |
| 110 | _installConfigurationTable: *const fn (guid: *const Guid, table: ?*anyopaque) callconv(cc) Status, |
| 111 | |
| 112 | /// Loads an EFI image into memory. |
| 113 | _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, |
| 114 | |
| 115 | /// Transfers control to a loaded image's entry point. |
| 116 | _startImage: *const fn (image_handle: Handle, exit_data_size: ?*usize, exit_data: ?*[*]u16) callconv(cc) Status, |
| 117 | |
| 118 | /// Terminates a loaded EFI image and returns control to boot services. |
| 119 | _exit: *const fn (image_handle: Handle, exit_status: Status, exit_data_size: usize, exit_data: ?[*]align(2) const u8) callconv(cc) Status, |
| 120 | |
| 121 | /// Unloads an image. |
| 122 | _unloadImage: *const fn (image_handle: Handle) callconv(cc) Status, |
| 123 | |
| 124 | /// Terminates all boot services. |
| 125 | _exitBootServices: *const fn (image_handle: Handle, map_key: MemoryMapKey) callconv(cc) Status, |
| 126 | |
| 127 | /// Returns a monotonically increasing count for the platform. |
| 128 | _getNextMonotonicCount: *const fn (count: *u64) callconv(cc) Status, |
| 129 | |
| 130 | /// Induces a fine-grained stall. |
| 131 | _stall: *const fn (microseconds: usize) callconv(cc) Status, |
| 132 | |
| 133 | /// Sets the system's watchdog timer. |
| 134 | _setWatchdogTimer: *const fn (timeout: usize, watchdog_code: u64, data_size: usize, watchdog_data: ?[*]const u16) callconv(cc) Status, |
| 135 | |
| 136 | /// Connects one or more drives to a controller. |
| 137 | _connectController: *const fn (controller_handle: Handle, driver_image_handle: ?[*:null]?Handle, remaining_device_path: ?*const DevicePathProtocol, recursive: bool) callconv(cc) Status, |
| 138 | |
| 139 | // Disconnects one or more drivers from a controller |
| 140 | _disconnectController: *const fn (controller_handle: Handle, driver_image_handle: ?Handle, child_handle: ?Handle) callconv(cc) Status, |
| 141 | |
| 142 | /// Queries a handle to determine if it supports a specified protocol. |
| 143 | _openProtocol: *const fn (handle: Handle, protocol: *const Guid, interface: ?*?*anyopaque, agent_handle: ?Handle, controller_handle: ?Handle, attributes: OpenProtocolAttributes) callconv(cc) Status, |
| 144 | |
| 145 | /// Closes a protocol on a handle that was opened using openProtocol(). |
| 146 | _closeProtocol: *const fn (handle: Handle, protocol: *const Guid, agent_handle: Handle, controller_handle: ?Handle) callconv(cc) Status, |
| 147 | |
| 148 | /// Retrieves the list of agents that currently have a protocol interface opened. |
| 149 | _openProtocolInformation: *const fn (handle: Handle, protocol: *const Guid, entry_buffer: *[*]ProtocolInformationEntry, entry_count: *usize) callconv(cc) Status, |
| 150 | |
| 151 | /// Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated from pool. |
| 152 | _protocolsPerHandle: *const fn (handle: Handle, protocol_buffer: *[*]*const Guid, protocol_buffer_count: *usize) callconv(cc) Status, |
| 153 | |
| 154 | /// Returns an array of handles that support the requested protocol in a buffer allocated from pool. |
| 155 | _locateHandleBuffer: *const fn (search_type: LocateSearchType, protocol: ?*const Guid, search_key: ?*const anyopaque, num_handles: *usize, buffer: *[*]Handle) callconv(cc) Status, |
| 156 | |
| 157 | /// Returns the first protocol instance that matches the given protocol. |
| 158 | _locateProtocol: *const fn (protocol: *const Guid, registration: ?EventRegistration, interface: *?*const anyopaque) callconv(cc) Status, |
| 159 | |
| 160 | /// Installs one or more protocol interfaces into the boot services environment |
| 161 | _installMultipleProtocolInterfaces: *const fn (handle: *?Handle, ...) callconv(cc) Status, |
| 162 | |
| 163 | /// Removes one or more protocol interfaces into the boot services environment |
| 164 | _uninstallMultipleProtocolInterfaces: *const fn (handle: Handle, ...) callconv(cc) Status, |
| 165 | |
| 166 | /// Computes and returns a 32-bit CRC for a data buffer. |
| 167 | _calculateCrc32: *const fn (data: [*]const u8, data_size: usize, *u32) callconv(cc) Status, |
| 168 | |
| 169 | /// Copies the contents of one buffer to another buffer |
| 170 | _copyMem: *const fn (dest: [*]u8, src: [*]const u8, len: usize) callconv(cc) void, |
| 171 | |
| 172 | /// Fills a buffer with a specified value |
| 173 | _setMem: *const fn (buffer: [*]u8, size: usize, value: u8) callconv(cc) void, |
| 174 | |
| 175 | /// Creates an event in a group. |
| 176 | _createEventEx: *const fn (type: u32, notify_tpl: usize, notify_func: EventNotify, notify_ctx: *const anyopaque, event_group: *const Guid, event: *Event) callconv(cc) Status, |
| 177 | |
| 178 | pub const AllocatePagesError = uefi.UnexpectedError || error{ |
| 179 | OutOfResources, |
| 180 | InvalidParameter, |
| 181 | NotFound, |
| 182 | }; |
| 183 | |
| 184 | pub const FreePagesError = uefi.UnexpectedError || error{ |
| 185 | NotFound, |
| 186 | InvalidParameter, |
| 187 | }; |
| 188 | |
| 189 | pub const GetMemoryMapError = uefi.UnexpectedError || error{ |
| 190 | InvalidParameter, |
| 191 | BufferTooSmall, |
| 192 | }; |
| 193 | |
| 194 | pub const AllocatePoolError = uefi.UnexpectedError || error{ |
| 195 | OutOfResources, |
| 196 | InvalidParameter, |
| 197 | }; |
| 198 | |
| 199 | pub const FreePoolError = uefi.UnexpectedError || error{ |
| 200 | InvalidParameter, |
| 201 | }; |
| 202 | |
| 203 | pub const CreateEventError = uefi.UnexpectedError || error{ |
| 204 | InvalidParameter, |
| 205 | OutOfResources, |
| 206 | }; |
| 207 | |
| 208 | pub const SetTimerError = uefi.UnexpectedError || error{ |
| 209 | InvalidParameter, |
| 210 | }; |
| 211 | |
| 212 | pub const WaitForEventError = uefi.UnexpectedError || error{ |
| 213 | InvalidParameter, |
| 214 | Unsupported, |
| 215 | }; |
| 216 | |
| 217 | pub const CheckEventError = uefi.UnexpectedError || error{ |
| 218 | InvalidParameter, |
| 219 | }; |
| 220 | |
| 221 | pub const ReinstallProtocolInterfaceError = uefi.UnexpectedError || error{ |
| 222 | NotFound, |
| 223 | AccessDenied, |
| 224 | InvalidParameter, |
| 225 | }; |
| 226 | |
| 227 | pub const HandleProtocolError = uefi.UnexpectedError || error{ |
| 228 | Unsupported, |
| 229 | }; |
| 230 | |
| 231 | pub const RegisterProtocolNotifyError = uefi.UnexpectedError || error{ |
| 232 | OutOfResources, |
| 233 | InvalidParameter, |
| 234 | }; |
| 235 | |
| 236 | pub const NumHandlesError = uefi.UnexpectedError; |
| 237 | |
| 238 | pub const LocateHandleError = uefi.UnexpectedError || error{ |
| 239 | BufferTooSmall, |
| 240 | InvalidParameter, |
| 241 | }; |
| 242 | |
| 243 | pub const LocateDevicePathError = uefi.UnexpectedError || error{ |
| 244 | NotFound, |
| 245 | InvalidParameter, |
| 246 | }; |
| 247 | |
| 248 | pub const InstallConfigurationTableError = uefi.UnexpectedError || error{ |
| 249 | InvalidParameter, |
| 250 | OutOfResources, |
| 251 | }; |
| 252 | |
| 253 | pub const UninstallConfigurationTableError = InstallConfigurationTableError || error{ |
| 254 | NotFound, |
| 255 | }; |
| 256 | |
| 257 | pub const LoadImageError = uefi.UnexpectedError || error{ |
| 258 | NotFound, |
| 259 | InvalidParameter, |
| 260 | Unsupported, |
| 261 | OutOfResources, |
| 262 | LoadError, |
| 263 | DeviceError, |
| 264 | AccessDenied, |
| 265 | SecurityViolation, |
| 266 | }; |
| 267 | |
| 268 | pub const StartImageError = uefi.UnexpectedError || error{ |
| 269 | InvalidParameter, |
| 270 | SecurityViolation, |
| 271 | }; |
| 272 | |
| 273 | pub const ExitError = uefi.UnexpectedError || error{ |
| 274 | InvalidParameter, |
| 275 | }; |
| 276 | |
| 277 | pub const ExitBootServicesError = uefi.UnexpectedError || error{ |
| 278 | InvalidParameter, |
| 279 | }; |
| 280 | |
| 281 | pub const GetNextMonotonicCountError = uefi.UnexpectedError || error{ |
| 282 | DeviceError, |
| 283 | InvalidParameter, |
| 284 | }; |
| 285 | |
| 286 | pub const SetWatchdogTimerError = uefi.UnexpectedError || error{ |
| 287 | InvalidParameter, |
| 288 | Unsupported, |
| 289 | DeviceError, |
| 290 | }; |
| 291 | |
| 292 | pub const ConnectControllerError = uefi.UnexpectedError || error{ |
| 293 | InvalidParameter, |
| 294 | NotFound, |
| 295 | SecurityViolation, |
| 296 | }; |
| 297 | |
| 298 | pub const DisconnectControllerError = uefi.UnexpectedError || error{ |
| 299 | InvalidParameter, |
| 300 | OutOfResources, |
| 301 | DeviceError, |
| 302 | }; |
| 303 | |
| 304 | pub const OpenProtocolError = uefi.UnexpectedError || error{ |
| 305 | InvalidParameter, |
| 306 | Unsupported, |
| 307 | AccessDenied, |
| 308 | AlreadyStarted, |
| 309 | }; |
| 310 | |
| 311 | pub const CloseProtocolError = uefi.UnexpectedError || error{ |
| 312 | InvalidParameter, |
| 313 | NotFound, |
| 314 | }; |
| 315 | |
| 316 | pub const OpenProtocolInformationError = uefi.UnexpectedError || error{ |
| 317 | OutOfResources, |
| 318 | }; |
| 319 | |
| 320 | pub const ProtocolsPerHandleError = uefi.UnexpectedError || error{ |
| 321 | InvalidParameter, |
| 322 | OutOfResources, |
| 323 | }; |
| 324 | |
| 325 | pub const LocateHandleBufferError = uefi.UnexpectedError || error{ |
| 326 | InvalidParameter, |
| 327 | OutOfResources, |
| 328 | }; |
| 329 | |
| 330 | pub const LocateProtocolError = uefi.UnexpectedError || error{ |
| 331 | InvalidParameter, |
| 332 | }; |
| 333 | |
| 334 | pub const InstallProtocolInterfacesError = uefi.UnexpectedError || error{ |
| 335 | AlreadyStarted, |
| 336 | OutOfResources, |
| 337 | InvalidParameter, |
| 338 | }; |
| 339 | |
| 340 | pub const UninstallProtocolInterfacesError = uefi.UnexpectedError || error{ |
| 341 | InvalidParameter, |
| 342 | }; |
| 343 | |
| 344 | pub const CalculateCrc32Error = uefi.UnexpectedError || error{ |
| 345 | InvalidParameter, |
| 346 | }; |
| 347 | |
| 348 | /// Allocates pages of memory. |
| 349 | /// |
| 350 | /// This function scans the memory map to locate free pages. When it finds a |
| 351 | /// physically contiguous block of pages that is large enough and also satisfies |
| 352 | /// the allocation requirements of `alloc_type`, it changes the memory map to |
| 353 | /// indicate that the pages are now of type `mem_type`. |
| 354 | /// |
| 355 | /// In general, UEFI OS loaders and UEFI applications should allocate memory |
| 356 | /// (and pool) of type `.loader_data`. UEFI boot service drivers must allocate |
| 357 | /// memory (and pool) of type `.boot_services_data`. UREFI runtime drivers |
| 358 | /// should allocate memory (and pool) of type `.runtime_services_data` |
| 359 | /// (although such allocation can only be made during boot services time). |
| 360 | /// |
| 361 | /// Allocation requests of `.allocate_any_pages` allocate any available range |
| 362 | /// of pages that satisfies the request. |
| 363 | /// |
| 364 | /// Allocation requests of `.allocate_max_address` allocate any available range |
| 365 | /// of pages whose uppermost address is less than or equal to the address |
| 366 | /// pointed to by the input. |
| 367 | /// |
| 368 | /// Allocation requests of `.allocate_address` allocate pages at the address |
| 369 | /// pointed to by the input. |
| 370 | pub fn allocatePages( |
| 371 | self: *BootServices, |
| 372 | location: AllocateLocation, |
| 373 | mem_type: MemoryType, |
| 374 | pages: usize, |
| 375 | ) AllocatePagesError![]align(4096) Page { |
| 376 | var ptr: [*]align(4096) Page = switch (location) { |
| 377 | .any => undefined, |
| 378 | .address, .max_address => |ptr| ptr, |
| 379 | }; |
| 380 | |
| 381 | switch (self._allocatePages( |
| 382 | std.meta.activeTag(location), |
| 383 | mem_type, |
| 384 | pages, |
| 385 | &ptr, |
| 386 | )) { |
| 387 | .success => return ptr[0..pages], |
| 388 | .out_of_resources => return error.OutOfResources, |
| 389 | .invalid_parameter => return error.InvalidParameter, |
| 390 | .not_found => return error.NotFound, |
| 391 | else => |status| return uefi.unexpectedStatus(status), |
| 392 | } |
| 393 | } |
| 394 | |
| 395 | pub fn freePages(self: *BootServices, pages: []align(4096) Page) FreePagesError!void { |
| 396 | switch (self._freePages(pages.ptr, pages.len)) { |
| 397 | .success => {}, |
| 398 | .not_found => return error.NotFound, |
| 399 | .invalid_parameter => return error.InvalidParameter, |
| 400 | else => |status| return uefi.unexpectedStatus(status), |
| 401 | } |
| 402 | } |
| 403 | |
| 404 | pub fn getMemoryMapInfo(self: *const BootServices) uefi.UnexpectedError!MemoryMapInfo { |
| 405 | var info: MemoryMapInfo = undefined; |
| 406 | info.len = 0; |
| 407 | |
| 408 | switch (self._getMemoryMap( |
| 409 | &info.len, |
| 410 | null, |
| 411 | &info.key, |
| 412 | &info.descriptor_size, |
| 413 | &info.descriptor_version, |
| 414 | )) { |
| 415 | .success, .buffer_too_small => { |
| 416 | info.len = @divExact(info.len, info.descriptor_size); |
| 417 | return info; |
| 418 | }, |
| 419 | else => |status| return uefi.unexpectedStatus(status), |
| 420 | } |
| 421 | } |
| 422 | |
| 423 | pub fn getMemoryMap( |
| 424 | self: *const BootServices, |
| 425 | buffer: []align(@alignOf(MemoryDescriptor)) u8, |
| 426 | ) GetMemoryMapError!MemoryMapSlice { |
| 427 | var info: MemoryMapInfo = undefined; |
| 428 | info.len = buffer.len; |
| 429 | |
| 430 | switch (self._getMemoryMap( |
| 431 | &info.len, |
| 432 | buffer.ptr, |
| 433 | &info.key, |
| 434 | &info.descriptor_size, |
| 435 | &info.descriptor_version, |
| 436 | )) { |
| 437 | .success => { |
| 438 | info.len = @divExact(info.len, info.descriptor_size); |
| 439 | return .{ .info = info, .ptr = buffer.ptr }; |
| 440 | }, |
| 441 | .buffer_too_small => return error.BufferTooSmall, |
| 442 | .invalid_parameter => return error.InvalidParameter, |
| 443 | else => |status| return uefi.unexpectedStatus(status), |
| 444 | } |
| 445 | } |
| 446 | |
| 447 | /// Allocates a memory region of `size` bytes from memory of type `pool_type` |
| 448 | /// and returns the allocated memory. Allocates pages from `.conventional_memory` |
| 449 | /// as needed to grow the requested pool type. |
| 450 | pub fn allocatePool( |
| 451 | self: *BootServices, |
| 452 | pool_type: MemoryType, |
| 453 | size: usize, |
| 454 | ) AllocatePoolError![]align(8) u8 { |
| 455 | var ptr: [*]align(8) u8 = undefined; |
| 456 | |
| 457 | switch (self._allocatePool(pool_type, size, &ptr)) { |
| 458 | .success => return ptr[0..size], |
| 459 | .out_of_resources => return error.OutOfResources, |
| 460 | .invalid_parameter => return error.InvalidParameter, |
| 461 | else => |status| return uefi.unexpectedStatus(status), |
| 462 | } |
| 463 | } |
| 464 | |
| 465 | pub fn freePool(self: *BootServices, ptr: [*]align(8) u8) FreePoolError!void { |
| 466 | switch (self._freePool(ptr)) { |
| 467 | .success => {}, |
| 468 | .invalid_parameter => return error.InvalidParameter, |
| 469 | else => |status| return uefi.unexpectedStatus(status), |
| 470 | } |
| 471 | } |
| 472 | |
| 473 | pub fn createEvent( |
| 474 | self: *BootServices, |
| 475 | event_type: uefi.EventType, |
| 476 | notify_opts: NotifyOpts, |
| 477 | ) CreateEventError!Event { |
| 478 | var evt: Event = undefined; |
| 479 | |
| 480 | switch (self._createEvent( |
| 481 | @bitCast(event_type), |
| 482 | notify_opts.tpl, |
| 483 | notify_opts.function, |
| 484 | notify_opts.context, |
| 485 | &evt, |
| 486 | )) { |
| 487 | .success => return evt, |
| 488 | .invalid_parameter => return error.InvalidParameter, |
| 489 | .out_of_resources => return error.OutOfResources, |
| 490 | else => |status| return uefi.unexpectedStatus(status), |
| 491 | } |
| 492 | } |
| 493 | |
| 494 | /// Cancels any previous time trigger setting for the event, and sets a new |
| 495 | /// trigger timer for the event. |
| 496 | /// |
| 497 | /// Returns `error.InvalidParameter` if the event is not a timer event. |
| 498 | pub fn setTimer( |
| 499 | self: *BootServices, |
| 500 | event: Event, |
| 501 | @"type": TimerDelay, |
| 502 | trigger_time: u64, |
| 503 | ) SetTimerError!void { |
| 504 | switch (self._setTimer(event, @"type", trigger_time)) { |
| 505 | .success => {}, |
| 506 | .invalid_parameter => return error.InvalidParameter, |
| 507 | else => |status| return uefi.unexpectedStatus(status), |
| 508 | } |
| 509 | } |
| 510 | |
| 511 | /// Returns the event that was signaled, along with its index in the slice. |
| 512 | pub fn waitForEvent( |
| 513 | self: *BootServices, |
| 514 | events: []const Event, |
| 515 | ) WaitForEventError!struct { *const Event, usize } { |
| 516 | var idx: usize = undefined; |
| 517 | switch (self._waitForEvent(events.len, events.ptr, &idx)) { |
| 518 | .success => return .{ &events[idx], idx }, |
| 519 | .invalid_parameter => return error.InvalidParameter, |
| 520 | .unsupported => return error.Unsupported, |
| 521 | else => |status| return uefi.unexpectedStatus(status), |
| 522 | } |
| 523 | } |
| 524 | |
| 525 | /// If `event` is `EventType.signal`, then the event’s notification function |
| 526 | /// is scheduled to be invoked at the event’s notification task priority level. |
| 527 | /// This function may be invoked from any task priority level. |
| 528 | /// |
| 529 | /// If the supplied Event is a part of an event group, then all of the events |
| 530 | /// in the event group are also signaled and their notification functions are |
| 531 | /// scheduled. |
| 532 | /// |
| 533 | /// When signaling an event group, it is possible to create an event in the |
| 534 | /// group, signal it and then close the event to remove it from the group. |
| 535 | pub fn signalEvent(self: *BootServices, event: Event) uefi.UnexpectedError!void { |
| 536 | switch (self._signalEvent(event)) { |
| 537 | .success => {}, |
| 538 | else => |status| return uefi.unexpectedStatus(status), |
| 539 | } |
| 540 | } |
| 541 | |
| 542 | pub fn closeEvent(self: *BootServices, event: Event) uefi.UnexpectedError!void { |
| 543 | switch (self._closeEvent(event)) { |
| 544 | .success => {}, |
| 545 | else => |status| return uefi.unexpectedStatus(status), |
| 546 | } |
| 547 | } |
| 548 | |
| 549 | /// Checks to see whether an event is signaled. |
| 550 | /// |
| 551 | /// The underlying function is equivalent to this pseudo-code: |
| 552 | /// ``` |
| 553 | /// if (event.type.signal) |
| 554 | /// return error.InvalidParameter; |
| 555 | /// |
| 556 | /// if (event.signaled) { |
| 557 | /// event.signaled = false; |
| 558 | /// return true; |
| 559 | /// } |
| 560 | /// |
| 561 | /// const notify = event.notification_function orelse return false; |
| 562 | /// notify(); |
| 563 | /// |
| 564 | /// if (event.signaled) { |
| 565 | /// event.signaled = false; |
| 566 | /// return true; |
| 567 | /// } |
| 568 | /// |
| 569 | /// return false; |
| 570 | /// ``` |
| 571 | pub fn checkEvent(self: *BootServices, event: Event) CheckEventError!bool { |
| 572 | switch (self._checkEvent(event)) { |
| 573 | .success => return true, |
| 574 | .not_ready => return false, |
| 575 | .invalid_parameter => return error.InvalidParameter, |
| 576 | else => |status| return uefi.unexpectedStatus(status), |
| 577 | } |
| 578 | } |
| 579 | |
| 580 | /// See `installProtocolInterfaces`. |
| 581 | /// |
| 582 | /// Does not call `self._installProtocolInterface`, because |
| 583 | /// `self._installMultipleProtocolInterfaces` performs more error checks. |
| 584 | pub fn installProtocolInterface( |
| 585 | self: *BootServices, |
| 586 | handle: ?Handle, |
| 587 | interface: anytype, |
| 588 | ) InstallProtocolInterfacesError!Handle { |
| 589 | return self.installProtocolInterfaces(handle, .{ |
| 590 | interface, |
| 591 | }); |
| 592 | } |
| 593 | |
| 594 | /// Reinstalls a protocol interface on a device handle. |
| 595 | /// |
| 596 | /// `new` may be the same as `old`. If it is, the registered protocol notifications |
| 597 | /// occur for the handle without replacing the interface on the handle. |
| 598 | /// |
| 599 | /// Any process that has registered to wait for the installation of the interface |
| 600 | /// is notified. |
| 601 | /// |
| 602 | /// The caller is responsible for ensuring that there are no references to `old` |
| 603 | /// if it is being removed. |
| 604 | pub fn reinstallProtocolInterface( |
| 605 | self: *BootServices, |
| 606 | handle: Handle, |
| 607 | Protocol: type, |
| 608 | old: ?*const Protocol, |
| 609 | new: ?*const Protocol, |
| 610 | ) ReinstallProtocolInterfaceError!void { |
| 611 | if (!@hasDecl(Protocol, "guid")) |
| 612 | @compileError("protocol is missing guid"); |
| 613 | |
| 614 | switch (self._reinstallProtocolInterface( |
| 615 | handle, |
| 616 | &Protocol.guid, |
| 617 | old, |
| 618 | new, |
| 619 | )) { |
| 620 | .success => {}, |
| 621 | .not_found => return error.NotFound, |
| 622 | .access_denied => return error.AccessDenied, |
| 623 | .invalid_parameter => return error.InvalidParameter, |
| 624 | else => |status| return uefi.unexpectedStatus(status), |
| 625 | } |
| 626 | } |
| 627 | |
| 628 | /// See `uninstallProtocolInterfaces`. |
| 629 | /// |
| 630 | /// Does not call `self._uninstallProtocolInterface`, because |
| 631 | /// `self._uninstallMultipleProtocolInterfaces` performs more error checks. |
| 632 | pub fn uninstallProtocolInterface( |
| 633 | self: *BootServices, |
| 634 | handle: Handle, |
| 635 | interface: anytype, |
| 636 | ) UninstallProtocolInterfacesError!void { |
| 637 | return self.uninstallProtocolInterfaces(handle, .{ |
| 638 | interface, |
| 639 | }); |
| 640 | } |
| 641 | |
| 642 | /// Returns a pointer to the `Protocol` interface if it's supported by the |
| 643 | /// handle. |
| 644 | /// |
| 645 | /// Note that UEFI implementations are no longer required to implement this |
| 646 | /// function, so it's implemented using `openProtocol` instead. |
| 647 | pub fn handleProtocol( |
| 648 | self: *BootServices, |
| 649 | Protocol: type, |
| 650 | handle: Handle, |
| 651 | ) HandleProtocolError!?*Protocol { |
| 652 | // per https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-handleprotocol |
| 653 | // handleProtocol is basically `openProtocol` where: |
| 654 | // 1. agent_handle is `uefi.handle` (aka handle passed to `EfiMain`) |
| 655 | // 2. controller_handle is `null` |
| 656 | // 3. attributes is `EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL` |
| 657 | |
| 658 | return self.openProtocol( |
| 659 | Protocol, |
| 660 | handle, |
| 661 | .{ .by_handle_protocol = .{ .agent = uefi.handle } }, |
| 662 | ) catch |err| switch (err) { |
| 663 | error.AlreadyStarted => return uefi.unexpectedStatus(.already_started), |
| 664 | error.AccessDenied => return uefi.unexpectedStatus(.access_denied), |
| 665 | error.InvalidParameter => return uefi.unexpectedStatus(.invalid_parameter), |
| 666 | else => return @errorCast(err), |
| 667 | }; |
| 668 | } |
| 669 | |
| 670 | pub fn registerProtocolNotify( |
| 671 | self: *BootServices, |
| 672 | Protocol: type, |
| 673 | event: Event, |
| 674 | ) RegisterProtocolNotifyError!EventRegistration { |
| 675 | if (!@hasDecl(Protocol, "guid")) |
| 676 | @compileError("Protocol is missing guid"); |
| 677 | |
| 678 | var registration: EventRegistration = undefined; |
| 679 | switch (self._registerProtocolNotify( |
| 680 | &Protocol.guid, |
| 681 | event, |
| 682 | &registration, |
| 683 | )) { |
| 684 | .success => return registration, |
| 685 | .out_of_resources => return error.OutOfResources, |
| 686 | .invalid_parameter => return error.InvalidParameter, |
| 687 | else => |status| return uefi.unexpectedStatus(status), |
| 688 | } |
| 689 | } |
| 690 | |
| 691 | /// Returns the number of handles that match the given search criteria. |
| 692 | pub fn locateHandleLen(self: *const BootServices, search: LocateSearch) NumHandlesError!usize { |
| 693 | var len: usize = 0; |
| 694 | switch (self._locateHandle( |
| 695 | std.meta.activeTag(search), |
| 696 | if (search == .by_protocol) search.by_protocol else null, |
| 697 | if (search == .by_register_notify) search.by_register_notify else null, |
| 698 | &len, |
| 699 | null, |
| 700 | )) { |
| 701 | // If len is zero, it should return not_found, otherwise buffer_too_small. |
| 702 | // This is because it can/should only return success when a valid buffer is |
| 703 | // passed with a non zero size, which is not the case. |
| 704 | // Thus this status is considered unreachable and will return error.Unexpected |
| 705 | // .success => unreachable, |
| 706 | .buffer_too_small => return @divExact(len, @sizeOf(uefi.Handle)), |
| 707 | .not_found => return 0, |
| 708 | // This function accounts for all possible causes of this error code |
| 709 | // as per the most recent UEFI spec 2.10A, therefore this branch is |
| 710 | // considered unreachable and will return error.Unexpected instead |
| 711 | // .invalid_parameter => unreachable |
| 712 | else => |status| return uefi.unexpectedStatus(status), |
| 713 | } |
| 714 | } |
| 715 | |
| 716 | /// To determine the necessary size of `buffer`, call `locateHandleLen` first. |
| 717 | pub fn locateHandle( |
| 718 | self: *BootServices, |
| 719 | search: LocateSearch, |
| 720 | buffer: []Handle, |
| 721 | ) LocateHandleError![]Handle { |
| 722 | var len: usize = @sizeOf(Handle) * buffer.len; |
| 723 | switch (self._locateHandle( |
| 724 | std.meta.activeTag(search), |
| 725 | if (search == .by_protocol) search.by_protocol else null, |
| 726 | if (search == .by_register_notify) search.by_register_notify else null, |
| 727 | &len, |
| 728 | buffer.ptr, |
| 729 | )) { |
| 730 | .success => return buffer[0..@divExact(len, @sizeOf(Handle))], |
| 731 | .not_found => return buffer[0..0], |
| 732 | .buffer_too_small => return error.BufferTooSmall, |
| 733 | .invalid_parameter => return error.InvalidParameter, |
| 734 | else => |status| return uefi.unexpectedStatus(status), |
| 735 | } |
| 736 | } |
| 737 | |
| 738 | /// Locates all devices on `device_path` that support `Protocol`. Once the closest |
| 739 | /// match to `device_path` is found, it returns the unmatched device path and handle. |
| 740 | pub fn locateDevicePath( |
| 741 | self: *const BootServices, |
| 742 | device_path: *const DevicePathProtocol, |
| 743 | Protocol: type, |
| 744 | ) LocateHandleError!?struct { *const DevicePathProtocol, Handle } { |
| 745 | if (!@hasDecl(Protocol, "guid")) |
| 746 | @compileError("Protocol is missing guid"); |
| 747 | |
| 748 | var dev_path = device_path; |
| 749 | var device: ?Handle = undefined; |
| 750 | switch (self._locateDevicePath( |
| 751 | &Protocol.guid, |
| 752 | &dev_path, |
| 753 | &device, |
| 754 | )) { |
| 755 | .success => return .{ dev_path, device.? }, |
| 756 | .not_found => return null, |
| 757 | .invalid_parameter => return error.InvalidParameter, |
| 758 | else => |status| return uefi.unexpectedStatus(status), |
| 759 | } |
| 760 | } |
| 761 | |
| 762 | pub fn installConfigurationTable( |
| 763 | self: *BootServices, |
| 764 | guid: *const Guid, |
| 765 | table: *anyopaque, |
| 766 | ) InstallConfigurationTableError!void { |
| 767 | switch (self._installConfigurationTable( |
| 768 | guid, |
| 769 | table, |
| 770 | )) { |
| 771 | .success => {}, |
| 772 | .invalid_parameter => return error.InvalidParameter, |
| 773 | .out_of_resources => return error.OutOfResources, |
| 774 | else => |status| return uefi.unexpectedStatus(status), |
| 775 | } |
| 776 | } |
| 777 | |
| 778 | pub fn uninstallConfigurationTable( |
| 779 | self: *BootServices, |
| 780 | guid: *const Guid, |
| 781 | ) UninstallConfigurationTableError!void { |
| 782 | switch (self._installConfigurationTable( |
| 783 | guid, |
| 784 | null, |
| 785 | )) { |
| 786 | .success => {}, |
| 787 | .not_found => return error.NotFound, |
| 788 | .invalid_parameter => return error.InvalidParameter, |
| 789 | .out_of_resources => return error.OutOfResources, |
| 790 | else => |status| return uefi.unexpectedStatus(status), |
| 791 | } |
| 792 | } |
| 793 | |
| 794 | pub const LoadImageSource = union(enum) { |
| 795 | buffer: []const u8, |
| 796 | device_path: *const DevicePathProtocol, |
| 797 | }; |
| 798 | |
| 799 | pub fn loadImage( |
| 800 | self: *BootServices, |
| 801 | boot_policy: bool, |
| 802 | parent_image: Handle, |
| 803 | source: LoadImageSource, |
| 804 | ) LoadImageError!Handle { |
| 805 | var handle: Handle = undefined; |
| 806 | |
| 807 | switch (self._loadImage( |
| 808 | boot_policy, |
| 809 | parent_image, |
| 810 | if (source == .device_path) source.device_path else null, |
| 811 | if (source == .buffer) source.buffer.ptr else null, |
| 812 | if (source == .buffer) source.buffer.len else 0, |
| 813 | &handle, |
| 814 | )) { |
| 815 | .success => return handle, |
| 816 | .not_found => return error.NotFound, |
| 817 | .invalid_parameter => return error.InvalidParameter, |
| 818 | .unsupported => return error.Unsupported, |
| 819 | .out_of_resources => return error.OutOfResources, |
| 820 | .load_error => return error.LoadError, |
| 821 | .device_error => return error.DeviceError, |
| 822 | .access_denied => return error.AccessDenied, |
| 823 | .security_violation => return error.SecurityViolation, |
| 824 | else => |status| return uefi.unexpectedStatus(status), |
| 825 | } |
| 826 | } |
| 827 | |
| 828 | pub fn startImage(self: *BootServices, image: Handle) StartImageError!ImageExitData { |
| 829 | var exit_data_size: usize = undefined; |
| 830 | var exit_data: [*]u16 = undefined; |
| 831 | |
| 832 | const exit_code = switch (self._startImage( |
| 833 | image, |
| 834 | &exit_data_size, |
| 835 | &exit_data, |
| 836 | )) { |
| 837 | .invalid_parameter => return error.InvalidParameter, |
| 838 | .security_violation => return error.SecurityViolation, |
| 839 | else => |exit_code| exit_code, |
| 840 | }; |
| 841 | |
| 842 | if (exit_data_size == 0) return .{ |
| 843 | .code = exit_code, |
| 844 | .description = null, |
| 845 | .data = null, |
| 846 | }; |
| 847 | |
| 848 | const description_ptr: [*:0]const u16 = @ptrCast(exit_data); |
| 849 | const description = std.mem.sliceTo(description_ptr, 0); |
| 850 | |
| 851 | return ImageExitData{ |
| 852 | .code = exit_code, |
| 853 | .description = description, |
| 854 | .data = exit_data[description.len + 1 .. exit_data_size], |
| 855 | }; |
| 856 | } |
| 857 | |
| 858 | /// `message` must be allocated using `allocatePool`. |
| 859 | pub fn exit( |
| 860 | self: *BootServices, |
| 861 | handle: Handle, |
| 862 | status: Status, |
| 863 | message: ?[:0]const u16, |
| 864 | ) ExitError!void { |
| 865 | switch (self._exit( |
| 866 | handle, |
| 867 | status, |
| 868 | if (message) |msg| (2 * msg.len) + 1 else 0, |
| 869 | if (message) |msg| @ptrCast(msg.ptr) else null, |
| 870 | )) { |
| 871 | .success => {}, |
| 872 | .invalid_parameter => return error.InvalidParameter, |
| 873 | else => |exit_status| return uefi.unexpectedStatus(exit_status), |
| 874 | } |
| 875 | } |
| 876 | |
| 877 | /// `message` should be a null-terminated u16 string followed by binary data |
| 878 | /// allocated using `allocatePool`. |
| 879 | pub fn exitWithData( |
| 880 | self: *BootServices, |
| 881 | handle: Handle, |
| 882 | status: Status, |
| 883 | data: []align(2) const u8, |
| 884 | ) ExitError!void { |
| 885 | switch (self._exit(handle, status, data.len, data.ptr)) { |
| 886 | .success => {}, |
| 887 | .invalid_parameter => return error.InvalidParameter, |
| 888 | else => |exit_status| return uefi.unexpectedStatus(exit_status), |
| 889 | } |
| 890 | } |
| 891 | |
| 892 | /// The result is the exit code of the unload handler. Any error codes are |
| 893 | /// `try/catch`-able, leaving only success and warning codes as the result. |
| 894 | pub fn unloadImage( |
| 895 | self: *BootServices, |
| 896 | image: Handle, |
| 897 | ) Status.Error!Status { |
| 898 | const status = self._unloadImage(image); |
| 899 | try status.err(); |
| 900 | return status; |
| 901 | } |
| 902 | |
| 903 | pub fn exitBootServices( |
| 904 | self: *BootServices, |
| 905 | image: Handle, |
| 906 | map_key: MemoryMapKey, |
| 907 | ) ExitBootServicesError!void { |
| 908 | switch (self._exitBootServices(image, map_key)) { |
| 909 | .success => {}, |
| 910 | .invalid_parameter => return error.InvalidParameter, |
| 911 | else => |status| return uefi.unexpectedStatus(status), |
| 912 | } |
| 913 | } |
| 914 | |
| 915 | pub fn getNextMonotonicCount( |
| 916 | self: *const BootServices, |
| 917 | count: *u64, |
| 918 | ) GetNextMonotonicCountError!void { |
| 919 | switch (self._getNextMonotonicCount(count)) { |
| 920 | .success => {}, |
| 921 | .device_error => return error.DeviceError, |
| 922 | .invalid_parameter => return error.InvalidParameter, |
| 923 | else => |status| return uefi.unexpectedStatus(status), |
| 924 | } |
| 925 | } |
| 926 | |
| 927 | pub fn stall(self: *const BootServices, microseconds: usize) uefi.UnexpectedError!void { |
| 928 | switch (self._stall(microseconds)) { |
| 929 | .success => {}, |
| 930 | else => |status| return uefi.unexpectedStatus(status), |
| 931 | } |
| 932 | } |
| 933 | |
| 934 | pub fn setWatchdogTimer( |
| 935 | self: *BootServices, |
| 936 | timeout: usize, |
| 937 | watchdog_code: u64, |
| 938 | data: ?[]const u16, |
| 939 | ) SetWatchdogTimerError!void { |
| 940 | switch (self._setWatchdogTimer( |
| 941 | timeout, |
| 942 | watchdog_code, |
| 943 | if (data) |d| d.len else 0, |
| 944 | if (data) |d| d.ptr else null, |
| 945 | )) { |
| 946 | .success => {}, |
| 947 | .invalid_parameter => return error.InvalidParameter, |
| 948 | .unsupported => return error.Unsupported, |
| 949 | .device_error => return error.DeviceError, |
| 950 | else => |status| return uefi.unexpectedStatus(status), |
| 951 | } |
| 952 | } |
| 953 | |
| 954 | /// `driver_image` should be a null-terminated ordered list of handles. |
| 955 | pub fn connectController( |
| 956 | self: *BootServices, |
| 957 | controller: Handle, |
| 958 | driver_image: ?[*:null]?Handle, |
| 959 | remaining_device_path: ?*const DevicePathProtocol, |
| 960 | recursive: bool, |
| 961 | ) ConnectControllerError!void { |
| 962 | switch (self._connectController( |
| 963 | controller, |
| 964 | driver_image, |
| 965 | remaining_device_path, |
| 966 | recursive, |
| 967 | )) { |
| 968 | .success => {}, |
| 969 | .invalid_parameter => return error.InvalidParameter, |
| 970 | .not_found => return error.NotFound, |
| 971 | .security_violation => return error.SecurityViolation, |
| 972 | else => |status| return uefi.unexpectedStatus(status), |
| 973 | } |
| 974 | } |
| 975 | |
| 976 | pub fn disconnectController( |
| 977 | self: *BootServices, |
| 978 | controller: Handle, |
| 979 | driver_image: ?Handle, |
| 980 | child: ?Handle, |
| 981 | ) DisconnectControllerError!void { |
| 982 | switch (self._disconnectController( |
| 983 | controller, |
| 984 | driver_image, |
| 985 | child, |
| 986 | )) { |
| 987 | .success => {}, |
| 988 | .invalid_parameter => return error.InvalidParameter, |
| 989 | .out_of_resources => return error.OutOfResources, |
| 990 | .device_error => return error.DeviceError, |
| 991 | else => |status| return uefi.unexpectedStatus(status), |
| 992 | } |
| 993 | } |
| 994 | |
| 995 | /// Opens a protocol with a structure as the loaded image for a UEFI application |
| 996 | /// |
| 997 | /// If `flag` is `.test_protocol`, then the only valid return value is `null`, |
| 998 | /// and `Status.unsupported` is returned. Otherwise, if `_openProtocol` returns |
| 999 | /// `Status.unsupported`, then `null` is returned. |
| 1000 | pub fn openProtocol( |
| 1001 | self: *BootServices, |
| 1002 | Protocol: type, |
| 1003 | handle: Handle, |
| 1004 | attributes: OpenProtocolArgs, |
| 1005 | ) OpenProtocolError!?*Protocol { |
| 1006 | if (!@hasDecl(Protocol, "guid")) |
| 1007 | @compileError("Protocol is missing guid: " ++ @typeName(Protocol)); |
| 1008 | |
| 1009 | const agent_handle: ?Handle, const controller_handle: ?Handle = switch (attributes) { |
| 1010 | inline else => |arg| .{ arg.agent, arg.controller }, |
| 1011 | }; |
| 1012 | |
| 1013 | var ptr: ?*Protocol = undefined; |
| 1014 | |
| 1015 | switch (self._openProtocol( |
| 1016 | handle, |
| 1017 | &Protocol.guid, |
| 1018 | @as(*?*anyopaque, @ptrCast(&ptr)), |
| 1019 | agent_handle, |
| 1020 | controller_handle, |
| 1021 | std.meta.activeTag(attributes), |
| 1022 | )) { |
| 1023 | .success => return if (attributes == .test_protocol) null else ptr, |
| 1024 | .unsupported => return if (attributes == .test_protocol) error.Unsupported else null, |
| 1025 | .access_denied => return error.AccessDenied, |
| 1026 | .already_started => return error.AlreadyStarted, |
| 1027 | else => |status| return uefi.unexpectedStatus(status), |
| 1028 | } |
| 1029 | } |
| 1030 | |
| 1031 | pub fn closeProtocol( |
| 1032 | self: *BootServices, |
| 1033 | handle: Handle, |
| 1034 | Protocol: type, |
| 1035 | agent: Handle, |
| 1036 | controller: ?Handle, |
| 1037 | ) CloseProtocolError!void { |
| 1038 | if (!@hasDecl(Protocol, "guid")) |
| 1039 | @compileError("protocol is missing guid: " ++ @typeName(Protocol)); |
| 1040 | |
| 1041 | switch (self._closeProtocol( |
| 1042 | handle, |
| 1043 | &Protocol.guid, |
| 1044 | agent, |
| 1045 | controller, |
| 1046 | )) { |
| 1047 | .success => {}, |
| 1048 | .invalid_parameter => return error.InvalidParameter, |
| 1049 | .not_found => return error.NotFound, |
| 1050 | else => |status| return uefi.unexpectedStatus(status), |
| 1051 | } |
| 1052 | } |
| 1053 | |
| 1054 | pub fn openProtocolInformation( |
| 1055 | self: *const BootServices, |
| 1056 | handle: Handle, |
| 1057 | Protocol: type, |
| 1058 | ) OpenProtocolInformationError!?[]ProtocolInformationEntry { |
| 1059 | var entries: [*]ProtocolInformationEntry = undefined; |
| 1060 | var len: usize = undefined; |
| 1061 | |
| 1062 | switch (self._openProtocolInformation( |
| 1063 | handle, |
| 1064 | &Protocol.guid, |
| 1065 | &entries, |
| 1066 | &len, |
| 1067 | )) { |
| 1068 | .success => return entries[0..len], |
| 1069 | .not_found => return null, |
| 1070 | .out_of_resources => return error.OutOfResources, |
| 1071 | else => |status| return uefi.unexpectedStatus(status), |
| 1072 | } |
| 1073 | } |
| 1074 | |
| 1075 | pub fn protocolsPerHandle( |
| 1076 | self: *const BootServices, |
| 1077 | handle: Handle, |
| 1078 | ) ProtocolsPerHandleError![]*const Guid { |
| 1079 | var guids: [*]*const Guid = undefined; |
| 1080 | var len: usize = undefined; |
| 1081 | |
| 1082 | switch (self._protocolsPerHandle( |
| 1083 | handle, |
| 1084 | &guids, |
| 1085 | &len, |
| 1086 | )) { |
| 1087 | .success => return guids[0..len], |
| 1088 | .invalid_parameter => return error.InvalidParameter, |
| 1089 | .out_of_resources => return error.OutOfResources, |
| 1090 | else => |status| return uefi.unexpectedStatus(status), |
| 1091 | } |
| 1092 | } |
| 1093 | |
| 1094 | pub fn locateHandleBuffer( |
| 1095 | self: *const BootServices, |
| 1096 | search: LocateSearch, |
| 1097 | ) LocateHandleBufferError!?[]Handle { |
| 1098 | var handles: [*]Handle = undefined; |
| 1099 | var len: usize = undefined; |
| 1100 | |
| 1101 | switch (self._locateHandleBuffer( |
| 1102 | std.meta.activeTag(search), |
| 1103 | if (search == .by_protocol) search.by_protocol else null, |
| 1104 | if (search == .by_register_notify) search.by_register_notify else null, |
| 1105 | &len, |
| 1106 | &handles, |
| 1107 | )) { |
| 1108 | .success => return handles[0..len], |
| 1109 | .invalid_parameter => return error.InvalidParameter, |
| 1110 | .not_found => return null, |
| 1111 | .out_of_resources => return error.OutOfResources, |
| 1112 | else => |status| return uefi.unexpectedStatus(status), |
| 1113 | } |
| 1114 | } |
| 1115 | |
| 1116 | pub fn locateProtocol( |
| 1117 | self: *const BootServices, |
| 1118 | Protocol: type, |
| 1119 | registration: ?EventRegistration, |
| 1120 | ) LocateProtocolError!?*Protocol { |
| 1121 | var interface: *Protocol = undefined; |
| 1122 | |
| 1123 | switch (self._locateProtocol( |
| 1124 | &Protocol.guid, |
| 1125 | registration, |
| 1126 | @ptrCast(&interface), |
| 1127 | )) { |
| 1128 | .success => return interface, |
| 1129 | .not_found => return null, |
| 1130 | .invalid_parameter => return error.InvalidParameter, |
| 1131 | else => |status| return uefi.unexpectedStatus(status), |
| 1132 | } |
| 1133 | } |
| 1134 | |
| 1135 | /// Installs a set of protocol interfaces into the boot services environment. |
| 1136 | /// |
| 1137 | /// This function's final argument should be a tuple of pointers to protocol |
| 1138 | /// interfaces. For example: |
| 1139 | /// |
| 1140 | /// ``` |
| 1141 | /// const handle = try boot_services.installProtocolInterfaces(null, .{ |
| 1142 | /// &my_interface_1, |
| 1143 | /// &my_interface_2, |
| 1144 | /// }); |
| 1145 | /// ``` |
| 1146 | /// |
| 1147 | /// The underlying function accepts a vararg list of pairs of Guid pointers |
| 1148 | /// and opaque pointers to the interface. To provide a guid, the interface |
| 1149 | /// types should declare a `guid` constant like so: |
| 1150 | /// |
| 1151 | /// ``` |
| 1152 | /// pub const guid: uefi.Guid = .{ ... }; |
| 1153 | /// ``` |
| 1154 | /// |
| 1155 | /// See `std.os.uefi.protocol` for examples of protocol type definitions. |
| 1156 | pub fn installProtocolInterfaces( |
| 1157 | self: *BootServices, |
| 1158 | handle: ?Handle, |
| 1159 | interfaces: anytype, |
| 1160 | ) InstallProtocolInterfacesError!Handle { |
| 1161 | var hdl: ?Handle = handle; |
| 1162 | const args_tuple = protocolInterfaces(&hdl, interfaces); |
| 1163 | |
| 1164 | switch (@call( |
| 1165 | .auto, |
| 1166 | self._installMultipleProtocolInterfaces, |
| 1167 | args_tuple, |
| 1168 | )) { |
| 1169 | .success => return hdl.?, |
| 1170 | .already_started => return error.AlreadyStarted, |
| 1171 | .out_of_resources => return error.OutOfResources, |
| 1172 | .invalid_parameter => return error.InvalidParameter, |
| 1173 | else => |status| return uefi.unexpectedStatus(status), |
| 1174 | } |
| 1175 | } |
| 1176 | |
| 1177 | pub fn uninstallProtocolInterfaces( |
| 1178 | self: *BootServices, |
| 1179 | handle: Handle, |
| 1180 | interfaces: anytype, |
| 1181 | ) UninstallProtocolInterfacesError!void { |
| 1182 | const args_tuple = protocolInterfaces(handle, interfaces); |
| 1183 | |
| 1184 | switch (@call( |
| 1185 | .auto, |
| 1186 | self._uninstallMultipleProtocolInterfaces, |
| 1187 | args_tuple, |
| 1188 | )) { |
| 1189 | .success => {}, |
| 1190 | .invalid_parameter => return error.InvalidParameter, |
| 1191 | else => |status| return uefi.unexpectedStatus(status), |
| 1192 | } |
| 1193 | } |
| 1194 | |
| 1195 | pub fn calculateCrc32( |
| 1196 | self: *const BootServices, |
| 1197 | data: []const u8, |
| 1198 | ) CalculateCrc32Error!u32 { |
| 1199 | var value: u32 = undefined; |
| 1200 | switch (self._calculateCrc32(data.ptr, data.len, &value)) { |
| 1201 | .success => return value, |
| 1202 | .invalid_parameter => return error.InvalidParameter, |
| 1203 | else => |status| return uefi.unexpectedStatus(status), |
| 1204 | } |
| 1205 | } |
| 1206 | |
| 1207 | pub const signature: u64 = 0x56524553544f4f42; |
| 1208 | |
| 1209 | pub const NotifyOpts = struct { |
| 1210 | tpl: TaskPriorityLevel = .application, |
| 1211 | function: ?*const fn (Event, ?*anyopaque) callconv(cc) void = null, |
| 1212 | context: ?*anyopaque = null, |
| 1213 | }; |
| 1214 | |
| 1215 | pub const TaskPriorityLevel = enum(usize) { |
| 1216 | application = 4, |
| 1217 | callback = 8, |
| 1218 | notify = 16, |
| 1219 | high_level = 31, |
| 1220 | _, |
| 1221 | }; |
| 1222 | |
| 1223 | pub const ImageExitData = struct { |
| 1224 | code: Status, |
| 1225 | description: ?[:0]const u16, |
| 1226 | data: ?[]const u16, |
| 1227 | }; |
| 1228 | }; |
| 1229 | |
| 1230 | fn protocolInterfaces( |
| 1231 | handle_arg: anytype, |
| 1232 | interfaces: anytype, |
| 1233 | ) ProtocolInterfaces(@TypeOf(handle_arg), @TypeOf(interfaces)) { |
| 1234 | var result: ProtocolInterfaces( |
| 1235 | @TypeOf(handle_arg), |
| 1236 | @TypeOf(interfaces), |
| 1237 | ) = undefined; |
| 1238 | result[0] = handle_arg; |
| 1239 | result[result.len - 1] = null; |
| 1240 | |
| 1241 | comptime var idx: usize = 1; |
| 1242 | inline for (interfaces) |interface| { |
| 1243 | const InterfacePtr = @TypeOf(interface); |
| 1244 | const Interface = switch (@typeInfo(InterfacePtr)) { |
| 1245 | .pointer => |pointer| pointer.child, |
| 1246 | else => @compileError("expected tuple of '*const Protocol', got " ++ @typeName(InterfacePtr)), |
| 1247 | }; |
| 1248 | |
| 1249 | if (!@hasDecl(Interface, "guid")) |
| 1250 | @compileError("protocol interface '" ++ @typeName(Interface) ++ |
| 1251 | "' does not declare a 'const guid: uefi.Guid'."); |
| 1252 | |
| 1253 | switch (@typeInfo(Interface)) { |
| 1254 | .@"struct" => |struct_info| if (struct_info.layout != .@"extern") |
| 1255 | @compileLog("protocol interface '" ++ @typeName(Interface) ++ |
| 1256 | "' is not extern - this is likely a mistake"), |
| 1257 | else => @compileError("protocol interface must be a struct, got " ++ @typeName(Interface)), |
| 1258 | } |
| 1259 | |
| 1260 | result[idx] = &Interface.guid; |
| 1261 | result[idx + 1] = @ptrCast(interface); |
| 1262 | idx += 2; |
| 1263 | } |
| 1264 | |
| 1265 | return result; |
| 1266 | } |
| 1267 | |
| 1268 | fn ProtocolInterfaces(HandleType: type, Interfaces: type) type { |
| 1269 | const interfaces_type_info = @typeInfo(Interfaces); |
| 1270 | if (interfaces_type_info != .@"struct" or !interfaces_type_info.@"struct".is_tuple) |
| 1271 | @compileError("expected tuple of protocol interfaces, got " ++ @typeName(Interfaces)); |
| 1272 | const interfaces_info = interfaces_type_info.@"struct"; |
| 1273 | |
| 1274 | var tuple_types: [interfaces_info.field_names.len * 2 + 2]type = undefined; |
| 1275 | tuple_types[0] = HandleType; |
| 1276 | tuple_types[tuple_types.len - 1] = ?*const Guid; |
| 1277 | |
| 1278 | var idx = 1; |
| 1279 | while (idx < tuple_types.len - 1) : (idx += 2) { |
| 1280 | tuple_types[idx] = *const Guid; |
| 1281 | tuple_types[idx + 1] = *const anyopaque; |
| 1282 | } |
| 1283 | |
| 1284 | return @Tuple(tuple_types[0..]); |
| 1285 | } |