Untitled_Kernel/src/start.s

127 lines
4.6 KiB
ArmAsm
Raw Normal View History

;start.s
;Entrypoint for kernel, hello world!
bits 32
;Some symbols we'll need from other files...
extern kern_main
extern gdtr
extern _kernel_start
extern _kernel_end
;This will be our entrypoint function name - gotta initialize it now as global so the linker knows later.
global start
; 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:
;We're gonna throw the TSS here too.
section .tss align=16 nobits
tss:
resb 104
section .bootstrap_tables nobits align=4096
bootstrap_PD:
resb 4096
bootstrap_PT:
resb 4096
;Actual code. Entry point goes here!
section .lower_text exec
;Here it is!
start:
;We made a GDT! Let's use it!
lgdt [gdtr - 0xC0000000]
;Now we start by setting the code segment (CS) with a far jump...
jmp 0x08:gdt_load
gdt_load:
;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
;So, we want to set up a page table and page directory. Let's take inventory.
;eax - preserve, mb_magic
;ebx - preserve, mb_info
;ecx,edx,esi - can use
;Can technically use esp as the stack is set to stack_top later.
;ecx = our current indexing for pages, this is a 4K-aligned address
mov ecx, 0x0
;edi = our pointer to the current page table entry. Array of 4byte entries. It's at, of course, where we put it earlier.
;Worth noting that it's actually physically at ~1M with the kernel. The pointer, however, is virtually inclined. So we need to adjust.
mov edi, bootstrap_PT - 0xC0000000
page_alloc_loop:
;If we're lower than our kernel, skip this page. If we've passed our kernel, we're done mapping.
cmp ecx, _kernel_start
jl next_page
cmp ecx, _kernel_end - 0xC0000000
jge page_alloc_done
;Okay, we're in kernel zone. Let's map this one.
;Let's make a page table entry in edx.
;The top bits for the page table entry are just the upper bits of the address, so we dont need to touch it.
mov edx, ecx
;Set last two bits, "present" and "writeable". Later on we'll make a proper page table with proper permissions, but we're bootstrapping here.
or edx, 0x003
;edi holds a pointer to the page table entry, so dereference it and throw our new entry (in edx) to it. Done!
mov [edi], edx
next_page:
;address page + 1
add ecx, 0x1000
;page table entry + 1
add edi, 4
jmp page_alloc_loop
page_alloc_done:
;By now we've mapped the kernel in a page table! Let's map VGA too, we'll need that address later.
mov dword [bootstrap_PT - 0xC0000000 + 1023 * 4], 0x000B8000 | 0x27
;We have our page tables mapped to the phys addr of kernel + VGA. Time to add them to our page directory!
;First identity maps, second maps to higher half.
mov dword [bootstrap_PD - 0xC0000000], bootstrap_PT - 0xC0000000 + 0x003
mov dword [bootstrap_PD - 0xC0000000 + 4 * (0xC0000000 >> 22)], bootstrap_PT - 0xC0000000 + 0x003
;Let's set it! You do this with cr3.
mov ecx, bootstrap_PD - 0xC0000000
mov cr3, ecx
;Enable paging in cr0
mov ecx, cr0
or ecx, 0x80010000
mov cr0, ecx
;Done! Leave to the higher half!
lea ecx, setup_c_env
jmp ecx
section .text
setup_c_env:
;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...