:: limine / common / protos / multiboot2.c 40.8 KB raw

1
#if defined (__x86_64__) || defined (__i386__)
2
3
#include <stdint.h>
4
#include <stddef.h>
5
#include <stdnoreturn.h>
6
#include <protos/multiboot2.h>
7
#include <protos/multiboot.h>
8
#include <config.h>
9
#include <lib/libc.h>
10
#include <lib/elf.h>
11
#include <lib/misc.h>
12
#include <lib/config.h>
13
#include <lib/print.h>
14
#include <lib/uri.h>
15
#include <lib/tpm.h>
16
#include <lib/fb.h>
17
#include <lib/term.h>
18
#include <lib/elsewhere.h>
19
#include <sys/pic.h>
20
#include <sys/cpu.h>
21
#include <sys/idt.h>
22
#include <sys/iommu.h>
23
#include <sys/lapic.h>
24
#include <fs/file.h>
25
#include <mm/vmm.h>
26
#include <lib/acpi.h>
27
#include <mm/pmm.h>
28
#include <lib/misc.h>
29
#include <drivers/vga_textmode.h>
30
#include <pxe/pxe.h>
31
32
#define LIMINE_BRAND "Limine " LIMINE_VERSION
33
34
#define MEMMAP_MAX 256
35
#define EFI_MEMMAP_MAX 1024
36
37
/// Returns the size required to store the multiboot2 info.
38
static size_t get_multiboot2_info_size(
39
    char *cmdline,
40
    size_t modules_size,
41
    uint32_t section_entry_size, uint32_t section_num,
42
    uint32_t smbios_tag_size
43
) {
44
#define OVERFLOW panic(true, "multiboot2: info size overflow")
45
    return ALIGN_UP(sizeof(struct multiboot2_start_tag), MULTIBOOT_TAG_ALIGN, OVERFLOW) +
46
        ALIGN_UP(sizeof(struct multiboot_tag_string) + strlen(cmdline) + 1, MULTIBOOT_TAG_ALIGN, OVERFLOW) +
47
        ALIGN_UP(sizeof(struct multiboot_tag_string) + sizeof(LIMINE_BRAND), MULTIBOOT_TAG_ALIGN, OVERFLOW) +
48
        ALIGN_UP(sizeof(struct multiboot_tag_framebuffer), MULTIBOOT_TAG_ALIGN, OVERFLOW) +
49
        ALIGN_UP(sizeof(struct multiboot_tag_new_acpi) + sizeof(struct rsdp), MULTIBOOT_TAG_ALIGN, OVERFLOW) +
50
        ALIGN_UP(sizeof(struct multiboot_tag_old_acpi) + 20, MULTIBOOT_TAG_ALIGN, OVERFLOW) +
51
        ALIGN_UP(sizeof(struct multiboot_tag_elf_sections) + CHECKED_MUL(section_entry_size, section_num, OVERFLOW), MULTIBOOT_TAG_ALIGN, OVERFLOW) +
52
        ALIGN_UP(modules_size, MULTIBOOT_TAG_ALIGN, OVERFLOW) +
53
        ALIGN_UP(sizeof(struct multiboot_tag_load_base_addr), MULTIBOOT_TAG_ALIGN, OVERFLOW) +
54
        ALIGN_UP(smbios_tag_size, MULTIBOOT_TAG_ALIGN, OVERFLOW) +
55
        ALIGN_UP(sizeof(struct multiboot_tag_basic_meminfo), MULTIBOOT_TAG_ALIGN, OVERFLOW) +
56
        ALIGN_UP(sizeof(struct multiboot_tag_mmap) + sizeof(struct multiboot_mmap_entry) * MEMMAP_MAX, MULTIBOOT_TAG_ALIGN, OVERFLOW) +
57
        #if defined (UEFI)
58
            ALIGN_UP(sizeof(struct multiboot_tag_efi_mmap) + (efi_desc_size * EFI_MEMMAP_MAX), MULTIBOOT_TAG_ALIGN, OVERFLOW) +
59
            #if defined (__i386__)
60
                ALIGN_UP(sizeof(struct multiboot_tag_efi32), MULTIBOOT_TAG_ALIGN, OVERFLOW) +
61
                ALIGN_UP(sizeof(struct multiboot_tag_efi32_ih), MULTIBOOT_TAG_ALIGN, OVERFLOW) +
62
            #elif defined (__x86_64__)
63
                ALIGN_UP(sizeof(struct multiboot_tag_efi64), MULTIBOOT_TAG_ALIGN, OVERFLOW) +
64
                ALIGN_UP(sizeof(struct multiboot_tag_efi64_ih), MULTIBOOT_TAG_ALIGN, OVERFLOW) +
65
            #endif
66
        #endif
67
        ALIGN_UP(sizeof(struct multiboot_tag_network) + DHCP_ACK_PACKET_LEN, MULTIBOOT_TAG_ALIGN, OVERFLOW) +
68
        ALIGN_UP(sizeof(struct multiboot_tag), MULTIBOOT_TAG_ALIGN, OVERFLOW);
69
#undef OVERFLOW
70
}
71
72
#define append_tag(P, TAG) do { \
73
    (P) += ALIGN_UP((TAG)->size, MULTIBOOT_TAG_ALIGN, panic(true, "multiboot2: tag size overflow")); \
74
} while (0)
75
76
noreturn void multiboot2_load(char *config, char* cmdline) {
77
    struct file_handle *kernel_file;
78
79
#if defined (UEFI)
80
    if (cmdline != NULL) {
81
        tpm_measure(TPM_PCR_BOOT_AUTH, TPM_EV_IPL,
82
                    cmdline, strlen(cmdline), "cmdline: ", cmdline);
83
    }
84
#endif
85
86
    char *kernel_path = config_get_value(config, 0, "PATH");
87
    if (kernel_path == NULL) {
88
        kernel_path = config_get_value(config, 0, "KERNEL_PATH");
89
    }
90
    if (kernel_path == NULL) {
91
        panic(true, "multiboot2: Executable path not specified");
92
    }
93
94
    print("multiboot2: Loading executable `%#`...\n", kernel_path);
95
96
    if ((kernel_file = uri_open(kernel_path, MEMMAP_KERNEL_AND_MODULES, false
97
#if defined (__i386__)
98
        , NULL, NULL
99
#endif
100
    )) == NULL)
101
        panic(true, "multiboot2: Failed to open executable with path `%#`. Is the path correct?", kernel_path);
102
103
    uint8_t *kernel = kernel_file->fd;
104
105
    size_t kernel_file_size = kernel_file->size;
106
107
#if defined (UEFI)
108
    tpm_measure_path(TPM_PCR_BOOT_AUTH, TPM_EV_IPL, "path: ", kernel_path);
109
    tpm_measure(TPM_PCR_LOADED_IMAGES, TPM_EV_IPL,
110
                kernel, kernel_file_size, "path: ", kernel_path);
111
#endif
112
113
    fclose(kernel_file);
114
115
    struct multiboot_header *header = NULL;
116
117
    // Per Multiboot2 spec, header must be within first 32768 bytes and 8-byte aligned.
118
    // Ensure we don't read past end of file when checking magic.
119
    size_t search_limit = MULTIBOOT_SEARCH;
120
    if (kernel_file_size < sizeof(struct multiboot_header)) {
121
        panic(true, "multiboot2: Kernel file too small to contain header");
122
    }
123
    if (search_limit > kernel_file_size - sizeof(struct multiboot_header)) {
124
        search_limit = kernel_file_size - sizeof(struct multiboot_header);
125
    }
126
127
    for (size_t header_offset = 0; header_offset <= search_limit; header_offset += MULTIBOOT_HEADER_ALIGN) {
128
        header = (void *)(kernel + header_offset);
129
130
        if (header->magic == MULTIBOOT2_HEADER_MAGIC) {
131
            break;
132
        }
133
    }
134
135
    if (header == NULL || header->magic != MULTIBOOT2_HEADER_MAGIC) {
136
        panic(true, "multiboot2: Invalid magic");
137
    }
138
139
    if (header->magic + header->architecture + header->checksum + header->header_length) {
140
        panic(true, "multiboot2: Header checksum is invalid");
141
    }
142
143
    if (header->architecture != MULTIBOOT_ARCHITECTURE_I386) {
144
        panic(true, "multiboot2: Unsupported architecture %u (expected i386)", header->architecture);
145
    }
146
147
    size_t header_offset_in_file = (uintptr_t)header - (uintptr_t)kernel;
148
    if (header->header_length > kernel_file_size - header_offset_in_file) {
149
        panic(true, "multiboot2: Header length exceeds kernel file size");
150
    }
151
152
    struct multiboot_header_tag_address *addresstag = NULL;
153
    struct multiboot_header_tag_framebuffer *fbtag = NULL;
154
155
    bool has_reloc_header = false;
156
    struct multiboot_header_tag_relocatable reloc_tag = {0};
157
158
    bool is_new_acpi_required = false;
159
    bool is_old_acpi_required = false;
160
161
    bool is_elf_info_requested = false;
162
163
#if defined (UEFI)
164
    bool is_framebuffer_required = false;
165
#endif
166
167
    uint64_t entry_point = 0xffffffff;
168
169
    // Iterate through the entries...
170
    for (struct multiboot_header_tag *tag = (struct multiboot_header_tag*)(header + 1); // header + 1 to skip the header struct.
171
       tag < (struct multiboot_header_tag *)((uintptr_t)header + header->header_length) && tag->type != MULTIBOOT_HEADER_TAG_END;
172
       ) {
173
        if (tag->size == 0) {
174
            break;
175
        }
176
        size_t tag_stride = ALIGN_UP(tag->size, MULTIBOOT_TAG_ALIGN, break);
177
        bool is_required = !(tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL);
178
        switch (tag->type) {
179
            case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST: {
180
                // Iterate the requests and check if they are supported by or not.
181
                struct multiboot_header_tag_information_request *request = (void *)tag;
182
                if (request->size < sizeof(struct multiboot_header_tag_information_request)) {
183
                    panic(true, "multiboot2: Invalid information request tag size");
184
                }
185
                size_t tag_remaining = (uintptr_t)header + header->header_length - (uintptr_t)tag;
186
                if (request->size > tag_remaining) {
187
                    panic(true, "multiboot2: Information request tag exceeds header bounds");
188
                }
189
                uint32_t size = (request->size - sizeof(struct multiboot_header_tag_information_request)) / sizeof(uint32_t);
190
191
                for (uint32_t i = 0; i < size; i++) {
192
                    uint32_t r = request->requests[i];
193
194
                    switch (r) {
195
                        // We already support the following requests:
196
                        case MULTIBOOT_TAG_TYPE_CMDLINE:
197
                        case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
198
                        case MULTIBOOT_TAG_TYPE_MODULE:
199
                        case MULTIBOOT_TAG_TYPE_MMAP:
200
                        case MULTIBOOT_TAG_TYPE_SMBIOS:
201
                        case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
202
                            break;
203
                        #if defined (UEFI)
204
                        case MULTIBOOT_TAG_TYPE_EFI_MMAP:
205
                            break;
206
                        case MULTIBOOT_TAG_TYPE_EFI32:
207
                        case MULTIBOOT_TAG_TYPE_EFI32_IH:
208
                        case MULTIBOOT_TAG_TYPE_EFI64:
209
                        case MULTIBOOT_TAG_TYPE_EFI64_IH:
210
                            break;
211
                        #endif
212
                        case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
213
                        #if defined (UEFI)
214
                            is_framebuffer_required = is_required;
215
                        #endif
216
                            break;
217
                        case MULTIBOOT_TAG_TYPE_ACPI_NEW:
218
                            is_new_acpi_required = is_required;
219
                            break;
220
                        case MULTIBOOT_TAG_TYPE_ACPI_OLD:
221
                            is_old_acpi_required = is_required;
222
                            break;
223
                        case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
224
                            is_elf_info_requested = is_required;
225
                            break;
226
                        case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR:
227
                        case MULTIBOOT_TAG_TYPE_NETWORK:
228
                            break;
229
                        default:
230
                            if (is_required)
231
                                panic(true, "multiboot2: Requested tag `%d` which is not supported", r);
232
                            break;
233
                    }
234
                }
235
                break;
236
            }
237
            case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS: {
238
#if defined (UEFI)
239
                if (tag->size < sizeof(struct multiboot_header_tag_console_flags))
240
                    break;
241
                struct multiboot_header_tag_console_flags *flags = (void *)tag;
242
                if ((flags->console_flags & (1 << 1)) && (flags->console_flags & (1 << 0))) {
243
                    panic(true, "multiboot2: OS requested EGA text mode, but UEFI does not support it");
244
                }
245
#endif
246
                break;
247
            }
248
            case MULTIBOOT_HEADER_TAG_FRAMEBUFFER: {
249
                if (tag->size < sizeof(struct multiboot_header_tag_framebuffer))
250
                    break;
251
                fbtag = (void *)tag;
252
                break;
253
            }
254
            case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS: {
255
                if (tag->size < sizeof(struct multiboot_header_tag_entry_address))
256
                    break;
257
                struct multiboot_header_tag_entry_address *entrytag = (void *)tag;
258
                entry_point = entrytag->entry_addr;
259
                break;
260
            }
261
            case MULTIBOOT_HEADER_TAG_ADDRESS: {
262
                if (tag->size < sizeof(struct multiboot_header_tag_address))
263
                    break;
264
                addresstag = (void *)tag;
265
                break;
266
            }
267
            // We always align the modules ;^)
268
            case MULTIBOOT_HEADER_TAG_MODULE_ALIGN:
269
                break;
270
            case MULTIBOOT_HEADER_TAG_EFI_BS:
271
                print("multiboot2: Warning: EFI_BS tag requested but not supported\n");
272
                if (is_required) {
273
                    panic(true, "multiboot2: EFI_BS tag is required but not supported");
274
                }
275
                break;
276
277
            case MULTIBOOT_HEADER_TAG_RELOCATABLE: {
278
                if (tag->size < sizeof(struct multiboot_header_tag_relocatable))
279
                    break;
280
                has_reloc_header = true;
281
                struct multiboot_header_tag_relocatable *reloc_tag_ptr = (void *)tag;
282
                reloc_tag = *reloc_tag_ptr;
283
                break;
284
            }
285
            case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64: {
286
                // Ignore EFI64 entry address tag as we do not support it.
287
                break;
288
            }
289
290
            default:
291
                if (is_required) {
292
                    if (tag->type <= 10 /* max specified ID */) {
293
                        panic(true, "multiboot2: Unsupported header tag type: %u\n", tag->type);
294
                    } else {
295
                        panic(true, "multiboot2: Unknown custom header tag type: %u\n", tag->type);
296
                    }
297
                } else {
298
                    if (tag->type > 10) {
299
                        print("multiboot2: Unknown custom header tag type: %u\n", tag->type);
300
                    }
301
                }
302
        }
303
        tag = (struct multiboot_header_tag *)((uintptr_t)tag + tag_stride);
304
    }
305
306
    bool section_hdr_info_valid = false;
307
    struct elf_section_hdr_info section_hdr_info = {0};
308
309
    struct elsewhere_range *ranges;
310
    uint64_t ranges_count = 1;
311
312
    if (addresstag != NULL) {
313
        size_t header_offset = (size_t)header - (size_t)kernel;
314
315
        size_t load_src;
316
        uintptr_t load_addr;
317
        if (addresstag->load_addr != (uint32_t)-1) {
318
            if (addresstag->load_addr > addresstag->header_addr) {
319
                panic(true, "multiboot2: Illegal load address");
320
            }
321
322
            size_t addr_diff = addresstag->header_addr - addresstag->load_addr;
323
            if (addr_diff > header_offset) {
324
                panic(true, "multiboot2: Address tag offset underflow");
325
            }
326
            load_src = header_offset - addr_diff;
327
            load_addr = addresstag->load_addr;
328
        } else {
329
            if (header_offset > addresstag->header_addr) {
330
                panic(true, "multiboot2: Header offset exceeds header address");
331
            }
332
            load_src = 0;
333
            load_addr = addresstag->header_addr - header_offset;
334
        }
335
336
        size_t load_size;
337
        if (addresstag->load_end_addr != 0) {
338
            if (addresstag->load_end_addr < load_addr) {
339
                panic(true, "multiboot2: Load end address less than load address");
340
            }
341
            load_size = addresstag->load_end_addr - load_addr;
342
        } else {
343
            if (load_src > kernel_file_size) {
344
                panic(true, "multiboot2: Load source exceeds kernel file size");
345
            }
346
            load_size = kernel_file_size - load_src;
347
        }
348
349
        size_t bss_size = 0;
350
        if (addresstag->bss_end_addr != 0) {
351
            uintptr_t bss_addr = CHECKED_ADD(load_addr, load_size,
352
                panic(true, "multiboot2: load_addr + load_size overflow"));
353
            if (addresstag->bss_end_addr < bss_addr) {
354
                panic(true, "multiboot2: Illegal bss end address");
355
            }
356
357
            bss_size = addresstag->bss_end_addr - bss_addr;
358
        }
359
360
        if (load_src > kernel_file_size || load_size > kernel_file_size - load_src) {
361
            panic(true, "multiboot2: load_src + load_size exceeds kernel file size");
362
        }
363
364
        size_t full_size = CHECKED_ADD(load_size, bss_size,
365
            panic(true, "multiboot2: load_size + bss_size overflow"));
366
367
        void *elsewhere = ext_mem_alloc(full_size);
368
369
        memcpy(elsewhere, kernel + load_src, load_size);
370
371
        if (entry_point == 0xffffffff) {
372
            panic(true, "multiboot2: Using address tag but entry address tag missing");
373
        }
374
375
        ranges = ext_mem_alloc(sizeof(struct elsewhere_range));
376
377
        ranges->elsewhere = (uintptr_t)elsewhere;
378
        ranges->target = load_addr;
379
        ranges->length = full_size;
380
    } else {
381
        uint64_t e;
382
        int bits = elf_bits(kernel, kernel_file_size);
383
384
        switch (bits) {
385
            case 32:
386
                if (!elf32_load_elsewhere(kernel, kernel_file_size, &e, &ranges))
387
                    panic(true, "multiboot2: ELF32 load failure");
388
389
                section_hdr_info = elf32_section_hdr_info(kernel, kernel_file_size);
390
                section_hdr_info_valid = true;
391
                break;
392
            case 64: {
393
                if (!elf64_load_elsewhere(kernel, kernel_file_size, &e, &ranges))
394
                    panic(true, "multiboot2: ELF64 load failure");
395
396
                section_hdr_info = elf64_section_hdr_info(kernel, kernel_file_size);
397
                section_hdr_info_valid = true;
398
                break;
399
            }
400
            default:
401
                panic(true, "multiboot2: Invalid ELF file bitness");
402
        }
403
404
        if (entry_point == 0xffffffff) {
405
            entry_point = e;
406
        }
407
    }
408
409
    int64_t reloc_slide = 0;
410
411
    if (has_reloc_header) {
412
        if (reloc_tag.align == 0) {
413
            panic(true, "multiboot2: Relocatable tag has align=0");
414
        }
415
416
        bool reloc_ascend;
417
        uint64_t relocated_base;
418
419
        switch (reloc_tag.preference) {
420
            default:
421
            case 0: case 1: // No preference / prefer lowest
422
                reloc_ascend = true;
423
                relocated_base = ALIGN_UP(reloc_tag.min_addr, reloc_tag.align, goto reloc_fail);
424
                if (CHECKED_ADD(relocated_base, ranges->length, goto reloc_fail) > reloc_tag.max_addr) {
425
                    goto reloc_fail;
426
                }
427
                break;
428
            case 2: // Prefer highest
429
                reloc_ascend = false;
430
                if (ranges->length > reloc_tag.max_addr) {
431
                    goto reloc_fail;
432
                }
433
                relocated_base = ALIGN_DOWN(reloc_tag.max_addr - ranges->length, reloc_tag.align);
434
                if (relocated_base < reloc_tag.min_addr) {
435
                    goto reloc_fail;
436
                }
437
                break;
438
        }
439
440
        for (;;) {
441
            if (check_usable_memory(relocated_base, CHECKED_ADD(relocated_base, ranges->length, goto reloc_fail))) {
442
                break;
443
            }
444
445
            if (reloc_ascend) {
446
                relocated_base += reloc_tag.align;
447
                if (CHECKED_ADD(relocated_base, ranges->length, goto reloc_fail) > reloc_tag.max_addr) {
448
                    goto reloc_fail;
449
                }
450
            } else {
451
                if (relocated_base - reloc_tag.min_addr < reloc_tag.align) {
452
                    goto reloc_fail;
453
                }
454
                relocated_base -= reloc_tag.align;
455
            }
456
        }
457
458
        reloc_slide = (int64_t)relocated_base - ranges->target;
459
460
        entry_point += reloc_slide;
461
462
        ranges->target = relocated_base;
463
    }
464
465
    if (!check_usable_memory(ranges->target, ranges->target + ranges->length)) {
466
reloc_fail:
467
        panic(true, "multiboot2: Could not find viable load address for executable");
468
    }
469
470
    // Get the load base address (AKA the lowest target in the ranges)
471
    uint64_t load_base_addr = ranges->target;
472
473
    size_t modules_size = 0;
474
    size_t n_modules;
475
476
    for (n_modules = 0;; n_modules++) {
477
        struct conf_tuple conf_tuple = config_get_tuple(config, n_modules, "MODULE_PATH", "MODULE_STRING");
478
        if (!conf_tuple.value1) break;
479
480
        char *module_cmdline = conf_tuple.value2;
481
        if (!module_cmdline) module_cmdline = "";
482
        modules_size += ALIGN_UP(sizeof(struct multiboot_tag_module) + strlen(module_cmdline) + 1, MULTIBOOT_TAG_ALIGN, panic(true, "multiboot2: modules size overflow"));
483
    }
484
485
    struct smbios_entry_point_32* smbios_entry_32 = NULL;
486
    struct smbios_entry_point_64* smbios_entry_64 = NULL;
487
488
    acpi_get_smbios((void **)&smbios_entry_32, (void **)&smbios_entry_64);
489
490
    uint32_t smbios_tag_size = 0;
491
492
    if (smbios_entry_32 != NULL)
493
        smbios_tag_size += ALIGN_UP(sizeof(struct multiboot_tag_smbios) + smbios_entry_32->length, MULTIBOOT_TAG_ALIGN, panic(true, "multiboot2: tag size overflow"));
494
    if (smbios_entry_64 != NULL)
495
        smbios_tag_size += ALIGN_UP(sizeof(struct multiboot_tag_smbios) + smbios_entry_64->length, MULTIBOOT_TAG_ALIGN, panic(true, "multiboot2: tag size overflow"));
496
497
    size_t mb2_info_size = get_multiboot2_info_size(
498
        cmdline,
499
        modules_size,
500
        section_hdr_info_valid ? section_hdr_info.section_entry_size : 0,
501
        section_hdr_info_valid ? section_hdr_info.num : 0,
502
        smbios_tag_size
503
    );
504
505
    size_t info_idx = 0;
506
507
    // Realloc elsewhere ranges to include mb2 info, modules, and elf sections
508
    uint64_t ranges_max = ranges_count
509
       + 1 /* mb2 info range */
510
       + n_modules
511
       + (section_hdr_info_valid ? section_hdr_info.num : 0);
512
    struct elsewhere_range *new_ranges = ext_mem_alloc_counted(ranges_max, sizeof(struct elsewhere_range));
513
514
    memcpy(new_ranges, ranges, sizeof(struct elsewhere_range) * ranges_count);
515
    pmm_free(ranges, sizeof(struct elsewhere_range) * ranges_count);
516
    ranges = new_ranges;
517
518
    // GRUB allocates boot info at 0x10000, *except* if the kernel happens
519
    // to overlap this region, then it gets moved to right after the
520
    // kernel, or whichever PHDR happens to sit at 0x10000.
521
    // Allocate it wherever, then move it to where GRUB puts it
522
    // afterwards.
523
524
    // Elsewhere append mb2 info *after* kernel but *before* modules.
525
    uint8_t *mb2_info = ext_mem_alloc(mb2_info_size);
526
    uint64_t mb2_info_final_loc = 0x10000;
527
528
    if (!elsewhere_append(true /* flexible target */,
529
            ranges, &ranges_count, ranges_max,
530
            mb2_info, &mb2_info_final_loc, mb2_info_size)) {
531
        panic(true, "multiboot2: Cannot allocate mb2 info");
532
    }
533
534
    struct multiboot2_start_tag *mbi_start = (struct multiboot2_start_tag *)mb2_info;
535
    info_idx += sizeof(struct multiboot2_start_tag);
536
537
    //////////////////////////////////////////////
538
    // Create ELF info tag
539
    //////////////////////////////////////////////
540
    if (section_hdr_info_valid == false) {
541
        if (is_elf_info_requested) {
542
            panic(true, "multiboot2: Cannot return ELF file information");
543
        }
544
    } else {
545
        size_t section_table_size = CHECKED_MUL(section_hdr_info.section_entry_size, section_hdr_info.num,
546
            panic(true, "multiboot2: ELF section table size overflow"));
547
        if (section_hdr_info.section_offset > kernel_file_size ||
548
            section_table_size > kernel_file_size - section_hdr_info.section_offset) {
549
            panic(true, "multiboot2: ELF section headers out of bounds");
550
        }
551
552
        uint32_t size = sizeof(struct multiboot_tag_elf_sections) + section_table_size;
553
        struct multiboot_tag_elf_sections *tag = (struct multiboot_tag_elf_sections*)(mb2_info + info_idx);
554
555
        tag->type = MULTIBOOT_TAG_TYPE_ELF_SECTIONS;
556
        tag->size = size;
557
558
        tag->num = section_hdr_info.num;
559
        tag->entsize = section_hdr_info.section_entry_size;
560
        tag->shndx = section_hdr_info.str_section_idx;
561
562
        memcpy(tag->sections, kernel + section_hdr_info.section_offset, section_table_size);
563
564
        int bits = elf_bits(kernel, kernel_file_size);
565
566
        if ((bits == 64 && section_hdr_info.section_entry_size < sizeof(struct elf64_shdr)) ||
567
            (bits == 32 && section_hdr_info.section_entry_size < sizeof(struct elf32_shdr))) {
568
            panic(true, "multiboot2: ELF section entry size too small");
569
        }
570
571
        for (size_t i = 0; i < section_hdr_info.num; i++) {
572
            if (bits == 64)  {
573
                struct elf64_shdr *shdr = (void *)tag->sections + i * section_hdr_info.section_entry_size;
574
575
                if (shdr->sh_addr != 0) {
576
                    shdr->sh_addr += reloc_slide;
577
                    continue;
578
                }
579
                if (shdr->sh_size == 0) {
580
                    continue;
581
                }
582
583
                if (shdr->sh_offset > kernel_file_size ||
584
                    shdr->sh_size > kernel_file_size - shdr->sh_offset) {
585
                    continue;
586
                }
587
588
                uint64_t section = (uint64_t)-1; /* no target preference, use top */
589
590
                if (!elsewhere_append(true /* flexible target */,
591
                        ranges, &ranges_count, ranges_max,
592
                        kernel + shdr->sh_offset, &section, shdr->sh_size)) {
593
                    panic(true, "multiboot2: Cannot allocate elf sections");
594
                }
595
596
                shdr->sh_addr = section;
597
            } else {
598
                struct elf32_shdr *shdr = (void *)tag->sections + i * section_hdr_info.section_entry_size;
599
600
                if (shdr->sh_addr != 0) {
601
                    shdr->sh_addr += (int32_t)reloc_slide;
602
                    continue;
603
                }
604
                if (shdr->sh_size == 0) {
605
                    continue;
606
                }
607
608
                if (shdr->sh_offset > kernel_file_size ||
609
                    shdr->sh_size > kernel_file_size - shdr->sh_offset) {
610
                    continue;
611
                }
612
613
                uint64_t section = (uint64_t)-1; /* no target preference, use top */
614
615
                if (!elsewhere_append(true /* flexible target */,
616
                        ranges, &ranges_count, ranges_max,
617
                        kernel + shdr->sh_offset, &section, shdr->sh_size)) {
618
                    panic(true, "multiboot2: Cannot allocate elf sections");
619
                }
620
621
                shdr->sh_addr = section;
622
            }
623
        }
624
625
        append_tag(info_idx, tag);
626
    }
627
628
    //////////////////////////////////////////////
629
    // Create load base address tag
630
    //////////////////////////////////////////////
631
    if (has_reloc_header) {
632
        uint32_t size = sizeof(struct multiboot_tag_load_base_addr);
633
        struct multiboot_tag_load_base_addr *tag = (void *)(mb2_info + info_idx);
634
635
        tag->type = MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR;
636
        tag->size = size;
637
638
        tag->load_base_addr = load_base_addr;
639
640
        append_tag(info_idx, tag);
641
    }
642
643
    //////////////////////////////////////////////
644
    // Create modules tag
645
    //////////////////////////////////////////////
646
    for (size_t i = 0; i < n_modules; i++) {
647
        struct conf_tuple conf_tuple = config_get_tuple(config, i, "MODULE_PATH", "MODULE_STRING");
648
        char *module_path = conf_tuple.value1;
649
        if (!module_path) panic(true, "multiboot2: Module disappeared unexpectedly");
650
651
        print("multiboot2: Loading module `%#`...\n", module_path);
652
653
        struct file_handle *f;
654
        if ((f = uri_open(module_path, MEMMAP_BOOTLOADER_RECLAIMABLE, false
655
#if defined (__i386__)
656
            , NULL, NULL
657
#endif
658
        )) == NULL)
659
            panic(true, "multiboot2: Failed to open module with path `%#`. Is the path correct?", module_path);
660
661
        // Module commandline can be null, so we guard against that and make the
662
        // string "".
663
        char *module_cmdline = conf_tuple.value2;
664
        if (!module_cmdline) module_cmdline = "";
665
666
        void *module_addr = f->fd;
667
        uint64_t module_target = (uint64_t)-1;
668
669
#if defined (UEFI)
670
        tpm_measure_path(TPM_PCR_BOOT_AUTH, TPM_EV_IPL, "module_path: ", module_path);
671
        tpm_measure(TPM_PCR_LOADED_IMAGES, TPM_EV_IPL,
672
                    module_addr, f->size, "module_path: ", module_path);
673
#endif
674
675
        if (!elsewhere_append(true /* flexible target */,
676
                ranges, &ranges_count, ranges_max,
677
                module_addr, &module_target, f->size)) {
678
            panic(true, "multiboot2: Cannot allocate module");
679
        }
680
681
        struct multiboot_tag_module *module_tag = (struct multiboot_tag_module *)(mb2_info + info_idx);
682
683
        module_tag->type = MULTIBOOT_TAG_TYPE_MODULE;
684
        module_tag->size = sizeof(struct multiboot_tag_module) + strlen(module_cmdline) + 1;
685
        module_tag->mod_start   = module_target;
686
        module_tag->mod_end     = module_tag->mod_start + f->size;
687
        strcpy(module_tag->cmdline, module_cmdline); // Copy over the command line
688
689
        fclose(f);
690
691
        if (verbose) {
692
            print("multiboot2: Requested module %u:\n", (uint32_t)i);
693
            print("            Path:   %s\n", module_path);
694
            print("            String: \"%s\"\n", module_cmdline ?: "");
695
            print("            Begin:  %x\n", module_tag->mod_start);
696
            print("            End:    %x\n", module_tag->mod_end);
697
        }
698
699
        append_tag(info_idx, module_tag);
700
    }
701
702
    //////////////////////////////////////////////
703
    // Create command line tag
704
    //////////////////////////////////////////////
705
    {
706
        uint32_t size = sizeof(struct multiboot_tag_string) + strlen(cmdline) + 1;
707
        struct multiboot_tag_string *tag = (struct multiboot_tag_string *)(mb2_info + info_idx);
708
709
        tag->type = MULTIBOOT_TAG_TYPE_CMDLINE;
710
        tag->size = size;
711
712
        strcpy(tag->string, cmdline);
713
        append_tag(info_idx, tag);
714
    }
715
716
    //////////////////////////////////////////////
717
    // Create bootloader name tag
718
    //////////////////////////////////////////////
719
    {
720
        uint32_t size = sizeof(struct multiboot_tag_string) + sizeof(LIMINE_BRAND);
721
        struct multiboot_tag_string *tag = (struct multiboot_tag_string *)(mb2_info + info_idx);
722
723
        tag->type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME;
724
        tag->size = size;
725
726
        strcpy(tag->string, LIMINE_BRAND);
727
        append_tag(info_idx, tag);
728
    }
729
730
    //////////////////////////////////////////////
731
    // Create EFI image handle tag
732
    //////////////////////////////////////////////
733
#if defined (UEFI)
734
    {
735
    #if defined (__i386__)
736
        struct multiboot_tag_efi32_ih *tag = (struct multiboot_tag_efi32_ih *)(mb2_info + info_idx);
737
738
        tag->type = MULTIBOOT_TAG_TYPE_EFI32_IH;
739
        tag->size = sizeof(struct multiboot_tag_efi32_ih);
740
    #elif defined (__x86_64__)
741
        struct multiboot_tag_efi64_ih *tag = (struct multiboot_tag_efi64_ih *)(mb2_info + info_idx);
742
743
        tag->type = MULTIBOOT_TAG_TYPE_EFI64_IH;
744
        tag->size = sizeof(struct multiboot_tag_efi64_ih);
745
    #endif
746
747
        tag->pointer = (uintptr_t)efi_image_handle;
748
        append_tag(info_idx, tag);
749
    }
750
#endif
751
752
    //////////////////////////////////////////////
753
    // Create framebuffer tag
754
    //////////////////////////////////////////////
755
    {
756
        struct multiboot_tag_framebuffer *tag = (struct multiboot_tag_framebuffer *)(mb2_info + info_idx);
757
758
        tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
759
760
        term_notready();
761
762
        size_t req_width = 0;
763
        size_t req_height = 0;
764
        size_t req_bpp = 0;
765
#if defined (BIOS)
766
        {
767
            char *textmode_str = config_get_value(config, 0, "TEXTMODE");
768
            bool textmode = textmode_str != NULL && strcmp(textmode_str, "yes") == 0;
769
            if (textmode) {
770
                goto textmode;
771
            }
772
        }
773
#endif
774
775
        if (fbtag) {
776
            req_width = fbtag->width;
777
            req_height = fbtag->height;
778
            req_bpp = fbtag->depth;
779
780
#if defined (UEFI)
781
modeset:;
782
#endif
783
            char *resolution = config_get_value(config, 0, "RESOLUTION");
784
            if (resolution != NULL)
785
                parse_resolution(&req_width, &req_height, &req_bpp, resolution);
786
787
            struct fb_info *fbs;
788
            size_t fbs_count;
789
            fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp, false, false);
790
            if (fbs_count == 0) {
791
#if defined (BIOS)
792
textmode:
793
                vga_textmode_init(false);
794
795
                tag->common.framebuffer_addr = 0xb8000;
796
                tag->common.framebuffer_pitch = 2 * 80;
797
                tag->common.framebuffer_width = 80;
798
                tag->common.framebuffer_height = 25;
799
                tag->common.framebuffer_bpp = 16;
800
                tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT;
801
                tag->common.size = sizeof(struct multiboot_tag_framebuffer_common);
802
#elif defined (UEFI)
803
                if (is_framebuffer_required) {
804
                    panic(true, "multiboot2: Failed to set video mode");
805
                } else {
806
                    goto skip_modeset;
807
                }
808
#endif
809
            } else {
810
                tag->common.framebuffer_addr = fbs[0].framebuffer_addr;
811
                tag->common.framebuffer_pitch = fbs[0].framebuffer_pitch;
812
                tag->common.framebuffer_width = fbs[0].framebuffer_width;
813
                tag->common.framebuffer_height = fbs[0].framebuffer_height;
814
                tag->common.framebuffer_bpp = fbs[0].framebuffer_bpp;
815
                tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB; // We only support RGB for VBE
816
                tag->common.size = sizeof(struct multiboot_tag_framebuffer);
817
818
                tag->framebuffer_red_field_position = fbs[0].red_mask_shift;
819
                tag->framebuffer_red_mask_size = fbs[0].red_mask_size;
820
                tag->framebuffer_green_field_position = fbs[0].green_mask_shift;
821
                tag->framebuffer_green_mask_size = fbs[0].green_mask_size;
822
                tag->framebuffer_blue_field_position = fbs[0].blue_mask_shift;
823
                tag->framebuffer_blue_mask_size = fbs[0].blue_mask_size;
824
            }
825
        } else {
826
#if defined (UEFI)
827
            print("multiboot2: Warning: Cannot use text mode with UEFI\n");
828
            goto modeset;
829
#elif defined (BIOS)
830
            goto textmode;
831
#endif
832
        }
833
834
        append_tag(info_idx, &tag->common);
835
836
#if defined (UEFI)
837
skip_modeset:;
838
#endif
839
    }
840
841
    //////////////////////////////////////////////
842
    // Create new ACPI info tag
843
    //////////////////////////////////////////////
844
    {
845
        void *new_rsdp = acpi_get_rsdp_v2();
846
847
        if (new_rsdp != NULL) {
848
            uint32_t size = sizeof(struct multiboot_tag_new_acpi) + sizeof(struct rsdp); // XSDP is 36 bytes wide
849
            struct multiboot_tag_new_acpi *tag = (struct multiboot_tag_new_acpi *)(mb2_info + info_idx);
850
851
            tag->type = MULTIBOOT_TAG_TYPE_ACPI_NEW;
852
            tag->size = size;
853
854
            memcpy(tag->rsdp, new_rsdp, sizeof(struct rsdp));
855
            append_tag(info_idx, tag);
856
        } else if (is_new_acpi_required) {
857
            panic(true, "multiboot2: XSDP requested but not found");
858
        }
859
    }
860
861
    //////////////////////////////////////////////
862
    // Create old ACPI info tag
863
    //////////////////////////////////////////////
864
    {
865
        void *old_rsdp = acpi_get_rsdp_v1();
866
867
        if (old_rsdp != NULL) {
868
            uint32_t size = sizeof(struct multiboot_tag_old_acpi) + 20; // RSDP is 20 bytes wide
869
            struct multiboot_tag_old_acpi *tag = (struct multiboot_tag_old_acpi *)(mb2_info + info_idx);
870
871
            tag->type = MULTIBOOT_TAG_TYPE_ACPI_OLD;
872
            tag->size = size;
873
874
            memcpy(tag->rsdp, old_rsdp, 20);
875
            append_tag(info_idx, tag);
876
        } else if (is_old_acpi_required) {
877
            panic(true, "multiboot2: RSDP requested but not found");
878
        }
879
    }
880
881
    //////////////////////////////////////////////
882
    // Create SMBIOS tag
883
    //////////////////////////////////////////////
884
    {
885
        // NOTE: The multiboot2 specification does not say anything about if both
886
        // smbios 32 and 64 bit entry points are present, then we pass both of them + smbios
887
        // support for grub2 is unimplemented. So, we are going to assume they expect us to
888
        // pass both of them if available. Oh well...
889
        if (smbios_entry_32 != NULL) {
890
            struct multiboot_tag_smbios *tag = (struct multiboot_tag_smbios *)(mb2_info + info_idx);
891
892
            tag->type = MULTIBOOT_TAG_TYPE_SMBIOS;
893
            tag->size = sizeof(struct multiboot_tag_smbios) + smbios_entry_32->length;
894
895
            tag->major = smbios_entry_32->major_version;
896
            tag->minor = smbios_entry_32->minor_version;
897
898
            memset(tag->reserved, 0, 6);
899
            memcpy(tag->tables, smbios_entry_32, smbios_entry_32->length);
900
901
            append_tag(info_idx, tag);
902
        }
903
904
        if (smbios_entry_64 != NULL) {
905
            struct multiboot_tag_smbios *tag = (struct multiboot_tag_smbios *)(mb2_info + info_idx);
906
907
            tag->type = MULTIBOOT_TAG_TYPE_SMBIOS;
908
            tag->size = sizeof(struct multiboot_tag_smbios) + smbios_entry_64->length;
909
910
            tag->major = smbios_entry_64->major_version;
911
            tag->minor = smbios_entry_64->minor_version;
912
913
            memset(tag->reserved, 0, 6);
914
            memcpy(tag->tables, smbios_entry_64, smbios_entry_64->length);
915
916
            append_tag(info_idx, tag);
917
        }
918
    }
919
920
    //////////////////////////////////////////////
921
    // Create EFI system table info tag
922
    //////////////////////////////////////////////
923
#if defined (UEFI)
924
    {
925
    #if defined (__i386__)
926
        uint32_t size = sizeof(struct multiboot_tag_efi32);
927
        struct multiboot_tag_efi32 *tag = (void *)(mb2_info + info_idx);
928
929
        tag->type = MULTIBOOT_TAG_TYPE_EFI32;
930
    #elif defined (__x86_64__)
931
        uint32_t size = sizeof(struct multiboot_tag_efi64);
932
        struct multiboot_tag_efi64 *tag = (void *)(mb2_info + info_idx);
933
934
        tag->type = MULTIBOOT_TAG_TYPE_EFI64;
935
    #endif
936
937
        tag->size = size;
938
        tag->pointer = (uintptr_t)gST;
939
940
        append_tag(info_idx, tag);
941
    }
942
#endif
943
944
    // Load relocation stub where it won't get overwritten (hopefully)
945
    size_t reloc_stub_size = (size_t)multiboot_reloc_stub_end - (size_t)multiboot_reloc_stub;
946
    void *reloc_stub = ext_mem_alloc(reloc_stub_size);
947
    memcpy(reloc_stub, multiboot_reloc_stub, reloc_stub_size);
948
949
#if defined (UEFI)
950
    efi_exit_boot_services();
951
#endif
952
953
    size_t mb_mmap_count;
954
    struct memmap_entry *raw_memmap = get_raw_memmap(&mb_mmap_count);
955
956
    //////////////////////////////////////////////
957
    // Create memory map tag
958
    //////////////////////////////////////////////
959
    {
960
        if (mb_mmap_count > MEMMAP_MAX) {
961
            panic(false, "multiboot2: too many memory map entries");
962
        }
963
964
        // Create the normal memory map tag.
965
        uint32_t mmap_size = sizeof(struct multiboot_tag_mmap) + sizeof(struct multiboot_mmap_entry) * mb_mmap_count;
966
        struct multiboot_tag_mmap *mmap_tag = (struct multiboot_tag_mmap *)(mb2_info + info_idx);
967
968
        mmap_tag->type = MULTIBOOT_TAG_TYPE_MMAP;
969
        mmap_tag->entry_size = sizeof(struct multiboot_mmap_entry);
970
        mmap_tag->entry_version = 0;
971
        mmap_tag->size = mmap_size;
972
973
        for (size_t i = 0; i < mb_mmap_count; i++) {
974
            struct multiboot_mmap_entry *entry = &mmap_tag->entries[i];
975
            entry->addr = raw_memmap[i].base;
976
            entry->len  = raw_memmap[i].length;
977
            entry->type = raw_memmap[i].type;
978
            entry->zero = 0;
979
        }
980
981
        append_tag(info_idx, mmap_tag);
982
    }
983
984
    //////////////////////////////////////////////
985
    // Create basic memory info tag
986
    //////////////////////////////////////////////
987
    {
988
        struct meminfo meminfo = mmap_get_info(mb_mmap_count, raw_memmap);
989
        struct multiboot_tag_basic_meminfo *tag = (struct multiboot_tag_basic_meminfo *)(mb2_info + info_idx);
990
991
        tag->type = MULTIBOOT_TAG_TYPE_BASIC_MEMINFO;
992
        tag->size = sizeof(struct multiboot_tag_basic_meminfo);
993
994
        // Convert the uppermem and lowermem fields from bytes to
995
        // KiB.
996
        tag->mem_upper = (uint32_t)(meminfo.uppermem / 1024);
997
        tag->mem_lower = (uint32_t)(meminfo.lowermem / 1024);
998
999
        append_tag(info_idx, tag);
1000
    }
1001
1002
    //////////////////////////////////////////////
1003
    // Create EFI memory map tag
1004
    //////////////////////////////////////////////
1005
#if defined (UEFI)
1006
    {
1007
        if ((efi_mmap_size / efi_desc_size) > EFI_MEMMAP_MAX) {
1008
            panic(false, "multiboot2: too many EFI memory map entries");
1009
        }
1010
1011
        // Create the EFI memory map tag.
1012
        uint32_t size = sizeof(struct multiboot_tag_efi_mmap) + efi_mmap_size;
1013
        struct multiboot_tag_efi_mmap *mmap_tag = (struct multiboot_tag_efi_mmap *)(mb2_info + info_idx);
1014
1015
        mmap_tag->type = MULTIBOOT_TAG_TYPE_EFI_MMAP;
1016
        mmap_tag->descr_vers = efi_desc_ver;
1017
        mmap_tag->descr_size = efi_desc_size;
1018
        mmap_tag->size = size;
1019
1020
        // Copy over the EFI memory map.
1021
        memcpy(mmap_tag->efi_mmap, efi_mmap, efi_mmap_size);
1022
        append_tag(info_idx, mmap_tag);
1023
    }
1024
#endif
1025
1026
    //////////////////////////////////////////////
1027
    // Create network info tag
1028
    //////////////////////////////////////////////
1029
    {
1030
        if (cached_dhcp_ack_valid) {
1031
            struct multiboot_tag_network *tag = (struct multiboot_tag_network *)(mb2_info + info_idx);
1032
1033
            tag->type = MULTIBOOT_TAG_TYPE_NETWORK;
1034
            tag->size = sizeof(struct multiboot_tag_network) + DHCP_ACK_PACKET_LEN;
1035
1036
            // Copy over the DHCP packet.
1037
            memcpy(tag->dhcpack, cached_dhcp_packet, DHCP_ACK_PACKET_LEN);
1038
            append_tag(info_idx, tag);
1039
        }
1040
    }
1041
1042
    //////////////////////////////////////////////
1043
    // Create end tag
1044
    //////////////////////////////////////////////
1045
    {
1046
        struct multiboot_tag *end_tag = (struct multiboot_tag *)(mb2_info + info_idx);
1047
        end_tag->type = MULTIBOOT_TAG_TYPE_END;
1048
        end_tag->size = sizeof(struct multiboot_tag);
1049
1050
        append_tag(info_idx, end_tag);
1051
    }
1052
1053
    mbi_start->size = info_idx;
1054
    mbi_start->reserved = 0x00;
1055
1056
    if (rdmsr(0x1b) & (1 << 10)) {
1057
        if (x2apic_disable()) {
1058
            printv("multiboot2: Firmware had x2APIC enabled, reverted to xAPIC mode\n");
1059
        } else {
1060
            printv("multiboot2: Firmware has x2APIC enabled and it could not be disabled\n");
1061
        }
1062
    }
1063
1064
    iommu_disable_all();
1065
1066
    irq_flush_type = IRQ_PIC_ONLY_FLUSH;
1067
1068
    common_spinup(multiboot_spinup_32, 6,
1069
                  (uint32_t)(uintptr_t)reloc_stub, (uint32_t)0x36d76289,
1070
                  (uint32_t)mb2_info_final_loc, (uint32_t)entry_point,
1071
                  (uint32_t)(uintptr_t)ranges, (uint32_t)ranges_count);
1072
}
1073
1074
#endif
tab: 248 wrap: offon