diff --git a/.gitignore b/.gitignore index ec9d1bd5..b27effaf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +/**/*.gen +/**/*.map /**/*.o /**/*.d /**/*.a diff --git a/Makefile b/Makefile index cc5beb67..5f8afdd3 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ all: stage2 decompressor gzip -n -9 < stage2/stage2.bin > stage2/stage2.bin.gz cd bootsect && nasm bootsect.asm -fbin -o ../limine.bin cd pxeboot && nasm bootsect.asm -fbin -o ../limine-pxe.bin + cp stage2/stage2.map ./ clean: stage2-clean decompressor-clean test-clean rm -f stage2/stage2.bin.gz @@ -55,6 +56,7 @@ echfs-test: limine-install test.img ext2-test: limine-install test.img $(MAKE) -C test + cp stage2.map test/ rm -rf test_image/ mkdir test_image sudo losetup -Pf --show test.img > loopback_dev @@ -62,8 +64,7 @@ ext2-test: limine-install test.img sudo mkfs.ext2 `cat loopback_dev`p1 sudo mount `cat loopback_dev`p1 test_image sudo mkdir test_image/boot - sudo cp test/test.elf test_image/boot/ - sudo cp test/limine.cfg test_image/ + sudo cp -rv test/* test_image/boot/ sync sudo umount test_image/ sudo losetup -d `cat loopback_dev` @@ -80,8 +81,7 @@ fat32-test: limine-install test.img sudo mkfs.fat -F 32 `cat loopback_dev`p1 sudo mount `cat loopback_dev`p1 test_image sudo mkdir test_image/boot - sudo cp test/test.elf test_image/boot/ - sudo cp test/limine.cfg test_image/ + sudo cp -rv test/* test_image/boot/ sync sudo umount test_image/ sudo losetup -d `cat loopback_dev` diff --git a/decompressor/main.c b/decompressor/main.c index 07db966f..6ef54587 100644 --- a/decompressor/main.c +++ b/decompressor/main.c @@ -9,8 +9,17 @@ void entry(uint8_t *compressed_stage2, size_t stage2_size, uint8_t boot_drive, i tinf_gzip_uncompress(dest, compressed_stage2, stage2_size); - __attribute__((noreturn)) - void (*stage2)(uint8_t boot_drive, int pxe) = (void *)dest; + asm volatile ( + "mov esp, 0x7c00\n\t" + "xor ebp, ebp\n\t" + "push %1\n\t" + "push %0\n\t" + "push 0\n\t" + "jmp 0x8000\n\t" + : + : "r" ((uint32_t)boot_drive), "r" (pxe) + : "memory" + ); - stage2(boot_drive, pxe); + for (;;); } diff --git a/limine-pxe.bin b/limine-pxe.bin index 0e50a21f..b7522ef6 100644 Binary files a/limine-pxe.bin and b/limine-pxe.bin differ diff --git a/limine.bin b/limine.bin index 82ca5687..0d10becd 100644 Binary files a/limine.bin and b/limine.bin differ diff --git a/stage2/Makefile b/stage2/Makefile index 8ac4c472..9e4ccdcf 100644 --- a/stage2/Makefile +++ b/stage2/Makefile @@ -1,9 +1,10 @@ CC = i386-elf-gcc LD = i386-elf-gcc OBJCOPY = i386-elf-objcopy +OBJDUMP = i386-elf-objdump WERROR = -Werror -CFLAGS = -flto -Os -pipe -Wall -Wextra $(WERROR) +CFLAGS = -Os -pipe -Wall -Wextra $(WERROR) INTERNAL_CFLAGS = \ -std=gnu11 \ @@ -11,7 +12,7 @@ INTERNAL_CFLAGS = \ -ffreestanding \ -fno-stack-protector \ -fno-pic \ - -fomit-frame-pointer \ + -fno-omit-frame-pointer \ -Wno-address-of-packed-member \ -masm=intel \ -mno-80387 \ @@ -23,7 +24,7 @@ INTERNAL_CFLAGS = \ -I. \ -I.. -LDFLAGS = -flto -Os +LDFLAGS = -Os INTERNAL_LDFLAGS = \ -lgcc \ @@ -41,11 +42,17 @@ ASM_FILES := $(shell find ./ -type f -name '*.asm' | sort) OBJ := $(ASM_FILES:.asm=.o) $(C_FILES:.c=.o) HEADER_DEPS := $(C_FILES:.c=.d) -all: stage2.bin +all: stage2.map stage2.bin -stage2.bin: $(OBJ) - $(LD) $(OBJ) $(LDFLAGS) $(INTERNAL_LDFLAGS) -o stage2.elf - $(OBJCOPY) -O binary stage2.elf stage2.bin +stage2.map: stage2.elf + ./gensyms.sh $(OBJDUMP) + nasm symlist.gen -f bin -o $@ + +stage2.bin: stage2.elf + $(OBJCOPY) -O binary $< $@ + +stage2.elf: $(OBJ) + $(LD) $(OBJ) $(LDFLAGS) $(INTERNAL_LDFLAGS) -o $@ -include $(HEADER_DEPS) @@ -56,4 +63,4 @@ stage2.bin: $(OBJ) nasm $< -f elf32 -o $@ clean: - rm -f stage2.bin stage2.elf $(OBJ) $(HEADER_DEPS) + rm -f symlist.gen stage2.map stage2.bin stage2.elf $(OBJ) $(HEADER_DEPS) diff --git a/stage2/gensyms.sh b/stage2/gensyms.sh new file mode 100755 index 00000000..16145d55 --- /dev/null +++ b/stage2/gensyms.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +set -e + +TMP1=$(mktemp) +TMP2=$(mktemp) +TMP3=$(mktemp) + +$1 -t stage2.elf | sed '/\bd\b/d' | sort > "$TMP1" +grep "\.text" < "$TMP1" | cut -d' ' -f1 > "$TMP2" +grep "\.text" < "$TMP1" | awk 'NF{ print $NF }' > "$TMP3" + +paste -d'$' "$TMP2" "$TMP3" | sed 's/^/dd 0x/g' | sed 's/$/", 0/g' | sed 's/\$/\ndb "/g' > symlist.gen + +echo "dd 0xffffffff" >> symlist.gen + +rm "$TMP1" "$TMP2" "$TMP3" diff --git a/stage2/lib/blib.c b/stage2/lib/blib.c index 3112bf4f..ce4596e2 100644 --- a/stage2/lib/blib.c +++ b/stage2/lib/blib.c @@ -4,6 +4,7 @@ #include #include #include +#include uint8_t boot_drive; @@ -73,6 +74,9 @@ __attribute__((noreturn)) void panic(const char *fmt, ...) { va_end(args); + print("\n"); + print_stacktrace(NULL); + for (;;) { asm volatile ("hlt" ::: "memory"); } diff --git a/stage2/lib/trace.c b/stage2/lib/trace.c new file mode 100644 index 00000000..1e392678 --- /dev/null +++ b/stage2/lib/trace.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char *stage2_map = NULL; + +void trace_init(void) { + char map_filename[80]; + if (!config_get_value(map_filename, 0, 80, "STAGE2_MAP")) + return; + + struct file_handle stage2_map_file; + if (!uri_open(&stage2_map_file, map_filename)) + panic("Could not open stage2 map file `%s`", map_filename); + + stage2_map = ext_mem_alloc(stage2_map_file.size); + fread(&stage2_map_file, stage2_map, 0, stage2_map_file.size); + + print("trace: Stage 2 map file `%s` loaded.\n", map_filename); +} + +char *trace_address(size_t *off, size_t addr) { + if (!stage2_map) + return NULL; + + uint32_t prev_addr = 0; + char *prev_sym = NULL; + + for (size_t i = 0;;) { + if (*((uint32_t *)&stage2_map[i]) >= addr) { + *off = addr - prev_addr; + return prev_sym; + } + prev_addr = *((uint32_t *)&stage2_map[i]); + i += sizeof(uint32_t); + prev_sym = &stage2_map[i]; + while (stage2_map[i++] != 0); + } +} + +void print_stacktrace(size_t *base_ptr) { + if (!stage2_map) + print("trace: Symbol names won't be resolved due to missing map file.\n"); + + if (base_ptr == NULL) { + asm volatile ( + "mov %0, ebp" + : "=g"(base_ptr) + :: "memory" + ); + } + print("Stacktrace:\n"); + for (;;) { + size_t old_bp = base_ptr[0]; + size_t ret_addr = base_ptr[1]; + if (!ret_addr) + break; + size_t off; + char *name = trace_address(&off, ret_addr); + if (name) + print(" [%x] <%s+%x>\n", ret_addr, name, off); + else + print(" [%x]\n", ret_addr); + if (!old_bp) + break; + base_ptr = (void*)old_bp; + } + print("End of trace.\n"); +} diff --git a/stage2/lib/trace.h b/stage2/lib/trace.h new file mode 100644 index 00000000..30c3cf47 --- /dev/null +++ b/stage2/lib/trace.h @@ -0,0 +1,10 @@ +#ifndef __LIB__TRACE_H__ +#define __LIB__TRACE_H__ + +#include + +void trace_init(void); +char *trace_address(size_t *off, size_t addr); +void print_stacktrace(size_t *base_ptr); + +#endif diff --git a/stage2/main.c b/stage2/main.c index dfdd9d4e..a2f2bb1f 100644 --- a/stage2/main.c +++ b/stage2/main.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,8 @@ void entry(uint8_t _boot_drive, int pxe_boot) { } } + trace_init(); + char *cmdline = menu(); char proto[32]; diff --git a/test/limine.cfg b/test/limine.cfg index 3d38a940..da6cfcd1 100644 --- a/test/limine.cfg +++ b/test/limine.cfg @@ -3,21 +3,25 @@ TIMEOUT=3 GRAPHICS=yes MENU_RESOLUTION=1024x768 E9_OUTPUT=yes +STAGE2_MAP=bios://:1/boot/stage2.map THEME_COLOURS=60000000;aa0000;00aaff;aa5500;0000aa;aa00aa;9076de;aaaaaa THEME_MARGIN=64 -BACKGROUND_PATH=guid://@GUID@/bg.bmp +BACKGROUND_PATH=bios://:1/boot/bg.bmp :Stivale Test PROTOCOL=stivale -KERNEL_PATH=guid://@GUID@/boot/test.elf +KERNEL_PATH=bios://:1/boot/test.elf KERNEL_CMDLINE=Hi! This is an example! MODULE_PATH=bios://:1/boot/test.elf MODULE_STRING=yooooo +MODULE_PATH=bios://:1/boot/bg.bmp +MODULE_STRING=yooooo + :Stivale2 Test PROTOCOL=stivale2 @@ -25,5 +29,5 @@ RESOLUTION=640x480x16 KERNEL_PATH=bios://:1/boot/test.elf KERNEL_CMDLINE=Woah! Another example! -MODULE_PATH=guid://@GUID@/boot/test.elf +MODULE_PATH=bios://:1/boot/bg.bmp MODULE_STRING=yooooo