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

Use runtime.g0, runtime.m0 and replace hardcoded offsets

The rt0 code implements a dedicated function for initializing the Go runtime
structures. Instead of reserving space for a dummy g struct, the rt0
code now uses the g0 and m0 symbols defined by the runtime package. In
addition to setting up g0, the rt0 also sets up the m0 struct and links
it to g0.

Setting up m0 is a requirement for properly bootstapping the
malloc-related code in the following commits
This commit is contained in:
Achilleas Anagnostopoulos 2017-06-27 18:55:26 +01:00
parent 6820ffef2b
commit b733915536

View File

@ -20,12 +20,9 @@ _rt0_idt_desc:
; Allocates space for the IRQ handlers pointers registered by the IRQ package
_rt0_irq_handlers resq IDT_ENTRIES
r0_g_ptr: resq 1 ; fs:0x00 is a pointer to the current g struct
r0_g:
r0_g_stack_lo: resq 1
r0_g_stack_hi: resq 1
r0_g_stackguard0: resq 1 ; rsp compared to this value in go stack growth prologue
r0_g_stackguard1: resq 1 ; rsp compared to this value in C stack growth prologue
; The FS register is loaded with the address of r0_g_ptr. fs:0x00 should contain
; a pointer to the currently active g struct (in this case runtime.g0)
r0_g_ptr: resq 1
section .text
@ -42,34 +39,7 @@ global _rt0_64_entry
_rt0_64_entry:
call _rt0_install_redirect_trampolines
call _rt0_64_load_idt
; According to the x86_64 ABI, the fs:0 should point to the address of
; the user-space thread structure. The actual TLS structure is located
; just before that (aligned). Go code tries to fetch the address to the
; active go-routine's g struct by accessing fs:-8. What we need to do
; is to setup a mock g0 struct, populate its stack_lo/hi/guard fields
; and then use wrmsr to update the FS register
extern stack_top
extern stack_bottom
; Setup r0_g
mov rax, stack_bottom
mov rbx, stack_top
mov rsi, r0_g
mov qword [rsi+0], rax ; stack_lo
mov qword [rsi+8], rbx ; stack_hi
mov qword [rsi+16], rax ; stackguard0
mov rax, r0_g_ptr
mov qword [rax], rsi
; Load 64-bit FS register address
; rax -> lower 32 bits
; rdx -> upper 32 bits
mov ecx, 0xc0000100 ; fs_base
mov rax, rsi ; lower 32 bits
shr rsi, 32
mov rdx, rsi ; high 32 bits
wrmsr
call _rt0_64_setup_go_runtime_structs
; Call the kernel entry point passing a pointer to the multiboot data
; copied by the 32-bit entry code
@ -93,6 +63,58 @@ _rt0_64_entry:
cli
hlt
;------------------------------------------------------------------------------
; Setup m0, g0 and other symbols required for bootstrapping the Go runtime.
; For the definitions of g and m see the Go runtime src: src/runtime/runtime2.go
;------------------------------------------------------------------------------
_rt0_64_setup_go_runtime_structs:
%include "go_asm_offsets.inc" ; generated by tools/offsets
; The Go allocator expects this symbol to be set to the system page size
; As the kernel bypass osinit() this needs to be set here.
extern runtime.physPageSize
mov rax, runtime.physPageSize
mov qword [rax], 0x1000 ; 4096
; Setup r0_g stack limits using the reserved stack
extern stack_top
extern stack_bottom
extern runtime.g0
mov rax, stack_bottom
mov rbx, stack_top
mov rsi, runtime.g0
mov qword [rsi+GO_G_STACK+GO_STACK_LO], rax ; g.stack.lo
mov qword [rsi+GO_G_STACK+GO_STACK_HI], rbx ; g.stack.hi
mov qword [rsi+GO_G_STACKGUARD0], rax ; g.stackguard0
; Link m0 to the g0
extern runtime.m0
mov rbx, runtime.m0
mov qword [rbx+GO_M_G0], rsi ; m.g0 = g0
mov qword [rsi+GO_G_M], rbx ; g.m = m
; Store the address of g0 in r0_g_ptr
mov rax, r0_g_ptr
mov qword [rax], rsi
; According to the x86_64 ABI, the fs register should contain the
; address after the pointer to the pointer to the user-space thread
; structure. This allows the Go runtime to retrieve the address of
; the currently active g structure by accessing fs:-0x8.
;
; Load 64-bit FS register address
; eax -> lower 32 bits
; edx -> upper 32 bits
mov ecx, 0xc0000100 ; fs_base
mov rsi, r0_g_ptr
add rsi, 8 ; fs -> r0_g_ptr + 0x8
mov rax, rsi ; lower 32 bits
shr rsi, 32
mov rdx, rsi ; high 32 bits
wrmsr
ret
;------------------------------------------------------------------------------
; Setup and load IDT. We preload each IDT entry with a pointer to a gate handler