1
0
mirror of https://github.com/taigrr/gopher-os synced 2025-01-18 04:43:13 -08:00

Update rt0 code to check for multiboot support and call kernel.Kmain

We still keep the required main func in stub.go to prevent the compiler
from optimizing the code out. We also force the compiler not to inline
the call to kernel.Kmain so we can find the symbol in the generated .o
file.
This commit is contained in:
Achilleas Anagnostopoulos 2017-03-29 07:50:29 +01:00
parent 244c8af752
commit c15f27235c
4 changed files with 91 additions and 22 deletions

View File

@ -24,17 +24,29 @@ section .text
bits 32
align 4
MULTIBOOT_MAGIC equ 0x36d76289
err_unsupported_bootloader db '[rt0] kernel not loaded by multiboot-compliant bootloader', 0
err_kmain_returned db '[rt0] kMain returned; halting system', 0
;------------------------------------------------------------------------------
; Kernel arch-specific entry point
;
; The boot loader will jump to this symbol after setting up the CPU according
; to the multiboot standard. At this point:
; - A20 is enabled
; - The CPU is using 32-bit protected mode
; - Interrupts are disabled
; - Paging is disabled
; - EAX contains the magic value 0x36d76289; the presence of this value indicates
; to the operating system that it was loaded by a Multiboot-compliant boot loader
; - EBX contains the 32-bit physical address of the Multiboot information structure
;------------------------------------------------------------------------------
global _rt0_entry
_rt0_entry:
cmp eax, MULTIBOOT_MAGIC
jne unsupported_bootloader
; Initalize our stack by pointing ESP to the BSS-allocated stack. In x86,
; stack grows downwards so we need to point ESP to stack_top
mov esp, stack_top
@ -48,19 +60,60 @@ _rt0_entry:
mov dword [g0_stack_lo], stack_bottom
mov dword [g0_stackguard0], stack_bottom
extern main.main
call main.main
; push multiboot info ptr to the stack and call the kernel entrypoint
push ebx
extern kernel.Kmain
call kernel.Kmain
; kmain should never return
mov edi, err_kmain_returned
call write_string
; Main should never return; halt the CPU
halt:
cli
hlt
unsupported_bootloader:
mov edi, err_unsupported_bootloader
call write_string
jmp halt
.end:
;------------------------------------------------------------------------------
; Write the NULL-terminated string contained in edi to the screen using white
; text on red background. Assumes that text-mode is enabled and that its
; physical address is 0xb8000.
;------------------------------------------------------------------------------
write_string:
push eax
push ebx
mov ebx,0xb8000
mov ah, 0x4F
next_char:
mov al, byte[edi]
test al, al
jz done
mov word [ebx], ax
add ebx, 2
inc edi
jmp next_char
done:
pop ebx
pop eax
ret
;------------------------------------------------------------------------------
; Load GDT and flush CPU caches
;------------------------------------------------------------------------------
_rt0_load_gdt:
push eax
push ebx
; Go code uses the GS register to access the TLS. Set the base address
; for the GS descriptor to point to our tls0 table
mov eax, tls0
@ -84,6 +137,8 @@ update_descriptors:
mov ax, GS_SEG
mov gs, ax
pop ebx
pop eax
ret
;------------------------------------------------------------------------------

18
boot.go
View File

@ -1,18 +0,0 @@
package main
import "github.com/achilleasa/gopher-os/kernel"
// main is the only Go symbol that is visible (exported) from the rt0 initialization
// code. This function works as a trampoline for calling the actual kernel entrypoint
// (kernel.Kmain) and its intentionally defined to prevent the Go compiler from
// optimizing away the actual kernel code as its not aware of the presence of the
// rt0 code.
//
// The main function is invoked by the rt0 assembly code after setting up the GDT
// and setting up a a minimal g0 struct that allows Go code using the 4K stack
// allocated by the assembly code.
//
// main is not expected to return. If it does, the rt0 code will halt the CPU.
func main() {
kernel.Kmain()
}

View File

@ -1,5 +1,22 @@
package kernel
// Kmain is invoked by the boot.go and implements the actual kernel entrypoint.
func Kmain() {
import (
_ "unsafe" // required for go:linkname
"github.com/achilleasa/gopher-os/kernel/multiboot"
)
// Kmain is the only Go symbol that is visible (exported) from the rt0 initialization
// code. This function is invoked by the rt0 assembly code after setting up the GDT
// and setting up a a minimal g0 struct that allows Go code using the 4K stack
// allocated by the assembly code.
//
// The rt0 code passes the address of the multiboot info payload provided by the
// bootloader.
//
// Kmain is not expected to return. If it does, the rt0 code will halt the CPU.
//
//go:noinline
func Kmain(multibootInfoPtr uint32) {
multiboot.SetInfoPtr(uintptr(multibootInfoPtr))
}

15
stub.go Normal file
View File

@ -0,0 +1,15 @@
package main
import "github.com/achilleasa/gopher-os/kernel"
var multibootInfoPtr uint32
// main makes a dummy call to the actual kernel main entrypoint function. It
// is intentionally defined to prevent the Go compiler from optimizing away the
// real kernel code.
//
// A global variable is passed as an argument to Kmain to prevent the compiler
// from inlining the actual call and removing Kmain from the generated .o file.
func main() {
kernel.Kmain(multibootInfoPtr)
}