Changeset View
Changeset View
Standalone View
Standalone View
head/sys/amd64/amd64/vm_machdep.c
Show First 20 Lines • Show All 279 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Intercept the return address from a freshly forked process that has NOT | * Intercept the return address from a freshly forked process that has NOT | ||||
* been scheduled yet. | * been scheduled yet. | ||||
* | * | ||||
* This is needed to make kernel threads stay in kernel mode. | * This is needed to make kernel threads stay in kernel mode. | ||||
*/ | */ | ||||
void | void | ||||
cpu_set_fork_handler(td, func, arg) | cpu_fork_kthread_handler(struct thread *td, void (*func)(void *), void *arg) | ||||
struct thread *td; | |||||
void (*func)(void *); | |||||
void *arg; | |||||
{ | { | ||||
/* | /* | ||||
* Note that the trap frame follows the args, so the function | * Note that the trap frame follows the args, so the function | ||||
* is really called like this: func(arg, frame); | * is really called like this: func(arg, frame); | ||||
*/ | */ | ||||
td->td_pcb->pcb_r12 = (long) func; /* function */ | td->td_pcb->pcb_r12 = (long) func; /* function */ | ||||
td->td_pcb->pcb_rbx = (long) arg; /* first arg */ | td->td_pcb->pcb_rbx = (long) arg; /* first arg */ | ||||
} | } | ||||
▲ Show 20 Lines • Show All 116 Lines • ▼ Show 20 Lines | cpu_set_syscall_retval(struct thread *td, int error) | ||||
default: | default: | ||||
td->td_frame->tf_rax = SV_ABI_ERRNO(td->td_proc, error); | td->td_frame->tf_rax = SV_ABI_ERRNO(td->td_proc, error); | ||||
td->td_frame->tf_rflags |= PSL_C; | td->td_frame->tf_rflags |= PSL_C; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Initialize machine state (pcb and trap frame) for a new thread about to | * Initialize machine state, mostly pcb and trap frame for a new | ||||
* upcall. Put enough state in the new thread's PCB to get it to go back | * thread, about to return to userspace. Put enough state in the new | ||||
* userret(), where we can intercept it again to set the return (upcall) | * thread's PCB to get it to go back to the fork_return(), which | ||||
* Address and stack, along with those from upcals that are from other sources | * finalizes the thread state and handles peculiarities of the first | ||||
* such as those generated in thread_userret() itself. | * return to userspace for the new thread. | ||||
*/ | */ | ||||
void | void | ||||
cpu_set_upcall(struct thread *td, struct thread *td0) | cpu_copy_thread(struct thread *td, struct thread *td0) | ||||
{ | { | ||||
struct pcb *pcb2; | struct pcb *pcb2; | ||||
/* Point the pcb to the top of the stack. */ | /* Point the pcb to the top of the stack. */ | ||||
pcb2 = td->td_pcb; | pcb2 = td->td_pcb; | ||||
/* | /* | ||||
* Copy the upcall pcb. This loads kernel regs. | * Copy the upcall pcb. This loads kernel regs. | ||||
Show All 39 Lines | cpu_copy_thread(struct thread *td, struct thread *td0) | ||||
*/ | */ | ||||
/* Setup to release spin count in fork_exit(). */ | /* Setup to release spin count in fork_exit(). */ | ||||
td->td_md.md_spinlock_count = 1; | td->td_md.md_spinlock_count = 1; | ||||
td->td_md.md_saved_flags = PSL_KERNEL | PSL_I; | td->td_md.md_saved_flags = PSL_KERNEL | PSL_I; | ||||
} | } | ||||
/* | /* | ||||
* Set that machine state for performing an upcall that has to | * Set that machine state for performing an upcall that starts | ||||
* be done in thread_userret() so that those upcalls generated | * the entry function with the given argument. | ||||
* in thread_userret() itself can be done as well. | |||||
*/ | */ | ||||
void | void | ||||
cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg, | cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg, | ||||
stack_t *stack) | stack_t *stack) | ||||
{ | { | ||||
/* | /* | ||||
* Do any extra cleaning that needs to be done. | * Do any extra cleaning that needs to be done. | ||||
* The thread may have optional components | * The thread may have optional components | ||||
* that are not present in a fresh thread. | * that are not present in a fresh thread. | ||||
* This may be a recycled thread so make it look | * This may be a recycled thread so make it look | ||||
* as though it's newly allocated. | * as though it's newly allocated. | ||||
*/ | */ | ||||
cpu_thread_clean(td); | cpu_thread_clean(td); | ||||
#ifdef COMPAT_FREEBSD32 | #ifdef COMPAT_FREEBSD32 | ||||
if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) { | if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) { | ||||
/* | /* | ||||
* Set the trap frame to point at the beginning of the uts | * Set the trap frame to point at the beginning of the entry | ||||
* function. | * function. | ||||
*/ | */ | ||||
td->td_frame->tf_rbp = 0; | td->td_frame->tf_rbp = 0; | ||||
td->td_frame->tf_rsp = | td->td_frame->tf_rsp = | ||||
(((uintptr_t)stack->ss_sp + stack->ss_size - 4) & ~0x0f) - 4; | (((uintptr_t)stack->ss_sp + stack->ss_size - 4) & ~0x0f) - 4; | ||||
td->td_frame->tf_rip = (uintptr_t)entry; | td->td_frame->tf_rip = (uintptr_t)entry; | ||||
/* | /* Pass the argument to the entry point. */ | ||||
* Pass the address of the mailbox for this kse to the uts | |||||
* function as a parameter on the stack. | |||||
*/ | |||||
suword32((void *)(td->td_frame->tf_rsp + sizeof(int32_t)), | suword32((void *)(td->td_frame->tf_rsp + sizeof(int32_t)), | ||||
(uint32_t)(uintptr_t)arg); | (uint32_t)(uintptr_t)arg); | ||||
return; | return; | ||||
} | } | ||||
#endif | #endif | ||||
/* | /* | ||||
* Set the trap frame to point at the beginning of the uts | * Set the trap frame to point at the beginning of the uts | ||||
* function. | * function. | ||||
*/ | */ | ||||
td->td_frame->tf_rbp = 0; | td->td_frame->tf_rbp = 0; | ||||
td->td_frame->tf_rsp = | td->td_frame->tf_rsp = | ||||
((register_t)stack->ss_sp + stack->ss_size) & ~0x0f; | ((register_t)stack->ss_sp + stack->ss_size) & ~0x0f; | ||||
td->td_frame->tf_rsp -= 8; | td->td_frame->tf_rsp -= 8; | ||||
td->td_frame->tf_rip = (register_t)entry; | td->td_frame->tf_rip = (register_t)entry; | ||||
td->td_frame->tf_ds = _udatasel; | td->td_frame->tf_ds = _udatasel; | ||||
td->td_frame->tf_es = _udatasel; | td->td_frame->tf_es = _udatasel; | ||||
td->td_frame->tf_fs = _ufssel; | td->td_frame->tf_fs = _ufssel; | ||||
td->td_frame->tf_gs = _ugssel; | td->td_frame->tf_gs = _ugssel; | ||||
td->td_frame->tf_flags = TF_HASSEGS; | td->td_frame->tf_flags = TF_HASSEGS; | ||||
/* | /* Pass the argument to the entry point. */ | ||||
* 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)arg; | td->td_frame->tf_rdi = (register_t)arg; | ||||
} | } | ||||
int | int | ||||
cpu_set_user_tls(struct thread *td, void *tls_base) | cpu_set_user_tls(struct thread *td, void *tls_base) | ||||
{ | { | ||||
struct pcb *pcb; | struct pcb *pcb; | ||||
▲ Show 20 Lines • Show All 175 Lines • Show Last 20 Lines |