From b127a659bbeaac59a61c23b9be3561b8c7da2b08 Mon Sep 17 00:00:00 2001 From: lordtet Date: Tue, 10 Jun 2025 23:41:51 -0400 Subject: [PATCH] This underwent some crazy scope creep. Just one more feature... - Changed primary assembler to NASM. Specifically so I could use - - Swapped start.s to intel syntax. I find it prettier. Learned a lot doing it tbh. - Changed the name of the multiboot structures in C. --- Makefile | 6 ++- linker.ld | 1 - src/main.c | 2 +- src/start.s | 135 +++++++++++++++++++++++++++++++++++----------------- 4 files changed, 96 insertions(+), 48 deletions(-) diff --git a/Makefile b/Makefile index 5ae0842..8f197e4 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ ###CONFIGURATION ARCH := i686 CROSS := $(ARCH)-elf- -AS := $(CROSS)as +AS := nasm CC := $(CROSS)gcc LD := $(CROSS)ld QEMU := qemu-system-i386 @@ -9,6 +9,8 @@ INCLUDES:= include/ CFLAGS := -I $(INCLUDES) -O2 -Wall -Wextra -ffreestanding -nostdlib -lgcc -g LDFLAGS := -T linker.ld -nostdlib +ASFLAGS := -f elf32 + SRC_DIR := src OBJ_DIR := obj @@ -39,7 +41,7 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(OBJ_DIR)/%.o: $(SRC_DIR)/%.s @mkdir -p $(dir $@) - $(AS) $< -o $@ + $(AS) $(ASFLAGS) $< -o $@ #Related targets diff --git a/linker.ld b/linker.ld index 85dda0f..76942a4 100644 --- a/linker.ld +++ b/linker.ld @@ -34,6 +34,5 @@ SECTIONS { *(COMMON) *(.bss) - *(.tss_sect) } } diff --git a/src/main.c b/src/main.c index 266e4cc..6d094d2 100644 --- a/src/main.c +++ b/src/main.c @@ -6,7 +6,7 @@ #include "kmultiboot.h" //finally, main. -void kern_main(uint32_t multiboot_magic, multiboot_info_t* multiboot_info) +void kern_main(uint32_t multiboot_magic, mb_info_t* multiboot_info) { //wipe the screen vga_clear(); diff --git a/src/start.s b/src/start.s index 14322da..702df0b 100644 --- a/src/start.s +++ b/src/start.s @@ -1,60 +1,107 @@ -//C main function for our kernel -//See: kernel.c -.extern kern_main -//This will be our entrypoint function name - gotta initialize it now as global so the linker knows later. -.global start +;C main function for our kernel +;See: kernel.c +bits 32 +extern kern_main +;This will be our entrypoint function name - gotta initialize it now as global so the linker knows later. +global start -//multiboot for GRUB to boot it. Ideally stage01_bootloader will be able to support the multiboot standard. -//regardless of who's doing it, we have to set the required stuff -.set MB_MAGIC, 0x1BADB002 // bytes that bootloader will use to find this place -.set MB_FLAGS, (1 << 0) | (1 << 1) // flags request the following from the bootloader: maintain page boundaries + provide a memory map -.set MB_CHECKSUM, (0 - (MB_MAGIC + MB_FLAGS)) // Fails if checksum doesn't pass. Kind of arbitrary, but required. +;multiboot for GRUB to boot it. Ideally stage01_bootloader will be able to support the multiboot standard. +;regardless of who's doing it, we have to set the required stuff +MB_MAGIC equ 0x1BADB002 ; bytes that bootloader will use to find this place +MB_FLAGS equ (1 << 0) | (1 << 1) ; flags request the following from the bootloader: maintain page boundaries + provide a memory map +MB_CHECKSUM equ (0 - (MB_MAGIC + MB_FLAGS)) ; Fails if checksum doesn't pass. Kind of arbitrary, but required. -//Now we actually place the multiboot stuff into the resulting executable... -.section .multiboot - .align 4 // 4 byte alignment - .long MB_MAGIC - .long MB_FLAGS - .long MB_CHECKSUM +;Now we actually place the multiboot stuff into the resulting executable... +section .multiboot align=4 + dd MB_MAGIC + dd MB_FLAGS + dd MB_CHECKSUM -// Set up for C code. Practically the only requirement for C-generated assembly to work properly is alignment and the presence of a stack. -.section .bss - .align 16 +; Set up for C code. Practically the only requirement for C-generated assembly to work properly is alignment and the presence of a stack. +section .bss align=16 stack_bottom: - .skip 4096 // 4096 bytes (4kb) large stack. by skipping some amount of data (and eventually filling it with zeroes?), we've essentially just reserved space for our stack. - //Remember, stack grows DOWNWARD! So the last thing in the section -> the highest memory address -> the very first thing on the stack! - //Therefore, we put a label here to represent the top of our stack for later. + resb 4096 ; 4096 bytes (4kb) large stack. by skipping some amount of data (and eventually filling it with zeroes?), we've essentially just reserved space for our stack. + ;Remember, stack grows DOWNWARD! So the last thing in the section -> the highest memory address -> the very first thing on the stack! + ;Therefore, we put a label here to represent the top of our stack for later. stack_top: - //Allocation of some space for our TSS. - - -.section .tss_sect: - .align 8 tss: - .skip 104 + resb 104 -.section .gdt_sect: - .align 8 + + ;We're putting the GDT here. I'll be thoroughly commenting the first entry for my own understanding. Rest will be minimal. +section .gdt_sect gdt: - .skip 48 + ;Null descriptor + dd 0x00000000 + dd 0x00000000 + ;Kernel code segment. + ;Limit: in 4kib pages. 0xFFFFF * 4K = full address space. + dw 0xFFFF + ;Base: Start at 0. We want the whole thing. + dw 0 + ;ALSO BASE: bits 16-23. All zeroes, still. + db 0 + ;Access byte. Defines flags for access permissions to the segment. This segment is: + ;RX, and code/data segment + db 0b10011010 + ;Next two segments are nibbles so I put them together (cant db only a nibble at once). + ;Upper limit bits (right hand nibble) is all ones to fill out the full 4gib in pages + ;Flags (left hand nibble) are set to say that the limit is meant to be read as pages, and we're working in 32bit. + db 0b11001111 + ;Final upper base bits. Still zero lol. + db 0 + ;Done! Now we move onto our next table entries, they are back to back. + ;Kernel Data Segment + dw 0xFFFF + dw 0 + db 0 + db 0b10010010 + db 0b11001111 + db 0 + ;User Code Segment + dw 0xFFFF + dw 0 + db 0 + db 0b11111010 + db 0b11001111 + db 0 + ;User Data Segment + dw 0xFFFF + dw 0 + db 0 + db 0b11110010 + db 0b11001111 + db 0 + ;Task State Segment + ;For a lot of this it's going to be zeroes so we can do it dynamically later (such as finding &tss). + ;Really, we just want to set the access bytes correctly. + dd 0 + db 0 + db 0b10001001 + dw 0 + gdtr: + dw gdtr - gdt - 1 + dd gdt - -//Actual code. Entry point goes here! -.section .text - //Here it is! +;Actual code. Entry point goes here! +section .text + ;Here it is! start: - //Lets set up the stack. Stack grows downward on x86. We did the work earlier of defining where the top of the stack is, so just tell esp. - mov $stack_top, %esp //set the stack pointer - pushl %ebx - pushl %eax - //To C-land! + ;We made a GDT! Let's use it! + lgdt [gdt] + + ;Lets set up the stack. Stack grows downward on x86. We did the work earlier of defining where the top of the stack is, so just tell esp. + mov esp, stack_top ;set the stack pointer + push ebx + push eax + ;To C-land! call kern_main - //You should never get here, but in case you do, we will just hang. + ;You should never get here, but in case you do, we will just hang. hang: - cli //Interrupts: off - hlt //Halt! - jmp hang //just in case... + cli ;Interrupts: off + hlt ;Halt! + jmp hang ;just in case...