├── .gitignore ├── LICENSE ├── README.md ├── build.zig ├── build.zig.zon └── src └── root.zig /.gitignore: -------------------------------------------------------------------------------- 1 | /.zig-cache 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2022-2024 48cf and contributors. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # limine-zig 2 | 3 | Zig bindings for the [The Limine Boot Protocol](https://github.com/limine-bootloader/limine/blob/trunk/PROTOCOL.md). 4 | 5 | To use this library, add it to your `build.zig.zon` file manually or use `zig fetch`: 6 | 7 | ```sh 8 | zig fetch --save git+https://github.com/48cf/limine-zig#trunk 9 | ``` 10 | 11 | Then, import the library in your `build.zig`: 12 | 13 | ```zig 14 | const limine_zig = b.dependency("limine_zig", .{ 15 | // The API revision of the Limine Boot Protocol to use, if not provided 16 | // it defaults to 0. Newer revisions may change the behavior of the bootloader. 17 | .api_revision = 3, 18 | // Whether to allow using deprecated features of the Limine Boot Protocol. 19 | // If set to false, the build will fail if deprecated features are used. 20 | .allow_deprecated = false, 21 | // Whether to expose pointers in the API. When set to true, any field 22 | // that is a pointer will be exposed as a raw address instead. 23 | .no_pointers = false, 24 | }); 25 | 26 | // Get the Limine module 27 | const limine_module = limine_zig.module("limine"); 28 | 29 | // Import the Limine module into the kernel 30 | kernel.addImport("limine", limine_module); 31 | ``` 32 | 33 | You can find an example kernel using this library [here](https://github.com/48cf/limine-zig-template). 34 | 35 | To use this library, you need at least Zig 0.14.0. 36 | -------------------------------------------------------------------------------- /build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | pub fn build(b: *std.Build) void { 4 | const api_revision = b.option(u32, "api_revision", "Limine API revision to use"); 5 | const allow_deprecated = b.option(bool, "allow_deprecated", "Whether to allow deprecated features"); 6 | const no_pointers = b.option(bool, "no_pointers", "Whether to expose pointers as addresses"); 7 | 8 | const config = b.addOptions(); 9 | config.addOption(u32, "api_revision", api_revision orelse 0); 10 | config.addOption(bool, "allow_deprecated", allow_deprecated orelse false); 11 | config.addOption(bool, "no_pointers", no_pointers orelse false); 12 | 13 | const module = b.addModule("limine", .{ 14 | .root_source_file = b.path("src/root.zig"), 15 | }); 16 | module.addImport("config", config.createModule()); 17 | } 18 | -------------------------------------------------------------------------------- /build.zig.zon: -------------------------------------------------------------------------------- 1 | .{ 2 | .name = .limine_zig, 3 | .version = "0.0.0", 4 | .fingerprint = 0x439c475b40f038d5, 5 | .minimum_zig_version = "0.14.0", 6 | .dependencies = .{}, 7 | .paths = .{ 8 | "build.zig", 9 | "build.zig.zon", 10 | "src", 11 | "LICENSE", 12 | "README.md", 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /src/root.zig: -------------------------------------------------------------------------------- 1 | const builtin = @import("builtin"); 2 | const config = @import("config"); 3 | const std = @import("std"); 4 | 5 | pub const Arch = enum { 6 | x86_64, 7 | aarch64, 8 | riscv64, 9 | loongarch64, 10 | }; 11 | 12 | pub const api_revision = config.api_revision; 13 | pub const arch: Arch = switch (builtin.cpu.arch) { 14 | .x86_64 => .x86_64, 15 | .aarch64 => .aarch64, 16 | .riscv64 => .riscv64, 17 | .loongarch64 => .loongarch64, 18 | else => |arch_tag| @compileError("Unsupported architecture: " ++ @tagName(arch_tag)), 19 | }; 20 | 21 | fn id(a: u64, b: u64) [4]u64 { 22 | return .{ 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b, a, b }; 23 | } 24 | 25 | fn LiminePtr(comptime Type: type) type { 26 | return if (config.no_pointers) u64 else Type; 27 | } 28 | 29 | const init_pointer = if (config.no_pointers) 30 | 0 31 | else 32 | null; 33 | 34 | pub const RequestsStartMarker = extern struct { 35 | marker: [4]u64 = .{ 36 | 0xf6b8f4b39de7d1ae, 37 | 0xfab91a6940fcb9cf, 38 | 0x785c6ed015d3e316, 39 | 0x181e920a7852b9d9, 40 | }, 41 | }; 42 | 43 | pub const RequestsEndMarker = extern struct { 44 | marker: [2]u64 = .{ 0xadc0e0531bb10d03, 0x9572709f31764c62 }, 45 | }; 46 | 47 | pub const BaseRevision = extern struct { 48 | magic: [2]u64 = .{ 0xf9562b2d5c95a6c8, 0x6a7b384944536bdc }, 49 | revision: u64, 50 | 51 | pub fn init(revision: u64) @This() { 52 | return .{ .revision = revision }; 53 | } 54 | 55 | pub fn loadedRevision(self: @This()) u64 { 56 | return self.magic[1]; 57 | } 58 | 59 | pub fn isValid(self: @This()) bool { 60 | return self.magic[1] != 0x6a7b384944536bdc; 61 | } 62 | 63 | pub fn isSupported(self: @This()) bool { 64 | return self.revision == 0; 65 | } 66 | }; 67 | 68 | pub const Uuid = extern struct { 69 | a: u32, 70 | b: u16, 71 | c: u16, 72 | d: [8]u8, 73 | }; 74 | 75 | pub const MediaType = enum(u32) { 76 | generic = 0, 77 | optical = 1, 78 | tftp = 2, 79 | _, 80 | }; 81 | 82 | const LimineFileV1 = extern struct { 83 | revision: u64, 84 | address: LiminePtr(*align(4096) anyopaque), 85 | size: u64, 86 | path: LiminePtr([*:0]u8), 87 | cmdline: LiminePtr([*:0]u8), 88 | media_type: MediaType, 89 | unused: u32, 90 | tftp_ip: u32, 91 | tftp_port: u32, 92 | partition_index: u32, 93 | mbr_disk_id: u32, 94 | gpt_disk_uuid: Uuid, 95 | gpt_part_uuid: Uuid, 96 | part_uuid: Uuid, 97 | }; 98 | 99 | const LimineFileV2 = extern struct { 100 | revision: u64, 101 | address: LiminePtr(*align(4096) anyopaque), 102 | size: u64, 103 | path: LiminePtr([*:0]u8), 104 | string: LiminePtr([*:0]u8), 105 | media_type: MediaType, 106 | unused: u32, 107 | tftp_ip: u32, 108 | tftp_port: u32, 109 | partition_index: u32, 110 | mbr_disk_id: u32, 111 | gpt_disk_uuid: Uuid, 112 | gpt_part_uuid: Uuid, 113 | part_uuid: Uuid, 114 | }; 115 | 116 | pub const File = if (config.api_revision >= 3) 117 | LimineFileV2 118 | else 119 | LimineFileV1; 120 | 121 | // Boot info 122 | 123 | pub const BootloaderInfoResponse = extern struct { 124 | revision: u64, 125 | name: LiminePtr([*:0]u8), 126 | version: LiminePtr([*:0]u8), 127 | }; 128 | 129 | pub const BootloaderInfoRequest = extern struct { 130 | id: [4]u64 = id(0xf55038d8e2a1202f, 0x279426fcf5f59740), 131 | revision: u64 = 0, 132 | response: LiminePtr(?*BootloaderInfoResponse) = init_pointer, 133 | }; 134 | 135 | // Executable command line 136 | 137 | pub const ExecutableCmdlineResponse = extern struct { 138 | revision: u64, 139 | cmdline: LiminePtr([*:0]u8), 140 | }; 141 | 142 | pub const ExecutableCmdlineRequest = extern struct { 143 | id: [4]u64 = id(0x4b161536e598651e, 0xb390ad4a2f1f303a), 144 | revision: u64 = 0, 145 | response: LiminePtr(?*ExecutableCmdlineResponse) = init_pointer, 146 | }; 147 | 148 | // Firmware type 149 | 150 | pub const FirmwareType = enum(u64) { 151 | x86_bios = 0, 152 | uefi32 = 1, 153 | uefi64 = 2, 154 | sbi = 3, 155 | _, 156 | }; 157 | 158 | pub const FirmwareTypeResponse = extern struct { 159 | revision: u64, 160 | firmware_type: FirmwareType, 161 | }; 162 | 163 | pub const FirmwareTypeRequest = extern struct { 164 | id: [4]u64 = id(0x8c2f75d90bef28a8, 0x7045a4688eac00c3), 165 | revision: u64 = 0, 166 | response: LiminePtr(?*FirmwareTypeResponse) = init_pointer, 167 | }; 168 | 169 | // Stack size 170 | 171 | pub const StackSizeResponse = extern struct { 172 | revision: u64, 173 | }; 174 | 175 | pub const StackSizeRequest = extern struct { 176 | id: [4]u64 = id(0x224ef0460a8e8926, 0xe1cb0fc25f46ea3d), 177 | revision: u64 = 0, 178 | response: LiminePtr(?*StackSizeResponse) = init_pointer, 179 | stack_size: u64, 180 | }; 181 | 182 | // HHDM 183 | 184 | pub const HhdmResponse = extern struct { 185 | revision: u64, 186 | offset: u64, 187 | }; 188 | 189 | pub const HhdmRequest = extern struct { 190 | id: [4]u64 = id(0x48dcf1cb8ad2b852, 0x63984e959a98244b), 191 | revision: u64 = 0, 192 | response: LiminePtr(?*HhdmResponse) = init_pointer, 193 | }; 194 | 195 | // Framebuffer 196 | 197 | pub const FramebufferMemoryModel = enum(u8) { 198 | rgb = 1, 199 | _, 200 | }; 201 | 202 | pub const VideoMode = extern struct { 203 | pitch: u64, 204 | width: u64, 205 | height: u64, 206 | bpp: u16, 207 | memory_model: FramebufferMemoryModel, 208 | red_mask_size: u8, 209 | red_mask_shift: u8, 210 | green_mask_size: u8, 211 | green_mask_shift: u8, 212 | blue_mask_size: u8, 213 | blue_mask_shift: u8, 214 | }; 215 | 216 | pub const Framebuffer = extern struct { 217 | address: LiminePtr(*anyopaque), 218 | width: u64, 219 | height: u64, 220 | pitch: u64, 221 | bpp: u16, 222 | memory_model: FramebufferMemoryModel, 223 | red_mask_size: u8, 224 | red_mask_shift: u8, 225 | green_mask_size: u8, 226 | green_mask_shift: u8, 227 | blue_mask_size: u8, 228 | blue_mask_shift: u8, 229 | edid_size: u64, 230 | edid: LiminePtr(?*anyopaque), 231 | // Response revision 1 232 | mode_count: u64, 233 | modes: LiminePtr([*]*VideoMode), 234 | 235 | /// Helper function to retrieve the EDID data as a slice. 236 | /// This function will return null if the EDID size is 0 or if 237 | /// the EDID pointer is null. 238 | pub fn getEdid(self: @This()) ?[*]u8 { 239 | if (self.edid_size == 0 or self.edid == null) { 240 | return null; 241 | } 242 | return @as([*]u8, self.edid.?)[0..self.edid_size]; 243 | } 244 | 245 | /// Helper function to retrieve a slice of the modes array. 246 | /// This function is only available since revision 1 of the response and 247 | /// will return an error if called with an older response. This is to 248 | /// prevent the user from possibly accessing uninitialized memory. 249 | pub fn getModes(self: @This(), response: *FramebufferResponse) ![]*VideoMode { 250 | if (response.revision < 1) { 251 | return error.NotSupported; 252 | } 253 | return self.modes[0..self.mode_count]; 254 | } 255 | }; 256 | 257 | pub const FramebufferResponse = extern struct { 258 | revision: u64, 259 | framebuffer_count: u64, 260 | framebuffers: LiminePtr(?[*]*Framebuffer), 261 | 262 | /// Helper function to retrieve a slice of the framebuffers array. 263 | /// This function will return null if the framebuffer count is 0 or if 264 | /// the framebuffers pointer is null. 265 | pub fn getFramebuffers(self: @This()) []*Framebuffer { 266 | if (self.framebuffer_count == 0 or self.framebuffers == null) { 267 | return &.{}; 268 | } 269 | return self.framebuffers.?[0..self.framebuffer_count]; 270 | } 271 | }; 272 | 273 | pub const FramebufferRequest = extern struct { 274 | id: [4]u64 = id(0x9d5827dcd881dd75, 0xa3148604f6fab11b), 275 | revision: u64 = 1, 276 | response: LiminePtr(?*FramebufferResponse) = init_pointer, 277 | }; 278 | 279 | // Terminal 280 | 281 | const TerminalDeprecated = struct { 282 | const deprecation_message = 283 | \\The Terminal feature was deprecated and is no longer available. 284 | \\Kernels are encouraged to manually implement terminal support 285 | \\using the Framebuffer feature instead. If you need an easy to 286 | \\integrate solution, consider using https://github.com/mintsuki/flanterm. 287 | ; 288 | 289 | pub const TerminalCallbackType = @compileError(deprecation_message); 290 | pub const TerminalCallbackEscapeParams = @compileError(deprecation_message); 291 | pub const TerminalCallbackPosReportParams = @compileError(deprecation_message); 292 | pub const TerminalCallbackKbdLedsState = @compileError(deprecation_message); 293 | pub const TerminalCallbackKbdLedsParams = @compileError(deprecation_message); 294 | pub const TerminalWrite = @compileError(deprecation_message); 295 | pub const TerminalCallback = @compileError(deprecation_message); 296 | pub const Terminal = @compileError(deprecation_message); 297 | pub const TerminalResponse = @compileError(deprecation_message); 298 | pub const TerminalRequest = @compileError(deprecation_message); 299 | }; 300 | 301 | const TerminalFeature = struct { 302 | pub const TerminalCallbackType = enum(u64) { 303 | dec = 10, 304 | bell = 20, 305 | private_id = 30, 306 | status_report = 40, 307 | pos_report = 50, 308 | kbd_leds = 60, 309 | mode = 70, 310 | linux = 80, 311 | _, 312 | }; 313 | 314 | pub const TerminalCallbackEscapeParams = struct { 315 | a1: u64, 316 | a2: u64, 317 | a3: u64, 318 | 319 | /// Initialize a TerminalCallbackEscapeParams struct, which is used for 320 | /// decoding the parameters of the terminal callbacks that handle escape sequences. 321 | pub fn init(a1: u64, a2: u64, a3: u64) @This() { 322 | return .{ .a1 = a1, .a2 = a2, .a3 = a3 }; 323 | } 324 | 325 | /// Retrieve the array of values passed to the escape sequence. 326 | pub fn values(self: @This()) []u32 { 327 | const values_ptr: [*]u32 = @intFromPtr(self.a2); 328 | return values_ptr[0..self.a1]; 329 | } 330 | 331 | /// Retrieve the final character in a DEC or ECMA-48 Mode Switch 332 | /// escape sequence. 333 | /// This is the character that is used to determine the type of 334 | /// sequence that was sent, usually 'h' or 'l'. 335 | pub fn finalChar(self: @This()) u8 { 336 | return @intCast(self.a3); 337 | } 338 | }; 339 | 340 | pub const TerminalCallbackPosReportParams = struct { 341 | a1: u64, 342 | a2: u64, 343 | 344 | /// Initialize a TerminalCallbackPosReportParams struct, which is used for 345 | /// decoding the parameters of a position report terminal callback. 346 | pub fn init(a1: u64, a2: u64) @This() { 347 | return .{ .a1 = a1, .a2 = a2 }; 348 | } 349 | 350 | /// Retrieve the X position of the cursor. 351 | pub fn x(self: @This()) u64 { 352 | return self.a1; 353 | } 354 | 355 | /// Retrieve the Y position of the cursor. 356 | pub fn y(self: @This()) u64 { 357 | return self.a2; 358 | } 359 | }; 360 | 361 | pub const TerminalCallbackKbdLedsState = enum(u64) { 362 | clear_all = 0, 363 | set_scroll_lock = 1, 364 | set_num_lock = 2, 365 | set_caps_lock = 3, 366 | _, 367 | }; 368 | 369 | pub const TerminalCallbackKbdLedsParams = struct { 370 | a1: u64, 371 | 372 | /// Initialize a TerminalCallbackKbdLedsParams struct, which is used for 373 | /// decoding the parameters of a keyboard LEDs terminal callback. 374 | pub fn init(a1: u64) @This() { 375 | return .{ .a1 = a1 }; 376 | } 377 | 378 | /// Retrieve the state of the Caps Lock LED. 379 | pub fn state(self: @This()) TerminalCallbackKbdLedsState { 380 | return @enumFromInt(self.a1); 381 | } 382 | }; 383 | 384 | pub const TerminalWrite = *const fn (*Terminal, [*]const u8, u64) callconv(.c) void; 385 | 386 | pub const TerminalCallback = *const fn (*Terminal, TerminalCallbackType, u64, u64, u64) callconv(.c) void; 387 | 388 | pub const Terminal = extern struct { 389 | columns: u64, 390 | rows: u64, 391 | framebuffer: LiminePtr(?*Framebuffer), 392 | }; 393 | 394 | pub const TerminalResponse = extern struct { 395 | revision: u64, 396 | terminal_count: u64, 397 | terminals: LiminePtr(?[*]*Terminal), 398 | write_fn: LiminePtr(TerminalWrite), 399 | 400 | /// Helper function to retrieve a slice of the terminals array. 401 | /// This function will return null if the terminal count is 0 or if 402 | /// the terminals pointer is null. 403 | pub fn getTerminals(self: @This()) []*Terminal { 404 | if (self.terminal_count == 0 or self.terminals == null) { 405 | return &.{}; 406 | } 407 | return self.terminals.?[0..self.terminal_count]; 408 | } 409 | 410 | /// Helper function to write to a terminal. 411 | pub fn write(self: @This(), terminal: *Terminal, data: []const u8) void { 412 | const write_fn: TerminalWrite = if (config.no_pointers) 413 | @ptrFromInt(self.write_fn) 414 | else 415 | self.write_fn; 416 | 417 | write_fn(terminal, data.ptr, data.len); 418 | } 419 | }; 420 | 421 | pub const TerminalRequest = extern struct { 422 | id: [4]u64 = id(0xc8ac59310c2b0844, 0xa68d0c7265d38878), 423 | revision: u64 = 0, 424 | response: LiminePtr(?*TerminalResponse) = init_pointer, 425 | callback: LiminePtr(?TerminalCallback), 426 | }; 427 | }; 428 | 429 | pub usingnamespace if (config.allow_deprecated) 430 | TerminalFeature 431 | else 432 | TerminalDeprecated; 433 | 434 | // Paging mode 435 | 436 | pub const PagingMode = switch (arch) { 437 | .x86_64 => enum(u64) { 438 | @"4lvl", 439 | @"5lvl", 440 | _, 441 | 442 | const min: @This() = .@"4lvl"; 443 | const max: @This() = .@"5lvl"; 444 | const default: @This() = .@"4lvl"; 445 | }, 446 | .aarch64 => enum(u64) { 447 | @"4lvl", 448 | @"5lvl", 449 | _, 450 | 451 | const min: @This() = .@"4lvl"; 452 | const max: @This() = .@"5lvl"; 453 | const default: @This() = .@"4lvl"; 454 | }, 455 | .riscv64 => enum(u64) { 456 | sv39, 457 | sv48, 458 | sv57, 459 | _, 460 | 461 | const min: @This() = .sv39; 462 | const max: @This() = .sv57; 463 | const default: @This() = .sv48; 464 | }, 465 | .loongarch64 => enum(u64) { 466 | @"4lvl", 467 | _, 468 | 469 | const min: @This() = .@"4lvl"; 470 | const max: @This() = .@"4lvl"; 471 | const default: @This() = .@"4lvl"; 472 | }, 473 | }; 474 | 475 | pub const PagingModeResponse = extern struct { 476 | revision: u64, 477 | mode: PagingMode, 478 | }; 479 | 480 | pub const PagingModeRequest = extern struct { 481 | id: [4]u64 = id(0x95c1a0edab0944cb, 0xa4e5cb3842f7488a), 482 | revision: u64 = 0, 483 | response: LiminePtr(?*PagingModeResponse) = init_pointer, 484 | mode: PagingMode = .default, 485 | max_mode: PagingMode = .max, 486 | min_mode: PagingMode = .min, 487 | }; 488 | 489 | // 5-level paging 490 | 491 | const FiveLevelPagingDeprecated = struct { 492 | const deprecation_message = 493 | \\The 5-level paging feature was deprecated and is no longer available. 494 | \\Kernels are encouraged to manually request 5-level paging support 495 | \\using the Paging mode feature instead. 496 | ; 497 | 498 | pub const FiveLevelPagingResponse = @compileError(deprecation_message); 499 | pub const FiveLevelPagingRequest = @compileError(deprecation_message); 500 | }; 501 | 502 | const FiveLevelPagingFeature = struct { 503 | pub const FiveLevelPagingResponse = extern struct { 504 | revision: u64, 505 | }; 506 | 507 | pub const FiveLevelPagingRequest = extern struct { 508 | id: [4]u64 = id(0x94469551da9b3192, 0xebe5e86db7382888), 509 | revision: u64 = 0, 510 | response: LiminePtr(?*FiveLevelPagingResponse) = init_pointer, 511 | }; 512 | }; 513 | 514 | pub usingnamespace if (config.allow_deprecated) 515 | FiveLevelPagingFeature 516 | else 517 | FiveLevelPagingDeprecated; 518 | 519 | // MP (formerly SMP) 520 | 521 | pub const GotoAddress = *const fn (*SmpMpInfo) callconv(.c) noreturn; 522 | 523 | const SmpMpFlags = switch (arch) { 524 | .x86_64 => packed struct(u32) { 525 | x2apic: bool = false, 526 | reserved: u31 = 0, 527 | }, 528 | .aarch64, .riscv64, .loongarch64 => packed struct(u64) { 529 | reserved: u64 = 0, 530 | }, 531 | }; 532 | 533 | const SmpMpInfo = switch (arch) { 534 | .x86_64 => extern struct { 535 | processor_id: u32, 536 | lapic_id: u32, 537 | reserved: u64, 538 | goto_address: LiminePtr(?GotoAddress), 539 | extra_argument: u64, 540 | }, 541 | .aarch64 => extern struct { 542 | processor_id: u32, 543 | mpidr: u64, 544 | reserved: u64, 545 | goto_address: LiminePtr(?GotoAddress), 546 | extra_argument: u64, 547 | }, 548 | .riscv64 => extern struct { 549 | processor_id: u64, 550 | hartid: u64, 551 | reserved: u64, 552 | goto_address: LiminePtr(?GotoAddress), 553 | extra_argument: u64, 554 | }, 555 | .loongarch64 => extern struct { 556 | reserved: u64, 557 | }, 558 | }; 559 | 560 | const SmpMpResponse = switch (arch) { 561 | .x86_64 => extern struct { 562 | revision: u64, 563 | flags: SmpMpFlags, 564 | bsp_lapic_id: u32, 565 | cpu_count: u64, 566 | cpus: LiminePtr(?[*]*SmpMpInfo), 567 | 568 | /// Helper function to retrieve a slice of the CPUs array. 569 | /// This function will return null if the CPU count is 0 or if 570 | /// the CPUs pointer is null. 571 | pub fn getCpus(self: @This()) []*SmpMpInfo { 572 | if (self.cpu_count == 0 or self.cpus == null) { 573 | return &.{}; 574 | } 575 | return self.cpus.?[0..self.cpu_count]; 576 | } 577 | }, 578 | .aarch64 => extern struct { 579 | revision: u64, 580 | flags: SmpMpFlags, 581 | bsp_mpidr: u64, 582 | cpu_count: u64, 583 | cpus: LiminePtr(?[*]*SmpMpInfo), 584 | 585 | /// Helper function to retrieve a slice of the CPUs array. 586 | /// This function will return null if the CPU count is 0 or if 587 | /// the CPUs pointer is null. 588 | pub fn getCpus(self: @This()) []*SmpMpInfo { 589 | if (self.cpu_count == 0 or self.cpus == null) { 590 | return &.{}; 591 | } 592 | return self.cpus.?[0..self.cpu_count]; 593 | } 594 | }, 595 | .riscv64 => extern struct { 596 | revision: u64, 597 | flags: SmpMpFlags, 598 | bsp_hartid: u64, 599 | cpu_count: u64, 600 | cpus: LiminePtr(?[*]*SmpMpInfo), 601 | 602 | /// Helper function to retrieve a slice of the CPUs array. 603 | /// This function will return null if the CPU count is 0 or if 604 | /// the CPUs pointer is null. 605 | pub fn getCpus(self: @This()) []*SmpMpInfo { 606 | if (self.cpu_count == 0 or self.cpus == null) { 607 | return &.{}; 608 | } 609 | return self.cpus.?[0..self.cpu_count]; 610 | } 611 | }, 612 | .loongarch64 => extern struct { 613 | cpu_count: u64, 614 | cpus: LiminePtr(?[*]*SmpMpInfo), 615 | 616 | /// Helper function to retrieve a slice of the CPUs array. 617 | /// This function will return null if the CPU count is 0 or if 618 | /// the CPUs pointer is null. 619 | pub fn getCpus(self: @This()) []*SmpMpInfo { 620 | if (self.cpu_count == 0 or self.cpus == null) { 621 | return &.{}; 622 | } 623 | return self.cpus.?[0..self.cpu_count]; 624 | } 625 | }, 626 | }; 627 | 628 | const SmpMpRequest = extern struct { 629 | id: [4]u64 = id(0x95a67b819a1b857e, 0xa0b61b723b6a73e0), 630 | revision: u64 = 0, 631 | response: LiminePtr(?*SmpMpResponse) = init_pointer, 632 | // The `flags` field in the request is 64-bit on *all* platforms, even 633 | // though the flags enum is 32-bit on x86_64. This is to ensure that the 634 | // struct is not too small on x86_64 there is a `reserved: u32` field after it. 635 | flags: SmpMpFlags = .{}, 636 | reserved: u32 = 0, 637 | }; 638 | 639 | const MpFeature = struct { 640 | pub const MpFlags = SmpMpFlags; 641 | pub const MpInfo = SmpMpInfo; 642 | pub const MpResponse = SmpMpResponse; 643 | pub const MpRequest = SmpMpRequest; 644 | }; 645 | 646 | const SmpFeature = struct { 647 | pub const SmpFlags = SmpMpFlags; 648 | pub const SmpInfo = SmpMpInfo; 649 | pub const SmpResponse = SmpMpResponse; 650 | pub const SmpRequest = SmpMpRequest; 651 | }; 652 | 653 | pub usingnamespace if (config.api_revision >= 1) 654 | MpFeature 655 | else 656 | SmpFeature; 657 | 658 | // Memory map 659 | 660 | const MemoryMapTypeV1 = enum(u64) { 661 | usable = 0, 662 | reserved = 1, 663 | acpi_reclaimable = 2, 664 | acpi_nvs = 3, 665 | bad_memory = 4, 666 | bootloader_reclaimable = 5, 667 | kernel_and_modules = 6, 668 | framebuffer = 7, 669 | _, 670 | }; 671 | 672 | const MemoryMapTypeV2 = enum(u64) { 673 | usable = 0, 674 | reserved = 1, 675 | acpi_reclaimable = 2, 676 | acpi_nvs = 3, 677 | bad_memory = 4, 678 | bootloader_reclaimable = 5, 679 | executable_and_modules = 6, 680 | framebuffer = 7, 681 | _, 682 | }; 683 | 684 | pub const MemoryMapType = if (config.api_revision >= 2) 685 | MemoryMapTypeV2 686 | else 687 | MemoryMapTypeV1; 688 | 689 | pub const MemoryMapEntry = extern struct { 690 | base: u64, 691 | length: u64, 692 | type: MemoryMapType, 693 | }; 694 | 695 | pub const MemoryMapResponse = extern struct { 696 | revision: u64, 697 | entry_count: u64, 698 | entries: LiminePtr(?[*]*MemoryMapEntry), 699 | 700 | /// Helper function to retrieve a slice of the entries array. 701 | /// This function will return null if the entry count is 0 or if 702 | /// the entries pointer is null. 703 | pub fn getEntries(self: @This()) []*MemoryMapEntry { 704 | if (self.entry_count == 0 or self.entries == null) { 705 | return &.{}; 706 | } 707 | return self.entries.?[0..self.entry_count]; 708 | } 709 | }; 710 | 711 | pub const MemoryMapRequest = extern struct { 712 | id: [4]u64 = id(0x67cf3d9d378a806f, 0xe304acdfc50c3c62), 713 | revision: u64 = 0, 714 | response: LiminePtr(?*MemoryMapResponse) = init_pointer, 715 | }; 716 | 717 | // Entry point 718 | 719 | pub const EntryPoint = *const fn () callconv(.c) noreturn; 720 | 721 | pub const EntryPointResponse = extern struct { 722 | revision: u64, 723 | }; 724 | 725 | pub const EntryPointRequest = extern struct { 726 | id: [4]u64 = id(0x13d86c035a1cd3e1, 0x2b0caa89d8f3026a), 727 | revision: u64 = 0, 728 | response: LiminePtr(?*EntryPointResponse) = init_pointer, 729 | entry: LiminePtr(EntryPoint), 730 | }; 731 | 732 | // Executable file (formerly Kernel file) 733 | 734 | const ExecutableFileFeature = struct { 735 | pub const ExecutableFileResponse = extern struct { 736 | revision: u64, 737 | executable_file: LiminePtr(*File), 738 | }; 739 | 740 | pub const ExecutableFileRequest = extern struct { 741 | id: [4]u64 = id(0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69), 742 | revision: u64 = 0, 743 | response: LiminePtr(?*ExecutableFileResponse) = init_pointer, 744 | }; 745 | }; 746 | 747 | const KernelFileFeature = struct { 748 | pub const KernelFileResponse = extern struct { 749 | revision: u64, 750 | kernel_file: LiminePtr(*File), 751 | }; 752 | 753 | pub const KernelFileRequest = extern struct { 754 | id: [4]u64 = id(0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69), 755 | revision: u64 = 0, 756 | response: LiminePtr(?*KernelFileResponse) = init_pointer, 757 | }; 758 | }; 759 | 760 | pub usingnamespace if (config.api_revision >= 2) 761 | ExecutableFileFeature 762 | else 763 | KernelFileFeature; 764 | 765 | // Module 766 | 767 | pub const InternalModuleFlag = packed struct(u64) { 768 | required: bool, 769 | compressed: bool, 770 | reserved: u62 = 0, 771 | }; 772 | 773 | const InternalModuleV1 = extern struct { 774 | path: LiminePtr([*:0]const u8), 775 | cmdline: LiminePtr([*:0]const u8), 776 | flags: InternalModuleFlag, 777 | }; 778 | 779 | const InternalModuleV2 = extern struct { 780 | path: LiminePtr([*:0]const u8), 781 | string: LiminePtr([*:0]const u8), 782 | flags: InternalModuleFlag, 783 | }; 784 | 785 | pub const InternalModule = if (config.api_revision >= 3) 786 | InternalModuleV2 787 | else 788 | InternalModuleV1; 789 | 790 | pub const ModuleResponse = extern struct { 791 | revision: u64, 792 | module_count: u64, 793 | modules: LiminePtr(?[*]*File), 794 | 795 | /// Helper function to retrieve a slice of the modules array. 796 | /// This function will return null if the module count is 0 or if 797 | /// the modules pointer is null. 798 | pub fn getModules(self: @This()) []*File { 799 | if (self.module_count == 0 or self.modules == null) { 800 | return &.{}; 801 | } 802 | return self.modules.?[0..self.module_count]; 803 | } 804 | }; 805 | 806 | pub const ModuleRequest = extern struct { 807 | id: [4]u64 = id(0x3e7e279702be32af, 0xca1c4f3bd1280cee), 808 | revision: u64 = 1, 809 | response: LiminePtr(?*ModuleResponse) = init_pointer, 810 | // Request revision 1 811 | internal_module_count: u64 = 0, 812 | internal_modules: LiminePtr(?[*]const *const InternalModule) = 813 | if (config.no_pointers) 0 else null, 814 | }; 815 | 816 | // RSDP 817 | 818 | const RsdpResponseV1 = extern struct { 819 | revision: u64, 820 | address: LiminePtr(*anyopaque), 821 | }; 822 | 823 | const RsdpResponseV2 = extern struct { 824 | revision: u64, 825 | address: u64, 826 | }; 827 | 828 | /// The response to the RSDP request. If the base revision is 1 or higher, 829 | /// the response will contain physical addresses to the RSDP, otherwise 830 | /// the response will contain virtual addresses to the RSDP. 831 | pub const RsdpResponse = if (config.api_revision >= 1) 832 | RsdpResponseV2 833 | else 834 | RsdpResponseV1; 835 | 836 | pub const RsdpRequest = extern struct { 837 | id: [4]u64 = id(0xc5e77b6b397e7b43, 0x27637845accdcf3c), 838 | revision: u64 = 0, 839 | response: LiminePtr(?*RsdpResponse) = init_pointer, 840 | }; 841 | 842 | // SMBIOS 843 | 844 | const SmBiosResponseV1 = extern struct { 845 | revision: u64, 846 | entry_32: LiminePtr(?*anyopaque), 847 | entry_64: LiminePtr(?*anyopaque), 848 | }; 849 | 850 | const SmBiosResponseV2 = extern struct { 851 | revision: u64, 852 | entry_32: u64, 853 | entry_64: u64, 854 | }; 855 | 856 | /// The response to the SMBIOS request. If the base revision is 3 or higher, 857 | /// the response will contain physical addresses to the SMBIOS entries, otherwise 858 | /// the response will contain virtual addresses to the SMBIOS entries. 859 | pub const SmBiosResponse = if (config.api_revision >= 1) 860 | SmBiosResponseV2 861 | else 862 | SmBiosResponseV1; 863 | 864 | pub const SmBiosRequest = extern struct { 865 | id: [4]u64 = id(0x9e9046f11e095391, 0xaa4a520fefbde5ee), 866 | revision: u64 = 0, 867 | response: LiminePtr(?*SmBiosResponse) = init_pointer, 868 | }; 869 | 870 | // EFI system table 871 | 872 | /// 873 | const EfiSystemTableResponseV1 = extern struct { 874 | revision: u64, 875 | address: LiminePtr(?*std.os.uefi.tables.SystemTable), 876 | }; 877 | 878 | const EfiSystemTableResponseV2 = extern struct { 879 | revision: u64, 880 | address: u64, 881 | }; 882 | 883 | /// The response to the EFI system table request. If the base revision is 3 884 | /// or higher, the response will contain a physical address to the system table, 885 | /// otherwise the response will contain a virtual address to the system table. 886 | pub const EfiSystemTableResponse = if (config.api_revision >= 1) 887 | EfiSystemTableResponseV2 888 | else 889 | EfiSystemTableResponseV1; 890 | 891 | pub const EfiSystemTableRequest = extern struct { 892 | id: [4]u64 = id(0x5ceba5163eaaf6d6, 0x0a6981610cf65fcc), 893 | revision: u64 = 0, 894 | response: LiminePtr(?*EfiSystemTableResponse) = init_pointer, 895 | }; 896 | 897 | // EFI memory map 898 | 899 | pub const EfiMemoryMapResponse = extern struct { 900 | revision: u64, 901 | memmap: LiminePtr(*anyopaque), 902 | memmap_size: u64, 903 | desc_size: u64, 904 | desc_version: u64, 905 | }; 906 | 907 | pub const EfiMemoryMapRequest = extern struct { 908 | id: [4]u64 = id(0x7df62a431d6872d5, 0xa4fcdfb3e57306c8), 909 | revision: u64 = 0, 910 | response: LiminePtr(?*EfiMemoryMapResponse) = init_pointer, 911 | }; 912 | 913 | // Date at boot (formerly Boot time) 914 | 915 | const DateAtBootFeature = struct { 916 | pub const DateAtBootResponse = extern struct { 917 | revision: u64, 918 | timestamp: i64, 919 | }; 920 | 921 | pub const DateAtBootRequest = extern struct { 922 | id: [4]u64 = id(0x502746e184c088aa, 0xfbc5ec83e6327893), 923 | revision: u64 = 0, 924 | response: LiminePtr(?*DateAtBootResponse) = init_pointer, 925 | }; 926 | }; 927 | 928 | const BootTimeFeature = struct { 929 | pub const BootTimeResponse = extern struct { 930 | revision: u64, 931 | boot_time: i64, 932 | }; 933 | 934 | pub const BootTimeRequest = extern struct { 935 | id: [4]u64 = id(0x502746e184c088aa, 0xfbc5ec83e6327893), 936 | revision: u64 = 0, 937 | response: LiminePtr(?*BootTimeResponse) = init_pointer, 938 | }; 939 | }; 940 | 941 | pub usingnamespace if (config.api_revision >= 3) 942 | DateAtBootFeature 943 | else 944 | BootTimeFeature; 945 | 946 | // Executable address (formerly Kernel address) 947 | 948 | const ExecutableAddressFeature = struct { 949 | pub const ExecutableAddressResponse = extern struct { 950 | revision: u64, 951 | physical_base: u64, 952 | virtual_base: u64, 953 | }; 954 | 955 | pub const ExecutableAddressRequest = extern struct { 956 | id: [4]u64 = id(0x71ba76863cc55f63, 0xb2644a48c516a487), 957 | revision: u64 = 0, 958 | response: LiminePtr(?*ExecutableAddressResponse) = init_pointer, 959 | }; 960 | }; 961 | 962 | const KernelAddressFeature = struct { 963 | pub const KernelAddressResponse = extern struct { 964 | revision: u64, 965 | physical_base: u64, 966 | virtual_base: u64, 967 | }; 968 | 969 | pub const KernelAddressRequest = extern struct { 970 | id: [4]u64 = id(0x71ba76863cc55f63, 0xb2644a48c516a487), 971 | revision: u64 = 0, 972 | response: LiminePtr(?*KernelAddressResponse) = init_pointer, 973 | }; 974 | }; 975 | 976 | pub usingnamespace if (config.api_revision >= 2) 977 | ExecutableAddressFeature 978 | else 979 | KernelAddressFeature; 980 | 981 | // Device Tree Blob 982 | 983 | pub const DtbResponse = extern struct { 984 | revision: u64, 985 | dtb_ptr: LiminePtr(*anyopaque), 986 | }; 987 | 988 | pub const DtbRequest = extern struct { 989 | id: [4]u64 = id(0xb40ddb48fb54bac7, 0x545081493f81ffb7), 990 | revision: u64 = 0, 991 | response: LiminePtr(?*DtbResponse) = init_pointer, 992 | }; 993 | 994 | // RISC-V Boot Hart ID 995 | 996 | pub const RiscvBootHartIdResponse = extern struct { 997 | revision: u64, 998 | bsp_hartid: u64, 999 | }; 1000 | 1001 | pub const RiscvBootHartIdRequest = extern struct { 1002 | id: [4]u64 = id(0x1369359f025525f9, 0x2ff2a56178391bb6), 1003 | revision: u64 = 0, 1004 | response: LiminePtr(?*RiscvBootHartIdResponse) = init_pointer, 1005 | }; 1006 | 1007 | comptime { 1008 | if (config.api_revision > 3) { 1009 | @compileError("Limine API revision must be 3 or lower"); 1010 | } 1011 | 1012 | std.testing.refAllDeclsRecursive(@This()); 1013 | } 1014 | --------------------------------------------------------------------------------