:: limine / test / limine.c 27.4 KB raw

1
#include <stdint.h>
2
#include <stddef.h>
3
#include <stdbool.h>
4
#include <limine.h>
5
#include <e9print.h>
6
#include <flanterm.h>
7
#include <flanterm_backends/fb.h>
8
9
int memcmp(const void *, const void *, size_t);
10
11
#ifdef ENABLE_QEMU_SHUTDOWN
12
static inline void outw(uint16_t port, uint16_t value) {
13
    __asm volatile ("outw %%ax, %1"  : : "a" (value), "Nd" (port) : "memory");
14
}
15
#endif
16
17
__attribute__((section(".limine_requests")))
18
static volatile uint64_t limine_base_revision[] = LIMINE_BASE_REVISION(6);
19
20
static void limine_main(void);
21
22
__attribute__((used, section(".limine_requests_start_marker")))
23
static volatile uint64_t limine_requests_start_marker[] = LIMINE_REQUESTS_START_MARKER;
24
25
__attribute__((used, section(".limine_requests")))
26
static volatile struct limine_entry_point_request entry_point_request = {
27
    .id = LIMINE_ENTRY_POINT_REQUEST_ID,
28
    .revision = 0, .response = NULL,
29
30
    .entry = limine_main
31
};
32
33
__attribute__((section(".limine_requests")))
34
static volatile struct limine_framebuffer_request framebuffer_request = {
35
    .id = LIMINE_FRAMEBUFFER_REQUEST_ID,
36
    .revision = 0, .response = NULL
37
};
38
39
__attribute__((section(".limine_requests")))
40
static volatile struct limine_bootloader_info_request bootloader_info_request = {
41
    .id = LIMINE_BOOTLOADER_INFO_REQUEST_ID,
42
    .revision = 0, .response = NULL
43
};
44
45
__attribute__((section(".limine_requests")))
46
static volatile struct limine_executable_cmdline_request executable_cmdline_request = {
47
    .id = LIMINE_EXECUTABLE_CMDLINE_REQUEST_ID,
48
    .revision = 0, .response = NULL
49
};
50
51
__attribute__((section(".limine_requests")))
52
static volatile struct limine_firmware_type_request firmware_type_request = {
53
    .id = LIMINE_FIRMWARE_TYPE_REQUEST_ID,
54
    .revision = 0, .response = NULL
55
};
56
57
__attribute__((section(".limine_requests")))
58
static volatile struct limine_hhdm_request hhdm_request = {
59
    .id = LIMINE_HHDM_REQUEST_ID,
60
    .revision = 0, .response = NULL
61
};
62
63
__attribute__((section(".limine_requests")))
64
static volatile struct limine_memmap_request memmap_request = {
65
    .id = LIMINE_MEMMAP_REQUEST_ID,
66
    .revision = 0, .response = NULL
67
};
68
69
__attribute__((section(".limine_requests")))
70
static volatile struct limine_executable_file_request exec_file_request = {
71
    .id = LIMINE_EXECUTABLE_FILE_REQUEST_ID,
72
    .revision = 0, .response = NULL
73
};
74
75
struct limine_internal_module internal_module1 = {
76
    .path = "/boot/test.elf",
77
    .string = "First internal module"
78
};
79
80
struct limine_internal_module internal_module2 = {
81
    .path = "test.elf",
82
    .string = "Second internal module"
83
};
84
85
struct limine_internal_module internal_module3 = {
86
    .path = "./limine.conf",
87
    .string = "Third internal module"
88
    /*  gzip test depends on this name to find
89
        the original to compare against.  */
90
};
91
92
#ifdef ENABLE_GZIP_TEST
93
struct limine_internal_module internal_module4 = {
94
    .path = "./limine.conf.gz",
95
    .string = "gzip-compressed limine.conf",
96
    .flags = LIMINE_INTERNAL_MODULE_COMPRESSED
97
};
98
#endif
99
100
struct limine_internal_module *internal_modules[] = {
101
    &internal_module1,
102
    &internal_module2,
103
    &internal_module3,
104
#ifdef ENABLE_GZIP_TEST
105
    &internal_module4,
106
#endif
107
};
108
109
__attribute__((section(".limine_requests")))
110
static volatile struct limine_module_request module_request = {
111
    .id = LIMINE_MODULE_REQUEST_ID,
112
    .revision = 1, .response = NULL,
113
114
    .internal_module_count = sizeof(internal_modules) / sizeof(internal_modules[0]),
115
    .internal_modules = internal_modules
116
};
117
118
__attribute__((section(".limine_requests")))
119
static volatile struct limine_rsdp_request rsdp_request = {
120
    .id = LIMINE_RSDP_REQUEST_ID,
121
    .revision = 0, .response = NULL
122
};
123
124
__attribute__((section(".limine_requests")))
125
static volatile struct limine_smbios_request smbios_request = {
126
    .id = LIMINE_SMBIOS_REQUEST_ID,
127
    .revision = 0, .response = NULL
128
};
129
130
__attribute__((section(".limine_requests")))
131
static volatile struct limine_efi_system_table_request est_request = {
132
    .id = LIMINE_EFI_SYSTEM_TABLE_REQUEST_ID,
133
    .revision = 0, .response = NULL
134
};
135
136
__attribute__((section(".limine_requests")))
137
static volatile struct limine_tpm_event_log_request tpm_event_log_request = {
138
    .id = LIMINE_TPM_EVENT_LOG_REQUEST_ID,
139
    .revision = 0, .response = NULL
140
};
141
142
__attribute__((section(".limine_requests")))
143
static volatile struct limine_efi_memmap_request efi_memmap_request = {
144
    .id = LIMINE_EFI_MEMMAP_REQUEST_ID,
145
    .revision = 0, .response = NULL
146
};
147
148
__attribute__((section(".limine_requests")))
149
static volatile struct limine_date_at_boot_request date_at_boot_request = {
150
    .id = LIMINE_DATE_AT_BOOT_REQUEST_ID,
151
    .revision = 0, .response = NULL
152
};
153
154
__attribute__((section(".limine_requests")))
155
static volatile struct limine_executable_address_request executable_address_request = {
156
    .id = LIMINE_EXECUTABLE_ADDRESS_REQUEST_ID,
157
    .revision = 0, .response = NULL
158
};
159
160
__attribute__((section(".limine_requests")))
161
static volatile struct limine_mp_request _mp_request = {
162
    .id = LIMINE_MP_REQUEST_ID,
163
    .revision = 0, .response = NULL
164
};
165
166
__attribute__((section(".limine_requests")))
167
static volatile struct limine_dtb_request _dtb_request = {
168
    .id = LIMINE_DTB_REQUEST_ID,
169
    .revision = 0, .response = NULL
170
};
171
172
__attribute__((section(".limine_requests")))
173
static volatile struct limine_paging_mode_request _pm_request = {
174
    .id = LIMINE_PAGING_MODE_REQUEST_ID,
175
    .revision = 1, .response = NULL,
176
#if defined (__x86_64__)
177
    .mode = LIMINE_PAGING_MODE_X86_64_5LVL,
178
    .max_mode = LIMINE_PAGING_MODE_X86_64_5LVL,
179
    .min_mode = LIMINE_PAGING_MODE_X86_64_MIN
180
#elif defined (__aarch64__)
181
    .mode = LIMINE_PAGING_MODE_AARCH64_5LVL,
182
    .max_mode = LIMINE_PAGING_MODE_AARCH64_5LVL,
183
    .min_mode = LIMINE_PAGING_MODE_AARCH64_MIN
184
#elif defined (__riscv)
185
    .mode = LIMINE_PAGING_MODE_RISCV_SV57,
186
    .max_mode = LIMINE_PAGING_MODE_RISCV_SV57,
187
    .min_mode = LIMINE_PAGING_MODE_RISCV_MIN,
188
#elif defined (__loongarch__)
189
    .mode = LIMINE_PAGING_MODE_LOONGARCH_DEFAULT,
190
    .max_mode = LIMINE_PAGING_MODE_LOONGARCH_DEFAULT,
191
    .min_mode = LIMINE_PAGING_MODE_LOONGARCH_MIN
192
#endif
193
};
194
195
#ifdef __riscv
196
__attribute__((section(".limine_requests")))
197
static volatile struct limine_riscv_bsp_hartid_request _bsp_request = {
198
    .id = LIMINE_RISCV_BSP_HARTID_REQUEST_ID,
199
    .revision = 0, .response = NULL,
200
};
201
#endif
202
203
__attribute__((section(".limine_requests")))
204
static volatile struct limine_tsc_frequency_request tsc_freq_request = {
205
    .id = LIMINE_TSC_FREQUENCY_REQUEST_ID,
206
    .revision = 0, .response = NULL,
207
};
208
209
__attribute__((section(".limine_requests")))
210
static volatile struct limine_bootloader_performance_request _perf_request = {
211
    .id = LIMINE_BOOTLOADER_PERFORMANCE_REQUEST_ID,
212
    .revision = 0, .response = NULL,
213
};
214
215
__attribute__((section(".limine_requests")))
216
static volatile struct limine_flanterm_fb_init_params_request fip_request = {
217
    .id = LIMINE_FLANTERM_FB_INIT_PARAMS_REQUEST_ID,
218
    .revision = 0, .response = NULL,
219
};
220
221
__attribute__((used, section(".limine_requests_end_marker")))
222
static volatile uint64_t limine_requests_end_marker[] = LIMINE_REQUESTS_END_MARKER;
223
224
static char *get_memmap_type(uint64_t type) {
225
    switch (type) {
226
        case LIMINE_MEMMAP_USABLE:
227
            return "Usable";
228
        case LIMINE_MEMMAP_RESERVED:
229
            return "Reserved";
230
        case LIMINE_MEMMAP_RESERVED_MAPPED:
231
            return "Reserved (Mapped)";
232
        case LIMINE_MEMMAP_ACPI_RECLAIMABLE:
233
            return "ACPI reclaimable";
234
        case LIMINE_MEMMAP_ACPI_NVS:
235
            return "ACPI NVS";
236
        case LIMINE_MEMMAP_BAD_MEMORY:
237
            return "Bad memory";
238
        case LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE:
239
            return "Bootloader reclaimable";
240
        case LIMINE_MEMMAP_EXECUTABLE_AND_MODULES:
241
            return "Executable and modules";
242
        case LIMINE_MEMMAP_FRAMEBUFFER:
243
            return "Framebuffer";
244
        default:
245
            return "???";
246
    }
247
}
248
249
static char *firmware_type_str(uint64_t t) {
250
    switch (t) {
251
        case LIMINE_FIRMWARE_TYPE_X86BIOS:
252
            return "x86 BIOS";
253
        case LIMINE_FIRMWARE_TYPE_EFI32:
254
            return "32-bit EFI";
255
        case LIMINE_FIRMWARE_TYPE_EFI64:
256
            return "64-bit EFI";
257
        default:
258
            return "???";
259
    }
260
}
261
262
static void print_file(struct limine_file *file) {
263
    e9_printf("File->Revision: %d", file->revision);
264
    e9_printf("File->Address: %x", file->address);
265
    e9_printf("File->Size: %x", file->size);
266
    e9_printf("File->Path: %s", file->path);
267
    e9_printf("File->String: %s", file->string);
268
    e9_printf("File->MediaType: %d", file->media_type);
269
    e9_printf("File->PartIndex: %d", file->partition_index);
270
    e9_printf("File->TFTPIP: %d.%d.%d.%d",
271
              (file->tftp_ip & (0xff << 0)) >> 0,
272
              (file->tftp_ip & (0xff << 8)) >> 8,
273
              (file->tftp_ip & (0xff << 16)) >> 16,
274
              (file->tftp_ip & (0xff << 24)) >> 24);
275
    e9_printf("File->TFTPPort: %d", file->tftp_port);
276
    e9_printf("File->MBRDiskId: %x", file->mbr_disk_id);
277
    e9_printf("File->GPTDiskUUID: %x-%x-%x-%x",
278
              file->gpt_disk_uuid.a,
279
              file->gpt_disk_uuid.b,
280
              file->gpt_disk_uuid.c,
281
              *(uint64_t *)file->gpt_disk_uuid.d);
282
    e9_printf("File->GPTPartUUID: %x-%x-%x-%x",
283
              file->gpt_part_uuid.a,
284
              file->gpt_part_uuid.b,
285
              file->gpt_part_uuid.c,
286
              *(uint64_t *)file->gpt_part_uuid.d);
287
    e9_printf("File->PartUUID: %x-%x-%x-%x",
288
              file->part_uuid.a,
289
              file->part_uuid.b,
290
              file->part_uuid.c,
291
              *(uint64_t *)file->part_uuid.d);
292
}
293
294
uint32_t ctr = 0;
295
296
void ap_entry(struct limine_mp_info *info) {
297
    e9_printf("Hello from AP!");
298
299
#if defined (__x86_64__)
300
    e9_printf("My LAPIC ID: %x", info->lapic_id);
301
#elif defined (__aarch64__)
302
    e9_printf("My MPIDR: %x", info->mpidr);
303
#elif defined (__riscv)
304
    e9_printf("My Hart ID: %x", info->hartid);
305
#elif defined (__loongarch__)
306
    e9_printf("My Phys ID: %x", info->phys_id);
307
#endif
308
309
    __atomic_fetch_add(&ctr, 1, __ATOMIC_SEQ_CST);
310
311
    while (1);
312
}
313
314
#define FEAT_START do {
315
#define FEAT_END } while (0);
316
317
extern char executable_start[];
318
319
struct flanterm_context *ft_ctx = NULL;
320
321
static uint8_t alloc_pool[16 * 1024 * 1024];
322
static size_t alloc_off = 0;
323
324
static void *simple_malloc(size_t size) {
325
    size = (size + 15) & ~(size_t)15;
326
    if (alloc_off + size > sizeof(alloc_pool)) {
327
        return NULL;
328
    }
329
    void *p = &alloc_pool[alloc_off];
330
    alloc_off += size;
331
    return p;
332
}
333
334
static void simple_free(void *ptr, size_t size) {
335
    (void)ptr;
336
    (void)size;
337
}
338
339
static void limine_main(void) {
340
    e9_printf("\nWe're alive");
341
342
    if (LIMINE_LOADED_BASE_REVISION_VALID(limine_base_revision) == true) {
343
        e9_printf("Bootloader has loaded us using base revision %d",
344
                  LIMINE_LOADED_BASE_REVISION(limine_base_revision));
345
    }
346
347
    if (LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) {
348
        e9_printf("Limine base revision not supported");
349
        for (;;);
350
    }
351
352
    e9_printf("");
353
354
    struct limine_framebuffer *fb = framebuffer_request.response->framebuffers[0];
355
356
    struct limine_flanterm_fb_init_params *fip = NULL;
357
    if (fip_request.response != NULL && fip_request.response->entry_count > 0) {
358
        fip = fip_request.response->entries[0];
359
    }
360
361
    if (fip != NULL) {
362
        ft_ctx = flanterm_fb_init(
363
            simple_malloc,
364
            simple_free,
365
            fb->address, fb->width, fb->height, fb->pitch,
366
            fb->red_mask_size, fb->red_mask_shift,
367
            fb->green_mask_size, fb->green_mask_shift,
368
            fb->blue_mask_size, fb->blue_mask_shift,
369
            fip->canvas,
370
            fip->ansi_colours, fip->ansi_bright_colours,
371
            &fip->default_bg, &fip->default_fg,
372
            &fip->default_bg_bright, &fip->default_fg_bright,
373
            fip->font, fip->font_width, fip->font_height, fip->font_spacing,
374
            fip->font_scale_x, fip->font_scale_y,
375
            fip->margin,
376
            fip->rotation
377
        );
378
    } else {
379
        ft_ctx = flanterm_fb_init(
380
            NULL,
381
            NULL,
382
            fb->address, fb->width, fb->height, fb->pitch,
383
            fb->red_mask_size, fb->red_mask_shift,
384
            fb->green_mask_size, fb->green_mask_shift,
385
            fb->blue_mask_size, fb->blue_mask_shift,
386
            NULL,
387
            NULL, NULL,
388
            NULL, NULL,
389
            NULL, NULL,
390
            NULL, 0, 0, 1,
391
            0, 0,
392
            0,
393
            FLANTERM_FB_ROTATE_0
394
        );
395
    }
396
397
    uint64_t executable_slide = (uint64_t)executable_start - 0xffffffff80000000;
398
399
    e9_printf("Executable start: %x", executable_start);
400
    e9_printf("Executable slide: %x", executable_slide);
401
402
FEAT_START
403
    e9_printf("");
404
    if (bootloader_info_request.response == NULL) {
405
        e9_printf("Bootloader info not passed");
406
        break;
407
    }
408
    struct limine_bootloader_info_response *bootloader_info_response = bootloader_info_request.response;
409
    e9_printf("Bootloader info feature, revision %d", bootloader_info_response->revision);
410
    e9_printf("Bootloader name: %s", bootloader_info_response->name);
411
    e9_printf("Bootloader version: %s", bootloader_info_response->version);
412
FEAT_END
413
414
FEAT_START
415
    e9_printf("");
416
    if (executable_cmdline_request.response == NULL) {
417
        e9_printf("Executable command line not passed");
418
        break;
419
    }
420
    struct limine_executable_cmdline_response *executable_cmdline_response = executable_cmdline_request.response;
421
    e9_printf("Executable command line feature, revision %d", executable_cmdline_response->revision);
422
    e9_printf("Command line: %s", executable_cmdline_response->cmdline);
423
FEAT_END
424
425
FEAT_START
426
    e9_printf("");
427
    if (firmware_type_request.response == NULL) {
428
        e9_printf("Firmware type not passed");
429
        break;
430
    }
431
    struct limine_firmware_type_response *firmware_type_response = firmware_type_request.response;
432
    e9_printf("Firmware type feature, revision %d", firmware_type_response->revision);
433
    e9_printf("Firmware type: %s", firmware_type_str(firmware_type_response->firmware_type));
434
FEAT_END
435
436
FEAT_START
437
    e9_printf("");
438
    if (executable_address_request.response == NULL) {
439
        e9_printf("Executable address not passed");
440
        break;
441
    }
442
    struct limine_executable_address_response *exec_addr_response = executable_address_request.response;
443
    e9_printf("Executable address feature, revision %d", exec_addr_response->revision);
444
    e9_printf("Physical base: %x", exec_addr_response->physical_base);
445
    e9_printf("Virtual base: %x", exec_addr_response->virtual_base);
446
FEAT_END
447
448
FEAT_START
449
    e9_printf("");
450
    if (hhdm_request.response == NULL) {
451
        e9_printf("HHDM not passed");
452
        break;
453
    }
454
    struct limine_hhdm_response *hhdm_response = hhdm_request.response;
455
    e9_printf("HHDM feature, revision %d", hhdm_response->revision);
456
    e9_printf("Higher half direct map at: %x", hhdm_response->offset);
457
FEAT_END
458
459
FEAT_START
460
    e9_printf("");
461
    if (memmap_request.response == NULL) {
462
        e9_printf("Memory map not passed");
463
        break;
464
    }
465
    struct limine_memmap_response *memmap_response = memmap_request.response;
466
    e9_printf("Memory map feature, revision %d", memmap_response->revision);
467
    e9_printf("%d memory map entries", memmap_response->entry_count);
468
    for (size_t i = 0; i < memmap_response->entry_count; i++) {
469
        struct limine_memmap_entry *e = memmap_response->entries[i];
470
        e9_printf("%x->%x %s", e->base, e->base + e->length, get_memmap_type(e->type));
471
    }
472
FEAT_END
473
474
FEAT_START
475
    e9_printf("");
476
    if (framebuffer_request.response == NULL) {
477
        e9_printf("Framebuffer not passed");
478
        break;
479
    }
480
    struct limine_framebuffer_response *fb_response = framebuffer_request.response;
481
    e9_printf("Framebuffers feature, revision %d", fb_response->revision);
482
    e9_printf("%d framebuffer(s)", fb_response->framebuffer_count);
483
    for (size_t i = 0; i < fb_response->framebuffer_count; i++) {
484
        struct limine_framebuffer *fb = fb_response->framebuffers[i];
485
        e9_printf("Address: %x", fb->address);
486
        e9_printf("Width: %d", fb->width);
487
        e9_printf("Height: %d", fb->height);
488
        e9_printf("Pitch: %d", fb->pitch);
489
        e9_printf("BPP: %d", fb->bpp);
490
        e9_printf("Memory model: %d", fb->memory_model);
491
        e9_printf("Red mask size: %d", fb->red_mask_size);
492
        e9_printf("Red mask shift: %d", fb->red_mask_shift);
493
        e9_printf("Green mask size: %d", fb->green_mask_size);
494
        e9_printf("Green mask shift: %d", fb->green_mask_shift);
495
        e9_printf("Blue mask size: %d", fb->blue_mask_size);
496
        e9_printf("Blue mask shift: %d", fb->blue_mask_shift);
497
        e9_printf("EDID size: %d", fb->edid_size);
498
        e9_printf("EDID at: %x", fb->edid);
499
        e9_printf("Video modes:");
500
        for (size_t j = 0; j < fb->mode_count; j++) {
501
            e9_printf("  %dx%dx%d", fb->modes[j]->width, fb->modes[j]->height, fb->modes[j]->bpp);
502
        }
503
    }
504
FEAT_END
505
506
FEAT_START
507
    e9_printf("");
508
    if (fip_request.response == NULL) {
509
        e9_printf("Flanterm FB init params not passed");
510
        break;
511
    }
512
    struct limine_flanterm_fb_init_params_response *fip_response = fip_request.response;
513
    e9_printf("Flanterm FB init params feature, revision %d", fip_response->revision);
514
    e9_printf("%d entry/entries", fip_response->entry_count);
515
    for (size_t i = 0; i < fip_response->entry_count; i++) {
516
        struct limine_flanterm_fb_init_params *p = fip_response->entries[i];
517
        e9_printf("--- Entry %d ---", i);
518
        e9_printf("Canvas: %x (size: %x)", p->canvas, p->canvas_size);
519
        e9_printf("Default BG: %x, FG: %x", p->default_bg, p->default_fg);
520
        e9_printf("Default BG bright: %x, FG bright: %x", p->default_bg_bright, p->default_fg_bright);
521
        e9_printf("ANSI colours: %x %x %x %x %x %x %x %x",
522
            p->ansi_colours[0], p->ansi_colours[1], p->ansi_colours[2], p->ansi_colours[3],
523
            p->ansi_colours[4], p->ansi_colours[5], p->ansi_colours[6], p->ansi_colours[7]);
524
        e9_printf("ANSI bright: %x %x %x %x %x %x %x %x",
525
            p->ansi_bright_colours[0], p->ansi_bright_colours[1], p->ansi_bright_colours[2], p->ansi_bright_colours[3],
526
            p->ansi_bright_colours[4], p->ansi_bright_colours[5], p->ansi_bright_colours[6], p->ansi_bright_colours[7]);
527
        e9_printf("Font: %x (%dx%d)", p->font, p->font_width, p->font_height);
528
        e9_printf("Font spacing: %d, scale: %dx%d", p->font_spacing, p->font_scale_x, p->font_scale_y);
529
        e9_printf("Margin: %d, Rotation: %d", p->margin, p->rotation);
530
    }
531
FEAT_END
532
533
FEAT_START
534
    e9_printf("");
535
    if (exec_file_request.response == NULL) {
536
        e9_printf("Executable file not passed");
537
        break;
538
    }
539
    struct limine_executable_file_response *exec_file_response = exec_file_request.response;
540
    e9_printf("Executable file feature, revision %d", exec_file_response->revision);
541
    print_file(exec_file_response->executable_file);
542
FEAT_END
543
544
FEAT_START
545
    e9_printf("");
546
    if (module_request.response == NULL) {
547
        e9_printf("Modules not passed");
548
        break;
549
    }
550
    struct limine_module_response *module_response = module_request.response;
551
    e9_printf("Modules feature, revision %d", module_response->revision);
552
    e9_printf("%d module(s)", module_response->module_count);
553
    for (size_t i = 0; i < module_response->module_count; i++) {
554
        struct limine_file *f = module_response->modules[i];
555
        e9_printf("---");
556
        print_file(f);
557
    }
558
559
#ifdef ENABLE_GZIP_TEST
560
    /*  Gzip decompression test: compare internal_module3 (plain limine.conf)
561
        against internal_module4 (limine.conf.gz, decompressed by bootloader).  */
562
    {
563
        struct limine_file *plain = NULL, *decompressed = NULL;
564
        for (size_t i = 0; i < module_response->module_count; i++) {
565
            struct limine_file *f = module_response->modules[i];
566
            if (f->string != NULL) {
567
                /*  Match by the module string we assigned.  */
568
                bool is_third = f->string[0] == 'T' && f->string[1] == 'h'
569
                             && f->string[2] == 'i' && f->string[3] == 'r'
570
                             && f->string[4] == 'd';
571
                bool is_gz    = f->string[0] == 'g' && f->string[1] == 'z';
572
                if (is_third) plain = f;
573
                if (is_gz)    decompressed = f;
574
            }
575
        }
576
        if (plain == NULL) {
577
            e9_printf("gzip: FAIL (plain module not found)");
578
        } else if (decompressed == NULL) {
579
            e9_printf("gzip: FAIL (decompressed module not found)");
580
        } else if (plain->size != decompressed->size) {
581
            e9_printf("gzip: FAIL (size mismatch: plain=%x, decompressed=%x)",
582
                      plain->size, decompressed->size);
583
        } else if (memcmp(plain->address, decompressed->address, plain->size) != 0) {
584
            e9_printf("gzip: FAIL (content mismatch, size=%x)", plain->size);
585
        } else {
586
            e9_printf("gzip: pass (size=%x)", plain->size);
587
        }
588
    }
589
#endif
590
FEAT_END
591
592
FEAT_START
593
    e9_printf("");
594
    if (rsdp_request.response == NULL) {
595
        e9_printf("RSDP not passed");
596
        break;
597
    }
598
    struct limine_rsdp_response *rsdp_response = rsdp_request.response;
599
    e9_printf("RSDP feature, revision %d", rsdp_response->revision);
600
    e9_printf("RSDP at: %x", rsdp_response->address);
601
FEAT_END
602
603
FEAT_START
604
    e9_printf("");
605
    if (smbios_request.response == NULL) {
606
        e9_printf("SMBIOS not passed");
607
        break;
608
    }
609
    struct limine_smbios_response *smbios_response = smbios_request.response;
610
    e9_printf("SMBIOS feature, revision %d", smbios_response->revision);
611
    e9_printf("SMBIOS 32-bit entry at: %x", smbios_response->entry_32);
612
    e9_printf("SMBIOS 64-bit entry at: %x", smbios_response->entry_64);
613
FEAT_END
614
615
FEAT_START
616
    e9_printf("");
617
    if (est_request.response == NULL) {
618
        e9_printf("EFI system table not passed");
619
        break;
620
    }
621
    struct limine_efi_system_table_response *est_response = est_request.response;
622
    e9_printf("EFI system table feature, revision %d", est_response->revision);
623
    e9_printf("EFI system table at: %x", est_response->address);
624
FEAT_END
625
626
FEAT_START
627
    e9_printf("");
628
    if (tpm_event_log_request.response == NULL) {
629
        e9_printf("TPM event log not passed");
630
        break;
631
    }
632
    struct limine_tpm_event_log_response *tpm_event_log_response = tpm_event_log_request.response;
633
    e9_printf("TPM event log feature, revision %d", tpm_event_log_response->revision);
634
    e9_printf("Format: %d (TCG_%s)", tpm_event_log_response->format,
635
              tpm_event_log_response->format == LIMINE_TPM_EVENT_LOG_FORMAT_TCG_2 ? "2" : "1.2");
636
    e9_printf("Size: %x bytes", tpm_event_log_response->size);
637
    e9_printf("Address: %x", tpm_event_log_response->address);
638
FEAT_END
639
640
FEAT_START
641
    e9_printf("");
642
    if (efi_memmap_request.response == NULL) {
643
        e9_printf("EFI memory map not passed");
644
        break;
645
    }
646
    struct limine_efi_memmap_response *efi_memmap_response = efi_memmap_request.response;
647
    e9_printf("EFI memory map feature, revision %d", efi_memmap_response->revision);
648
    e9_printf("EFI memory map at: %x", efi_memmap_response->memmap);
649
    e9_printf("EFI memory map size: %x", efi_memmap_response->memmap_size);
650
    e9_printf("EFI memory descriptor size: %x", efi_memmap_response->desc_size);
651
    e9_printf("EFI memory descriptor version: %d", efi_memmap_response->desc_version);
652
FEAT_END
653
654
FEAT_START
655
    e9_printf("");
656
    if (date_at_boot_request.response == NULL) {
657
        e9_printf("Boot time not passed");
658
        break;
659
    }
660
    struct limine_date_at_boot_response *date_at_boot_response = date_at_boot_request.response;
661
    e9_printf("Date at boot feature, revision %d", date_at_boot_response->revision);
662
    e9_printf("Timestamp: %d", date_at_boot_response->timestamp);
663
FEAT_END
664
665
FEAT_START
666
    e9_printf("");
667
    if (_mp_request.response == NULL) {
668
        e9_printf("MP info not passed");
669
        break;
670
    }
671
    struct limine_mp_response *mp_response = _mp_request.response;
672
    e9_printf("MP feature, revision %d", mp_response->revision);
673
    e9_printf("Flags: %x", mp_response->flags);
674
#if defined (__x86_64__)
675
    e9_printf("BSP LAPIC ID: %x", mp_response->bsp_lapic_id);
676
#elif defined (__aarch64__)
677
    e9_printf("BSP MPIDR: %x", mp_response->bsp_mpidr);
678
#elif defined (__riscv)
679
    e9_printf("BSP Hart ID: %x", mp_response->bsp_hartid);
680
#elif defined (__loongarch__)
681
    e9_printf("BSP Phys ID: %x", mp_response->bsp_phys_id);
682
#endif
683
    e9_printf("CPU count: %d", mp_response->cpu_count);
684
    for (size_t i = 0; i < mp_response->cpu_count; i++) {
685
        struct limine_mp_info *cpu = mp_response->cpus[i];
686
        e9_printf("Processor ID: %x", cpu->processor_id);
687
#if defined (__x86_64__)
688
        e9_printf("LAPIC ID: %x", cpu->lapic_id);
689
#elif defined (__aarch64__)
690
        e9_printf("MPIDR: %x", cpu->mpidr);
691
#elif defined (__riscv)
692
        e9_printf("Hart ID: %x", cpu->hartid);
693
#elif defined (__loongarch__)
694
        e9_printf("Phys ID: %x", cpu->phys_id);
695
#endif
696
697
698
#if defined (__x86_64__)
699
        if (cpu->lapic_id != mp_response->bsp_lapic_id) {
700
#elif defined (__aarch64__)
701
        if (cpu->mpidr != mp_response->bsp_mpidr) {
702
#elif defined (__riscv)
703
        if (cpu->hartid != mp_response->bsp_hartid) {
704
#elif defined (__loongarch__)
705
        if (cpu->phys_id != mp_response->bsp_phys_id) {
706
#endif
707
            uint32_t old_ctr = __atomic_load_n(&ctr, __ATOMIC_SEQ_CST);
708
709
            __atomic_store_n(&cpu->goto_address, ap_entry, __ATOMIC_SEQ_CST);
710
711
            while (__atomic_load_n(&ctr, __ATOMIC_SEQ_CST) == old_ctr)
712
                ;
713
        }
714
    }
715
FEAT_END
716
717
FEAT_START
718
    e9_printf("");
719
    if (_dtb_request.response == NULL) {
720
        e9_printf("Device tree blob not passed");
721
        break;
722
    }
723
    struct limine_dtb_response *dtb_response = _dtb_request.response;
724
    e9_printf("Device tree blob feature, revision %d", dtb_response->revision);
725
    e9_printf("Device tree blob pointer: %x", dtb_response->dtb_ptr);
726
	uint32_t dtb_magic = *(uint32_t*)dtb_response->dtb_ptr;
727
	e9_printf("Device tree header magic: %x", dtb_magic);
728
FEAT_END
729
730
FEAT_START
731
    e9_printf("");
732
    if (_pm_request.response == NULL) {
733
        e9_printf("Paging mode not passed");
734
        break;
735
    }
736
    struct limine_paging_mode_response *pm_response = _pm_request.response;
737
    e9_printf("Paging mode feature, revision %d", pm_response->revision);
738
    e9_printf("  mode: %d", pm_response->mode);
739
FEAT_END
740
741
#if defined (__riscv)
742
FEAT_START
743
    e9_printf("");
744
    struct limine_riscv_bsp_hartid_response *bsp_response = _bsp_request.response;
745
    if (bsp_response == NULL) {
746
        e9_printf("RISC-V BSP Hart ID was not passed");
747
        break;
748
    }
749
    e9_printf("RISC-V BSP Hart ID: %x", bsp_response->bsp_hartid);
750
FEAT_END
751
#endif
752
753
FEAT_START
754
    e9_printf("");
755
    struct limine_tsc_frequency_response *tsc_freq_response = tsc_freq_request.response;
756
    if (tsc_freq_response == NULL) {
757
        e9_printf("TSC frequency not passed");
758
        break;
759
    }
760
    e9_printf("TSC frequency feature, revision %d", tsc_freq_response->revision);
761
    e9_printf("Frequency: %d Hz", tsc_freq_response->frequency);
762
FEAT_END
763
764
FEAT_START
765
    e9_printf("");
766
    struct limine_bootloader_performance_response *perf_response = _perf_request.response;
767
    if (perf_response == NULL) {
768
        e9_printf("Bootloader performance not passed");
769
        break;
770
    }
771
    e9_printf("Bootloader performance feature, revision %d", perf_response->revision);
772
    e9_printf("Reset time: %d usec", perf_response->reset_usec);
773
    e9_printf("Init time: %d usec", perf_response->init_usec);
774
    e9_printf("Exec time: %d usec", perf_response->exec_usec);
775
FEAT_END
776
777
#ifdef ENABLE_QEMU_SHUTDOWN
778
    outw(0x604, 0x2000); /*  QEMU-specific shutdown, used by automated tests.  */
779
#endif
780
    for (;;);
781
}
tab: 248 wrap: offon