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