;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 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 ; 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: 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: tss: resb 104 ;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: ;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! start: ;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. hang: cli ;Interrupts: off hlt ;Halt! jmp hang ;just in case...