From b733915536f3eb28df2c44cf42bb74e5ed248a12 Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Tue, 27 Jun 2017 18:55:26 +0100 Subject: [PATCH] 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 --- arch/x86_64/asm/rt0_64.s | 90 +++++++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/arch/x86_64/asm/rt0_64.s b/arch/x86_64/asm/rt0_64.s index 83c2077..40e9a0d 100644 --- a/arch/x86_64/asm/rt0_64.s +++ b/arch/x86_64/asm/rt0_64.s @@ -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