| 1 | #include <stddef.h> |
| 2 | #include <stdint.h> |
| 3 | #include <stdbool.h> |
| 4 | #include <stdnoreturn.h> |
| 5 | #include <lib/term.h> |
| 6 | #include <lib/real.h> |
| 7 | #include <lib/misc.h> |
| 8 | #include <lib/libc.h> |
| 9 | #include <lib/part.h> |
| 10 | #include <lib/config.h> |
| 11 | #include <lib/trace.h> |
| 12 | #include <sys/e820.h> |
| 13 | #include <sys/a20.h> |
| 14 | #include <lib/print.h> |
| 15 | #include <fs/file.h> |
| 16 | #include <lib/elf.h> |
| 17 | #include <mm/pmm.h> |
| 18 | #include <protos/linux.h> |
| 19 | #include <protos/chainload.h> |
| 20 | #include <menu.h> |
| 21 | #include <pxe/pxe.h> |
| 22 | #include <pxe/tftp.h> |
| 23 | #include <drivers/disk.h> |
| 24 | #include <sys/idt.h> |
| 25 | #include <sys/cpu.h> |
| 26 | |
| 27 | struct volume *boot_volume; |
| 28 | |
| 29 | #if defined (BIOS) |
| 30 | |
| 31 | bool stage3_loaded = false; |
| 32 | static bool stage3_found = false; |
| 33 | |
| 34 | extern symbol stage3_addr; |
| 35 | extern symbol limine_bios_sys_size; |
| 36 | extern symbol build_id_s2; |
| 37 | extern symbol build_id_s3; |
| 38 | |
| 39 | static bool stage3_init(struct volume *part) { |
| 40 | struct file_handle *stage3; |
| 41 | |
| 42 | bool old_cif = case_insensitive_fopen; |
| 43 | case_insensitive_fopen = true; |
| 44 | if (true |
| 45 | && (stage3 = fopen(part, "/boot/limine/limine-bios.sys")) == NULL |
| 46 | && (stage3 = fopen(part, "/boot/limine-bios.sys")) == NULL |
| 47 | && (stage3 = fopen(part, "/limine/limine-bios.sys")) == NULL |
| 48 | && (stage3 = fopen(part, "/limine-bios.sys")) == NULL |
| 49 | ) { |
| 50 | case_insensitive_fopen = old_cif; |
| 51 | return false; |
| 52 | } |
| 53 | case_insensitive_fopen = old_cif; |
| 54 | |
| 55 | stage3_found = true; |
| 56 | |
| 57 | if (stage3->size != (size_t)limine_bios_sys_size) { |
| 58 | print("limine-bios.sys size incorrect.\n"); |
| 59 | return false; |
| 60 | } |
| 61 | |
| 62 | fread(stage3, stage3_addr, |
| 63 | (uintptr_t)stage3_addr - 0xf000, |
| 64 | stage3->size - ((uintptr_t)stage3_addr - 0xf000)); |
| 65 | |
| 66 | fclose(stage3); |
| 67 | |
| 68 | if (memcmp(build_id_s2 + 16, build_id_s3 + 16, 20) != 0) { |
| 69 | print("limine-bios.sys build ID mismatch.\n"); |
| 70 | return false; |
| 71 | } |
| 72 | |
| 73 | stage3_loaded = true; |
| 74 | |
| 75 | return true; |
| 76 | } |
| 77 | |
| 78 | enum { |
| 79 | BOOTED_FROM_HDD = 0, |
| 80 | BOOTED_FROM_PXE = 1, |
| 81 | BOOTED_FROM_CD = 2 |
| 82 | }; |
| 83 | |
| 84 | noreturn void entry(uint8_t boot_drive, int boot_from) { |
| 85 | // XXX DO NOT MOVE A20 ENABLE CALL |
| 86 | if (!a20_enable()) { |
| 87 | panic(false, "Could not enable A20 line"); |
| 88 | } |
| 89 | |
| 90 | calibrate_tsc(); |
| 91 | uint64_t usec_at_entry = rdtsc_usec(); |
| 92 | |
| 93 | init_e820(); |
| 94 | init_memmap(); |
| 95 | |
| 96 | init_idt(); |
| 97 | |
| 98 | disk_create_index(); |
| 99 | |
| 100 | if (boot_from == BOOTED_FROM_HDD || boot_from == BOOTED_FROM_CD) { |
| 101 | boot_volume = volume_get_by_bios_drive(boot_drive); |
| 102 | } else if (boot_from == BOOTED_FROM_PXE) { |
| 103 | pxe_init(); |
| 104 | boot_volume = pxe_bind_volume(); |
| 105 | } |
| 106 | |
| 107 | if (boot_volume == NULL) { |
| 108 | panic(false, "Could not determine boot drive"); |
| 109 | } |
| 110 | |
| 111 | volume_iterate_parts(boot_volume, |
| 112 | if (stage3_init(_PART)) { |
| 113 | break; |
| 114 | } |
| 115 | ); |
| 116 | |
| 117 | if (!stage3_found) { |
| 118 | print("\n" |
| 119 | "!! Stage 3 file not found!\n" |
| 120 | "!! Have you copied limine-bios.sys to the root, /boot, /limine, or /boot/limine\n" |
| 121 | "!! directories of one of the partitions on the boot device?\n\n"); |
| 122 | } |
| 123 | |
| 124 | if (!stage3_loaded) { |
| 125 | panic(false, "Failed to load stage 3."); |
| 126 | } |
| 127 | |
| 128 | term_fallback(); |
| 129 | |
| 130 | usec_at_bootloader_entry = usec_at_entry; |
| 131 | stage3_common(); |
| 132 | } |
| 133 | |
| 134 | #endif |