From 6ae48dd8704f6f6b754d5edcc94045bc5c2b4615 Mon Sep 17 00:00:00 2001 From: Mitchell Horne Date: Sun, 9 Jun 2019 15:43:38 +0000 Subject: [PATCH] Fix global pointer relaxations in the RISC-V kernel The gp register is intended to used by the linker as another means of performing relaxations, and should point to the small data section (.sdata). Currently gp is being used as the pcpu pointer within the kernel, but the more appropriate choice for this is the tp register, which is unused. Swap existing usage of gp with tp within the kernel, and set up gp properly at boot with the value of __global_pointer$ for all harts. Additionally, remove some cases of accessing tp from the PCB, as it is not part of the per-thread state. The user's tp and gp should be tracked only through the trapframe. Reviewed by: markj, jhb Approved by: markj (mentor) MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D19893 --- sys/conf/ldscript.riscv | 6 +++++- sys/riscv/include/asm.h | 2 +- sys/riscv/include/pcpu.h | 4 ++-- sys/riscv/riscv/exception.S | 23 ++++++++++++++++------- sys/riscv/riscv/locore.S | 20 +++++++++++++------- sys/riscv/riscv/machdep.c | 2 +- sys/riscv/riscv/mp_machdep.c | 2 +- sys/riscv/riscv/swtch.S | 19 +++++++++---------- sys/riscv/riscv/vm_machdep.c | 23 ++++++----------------- 9 files changed, 54 insertions(+), 47 deletions(-) diff --git a/sys/conf/ldscript.riscv b/sys/conf/ldscript.riscv index 6fbdd9ad507f..449575cb6ede 100644 --- a/sys/conf/ldscript.riscv +++ b/sys/conf/ldscript.riscv @@ -89,7 +89,11 @@ SECTIONS can access them all, and initialized data all before uninitialized, so we can shorten the on-disk segment size. */ . = ALIGN(8); - .sdata : { *(.sdata) } + .sdata : + { + __global_pointer$ = . + 0x800; + *(.sdata) + } _edata = .; PROVIDE (edata = .); /* Ensure __bss_start is associated with the next section in case orphan diff --git a/sys/riscv/include/asm.h b/sys/riscv/include/asm.h index 87736980cdc0..5fd84cfa423d 100644 --- a/sys/riscv/include/asm.h +++ b/sys/riscv/include/asm.h @@ -59,7 +59,7 @@ .set alias,sym #define SET_FAULT_HANDLER(handler, tmp) \ - ld tmp, PC_CURTHREAD(gp); \ + ld tmp, PC_CURTHREAD(tp); \ ld tmp, TD_PCB(tmp); /* Load the pcb */ \ sd handler, PCB_ONFAULT(tmp) /* Set the handler */ diff --git a/sys/riscv/include/pcpu.h b/sys/riscv/include/pcpu.h index 0f04db0a5efb..28c5a7422d1c 100644 --- a/sys/riscv/include/pcpu.h +++ b/sys/riscv/include/pcpu.h @@ -60,7 +60,7 @@ get_pcpu(void) { struct pcpu *pcpu; - __asm __volatile("mv %0, gp" : "=&r"(pcpu)); + __asm __volatile("mv %0, tp" : "=&r"(pcpu)); return (pcpu); } @@ -70,7 +70,7 @@ get_curthread(void) { struct thread *td; - __asm __volatile("ld %0, 0(gp)" : "=&r"(td)); + __asm __volatile("ld %0, 0(tp)" : "=&r"(td)); return (td); } diff --git a/sys/riscv/riscv/exception.S b/sys/riscv/riscv/exception.S index d486938bcd07..0adfda72046a 100644 --- a/sys/riscv/riscv/exception.S +++ b/sys/riscv/riscv/exception.S @@ -44,11 +44,18 @@ __FBSDID("$FreeBSD$"); addi sp, sp, -(TF_SIZE) sd ra, (TF_RA)(sp) - sd tp, (TF_TP)(sp) -.if \el == 0 /* We came from userspace. Load our pcpu */ +.if \el == 0 /* We came from userspace. */ sd gp, (TF_GP)(sp) - ld gp, (TF_SIZE)(sp) +.option push +.option norelax + /* Load the kernel's global pointer */ + la gp, __global_pointer$ +.option pop + + /* Load our pcpu */ + sd tp, (TF_TP)(sp) + ld tp, (TF_SIZE)(sp) .endif sd t0, (TF_T + 0 * 8)(sp) @@ -128,13 +135,15 @@ __FBSDID("$FreeBSD$"); ld t0, (TF_SP)(sp) csrw sscratch, t0 - /* And store our pcpu */ - sd gp, (TF_SIZE)(sp) + /* Store our pcpu */ + sd tp, (TF_SIZE)(sp) + ld tp, (TF_TP)(sp) + + /* And restore the user's global pointer */ ld gp, (TF_GP)(sp) .endif ld ra, (TF_RA)(sp) - ld tp, (TF_TP)(sp) ld t0, (TF_T + 0 * 8)(sp) ld t1, (TF_T + 1 * 8)(sp) @@ -175,7 +184,7 @@ __FBSDID("$FreeBSD$"); 1: csrci sstatus, (SSTATUS_SIE) - ld a1, PC_CURTHREAD(gp) + ld a1, PC_CURTHREAD(tp) lw a2, TD_FLAGS(a1) li a3, (TDF_ASTPENDING|TDF_NEEDRESCHED) diff --git a/sys/riscv/riscv/locore.S b/sys/riscv/riscv/locore.S index c79b4f4a5c1f..533bfef93fe6 100644 --- a/sys/riscv/riscv/locore.S +++ b/sys/riscv/riscv/locore.S @@ -171,12 +171,18 @@ va: li t0, 0 csrw sscratch, t0 + /* Set the global pointer */ +.option push +.option norelax + la gp, __global_pointer$ +.option pop + /* Initialize stack pointer */ la s3, initstack_end mv sp, s3 addi sp, sp, -PCB_SIZE - /* Clear BSS */ + /* Clear BSS */ la s0, _C_LABEL(__bss_start) la s1, _C_LABEL(_end) 1: @@ -251,12 +257,6 @@ virt_map: hart_lottery: .space 4 - /* Not in use, but required for linking. */ - .align 3 - .globl __global_pointer$ -__global_pointer$: - .space 8 - .globl init_pt_va init_pt_va: .quad pagetable_l2 /* XXX: Keep page tables VA */ @@ -324,6 +324,12 @@ mpva: li t0, 0 csrw sscratch, t0 + /* Set the global pointer */ +.option push +.option norelax + la gp, __global_pointer$ +.option pop + call init_secondary END(mpentry) #endif diff --git a/sys/riscv/riscv/machdep.c b/sys/riscv/riscv/machdep.c index 76f5f6ce89af..7a1850c7e307 100644 --- a/sys/riscv/riscv/machdep.c +++ b/sys/riscv/riscv/machdep.c @@ -822,7 +822,7 @@ initriscv(struct riscv_bootparams *rvbp) pcpup->pc_hart = boot_hart; /* Set the pcpu pointer */ - __asm __volatile("mv gp, %0" :: "r"(pcpup)); + __asm __volatile("mv tp, %0" :: "r"(pcpup)); PCPU_SET(curthread, &thread0); diff --git a/sys/riscv/riscv/mp_machdep.c b/sys/riscv/riscv/mp_machdep.c index 3d3dbcc0976e..0f6d22962b6c 100644 --- a/sys/riscv/riscv/mp_machdep.c +++ b/sys/riscv/riscv/mp_machdep.c @@ -234,7 +234,7 @@ init_secondary(uint64_t hart) /* Setup the pcpu pointer */ pcpup = &__pcpu[cpuid]; - __asm __volatile("mv gp, %0" :: "r"(pcpup)); + __asm __volatile("mv tp, %0" :: "r"(pcpup)); /* Workaround: make sure wfi doesn't halt the hart */ csr_set(sie, SIE_SSIE); diff --git a/sys/riscv/riscv/swtch.S b/sys/riscv/riscv/swtch.S index b57c0487610b..39213d3d31b9 100644 --- a/sys/riscv/riscv/swtch.S +++ b/sys/riscv/riscv/swtch.S @@ -217,15 +217,14 @@ ENTRY(cpu_throw) mv a0, s0 /* Store the new curthread */ - sd a0, PC_CURTHREAD(gp) + sd a0, PC_CURTHREAD(tp) /* And the new pcb */ ld x13, TD_PCB(a0) - sd x13, PC_CURPCB(gp) + sd x13, PC_CURPCB(tp) /* Load registers */ ld ra, (PCB_RA)(x13) ld sp, (PCB_SP)(x13) - ld tp, (PCB_TP)(x13) /* s[0-11] */ ld s0, (PCB_S + 0 * 8)(x13) @@ -267,10 +266,10 @@ END(cpu_throw) */ ENTRY(cpu_switch) /* Store the new curthread */ - sd a1, PC_CURTHREAD(gp) + sd a1, PC_CURTHREAD(tp) /* And the new pcb */ ld x13, TD_PCB(a1) - sd x13, PC_CURPCB(gp) + sd x13, PC_CURPCB(tp) /* Save the old context. */ ld x13, TD_PCB(a0) @@ -278,7 +277,6 @@ ENTRY(cpu_switch) /* Store ra, sp and the callee-saved registers */ sd ra, (PCB_RA)(x13) sd sp, (PCB_SP)(x13) - sd tp, (PCB_TP)(x13) /* s[0-11] */ sd s0, (PCB_S + 0 * 8)(x13) @@ -340,7 +338,6 @@ ENTRY(cpu_switch) ld x13, TD_PCB(a1) /* Restore the registers */ - ld tp, (PCB_TP)(x13) ld ra, (PCB_RA)(x13) ld sp, (PCB_SP)(x13) @@ -429,15 +426,16 @@ ENTRY(fork_trampoline) ld a6, (TF_A + 6 * 8)(sp) ld a7, (TF_A + 7 * 8)(sp) - /* Load user ra and sp */ + /* Load user ra and gp */ ld ra, (TF_RA)(sp) + ld gp, (TF_GP)(sp) /* * Store our pcpup on stack, we will load it back * on kernel mode trap. */ - sd gp, (TF_SIZE)(sp) - ld gp, (TF_GP)(sp) + sd tp, (TF_SIZE)(sp) + ld tp, (TF_TP)(sp) /* Save kernel stack so we can use it doing a user trap */ addi sp, sp, TF_SIZE @@ -454,6 +452,7 @@ ENTRY(savectx) sd ra, (PCB_RA)(a0) sd sp, (PCB_SP)(a0) sd tp, (PCB_TP)(a0) + sd gp, (PCB_GP)(a0) /* s[0-11] */ sd s0, (PCB_S + 0 * 8)(a0) diff --git a/sys/riscv/riscv/vm_machdep.c b/sys/riscv/riscv/vm_machdep.c index 7bcd13abc47d..f00928e385b1 100644 --- a/sys/riscv/riscv/vm_machdep.c +++ b/sys/riscv/riscv/vm_machdep.c @@ -69,22 +69,11 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) { struct pcb *pcb2; struct trapframe *tf; - register_t val; if ((flags & RFPROC) == 0) return; - if (td1 == curthread) { - /* - * Save the tp. These normally happen in cpu_switch, - * but if userland changes this then forks this may - * not have happened. - */ - __asm __volatile("mv %0, tp" : "=&r"(val)); - td1->td_pcb->pcb_tp = val; - - /* RISCVTODO: save the FPU state here */ - } + /* RISCVTODO: save the FPU state here */ pcb2 = (struct pcb *)(td2->td_kstack + td2->td_kstack_pages * PAGE_SIZE) - 1; @@ -205,15 +194,15 @@ cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg, int cpu_set_user_tls(struct thread *td, void *tls_base) { - struct pcb *pcb; if ((uintptr_t)tls_base >= VM_MAXUSER_ADDRESS) return (EINVAL); - pcb = td->td_pcb; - pcb->pcb_tp = (register_t)tls_base + TP_OFFSET; - if (td == curthread) - __asm __volatile("mv tp, %0" :: "r"(pcb->pcb_tp)); + /* + * The user TLS is set by modifying the trapframe's tp value, which + * will be restored when returning to userspace. + */ + td->td_frame->tf_tp = (register_t)tls_base + TP_OFFSET; return (0); }