diff --git a/stage23/Makefile b/stage23/Makefile index f57e7021..509721f5 100644 --- a/stage23/Makefile +++ b/stage23/Makefile @@ -61,6 +61,9 @@ limine.sys: limine.elf $(OBJCOPY) -O binary $< $@ limine_nomap.elf: $(OBJ) + $(LD) $(OBJ) $(LDFLAGS) $(INTERNAL_LDFLAGS) -Wl,--gc-sections -Tlinker_stage2only.ld -o $@ || \ + ( echo "This error means that stage2 was trying to use stage3 symbols before loading stage 3" && \ + false ) $(LD) $(OBJ) $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_nomap.ld -o $@ limine.elf: $(OBJ) limine.map.o diff --git a/stage23/lib/blib.c b/stage23/lib/blib.c index 9505f629..0fb435c8 100644 --- a/stage23/lib/blib.c +++ b/stage23/lib/blib.c @@ -6,9 +6,10 @@ #include #include #include +#include -uint64_t build_id = BUILD_ID; -stage3_data uint64_t stage3_build_id = BUILD_ID; +__attribute__((section(".stage3_build_id"))) +uint64_t stage3_build_id = BUILD_ID; uint8_t boot_drive; int boot_partition = -1; @@ -17,6 +18,39 @@ bool booted_from_pxe = false; bool booted_from_cd = false; bool stage3_loaded = false; +extern symbol stage3_addr; +extern symbol limine_sys_size; + +__attribute__((noreturn)) +void (*stage3)(void) = (void *)stage3_addr; + +bool stage3_init(struct volume *part) { + struct file_handle stage3; + + if (fopen(&stage3, part, "/limine.sys") + && fopen(&stage3, part, "/boot/limine.sys")) { + return false; + } + + if (stage3.size != (size_t)limine_sys_size) { + print("limine.sys size incorrect.\n"); + return false; + } + + fread(&stage3, stage3_addr, + (uintptr_t)stage3_addr - 0x8000, + stage3.size - ((uintptr_t)stage3_addr - 0x8000)); + + if (BUILD_ID != stage3_build_id) { + print("limine.sys build ID mismatch.\n"); + return false; + } + + stage3_loaded = true; + + return true; +} + bool parse_resolution(int *width, int *height, int *bpp, const char *buf) { int res[3] = {0}; diff --git a/stage23/lib/blib.h b/stage23/lib/blib.h index 880c57af..54586682 100644 --- a/stage23/lib/blib.h +++ b/stage23/lib/blib.h @@ -4,6 +4,7 @@ #include #include #include +#include extern uint8_t boot_drive; extern int boot_partition; @@ -48,7 +49,7 @@ typedef char symbol[]; #define stage3_text __attribute__((section(".stage3_text"))) #define stage3_data __attribute__((section(".stage3_data"))) -extern uint64_t build_id; -extern uint64_t stage3_build_id; +__attribute__((noreturn)) extern void (*stage3)(void); +bool stage3_init(struct volume *part); #endif diff --git a/stage23/lib/config.c b/stage23/lib/config.c index 58b755df..c9c7fa9b 100644 --- a/stage23/lib/config.c +++ b/stage23/lib/config.c @@ -16,28 +16,7 @@ bool config_ready = false; static char *config_addr; -extern symbol stage3_addr; - int init_config_disk(struct volume *part) { - if (!stage3_loaded) { - struct file_handle stage3; - - if (fopen(&stage3, part, "/limine.sys") - && fopen(&stage3, part, "/boot/limine.sys")) { - panic("Could not open stage 3"); - } - - fread(&stage3, stage3_addr, - (uintptr_t)stage3_addr - 0x8000, - stage3.size - ((uintptr_t)stage3_addr - 0x8000)); - - if (build_id != stage3_build_id) { - panic("Limine build ID mismatch. Use the correct limine.sys."); - } - - stage3_loaded = true; - } - struct file_handle f; if (fopen(&f, part, "/limine.cfg") @@ -56,12 +35,6 @@ int init_config_disk(struct volume *part) { } int init_config_pxe(void) { - struct tftp_file_handle stage3; - if (tftp_open(&stage3, 0, 69, "limine.sys")) { - panic("Could not open stage 3"); - } - tftp_read(&stage3, stage3_addr, 0, stage3.file_size); - struct tftp_file_handle cfg; if (tftp_open(&cfg, 0, 69, "limine.cfg") && tftp_open(&cfg, 0, 69, "tomatboot.cfg")) { diff --git a/stage23/lib/term.c b/stage23/lib/term.c index ab049516..d4bffe18 100644 --- a/stage23/lib/term.c +++ b/stage23/lib/term.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -27,6 +28,7 @@ void (*term_double_buffer_flush)(void); int term_rows, term_cols; +stage3_text void term_vbe(uint32_t *colours, int margin, int margin_gradient, struct image *background) { term_deinit(); if (!vbe_tty_init(&term_rows, &term_cols, colours, margin, margin_gradient, background)) { diff --git a/stage23/linker.ld b/stage23/linker.ld index 2c0f573b..fa9e81f3 100644 --- a/stage23/linker.ld +++ b/stage23/linker.ld @@ -6,11 +6,11 @@ SECTIONS . = 0x8000; .entry : { - KEEP(*(.entry*)) + *(.entry*) } .realmode : { - KEEP(*(.realmode*)) + *(.realmode*) } .stage2.text : { @@ -24,6 +24,8 @@ SECTIONS .stage3.text : { stage3_addr = .; + *(.stage3_entry*) + *(.stage3_build_id*) *(.stage3_text*) } @@ -32,7 +34,8 @@ SECTIONS } .map : { - KEEP(*(.map*)) + *(.map*) + limine_sys_size = . - 0x8000; } .bss : { diff --git a/stage23/linker_nomap.ld b/stage23/linker_nomap.ld index 80a70c16..99d6b439 100644 --- a/stage23/linker_nomap.ld +++ b/stage23/linker_nomap.ld @@ -6,11 +6,11 @@ SECTIONS . = 0x8000; .entry : { - KEEP(*(.entry*)) + *(.entry*) } .realmode : { - KEEP(*(.realmode*)) + *(.realmode*) } .stage2.text : { @@ -24,6 +24,8 @@ SECTIONS .stage3.text : { stage3_addr = .; + *(.stage3_entry*) + *(.stage3_build_id*) *(.stage3_text*) } @@ -33,6 +35,7 @@ SECTIONS .map : { limine_map = .; + limine_sys_size = .; } .bss : { diff --git a/stage23/linker_stage2only.ld b/stage23/linker_stage2only.ld new file mode 100644 index 00000000..3e12ccce --- /dev/null +++ b/stage23/linker_stage2only.ld @@ -0,0 +1,39 @@ +OUTPUT_FORMAT(elf32-i386) +ENTRY(_start) + +SECTIONS +{ + . = 0x8000; + + .entry : { + *(.entry*) + } + + .realmode : { + *(.realmode*) + } + + .stage2.text : { + *(.text*) + } + + .stage2.data : { + *(.data*) + *(.rodata*) + stage3_addr = .; + *(.stage3_build_id*) + limine_map = .; + limine_sys_size = .; + } + + .bss : { + bss_begin = .; + *(COMMON) + *(.bss*) + bss_end = .; + } + + /DISCARD/ : { + *(*) + } +} diff --git a/stage23/main.c b/stage23/main.c index d4be236a..216e730d 100644 --- a/stage23/main.c +++ b/stage23/main.c @@ -26,6 +26,7 @@ enum { BOOT_FROM_CD }; +__attribute__((noreturn)) void entry(uint8_t _boot_drive, int boot_from) { boot_drive = _boot_drive; @@ -44,31 +45,39 @@ void entry(uint8_t _boot_drive, int boot_from) { init_e820(); init_memmap(); - struct volume part; volume_create_index(); switch (boot_from) { - case BOOT_FROM_HDD: + case BOOT_FROM_HDD: { print("Boot drive: %x\n", boot_drive); - // Look for config file. - print("Searching for config file...\n"); + struct volume boot_volume; + volume_get_by_coord(&boot_volume, boot_drive, -1); + struct volume part = boot_volume; + bool stage3_loaded = false, config_loaded = false; for (int i = 0; ; i++) { - int ret = volume_get_by_coord(&part, boot_drive, i); + if (!stage3_loaded && stage3_init(&part)) { + stage3_loaded = true; + print("Stage 3 found and loaded.\n"); + } + if (!config_loaded && !init_config_disk(&part)) { + config_loaded = true; + print("Config file found and loaded.\n"); + boot_partition = i - 1; + } + int ret = part_get(&part, &boot_volume, i); switch (ret) { case INVALID_TABLE: - panic("Partition table of boot drive is invalid."); case END_OF_TABLE: - panic("Config file not found."); - case NO_PARTITION: - continue; - } - if (!init_config_disk(&part)) { - print("Config file found and loaded.\n"); - boot_partition = i; - break; + goto break2; } } +break2: + if (!stage3_loaded) + panic("Stage 3 not loaded."); + if (!config_loaded) + panic("Config file not found."); break; + } case BOOT_FROM_PXE: pxe_init(); @@ -77,15 +86,14 @@ void entry(uint8_t _boot_drive, int boot_from) { } print("Config loaded via PXE\n"); break; - - case BOOT_FROM_CD: - boot_partition = -1; // raw device - volume_get_by_coord(&part, boot_drive, boot_partition); - if (init_config_disk(&part)) - panic("Failed to load config file"); - break; } + stage3(); +} + +__attribute__((noreturn)) +__attribute__((section(".stage3_entry"))) +void stage3_entry(void) { char *cmdline; char *config = menu(&cmdline); @@ -105,4 +113,6 @@ void entry(uint8_t _boot_drive, int boot_from) { } else { panic("Invalid protocol specified"); } + + for (;;); }