summaryrefslogtreecommitdiffstats
path: root/sys/amd64
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2003-07-24 08:52:44 +0000
committerdavidxu <davidxu@FreeBSD.org>2003-07-24 08:52:44 +0000
commit28420f22f746f5c9bcaa97310e39e206c789b1ef (patch)
treefdbdc15cfc6c0ce1d68827987b2892af51f91e53 /sys/amd64
parent181093ade7e06086c04e2ecab88d6f11b2550cb2 (diff)
downloadFreeBSD-src-28420f22f746f5c9bcaa97310e39e206c789b1ef.zip
FreeBSD-src-28420f22f746f5c9bcaa97310e39e206c789b1ef.tar.gz
Implement cpu_set_upcall and cpu_set_upcall_kse.
Reviewed by: peter
Diffstat (limited to 'sys/amd64')
-rw-r--r--sys/amd64/amd64/vm_machdep.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c
index d3a544e..21dc35e 100644
--- a/sys/amd64/amd64/vm_machdep.c
+++ b/sys/amd64/amd64/vm_machdep.c
@@ -221,6 +221,51 @@ cpu_thread_setup(struct thread *td)
void
cpu_set_upcall(struct thread *td, struct thread *td0)
{
+ struct pcb *pcb2;
+
+ /* Point the pcb to the top of the stack. */
+ pcb2 = td->td_pcb;
+
+ /*
+ * Copy the upcall pcb. This loads kernel regs.
+ * Those not loaded individually below get their default
+ * values here.
+ *
+ * XXXKSE It might be a good idea to simply skip this as
+ * the values of the other registers may be unimportant.
+ * This would remove any requirement for knowing the KSE
+ * at this time (see the matching comment below for
+ * more analysis) (need a good safe default).
+ */
+ bcopy(td0->td_pcb, pcb2, sizeof(*pcb2));
+
+ /*
+ * Create a new fresh stack for the new thread.
+ * Don't forget to set this stack value into whatever supplies
+ * the address for the fault handlers.
+ * The contexts are filled in at the time we actually DO the
+ * upcall as only then do we know which KSE we got.
+ */
+ bcopy(td0->td_frame, td->td_frame, sizeof(struct trapframe));
+
+ /*
+ * Set registers for trampoline to user mode. Leave space for the
+ * return address on stack. These are the kernel mode register values.
+ */
+ pcb2->pcb_cr3 = vtophys(vmspace_pmap(td->td_proc->p_vmspace)->pm_pml4);
+ pcb2->pcb_r12 = (register_t)fork_return; /* trampoline arg */
+ pcb2->pcb_rbp = 0;
+ pcb2->pcb_rsp = (register_t)td->td_frame - sizeof(void *); /* trampoline arg */
+ pcb2->pcb_rbx = (register_t)td; /* trampoline arg */
+ pcb2->pcb_rip = (register_t)fork_trampoline;
+ pcb2->pcb_rflags = td->td_frame->tf_rflags & ~PSL_I; /* ints disabled */
+ /*
+ * If we didn't copy the pcb, we'd need to do the following registers:
+ * pcb2->pcb_savefpu: cloned above.
+ * pcb2->pcb_rflags: cloned above.
+ * pcb2->pcb_onfault: cloned above (always NULL here?).
+ * pcb2->pcb_[fg]sbase: cloned above
+ */
}
/*
@@ -231,6 +276,29 @@ cpu_set_upcall(struct thread *td, struct thread *td0)
void
cpu_set_upcall_kse(struct thread *td, struct kse_upcall *ku)
{
+
+ /*
+ * Do any extra cleaning that needs to be done.
+ * The thread may have optional components
+ * that are not present in a fresh thread.
+ * This may be a recycled thread so make it look
+ * as though it's newly allocated.
+ */
+ cpu_thread_clean(td);
+
+ /*
+ * Set the trap frame to point at the beginning of the uts
+ * function.
+ */
+ td->td_frame->tf_rsp =
+ ((register_t)ku->ku_stack.ss_sp + ku->ku_stack.ss_size) & ~0x0f;
+ td->td_frame->tf_rip = (register_t)ku->ku_func;
+
+ /*
+ * Pass the address of the mailbox for this kse to the uts
+ * function as a parameter on the stack.
+ */
+ td->td_frame->tf_rdi = (register_t)ku->ku_mailbox;
}
OpenPOWER on IntegriCloud