diff --git a/sys/riscv/include/frame.h b/sys/riscv/include/frame.h --- a/sys/riscv/include/frame.h +++ b/sys/riscv/include/frame.h @@ -57,6 +57,10 @@ uint64_t tf_scause; }; +#ifdef _KERNEL +#define TF_SIZE (roundup2(sizeof(struct trapframe), STACKALIGNBYTES + 1)) +#endif + /* * Signal frame. Pushed onto user stack before calling sigcode. */ @@ -65,6 +69,16 @@ ucontext_t sf_uc; /* actual saved ucontext */ }; +#ifdef _KERNEL +/* + * Kernel frame. Reserved near the top of kernel stacks for saving kernel + * state while in userspace. + */ +struct kernframe { + register_t kf_tp; +}; +#endif + #endif /* !LOCORE */ /* Definitions for syscalls */ diff --git a/sys/riscv/riscv/exception.S b/sys/riscv/riscv/exception.S --- a/sys/riscv/riscv/exception.S +++ b/sys/riscv/riscv/exception.S @@ -53,7 +53,7 @@ .option pop /* Load our pcpu */ - ld tp, (TF_SIZE)(sp) + ld tp, (TF_SIZE + KF_TP)(sp) .endif sd t0, (TF_T + 0 * 8)(sp) @@ -139,7 +139,7 @@ csrw sscratch, t0 /* Store our pcpu */ - sd tp, (TF_SIZE)(sp) + sd tp, (TF_SIZE + KF_TP)(sp) ld tp, (TF_TP)(sp) /* And restore the user's global pointer */ diff --git a/sys/riscv/riscv/genassym.c b/sys/riscv/riscv/genassym.c --- a/sys/riscv/riscv/genassym.c +++ b/sys/riscv/riscv/genassym.c @@ -85,7 +85,7 @@ ASSYM(TD_MD, offsetof(struct thread, td_md)); ASSYM(TD_LOCK, offsetof(struct thread, td_lock)); -ASSYM(TF_SIZE, roundup2(sizeof(struct trapframe), STACKALIGNBYTES + 1)); +ASSYM(TF_SIZE, TF_SIZE); ASSYM(TF_RA, offsetof(struct trapframe, tf_ra)); ASSYM(TF_SP, offsetof(struct trapframe, tf_sp)); ASSYM(TF_GP, offsetof(struct trapframe, tf_gp)); @@ -98,6 +98,8 @@ ASSYM(TF_SCAUSE, offsetof(struct trapframe, tf_scause)); ASSYM(TF_SSTATUS, offsetof(struct trapframe, tf_sstatus)); +ASSYM(KF_TP, offsetof(struct kernframe, kf_tp)); + ASSYM(HYP_H_RA, offsetof(struct hypctx, host_regs.hyp_ra)); ASSYM(HYP_H_SP, offsetof(struct hypctx, host_regs.hyp_sp)); ASSYM(HYP_H_GP, offsetof(struct hypctx, host_regs.hyp_gp)); diff --git a/sys/riscv/riscv/swtch.S b/sys/riscv/riscv/swtch.S --- a/sys/riscv/riscv/swtch.S +++ b/sys/riscv/riscv/swtch.S @@ -419,7 +419,7 @@ * Store our pcpup on stack, we will load it back * on kernel mode trap. */ - sd tp, (TF_SIZE)(sp) + sd tp, (TF_SIZE + KF_TP)(sp) ld tp, (TF_TP)(sp) /* Save kernel stack so we can use it doing a user trap */ diff --git a/sys/riscv/riscv/vm_machdep.c b/sys/riscv/riscv/vm_machdep.c --- a/sys/riscv/riscv/vm_machdep.c +++ b/sys/riscv/riscv/vm_machdep.c @@ -57,6 +57,26 @@ #define TP_OFFSET 16 /* sizeof(struct tcb) */ #endif +static void +cpu_set_pcb_frame(struct thread *td) +{ + td->td_pcb = (struct pcb *)((char *)td->td_kstack + + td->td_kstack_pages * PAGE_SIZE) - 1; + + /* + * td->td_frame + TF_SIZE will be the saved kernel stack pointer whilst + * in userspace, so keep it aligned so it's also aligned when we + * subtract TF_SIZE in the trap handler (and here for the initial stack + * pointer). This also keeps the struct kernframe just afterwards + * aligned no matter what's in it or struct pcb. + * + * NB: TF_SIZE not sizeof(struct trapframe) as we need the rounded + * value to match the trap handler. + */ + td->td_frame = (struct trapframe *)(STACKALIGN( + (char *)td->td_pcb - sizeof(struct kernframe)) - TF_SIZE); +} + /* * Finish a fork operation, with process p2 nearly set up. * Copy and update the pcb, set up the stack so that the child @@ -73,13 +93,12 @@ /* RISCVTODO: save the FPU state here */ - pcb2 = (struct pcb *)(td2->td_kstack + - td2->td_kstack_pages * PAGE_SIZE) - 1; + cpu_set_pcb_frame(td2); - td2->td_pcb = pcb2; + pcb2 = td2->td_pcb; bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); - tf = (struct trapframe *)STACKALIGN((struct trapframe *)pcb2 - 1); + tf = td2->td_frame; bcopy(td1->td_frame, tf, sizeof(*tf)); /* Clear syscall error flag */ @@ -91,8 +110,6 @@ tf->tf_sstatus |= (SSTATUS_SPIE); /* Enable interrupts. */ tf->tf_sstatus &= ~(SSTATUS_SPP); /* User mode. */ - td2->td_frame = tf; - /* Set the return value registers for fork() */ td2->td_pcb->pcb_s[0] = (uintptr_t)fork_return; td2->td_pcb->pcb_s[1] = (uintptr_t)td2; @@ -206,11 +223,7 @@ void cpu_thread_alloc(struct thread *td) { - - td->td_pcb = (struct pcb *)(td->td_kstack + - td->td_kstack_pages * PAGE_SIZE) - 1; - td->td_frame = (struct trapframe *)STACKALIGN( - (caddr_t)td->td_pcb - 8 - sizeof(struct trapframe)); + cpu_set_pcb_frame(td); } void