Changeset View
Standalone View
sys/riscv/riscv/vm_machdep.c
| Show First 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
| #include <vm/vm.h> | #include <vm/vm.h> | ||||
| #include <vm/vm_page.h> | #include <vm/vm_page.h> | ||||
| #include <vm/vm_map.h> | #include <vm/vm_map.h> | ||||
| #include <vm/uma.h> | #include <vm/uma.h> | ||||
| #include <vm/uma_int.h> | #include <vm/uma_int.h> | ||||
| #include <machine/riscvreg.h> | #include <machine/riscvreg.h> | ||||
| #include <machine/cpu.h> | #include <machine/cpu.h> | ||||
| #include <machine/fpe.h> | |||||
| #include <machine/cpufunc.h> | #include <machine/cpufunc.h> | ||||
| #include <machine/pcb.h> | #include <machine/pcb.h> | ||||
| #include <machine/frame.h> | #include <machine/frame.h> | ||||
| #include <machine/sbi.h> | #include <machine/sbi.h> | ||||
| #if __riscv_xlen == 64 | #if __riscv_xlen == 64 | ||||
| #define TP_OFFSET 16 /* sizeof(struct tcb) */ | #define TP_OFFSET 16 /* sizeof(struct tcb) */ | ||||
| #endif | #endif | ||||
| Show All 27 Lines | |||||
| cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) | cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) | ||||
| { | { | ||||
| struct pcb *pcb2; | struct pcb *pcb2; | ||||
| struct trapframe *tf; | struct trapframe *tf; | ||||
| if ((flags & RFPROC) == 0) | if ((flags & RFPROC) == 0) | ||||
| return; | return; | ||||
| /* RISCVTODO: save the FPU state here */ | /* Ensure the floating-point state is saved before copying the pcb. */ | ||||
| if ((td1->td_pcb->pcb_fpflags & PCB_FP_STARTED) != 0) { | |||||
| critical_enter(); | |||||
| fpe_state_save(td1); | |||||
| critical_exit(); | |||||
| } | |||||
| cpu_set_pcb_frame(td2); | cpu_set_pcb_frame(td2); | ||||
| pcb2 = td2->td_pcb; | pcb2 = td2->td_pcb; | ||||
| bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); | bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); | ||||
| tf = td2->td_frame; | tf = td2->td_frame; | ||||
| bcopy(td1->td_frame, tf, sizeof(*tf)); | bcopy(td1->td_frame, tf, sizeof(*tf)); | ||||
| ▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | |||||
| * thread, about to return to userspace. Put enough state in the new | * thread, about to return to userspace. Put enough state in the new | ||||
| * thread's PCB to get it to go back to the fork_return(), which | * thread's PCB to get it to go back to the fork_return(), which | ||||
| * finalizes the thread state and handles peculiarities of the first | * finalizes the thread state and handles peculiarities of the first | ||||
| * return to userspace for the new thread. | * return to userspace for the new thread. | ||||
| */ | */ | ||||
| void | void | ||||
| cpu_copy_thread(struct thread *td, struct thread *td0) | cpu_copy_thread(struct thread *td, struct thread *td0) | ||||
| { | { | ||||
mhorne: Looking at other implementations, we need to save the FPE context here as well.
This one is… | |||||
Done Inline ActionsAMD64 & PowerPC seem to be like what you say but it looks like ARM64 does not save FP registers in cpu_copy_thread() ARM64 calls vfp_new_thread() in both functions but this function just makes some modifications to a new thread _after_ it has been copied. In the case of AMD64 these both functions cpu_copy_thread() and cpu_fork() share a lot of common code in copy_thread() which calls fpuexit() which saves (after some further calls) fp-registers and thus corresponds the new code in this patch. PowerPC seems to be similar to AMD64. Both functions call cpu_update_pcb() which saves fp-registers to pcb. So a question can be asked, do AMD64 and PowerPC do this just because their functions share a common function call together or do these differences (AMD64 & PowerPC vs. ARM64) reflect more genuine differences between these archs. jsihv_gmx.com: AMD64 & PowerPC seem to be like what you say but it looks like ARM64 does not save FP registers… | |||||
| bcopy(td0->td_frame, td->td_frame, sizeof(struct trapframe)); | bcopy(td0->td_frame, td->td_frame, sizeof(struct trapframe)); | ||||
| bcopy(td0->td_pcb, td->td_pcb, sizeof(struct pcb)); | bcopy(td0->td_pcb, td->td_pcb, sizeof(struct pcb)); | ||||
| td->td_pcb->pcb_s[0] = (uintptr_t)fork_return; | td->td_pcb->pcb_s[0] = (uintptr_t)fork_return; | ||||
| td->td_pcb->pcb_s[1] = (uintptr_t)td; | td->td_pcb->pcb_s[1] = (uintptr_t)td; | ||||
| td->td_pcb->pcb_ra = (uintptr_t)fork_trampoline; | td->td_pcb->pcb_ra = (uintptr_t)fork_trampoline; | ||||
| td->td_pcb->pcb_sp = (uintptr_t)td->td_frame; | td->td_pcb->pcb_sp = (uintptr_t)td->td_frame; | ||||
| ▲ Show 20 Lines • Show All 106 Lines • Show Last 20 Lines | |||||
Looking at other implementations, we need to save the FPE context here as well.
This one is invoked when creating a new thread in the same process, while above is invoked when forking/creating a new process.