Changeset View
Changeset View
Standalone View
Standalone View
head/sys/amd64/amd64/vm_machdep.c
Show First 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | |||||
#include <vm/vm_kern.h> | #include <vm/vm_kern.h> | ||||
#include <vm/vm_page.h> | #include <vm/vm_page.h> | ||||
#include <vm/vm_map.h> | #include <vm/vm_map.h> | ||||
#include <vm/vm_param.h> | #include <vm/vm_param.h> | ||||
_Static_assert(OFFSETOF_MONITORBUF == offsetof(struct pcpu, pc_monitorbuf), | _Static_assert(OFFSETOF_MONITORBUF == offsetof(struct pcpu, pc_monitorbuf), | ||||
"OFFSETOF_MONITORBUF does not correspond with offset of pc_monitorbuf."); | "OFFSETOF_MONITORBUF does not correspond with offset of pc_monitorbuf."); | ||||
struct savefpu * | void | ||||
get_pcb_user_save_td(struct thread *td) | set_top_of_stack_td(struct thread *td) | ||||
{ | { | ||||
vm_offset_t p; | td->td_md.md_stack_base = td->td_kstack + | ||||
td->td_kstack_pages * PAGE_SIZE - | |||||
p = td->td_kstack + td->td_kstack_pages * PAGE_SIZE - | |||||
roundup2(cpu_max_ext_state_size, XSAVE_AREA_ALIGN); | roundup2(cpu_max_ext_state_size, XSAVE_AREA_ALIGN); | ||||
KASSERT((p % XSAVE_AREA_ALIGN) == 0, ("Unaligned pcb_user_save area")); | |||||
return ((struct savefpu *)p); | |||||
} | } | ||||
struct savefpu * | struct savefpu * | ||||
get_pcb_user_save_pcb(struct pcb *pcb) | get_pcb_user_save_td(struct thread *td) | ||||
{ | { | ||||
vm_offset_t p; | vm_offset_t p; | ||||
p = (vm_offset_t)(pcb + 1); | p = td->td_md.md_stack_base; | ||||
KASSERT((p % XSAVE_AREA_ALIGN) == 0, | |||||
("Unaligned pcb_user_save area ptr %#lx td %p", p, td)); | |||||
return ((struct savefpu *)p); | return ((struct savefpu *)p); | ||||
} | } | ||||
struct pcb * | struct pcb * | ||||
get_pcb_td(struct thread *td) | get_pcb_td(struct thread *td) | ||||
{ | { | ||||
vm_offset_t p; | |||||
p = td->td_kstack + td->td_kstack_pages * PAGE_SIZE - | return (&td->td_md.md_pcb); | ||||
roundup2(cpu_max_ext_state_size, XSAVE_AREA_ALIGN) - | |||||
sizeof(struct pcb); | |||||
return ((struct pcb *)p); | |||||
} | } | ||||
struct savefpu * | |||||
get_pcb_user_save_pcb(struct pcb *pcb) | |||||
{ | |||||
struct thread *td; | |||||
td = __containerof(pcb, struct thread, td_md.md_pcb); | |||||
return (get_pcb_user_save_td(td)); | |||||
} | |||||
void * | void * | ||||
alloc_fpusave(int flags) | alloc_fpusave(int flags) | ||||
{ | { | ||||
void *res; | void *res; | ||||
struct savefpu_ymm *sf; | struct savefpu_ymm *sf; | ||||
res = malloc(cpu_max_ext_state_size, M_DEVBUF, flags); | res = malloc(cpu_max_ext_state_size, M_DEVBUF, flags); | ||||
if (use_xsave) { | if (use_xsave) { | ||||
Show All 31 Lines | if ((flags & RFPROC) == 0) { | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
/* Ensure that td1's pcb is up to date. */ | /* Ensure that td1's pcb is up to date. */ | ||||
fpuexit(td1); | fpuexit(td1); | ||||
update_pcb_bases(td1->td_pcb); | update_pcb_bases(td1->td_pcb); | ||||
/* Point the pcb to the top of the stack */ | /* Point the stack and pcb to the actual location */ | ||||
pcb2 = get_pcb_td(td2); | set_top_of_stack_td(td2); | ||||
td2->td_pcb = pcb2; | td2->td_pcb = pcb2 = get_pcb_td(td2); | ||||
/* Copy td1's pcb */ | /* Copy td1's pcb */ | ||||
bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); | bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); | ||||
/* Properly initialize pcb_save */ | /* Properly initialize pcb_save */ | ||||
pcb2->pcb_save = get_pcb_user_save_pcb(pcb2); | pcb2->pcb_save = get_pcb_user_save_pcb(pcb2); | ||||
bcopy(get_pcb_user_save_td(td1), get_pcb_user_save_pcb(pcb2), | bcopy(get_pcb_user_save_td(td1), get_pcb_user_save_pcb(pcb2), | ||||
cpu_max_ext_state_size); | cpu_max_ext_state_size); | ||||
/* Point mdproc and then copy over td1's contents */ | /* Point mdproc and then copy over td1's contents */ | ||||
mdp2 = &p2->p_md; | mdp2 = &p2->p_md; | ||||
bcopy(&p1->p_md, mdp2, sizeof(*mdp2)); | bcopy(&p1->p_md, mdp2, sizeof(*mdp2)); | ||||
/* | /* | ||||
* Create a new fresh stack for the new process. | * Create a new fresh stack for the new process. | ||||
* Copy the trap frame for the return to user mode as if from a | * Copy the trap frame for the return to user mode as if from a | ||||
* syscall. This copies most of the user mode register values. | * syscall. This copies most of the user mode register values. | ||||
*/ | */ | ||||
td2->td_frame = (struct trapframe *)td2->td_pcb - 1; | td2->td_frame = (struct trapframe *)td2->td_md.md_stack_base - 1; | ||||
bcopy(td1->td_frame, td2->td_frame, sizeof(struct trapframe)); | bcopy(td1->td_frame, td2->td_frame, sizeof(struct trapframe)); | ||||
td2->td_frame->tf_rax = 0; /* Child returns zero */ | td2->td_frame->tf_rax = 0; /* Child returns zero */ | ||||
td2->td_frame->tf_rflags &= ~PSL_C; /* success */ | td2->td_frame->tf_rflags &= ~PSL_C; /* success */ | ||||
td2->td_frame->tf_rdx = 1; | td2->td_frame->tf_rdx = 1; | ||||
/* | /* | ||||
* If the parent process has the trap bit set (i.e. a debugger had | * If the parent process has the trap bit set (i.e. a debugger had | ||||
▲ Show 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
void | void | ||||
cpu_thread_alloc(struct thread *td) | cpu_thread_alloc(struct thread *td) | ||||
{ | { | ||||
struct pcb *pcb; | struct pcb *pcb; | ||||
struct xstate_hdr *xhdr; | struct xstate_hdr *xhdr; | ||||
set_top_of_stack_td(td); | |||||
td->td_pcb = pcb = get_pcb_td(td); | td->td_pcb = pcb = get_pcb_td(td); | ||||
td->td_frame = (struct trapframe *)pcb - 1; | td->td_frame = (struct trapframe *)td->td_md.md_stack_base - 1; | ||||
pcb->pcb_save = get_pcb_user_save_pcb(pcb); | pcb->pcb_save = get_pcb_user_save_pcb(pcb); | ||||
if (use_xsave) { | if (use_xsave) { | ||||
xhdr = (struct xstate_hdr *)(pcb->pcb_save + 1); | xhdr = (struct xstate_hdr *)(pcb->pcb_save + 1); | ||||
bzero(xhdr, sizeof(*xhdr)); | bzero(xhdr, sizeof(*xhdr)); | ||||
xhdr->xstate_bv = xsave_mask; | xhdr->xstate_bv = xsave_mask; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 121 Lines • ▼ Show 20 Lines | |||||
* 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) | ||||
{ | { | ||||
struct pcb *pcb2; | struct pcb *pcb2; | ||||
/* 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. | ||||
* Those not loaded individually below get their default | * Those not loaded individually below get their default | ||||
* values here. | * values here. | ||||
*/ | */ | ||||
update_pcb_bases(td0->td_pcb); | update_pcb_bases(td0->td_pcb); | ||||
▲ Show 20 Lines • Show All 160 Lines • Show Last 20 Lines |