diff --git a/Makefile b/Makefile index c27e0ba3..7dfa4a98 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ all: stage2 decompressor gzip -n -9 < stage2/stage2.bin > stage2/stage2.bin.gz cd bootsect && nasm bootsect.asm -fbin -o ../limine.bin -clean: stage2-clean decompressor-clean +clean: stage2-clean decompressor-clean test-clean rm -f stage2/stage2.bin.gz stage2: @@ -23,6 +23,9 @@ decompressor: decompressor-clean: $(MAKE) -C decompressor clean +test-clean: + $(MAKE) -C test clean + toolchain: cd toolchain && ./make_toolchain.sh -j`nproc` diff --git a/test/Makefile b/test/Makefile index 8dc22c83..a9336673 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,3 +1,22 @@ -test.elf: test.asm linker.ld - nasm test.asm -felf64 -o test.o - ld test.o -no-pie -nostdlib -T ./linker.ld -o test.elf +TARGET := test.elf + +CC = cc +CFLAGS = -O2 +LD = ld +QEMU = qemu-system-x86_64 +QEMUFLAGS = -m 1G -enable-kvm -cpu host +LDINTERNALFLAGS := -Tlinker.ld -static -nostdlib -no-pie +INTERNALCFLAGS := -I../stivale -I. -ffreestanding -fno-stack-protector \ + -fno-pic -fomit-frame-pointer -mno-80387 -mno-mmx -mno-3dnow -mno-sse \ + -mno-sse2 -masm=intel + +all: $(TARGET) + +$(TARGET): stivale.o stivale2.o e9print.o + $(LD) $(LDINTERNALFLAGS) stivale.o stivale2.o e9print.o -o $@ + +%.o: %.c + $(CC) $(CFLAGS) $(INTERNALCFLAGS) -c $< -o $@ + +clean: + rm -rf $(TARGET) stivale.o stivale2.o e9print.o diff --git a/test/e9print.c b/test/e9print.c new file mode 100644 index 00000000..f027e4ec --- /dev/null +++ b/test/e9print.c @@ -0,0 +1,82 @@ +#include +#include + +static const char CONVERSION_TABLE[] = "0123456789abcdef"; + +void e9_putc(char c) { + asm volatile ("out dx, al" :: "a" (c), "d" (0xE9) : "memory"); +} + +void e9_print(const char *msg) { + for (size_t i = 0; msg[i]; i++) { + e9_putc(msg[i]); + } +} + +void e9_puts(const char *msg) { + e9_print(msg); + e9_putc('\n'); +} + +static void e9_printhex(size_t num) { + int i; + char buf[17]; + + if (!num) { + e9_print("0x0"); + return; + } + + buf[16] = 0; + + for (i = 15; num; i--) { + buf[i] = CONVERSION_TABLE[num % 16]; + num /= 16; + } + + i++; + e9_print("0x"); + e9_print(&buf[i]); +} + +static void e9_printdec(size_t num) { + int i; + char buf[21] = {0}; + + if (!num) { + e9_putc('0'); + return; + } + + for (i = 19; num; i--) { + buf[i] = (num % 10) + 0x30; + num = num / 10; + } + + i++; + e9_print(buf + i); +} + +void e9_printf(const char *format, ...) { + va_list argp; + va_start(argp, format); + + while (*format != '\0') { + if (*format == '%') { + format++; + if (*format == 'x') { + e9_printhex(va_arg(argp, size_t)); + } else if (*format == 'd') { + e9_printdec(va_arg(argp, size_t)); + } else if (*format == 's') { + e9_print(va_arg(argp, char*)); + } + } else { + e9_putc(*format); + } + format++; + } + + e9_putc('\n'); + va_end(argp); +} diff --git a/test/e9print.h b/test/e9print.h new file mode 100644 index 00000000..44ac8e2f --- /dev/null +++ b/test/e9print.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +void e9_putc(char c); +void e9_print(const char *msg); +void e9_puts(const char *msg); +void e9_printf(const char *format, ...); diff --git a/test/limine.cfg b/test/limine.cfg index ab43e465..380682f3 100644 --- a/test/limine.cfg +++ b/test/limine.cfg @@ -1,4 +1,4 @@ -DEFAULT_ENTRY=2 +DEFAULT_ENTRY=0 TIMEOUT=3 GRAPHICS=yes @@ -16,26 +16,16 @@ THEME_MARGIN=64 BACKGROUND_PARTITION=0 BACKGROUND_PATH=bg.bmp -:MyOS 0 - -PROTOCOL=stivale2 +:Stivale Test +PROTOCOL=stivale KERNEL_PARTITION=0 KERNEL_PATH=boot/test.elf -KERNEL_CMDLINE=something +KERNEL_CMDLINE=Hi! This is an example! -:MyOS 1 +:Stivale2 Test PROTOCOL=stivale2 - KERNEL_PARTITION=0 KERNEL_PATH=boot/test.elf -KERNEL_CMDLINE=something - -:MyOS 2 - -PROTOCOL=stivale2 - -KERNEL_PARTITION=0 -KERNEL_PATH=boot/test.elf -KERNEL_CMDLINE=something +KERNEL_CMDLINE=Woah! Another example! diff --git a/test/linker.ld b/test/linker.ld index 14f6027d..768751a6 100644 --- a/test/linker.ld +++ b/test/linker.ld @@ -1,26 +1,37 @@ -ENTRY(_start) +ENTRY(stivale_main) -SECTIONS { - . = 0xffffffff80100000; +SECTIONS +{ + . = 0x100000; - .stivalehdr : ALIGN(4K) { - *(.stivalehdr) + .stivalehdr ALIGN(4K) : + { + KEEP(*(.stivalehdr)) } - .text : ALIGN(4K) { - *(.text*) + .stivale2hdr ALIGN(4K) : + { + KEEP(*(.stivale2hdr)) } - .rodata : ALIGN(4K) { - *(.rodata*) + .text ALIGN(4K) : + { + KEEP(*(.text*)) } - .data : ALIGN(4K) { - *(.data*) + .rodata ALIGN(4K) : + { + KEEP(*(.rodata*)) } - .bss : ALIGN(4K) { - *(.bss*) - *(COMMON) + .data ALIGN(4K) : + { + KEEP(*(.data*)) + } + + .bss ALIGN(4K) : + { + KEEP(*(COMMON)) + KEEP(*(.bss*)) } } diff --git a/test/stivale.c b/test/stivale.c new file mode 100644 index 00000000..4616ec6b --- /dev/null +++ b/test/stivale.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include + +static uint8_t stack[4096] = {0}; +void stivale_main(struct stivale_struct *info); + +__attribute__((section(".stivalehdr"), used)) +struct stivale_header header = { + .stack = (uint64_t)(uintptr_t)stack + sizeof(stack), + .framebuffer_bpp = 0, + .framebuffer_width = 0, + .framebuffer_height = 0, + .flags = 1, + .entry_point = (uint64_t)(uintptr_t)stivale_main +}; + +void stivale_main(struct stivale_struct *info) { + // Print some info. + e9_puts("Stivale information passed to the kernel:"); + e9_printf("Cmdline: %s", (char*)info->cmdline); + e9_printf("Memory map at %x with contents:", info->memory_map_addr); + + struct stivale_mmap_entry *memmap = ((struct stivale_mmap_entry *)(info->memory_map_addr)); + for (size_t i = 0; i < info->memory_map_entries; i++) { + struct stivale_mmap_entry e = memmap[i]; + e9_printf("\tEntry %d: [%x+%x] %x", i, e.base, e.length, e.type); + } + + e9_printf("Framebuffer at %x with specifics:", info->framebuffer_addr); + e9_printf("\tPitch: %d", info->framebuffer_pitch); + e9_printf("\tWidth: %d", info->framebuffer_width); + e9_printf("\tHeight: %d", info->framebuffer_height); + e9_printf("\tBPP: %d", info->framebuffer_bpp); + e9_printf("RSDP at %x", info->rsdp); + + e9_printf("Module map at %x with modules:", info->modules); + struct stivale_module *modules = ((struct stivale_module *)(info->modules)); + for (size_t i = 0; i < info->module_count; i++) { + struct stivale_module e = *modules; + e9_printf("\tModule %d: [%x+%x] %s", i, e.begin, e.end, e.string); + modules = (struct stivale_module *)e.next; + } + + e9_printf("Epoch is %x", info->epoch); + e9_printf("Flags are %x", info->flags); + + // Guru meditation. + for (;;); +} diff --git a/test/stivale2.c b/test/stivale2.c new file mode 100644 index 00000000..ef0989b0 --- /dev/null +++ b/test/stivale2.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include + +static uint8_t stack[4096] = {0}; +void stivale2_main(struct stivale2_struct *info); + +struct stivale2_header_tag_smp smp_request = { + .tag = { + .identifier = STIVALE2_HEADER_TAG_SMP_ID, + .next = 0 + }, + .flags = 0 +}; + +struct stivale2_header_tag_framebuffer framebuffer_request = { + .tag = { + .identifier = STIVALE2_HEADER_TAG_FRAMEBUFFER_ID, + .next = (uint64_t)&smp_request + }, + .framebuffer_width = 0, + .framebuffer_height = 0, + .framebuffer_bpp = 0, +}; + +__attribute__((section(".stivale2hdr"), used)) +struct stivale2_header header2 = { + .entry_point = (uint64_t)stivale2_main, + .stack = (uintptr_t)stack + sizeof(stack), + .flags = 0, + .tags = (uint64_t)&framebuffer_request +}; + +void stivale2_main(struct stivale2_struct *info) { + // Print stuff. + e9_puts("Stivale2 info passed to the kernel:"); + e9_printf("Bootloader brand: %s", info->bootloader_brand); + e9_printf("Bootloader version: %s", info->bootloader_version); + + // Print the tags. + struct stivale2_tag *tag = (struct stivale2_tag *)info->tags; + + while (tag != NULL) { + switch (tag->identifier) { + case STIVALE2_STRUCT_TAG_CMDLINE_ID: { + struct stivale2_struct_tag_cmdline *c = (struct stivale2_struct_tag_cmdline *)tag; + e9_puts("Commandline tag:"); + e9_printf("\tCmdline: %s", (char*)(c->cmdline)); + break; + } + case STIVALE2_STRUCT_TAG_MEMMAP_ID: { + struct stivale2_struct_tag_memmap *m = (struct stivale2_struct_tag_memmap *)tag; + e9_puts("Memmap tag:"); + e9_printf("\tEntries: %d", m->entries); + for (size_t i = 0; i < m->entries; i++) { + struct stivale2_mmap_entry me = m->memmap[i]; + e9_printf("\t\t[%x+%x] %x", me.base, me.length, me.type); + } + break; + } + case STIVALE2_STRUCT_TAG_FRAMEBUFFER_ID: { + struct stivale2_struct_tag_framebuffer *f = (struct stivale2_struct_tag_framebuffer *)tag; + e9_puts("Framebuffer tag:"); + e9_printf("\tAddress: %x", f->framebuffer_addr); + e9_printf("\tWidth: %d", f->framebuffer_width); + e9_printf("\tHeight: %d", f->framebuffer_height); + e9_printf("\tPitch: %d", f->framebuffer_pitch); + e9_printf("\tBPP: %d", f->framebuffer_bpp); + break; + } + case STIVALE2_STRUCT_TAG_MODULES_ID: { + struct stivale2_struct_tag_modules *m = (struct stivale2_struct_tag_modules *)tag; + e9_puts("Modules tag:"); + e9_printf("\tCount: %d", m->module_count); + for (size_t i = 0; i < m->module_count; i++) { + struct stivale2_module me = m->modules[i]; + e9_printf("\t\t[%x+%x] %s", me.begin, me.end, me.string); + } + break; + } + case STIVALE2_STRUCT_TAG_RSDP_ID: { + struct stivale2_struct_tag_rsdp *r = (struct stivale2_struct_tag_rsdp *)tag; + e9_puts("RSDP tag:"); + e9_printf("\tRSDP: %x", r->rsdp); + break; + } + case STIVALE2_STRUCT_TAG_EPOCH_ID: { + struct stivale2_struct_tag_epoch *e = (struct stivale2_struct_tag_epoch *)tag; + e9_puts("Epoch tag:"); + e9_printf("\tEpoch: %x", e->epoch); + break; + } + case STIVALE2_STRUCT_TAG_FIRMWARE_ID: { + struct stivale2_struct_tag_firmware *f = (struct stivale2_struct_tag_firmware *)tag; + e9_puts("Firmware tag:"); + e9_printf("\tFlags: %x", f->flags); + break; + } + case STIVALE2_STRUCT_TAG_SMP_ID: { + struct stivale2_struct_tag_smp *s = (struct stivale2_struct_tag_smp *)tag; + e9_puts("SMP tag:"); + e9_printf("\tFlags: %x", s->flags); + e9_printf("\tCPU Count: %d", s->cpu_count); + for (size_t i = 0; i < s->cpu_count; i++) { + struct stivale2_smp_info in = s->smp_info[i]; + e9_printf("\t\tProcessor ID: %d", in.processor_id); + e9_printf("\t\tLAPIC ID: %d", in.lapic_id); + e9_printf("\t\tTarget Stack: %x", in.target_stack); + e9_printf("\t\tGOTO Address: %x", in.goto_address); + e9_printf("\t\tExtra Argument: %x", in.extra_argument); + } + break; + } + default: + e9_printf("BUG: Unidentifier tag %x", tag->identifier); + } + + tag = (struct stivale2_tag *)tag->next; + } + + // Enter our sublime pale slumber. + for (;;); +} diff --git a/test/test.asm b/test/test.asm deleted file mode 100644 index 69bde7c6..00000000 --- a/test/test.asm +++ /dev/null @@ -1,42 +0,0 @@ -; This is a compliant "kernel" meant for testing purposes. - -; Header -section .stivale2hdr - -stivale_header: - dq 0 ; entry point - dq stack.top ; rsp - dq 0 ; flags - dq lv5 ; tags - -section .rodata - -lv5: - dq 0x932f477032007e8f - dq smp - -smp: - dq 0x1ab015085f3273df - dq 0 - dq 1 - -section .bss - -stack: - resb 4096 - .top: - -section .text - -; Entry point - -global _start -_start: - mov rax, 'h e l l ' - mov rbx, 'o w o ' - mov rcx, 'r l d ' - mov rdx, 0xb8000 - mov [rdx], rax - mov [rdx+8], rbx - mov [rdx+16], rcx - jmp $