misc: Add measures to prevent stage 2 from accidentally relying on stage 3 before the latter is loaded
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 <lib/print.h>
#include <lib/trace.h>
#include <lib/real.h>
+#include <fs/file.h>
-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 <stddef.h>
#include <stdint.h>
#include <stdbool.h>
+#include <fs/file.h>
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 <lib/term.h>
#include <lib/real.h>
#include <lib/image.h>
+#include <lib/blib.h>
#include <drivers/vga_textmode.h>
#include <drivers/vbe.h>
@@ -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 (;;);
}
