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.
This commit is contained in:
lordtet 2025-06-10 23:41:51 -04:00
parent d97ec36f8c
commit b127a659bb
4 changed files with 96 additions and 48 deletions

View file

@ -1,7 +1,7 @@
###CONFIGURATION ###CONFIGURATION
ARCH := i686 ARCH := i686
CROSS := $(ARCH)-elf- CROSS := $(ARCH)-elf-
AS := $(CROSS)as AS := nasm
CC := $(CROSS)gcc CC := $(CROSS)gcc
LD := $(CROSS)ld LD := $(CROSS)ld
QEMU := qemu-system-i386 QEMU := qemu-system-i386
@ -9,6 +9,8 @@ INCLUDES:= include/
CFLAGS := -I $(INCLUDES) -O2 -Wall -Wextra -ffreestanding -nostdlib -lgcc -g CFLAGS := -I $(INCLUDES) -O2 -Wall -Wextra -ffreestanding -nostdlib -lgcc -g
LDFLAGS := -T linker.ld -nostdlib LDFLAGS := -T linker.ld -nostdlib
ASFLAGS := -f elf32
SRC_DIR := src SRC_DIR := src
OBJ_DIR := obj OBJ_DIR := obj
@ -39,7 +41,7 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.s $(OBJ_DIR)/%.o: $(SRC_DIR)/%.s
@mkdir -p $(dir $@) @mkdir -p $(dir $@)
$(AS) $< -o $@ $(AS) $(ASFLAGS) $< -o $@
#Related targets #Related targets

View file

@ -34,6 +34,5 @@ SECTIONS
{ {
*(COMMON) *(COMMON)
*(.bss) *(.bss)
*(.tss_sect)
} }
} }

View file

@ -6,7 +6,7 @@
#include "kmultiboot.h" #include "kmultiboot.h"
//finally, main. //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 //wipe the screen
vga_clear(); vga_clear();

View file

@ -1,60 +1,107 @@
//C main function for our kernel ;C main function for our kernel
//See: kernel.c ;See: kernel.c
.extern kern_main bits 32
//This will be our entrypoint function name - gotta initialize it now as global so the linker knows later. extern kern_main
.global start ;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. ;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 ;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 MB_MAGIC equ 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 MB_FLAGS equ (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. 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... ;Now we actually place the multiboot stuff into the resulting executable...
.section .multiboot section .multiboot align=4
.align 4 // 4 byte alignment dd MB_MAGIC
.long MB_MAGIC dd MB_FLAGS
.long MB_FLAGS dd MB_CHECKSUM
.long 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. ; 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 section .bss align=16
.align 16
stack_bottom: 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. 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! ;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. ;Therefore, we put a label here to represent the top of our stack for later.
stack_top: stack_top:
//Allocation of some space for our TSS.
.section .tss_sect:
.align 8
tss: 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: 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!
//Actual code. Entry point goes here! section .text
.section .text ;Here it is!
//Here it is!
start: 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. ;We made a GDT! Let's use it!
mov $stack_top, %esp //set the stack pointer lgdt [gdt]
pushl %ebx
pushl %eax ;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.
//To C-land! mov esp, stack_top ;set the stack pointer
push ebx
push eax
;To C-land!
call kern_main 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: hang:
cli //Interrupts: off cli ;Interrupts: off
hlt //Halt! hlt ;Halt!
jmp hang //just in case... jmp hang ;just in case...