summaryrefslogtreecommitdiffstats
path: root/rsnix/src/uefi.rs
blob: 234ad65cf95345a7f74e79fe064f4a9ab92f9a82 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
use core::ffi::c_void;

/// Opaque EFI handle
pub type Handle = *mut c_void;

/// EFI status (0 = success, bit 63 = error code)
pub type Status = u64;

/// Helper: UEFI error codes always have bit 63 set
const fn efi_err(n: u64) -> u64 {
    n | (1u64 << 63)
}

pub const EFI_SUCCESS: Status = 0;
pub const EFI_LOAD_ERROR: Status = efi_err(1);
pub const EFI_INVALID_PARAMETER: Status = efi_err(2);
#[allow(dead_code)]
pub const EFI_UNSUPPORTED: Status = efi_err(3);
pub const EFI_BUFFER_TOO_SMALL: Status = efi_err(5);
#[allow(dead_code)]
pub const EFI_NOT_FOUND: Status = efi_err(14);
pub const EFI_OUT_OF_RESOURCES: Status = efi_err(9);

// ---------------------------------------------------------------------------
// GUID
// ---------------------------------------------------------------------------
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Guid {
    pub a: u32,
    pub b: u16,
    pub c: u16,
    pub d: [u8; 8],
}

pub const EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID: Guid = Guid {
    a: 0x9042a9de,
    b: 0x23dc,
    c: 0x4a38,
    d: [0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a],
};

pub const EFI_LOADED_IMAGE_PROTOCOL_GUID: Guid = Guid {
    a: 0x5b1b31a1,
    b: 0x9562,
    c: 0x11d2,
    d: [0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b],
};

/// Minimal EFI_LOADED_IMAGE_PROTOCOL — we only need the image base/size
/// to reserve the kernel's own code/data/bss pages so the heap and page
/// allocators can never overwrite the running kernel.
#[repr(C)]
pub struct LoadedImageProtocol {
    pub revision: u32,
    _pad0: u32,
    pub parent_handle: Handle,
    pub system_table: *mut core::ffi::c_void,
    pub device_handle: Handle,
    pub file_path: *mut core::ffi::c_void,
    _reserved: *mut core::ffi::c_void,
    pub load_options_size: u32,
    _pad1: u32,
    pub load_options: *mut core::ffi::c_void,
    pub image_base: *mut core::ffi::c_void,
    pub image_size: u64,
}

// ---------------------------------------------------------------------------
// Table header
// ---------------------------------------------------------------------------
#[repr(C)]
pub struct TableHeader {
    pub signature: u64,
    pub revision: u32,
    pub header_size: u32,
    pub crc32: u32,
    pub reserved: u32,
}

// ---------------------------------------------------------------------------
// Simple text output protocol (console output)
// ---------------------------------------------------------------------------
#[repr(C)]
pub struct SimpleTextOutput {
    _reset: *mut c_void,
    pub output_string: unsafe extern "efiapi" fn(*mut SimpleTextOutput, *const u16) -> Status,
    _test_string: *mut c_void,
    _query_mode: *mut c_void,
    _set_mode: *mut c_void,
    _set_attribute: *mut c_void,
    _clear_screen: *mut c_void,
    _set_cursor_position: *mut c_void,
    _enable_cursor: *mut c_void,
    _mode: *mut c_void,
}

// ---------------------------------------------------------------------------
// Simple text input protocol (keyboard input)
// ---------------------------------------------------------------------------
#[repr(C)]
pub struct InputKey {
    pub scan_code: u16,
    pub unicode_char: u16,
}

#[repr(C)]
pub struct SimpleTextInput {
    _reset: *mut c_void,
    pub read_key_stroke: unsafe extern "efiapi" fn(*mut SimpleTextInput, *mut InputKey) -> Status,
    _wait_for_key: Handle,
}

// ---------------------------------------------------------------------------
// Runtime services
// ---------------------------------------------------------------------------

/// `EFI_RESET_SYSTEM` — ResetType, ResetStatus, DataSize, ResetData.
/// ResetType: 0 cold, 1 warm, 2 shutdown, 3 platform-specific.
pub type EfiResetSystem = unsafe extern "efiapi" fn(u32, u64, usize, *const u16) -> Status;

pub const RESET_COLD: u32 = 0;
#[allow(dead_code)]
pub const RESET_WARM: u32 = 1;
pub const RESET_SHUTDOWN: u32 = 2;
#[allow(dead_code)]
pub const RESET_PLATFORM_SPECIFIC: u32 = 3;

/// EFI_RUNTIME_SERVICES — function pointers in spec order after the header.
/// We only use ResetSystem; the rest stay opaque.  The table remains
/// callable after ExitBootServices because we never call SetVirtualAddressMap,
/// so the pointers keep working with physical (identity) addresses.
#[repr(C)]
pub struct RuntimeServices {
    _hdr: TableHeader,
    _get_time: *mut c_void,                      // 0
    _set_time: *mut c_void,                      // 1
    _get_wakeup_time: *mut c_void,               // 2
    _set_wakeup_time: *mut c_void,               // 3
    _set_virtual_address_map: *mut c_void,       // 4
    _convert_pointer: *mut c_void,               // 5
    _get_variable: *mut c_void,                  // 6
    _get_next_variable_name: *mut c_void,        // 7
    _set_variable: *mut c_void,                  // 8
    _get_next_high_monotonic_count: *mut c_void, // 9
    pub reset_system: EfiResetSystem,            // 10
    _update_capsule: *mut c_void,                // 11
    _query_capsule_capabilities: *mut c_void,    // 12
    _query_variable_info: *mut c_void,           // 13
}

// ---------------------------------------------------------------------------
// Configuration table entry
// ---------------------------------------------------------------------------
#[repr(C)]
pub struct ConfigurationTable {
    pub vendor_guid: Guid,
    pub vendor_table: *mut c_void,
}

// ---------------------------------------------------------------------------
/// UEFI memory descriptor (from GetMemoryMap)
// ---------------------------------------------------------------------------
#[repr(C)]
pub struct MemoryDescriptor {
    pub kind: u32,
    pub pad: u32,
    pub physical_start: u64,
    pub virtual_start: u64,
    pub number_of_pages: u64,
    pub attribute: u64,
}

pub const MEMORY_TYPE_RESERVED: u32 = 0;
pub const MEMORY_TYPE_LOADER_CODE: u32 = 1;
pub const MEMORY_TYPE_LOADER_DATA: u32 = 2;
pub const MEMORY_TYPE_BOOT_SERVICES_CODE: u32 = 3;
pub const MEMORY_TYPE_BOOT_SERVICES_DATA: u32 = 4;
pub const MEMORY_TYPE_RUNTIME_CODE: u32 = 5;
pub const MEMORY_TYPE_RUNTIME_DATA: u32 = 6;
pub const MEMORY_TYPE_CONVENTIONAL: u32 = 7;
pub const MEMORY_TYPE_UNUSABLE: u32 = 8;
pub const MEMORY_TYPE_ACPI_RECLAIM: u32 = 9;
pub const MEMORY_TYPE_ACPI_NVS: u32 = 10;
pub const MEMORY_TYPE_MMIO: u32 = 11;
pub const MEMORY_TYPE_MMIO_PORT: u32 = 12;
pub const MEMORY_TYPE_PAL_CODE: u32 = 13;
pub const MEMORY_TYPE_PERSISTENT: u32 = 14;

/// Human-readable name for a UEFI memory type.
pub fn memory_type_name(kind: u32) -> &'static str {
    match kind {
        0 => "Reserved",
        1 => "LoaderCode",
        2 => "LoaderData",
        3 => "BootServicesCode",
        4 => "BootServicesData",
        5 => "RuntimeCode",
        6 => "RuntimeData",
        7 => "Conventional",
        8 => "Unusable",
        9 => "ACPIReclaim",
        10 => "ACPINVS",
        11 => "MMIO",
        12 => "MMIOPort",
        13 => "PalCode",
        14 => "Persistent",
        _ => "Unknown",
    }
}

// ---------------------------------------------------------------------------
// Boot services table
// ---------------------------------------------------------------------------
pub type EfiGetMemoryMap = unsafe extern "efiapi" fn(
    *mut usize,
    *mut MemoryDescriptor,
    *mut usize,
    *mut usize,
    *mut u32,
) -> Status;

pub type EfiExitBootServices = unsafe extern "efiapi" fn(Handle, usize) -> Status;

pub type EfiHandleProtocol =
    unsafe extern "efiapi" fn(Handle, *const Guid, *mut *mut c_void) -> Status;

pub type EfiLocateProtocol =
    unsafe extern "efiapi" fn(*const Guid, *mut c_void, *mut *mut c_void) -> Status;

pub type EfiAllocatePool = unsafe extern "efiapi" fn(u8, usize, *mut *mut c_void) -> Status;

pub type EfiFreePool = unsafe extern "efiapi" fn(*mut c_void) -> Status;

pub type EfiStall = unsafe extern "efiapi" fn(usize) -> Status;

#[repr(C)]
pub struct BootServices {
    pub hdr: TableHeader,

    // 0-1: task priority
    pub raise_tpl: *mut c_void,
    pub restore_tpl: *mut c_void,

    // 2-3: memory allocation
    pub allocate_pages: *mut c_void,
    pub free_pages: *mut c_void,

    // 4: GetMemoryMap
    pub get_memory_map: EfiGetMemoryMap,

    // 5-6: pool
    pub allocate_pool: EfiAllocatePool,
    pub free_pool: EfiFreePool,

    // 7-12: events
    pub create_event: *mut c_void,
    pub set_timer: *mut c_void,
    pub wait_for_event: *mut c_void,
    pub signal_event: *mut c_void,
    pub close_event: *mut c_void,
    pub check_event: *mut c_void,

    // 13-14: protocol install
    pub install_protocol_interface: *mut c_void,
    pub reinstall_protocol_interface: *mut c_void,
    pub uninstall_protocol_interface: *mut c_void,

    // 16: HandleProtocol
    pub handle_protocol: EfiHandleProtocol,

    pub _reserved: *mut c_void,

    // 18: register protocol notify
    pub register_protocol_notify: *mut c_void,

    // 19-21: locate
    pub locate_handle: *mut c_void,
    pub locate_device_path: *mut c_void,
    pub install_configuration_table: *mut c_void,

    // 22-23: image loading
    pub load_image: *mut c_void,
    pub start_image: *mut c_void,

    // 24-25
    pub exit: *mut c_void,
    pub unload_image: *mut c_void,

    // 26: ExitBootServices
    pub exit_boot_services: EfiExitBootServices,

    // 27-29
    pub get_next_monotonic_count: *mut c_void,
    pub stall: EfiStall,
    pub set_watchdog_timer: *mut c_void,

    // 30-36
    pub connect_controller: *mut c_void,
    pub disconnect_controller: *mut c_void,
    pub open_protocol: *mut c_void,
    pub close_protocol: *mut c_void,
    pub open_protocol_information: *mut c_void,
    pub protocols_per_handle: *mut c_void,
    pub locate_handle_buffer: *mut c_void,

    // 37: LocateProtocol
    pub locate_protocol: EfiLocateProtocol,

    // 38-43
    pub install_multiple_protocol_interfaces: *mut c_void,
    pub uninstall_multiple_protocol_interfaces: *mut c_void,
    pub calculate_crc32: *mut c_void,
    pub copy_mem: *mut c_void,
    pub set_mem: *mut c_void,
    pub create_event_ex: *mut c_void,
}

// ---------------------------------------------------------------------------
// Graphics Output Protocol (GOP)
// ---------------------------------------------------------------------------
#[repr(C)]
pub struct GopModeInfo {
    pub version: u32,
    pub horizontal_resolution: u32,
    pub vertical_resolution: u32,
    pub pixel_format: u32, // PixelFormat enum
    pub red_mask: u32,
    pub green_mask: u32,
    pub blue_mask: u32,
    pub reserved_mask: u32,
    pub pixels_per_scan_line: u32,
}

pub const PIXEL_RGB: u32 = 0;
pub const PIXEL_BGR: u32 = 1;

#[repr(C)]
pub struct GopMode {
    pub max_mode: u32,
    pub mode: u32,
    pub info: *mut GopModeInfo,
    pub info_size: usize,
    pub framebuffer_base: *mut c_void,
    pub framebuffer_size: usize,
}

#[repr(C)]
pub struct GraphicsOutputProtocol {
    pub query_mode: EfiGopQueryMode,
    pub set_mode: EfiGopSetMode,
    pub get_current_mode: EfiGopGetMode,
    pub mode: *mut GopMode,
}

pub type EfiGopQueryMode = unsafe extern "efiapi" fn(
    *mut GraphicsOutputProtocol,
    u32,                   // mode number
    *mut usize,            // out: size of info
    *mut *mut GopModeInfo, // out: info pointer (firmware-owned)
) -> Status;

pub type EfiGopSetMode = unsafe extern "efiapi" fn(*mut GraphicsOutputProtocol, u32) -> Status;

pub type EfiGopGetMode = unsafe extern "efiapi" fn(
    *mut GraphicsOutputProtocol,
    *mut u32,              // out: current mode
    *mut u32,              // out: size of info
    *mut *mut GopModeInfo, // out: info pointer
) -> Status;

// ---------------------------------------------------------------------------
// System table
// ---------------------------------------------------------------------------
#[repr(C)]
pub struct SystemTable {
    pub hdr: TableHeader,
    pub firmware_vendor: *const u16,
    pub firmware_revision: u32,
    pub console_in_handle: Handle,
    pub con_in: *mut SimpleTextInput,
    pub console_out_handle: Handle,
    pub con_out: *mut SimpleTextOutput,
    pub stderr_handle: Handle,
    pub std_err: *mut SimpleTextOutput,
    pub runtime_services: *mut RuntimeServices,
    pub boot_services: *mut BootServices,
    pub number_of_table_entries: usize,
    pub configuration_table: *const ConfigurationTable,
}