poline) * 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 index 26b8c0dffcde..0e9a52ba89b0 100644 --- a/sys/riscv/riscv/vm_machdep.c +++ b/sys/riscv/riscv/vm_machdep.c @@ -58,6 +58,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 @@ -74,13 +94,12 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) /* 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 */ @@ -92,8 +111,6 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) 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; @@ -217,11 +234,7 @@ cpu_thread_exit(struct thread *td) 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