Compare commits

...

3 commits

Author SHA1 Message Date
978fd36490 Definitely plan on using more assembly for... assorted assembly related
tasks, so I'm doing some housekeeping.

gdt structure and related pointers go to gdt.structure.
multiboot magic numbers go into multiboot.s.
main code routine goes to start.s for bootstrapping C.
2025-06-11 00:27:15 -04:00
8fadee6baf They're calling him "mr has a working custom GDT"
...
...
...I'm sorry they don't call me that.
2025-06-10 23:58:28 -04:00
b127a659bb 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.
2025-06-10 23:41:51 -04:00
6 changed files with 122 additions and 52 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)
} }
} }

56
src/gdt.s Normal file
View file

@ -0,0 +1,56 @@
global gdtr
section .gdt_sect
gdt:
;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

View file

@ -6,8 +6,13 @@
#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)
{ {
//Hello C! Let's get to work in cleaning up our environment a bit and creating some safety.
//First interrupts.
//wipe the screen //wipe the screen
vga_clear(); vga_clear();
//We're going to use this buffer as our 8char hex representation for reading mem //We're going to use this buffer as our 8char hex representation for reading mem

13
src/multiboot.s Normal file
View file

@ -0,0 +1,13 @@
;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
dd MB_MAGIC
dd MB_FLAGS
dd MB_CHECKSUM

View file

@ -1,60 +1,55 @@
//C main function for our kernel ; Bootloader places us in 32 bit mode :)
//See: kernel.c bits 32
.extern kern_main ;Some symbols we'll need from other files...
//This will be our entrypoint function name - gotta initialize it now as global so the linker knows later. extern kern_main
.global start extern gdtr
;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. ; Set up for C code. Practically the only requirement for C-generated assembly to work properly is alignment and the presence of a stack.
//regardless of who's doing it, we have to set the required stuff section .bss align=16
.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.
//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
// 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: 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. ;We're gonna throw the TSS here too.
.section .tss_sect:
.align 8
tss: tss:
.skip 104 resb 104
.section .gdt_sect:
.align 8
gdt:
.skip 48
//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 [gdtr]
pushl %ebx ;Now we start by setting the code segment (CS) with a far jump...
pushl %eax jmp 0x08:segment_be_gone
//To C-land!
segment_be_gone:
;Now we go ahead and dump our kernel mode data segment (0x10) into the rest of our segments.
;Also preserving eax because it has the bootloader's multiboot magic in it and I want to check it in main.
mov cx, 0x10
mov ds, cx
mov es, cx
mov ss, cx
mov fs, cx
mov gs, cx
;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 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...