57 changes: 16 additions & 41 deletions usr/src/uts/i86pc/os/trap.c
Original file line number Diff line number Diff line change
Expand Up @@ -993,50 +993,25 @@ trap(struct regs *rp, caddr_t addr, processorid_t cpuid)
fault = FLTIOVF;
break;

/*
* When using an eager FPU on x86, the #NM trap is no longer meaningful.
* Userland should not be able to trigger it. Anything that does
* represents a fatal error in the kernel and likely in the register
* state of the system. User FPU state should always be valid.
*/
case T_NOEXTFLT + USER: /* math coprocessor not available */
if (tudebug && tudebugfpe)
showregs(type, rp, addr);
if (fpnoextflt(rp)) {
siginfo.si_signo = SIGILL;
siginfo.si_code = ILL_ILLOPC;
siginfo.si_addr = (caddr_t)rp->r_pc;
fault = FLTILL;
}
break;

case T_EXTOVRFLT: /* extension overrun fault */
/* check if we took a kernel trap on behalf of user */
{
extern void ndptrap_frstor(void);
if (rp->r_pc != (uintptr_t)ndptrap_frstor) {
sti(); /* T_EXTOVRFLT comes in via cmninttrap */
(void) die(type, rp, addr, cpuid);
}
type |= USER;
}
/*FALLTHROUGH*/
case T_EXTOVRFLT + USER: /* extension overrun fault */
if (tudebug && tudebugfpe)
showregs(type, rp, addr);
if (fpextovrflt(rp)) {
siginfo.si_signo = SIGSEGV;
siginfo.si_code = SEGV_MAPERR;
siginfo.si_addr = (caddr_t)rp->r_pc;
fault = FLTBOUNDS;
}
case T_NOEXTFLT:
(void) die(type, rp, addr, cpuid);
break;

/*
* Kernel threads leveraging floating point need to mask the exceptions
* or ensure that they cannot happen. There is no recovery from this.
*/
case T_EXTERRFLT: /* x87 floating point exception pending */
/* check if we took a kernel trap on behalf of user */
{
extern void ndptrap_frstor(void);
if (rp->r_pc != (uintptr_t)ndptrap_frstor) {
sti(); /* T_EXTERRFLT comes in via cmninttrap */
(void) die(type, rp, addr, cpuid);
}
type |= USER;
}
/*FALLTHROUGH*/
sti(); /* T_EXTERRFLT comes in via cmninttrap */
(void) die(type, rp, addr, cpuid);
break;

case T_EXTERRFLT + USER: /* x87 floating point exception pending */
if (tudebug && tudebugfpe)
Expand Down Expand Up @@ -1939,7 +1914,7 @@ kern_gpfault(struct regs *rp)
}

#if defined(__amd64)
if (trp == NULL && lwp->lwp_pcb.pcb_rupdate != 0) {
if (trp == NULL && PCB_NEED_UPDATE_SEGS(&lwp->lwp_pcb)) {

/*
* This is the common case -- we're trying to load
Expand Down
228 changes: 4 additions & 224 deletions usr/src/uts/intel/ia32/ml/exception.s
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,7 @@
#include <sys/traptrace.h>
#include <sys/machparam.h>

/*
* only one routine in this file is interesting to lint
*/

#if defined(__lint)

void
ndptrap_frstor(void)
{}

#else
#if !defined(__lint)

#include "assym.h"

Expand Down Expand Up @@ -643,220 +633,16 @@ _emul_done:

#endif /* __i386 */

#if defined(__amd64)

/*
* #NM
*/
#if defined(__xpv)

ENTRY_NP(ndptrap)
/*
* (On the hypervisor we must make a hypercall so we might as well
* save everything and handle as in a normal trap.)
*/
TRAP_NOERR(T_NOEXTFLT) /* $7 */
INTR_PUSH

/*
* We want to do this quickly as every lwp using fp will take this
* after a context switch -- we do the frequent path in ndptrap_frstor
* below; for all other cases, we let the trap code handle it
*/
LOADCPU(%rax) /* swapgs handled in hypervisor */
cmpl $0, fpu_exists(%rip)
je .handle_in_trap /* let trap handle no fp case */
movq CPU_THREAD(%rax), %rbx /* %rbx = curthread */
movl $FPU_EN, %eax
movq T_LWP(%rbx), %rbx /* %rbx = lwp */
testq %rbx, %rbx
jz .handle_in_trap /* should not happen? */
#if LWP_PCB_FPU != 0
addq $LWP_PCB_FPU, %rbx /* &lwp->lwp_pcb.pcb_fpu */
#endif
testl %eax, PCB_FPU_FLAGS(%rbx)
jz .handle_in_trap /* must be the first fault */
CLTS
andl $_BITNOT(FPU_VALID), PCB_FPU_FLAGS(%rbx)
#if FPU_CTX_FPU_REGS != 0
addq $FPU_CTX_FPU_REGS, %rbx
#endif

movl FPU_CTX_FPU_XSAVE_MASK(%rbx), %eax /* for xrstor */
movl FPU_CTX_FPU_XSAVE_MASK+4(%rbx), %edx /* for xrstor */

/*
* the label below is used in trap.c to detect FP faults in
* kernel due to user fault.
*/
ALTENTRY(ndptrap_frstor)
movq (%rbx), %rbx /* fpu_regs.kfpu_u.kfpu_XX pointer */
.globl _patch_xrstorq_rbx
_patch_xrstorq_rbx:
fxrstorq (%rbx)
cmpw $KCS_SEL, REGOFF_CS(%rsp)
je .return_to_kernel

ASSERT_UPCALL_MASK_IS_SET
USER_POP
IRET /* return to user mode */
/*NOTREACHED*/

.return_to_kernel:
INTR_POP
IRET
/*NOTREACHED*/

.handle_in_trap:
INTR_POP
pushq $0 /* can not use TRAP_NOERR */
pushq $T_NOEXTFLT
jmp cmninttrap
SET_SIZE(ndptrap_frstor)
SET_SIZE(ndptrap)

#else /* __xpv */

ENTRY_NP(ndptrap)
/*
* We want to do this quickly as every lwp using fp will take this
* after a context switch -- we do the frequent path in ndptrap_frstor
* below; for all other cases, we let the trap code handle it
*/
pushq %rax
pushq %rbx
cmpw $KCS_SEL, 24(%rsp) /* did we come from kernel mode? */
jne 1f
LOADCPU(%rax) /* if yes, don't swapgs */
jmp 2f
1:
SWAPGS /* if from user, need swapgs */
LOADCPU(%rax)
SWAPGS
2:
/*
* Xrstor needs to use edx as part of its flag.
* NOTE: have to push rdx after "cmpw ...24(%rsp)", otherwise rsp+$24
* will not point to CS.
*/
pushq %rdx
cmpl $0, fpu_exists(%rip)
je .handle_in_trap /* let trap handle no fp case */
movq CPU_THREAD(%rax), %rbx /* %rbx = curthread */
movl $FPU_EN, %eax
movq T_LWP(%rbx), %rbx /* %rbx = lwp */
testq %rbx, %rbx
jz .handle_in_trap /* should not happen? */
#if LWP_PCB_FPU != 0
addq $LWP_PCB_FPU, %rbx /* &lwp->lwp_pcb.pcb_fpu */
#endif
testl %eax, PCB_FPU_FLAGS(%rbx)
jz .handle_in_trap /* must be the first fault */
clts
andl $_BITNOT(FPU_VALID), PCB_FPU_FLAGS(%rbx)
#if FPU_CTX_FPU_REGS != 0
addq $FPU_CTX_FPU_REGS, %rbx
#endif

movl FPU_CTX_FPU_XSAVE_MASK(%rbx), %eax /* for xrstor */
movl FPU_CTX_FPU_XSAVE_MASK+4(%rbx), %edx /* for xrstor */

/*
* the label below is used in trap.c to detect FP faults in
* kernel due to user fault.
*/
ALTENTRY(ndptrap_frstor)
movq (%rbx), %rbx /* fpu_regs.kfpu_u.kfpu_XX pointer */
.globl _patch_xrstorq_rbx
_patch_xrstorq_rbx:
fxrstorq (%rbx)
popq %rdx
popq %rbx
popq %rax
jmp tr_iret_auto
/*NOTREACHED*/

.handle_in_trap:
popq %rdx
popq %rbx
popq %rax
TRAP_NOERR(T_NOEXTFLT) /* $7 */
jmp cmninttrap
SET_SIZE(ndptrap_frstor)
SET_SIZE(ndptrap)

#endif /* __xpv */

#elif defined(__i386)

ENTRY_NP(ndptrap)
/*
* We want to do this quickly as every lwp using fp will take this
* after a context switch -- we do the frequent path in fpnoextflt
* below; for all other cases, we let the trap code handle it
*/
pushl %eax
pushl %ebx
pushl %edx /* for xrstor */
pushl %ds
pushl %gs
movl $KDS_SEL, %ebx
movw %bx, %ds
movl $KGS_SEL, %eax
movw %ax, %gs
LOADCPU(%eax)
cmpl $0, fpu_exists
je .handle_in_trap /* let trap handle no fp case */
movl CPU_THREAD(%eax), %ebx /* %ebx = curthread */
movl $FPU_EN, %eax
movl T_LWP(%ebx), %ebx /* %ebx = lwp */
testl %ebx, %ebx
jz .handle_in_trap /* should not happen? */
#if LWP_PCB_FPU != 0
addl $LWP_PCB_FPU, %ebx /* &lwp->lwp_pcb.pcb_fpu */
#endif
testl %eax, PCB_FPU_FLAGS(%ebx)
jz .handle_in_trap /* must be the first fault */
CLTS
andl $_BITNOT(FPU_VALID), PCB_FPU_FLAGS(%ebx)
#if FPU_CTX_FPU_REGS != 0
addl $FPU_CTX_FPU_REGS, %ebx
#endif

movl FPU_CTX_FPU_XSAVE_MASK(%ebx), %eax /* for xrstor */
movl FPU_CTX_FPU_XSAVE_MASK+4(%ebx), %edx /* for xrstor */

/*
* the label below is used in trap.c to detect FP faults in kernel
* due to user fault.
*/
ALTENTRY(ndptrap_frstor)
movl (%ebx), %ebx /* fpu_regs.kfpu_u.kfpu_XX pointer */
.globl _patch_fxrstor_ebx
_patch_fxrstor_ebx:
.globl _patch_xrstor_ebx
_patch_xrstor_ebx:
frstor (%ebx) /* may be patched to fxrstor or xrstor */
popl %gs
popl %ds
popl %edx
popl %ebx
popl %eax
IRET

.handle_in_trap:
popl %gs
popl %ds
popl %edx
popl %ebx
popl %eax
TRAP_NOERR(T_NOEXTFLT) /* $7 */
jmp cmninttrap
SET_SIZE(ndptrap_frstor)
TRAP_NOERR(T_NOEXTFLT) /* $0 */
SET_CPU_GSBASE
jmp cmntrap
SET_SIZE(ndptrap)

#endif /* __i386 */

#if !defined(__xpv)
#if defined(__amd64)

Expand Down Expand Up @@ -1036,12 +822,6 @@ make_frame:
#endif /* __i386 */
#endif /* !__xpv */

ENTRY_NP(overrun)
push $0
TRAP_NOERR(T_EXTOVRFLT) /* $9 i386 only - not generated */
jmp cmninttrap
SET_SIZE(overrun)

/*
* #TS
*/
Expand Down
516 changes: 40 additions & 476 deletions usr/src/uts/intel/ia32/ml/float.s

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions usr/src/uts/intel/ia32/os/archdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ setfpregs(klwp_t *lwp, fpregset_t *fp)

fpu->fpu_regs.kfpu_status = fp->fp_reg_set.fpchip_state.status;
fpu->fpu_flags |= FPU_VALID;
PCB_SET_UPDATE_FPU(&lwp->lwp_pcb);
}

/*
Expand Down Expand Up @@ -464,7 +465,7 @@ getgregs(klwp_t *lwp, gregset_t grp)
grp[REG_GSBASE] = pcb->pcb_gsbase;
if (thisthread)
kpreempt_disable();
if (pcb->pcb_rupdate == 1) {
if (PCB_NEED_UPDATE_SEGS(pcb)) {
grp[REG_DS] = pcb->pcb_ds;
grp[REG_ES] = pcb->pcb_es;
grp[REG_FS] = pcb->pcb_fs;
Expand Down Expand Up @@ -500,7 +501,7 @@ getgregs32(klwp_t *lwp, gregset32_t grp)

if (thisthread)
kpreempt_disable();
if (pcb->pcb_rupdate == 1) {
if (PCB_NEED_UPDATE_SEGS(pcb)) {
grp[GS] = (uint16_t)pcb->pcb_gs;
grp[FS] = (uint16_t)pcb->pcb_fs;
grp[DS] = (uint16_t)pcb->pcb_ds;
Expand Down Expand Up @@ -753,7 +754,7 @@ setgregs(klwp_t *lwp, gregset_t grp)
/*
* Ensure that we go out via update_sregs
*/
pcb->pcb_rupdate = 1;
PCB_SET_UPDATE_SEGS(pcb);
lwptot(lwp)->t_post_sys = 1;
if (thisthread)
kpreempt_enable();
Expand Down Expand Up @@ -790,7 +791,7 @@ setgregs(klwp_t *lwp, gregset_t grp)
/*
* Ensure that we go out via update_sregs
*/
pcb->pcb_rupdate = 1;
PCB_SET_UPDATE_SEGS(pcb);
lwptot(lwp)->t_post_sys = 1;
if (thisthread)
kpreempt_enable();
Expand Down
601 changes: 431 additions & 170 deletions usr/src/uts/intel/ia32/os/fpu.c

Large diffs are not rendered by default.

55 changes: 27 additions & 28 deletions usr/src/uts/intel/ia32/os/sundep.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2017 Joyent, Inc.
* Copyright 2018 Joyent, Inc.
*/

/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
Expand Down Expand Up @@ -393,12 +393,12 @@ lwp_forkregs(klwp_t *lwp, klwp_t *clwp)
struct pcb *pcb = &clwp->lwp_pcb;
struct regs *rp = lwptoregs(lwp);

if (pcb->pcb_rupdate == 0) {
if (!PCB_NEED_UPDATE_SEGS(pcb)) {
pcb->pcb_ds = rp->r_ds;
pcb->pcb_es = rp->r_es;
pcb->pcb_fs = rp->r_fs;
pcb->pcb_gs = rp->r_gs;
pcb->pcb_rupdate = 1;
PCB_SET_UPDATE_SEGS(pcb);
lwptot(clwp)->t_post_sys = 1;
}
ASSERT(lwptot(clwp)->t_post_sys);
Expand Down Expand Up @@ -436,22 +436,22 @@ lwp_pcb_exit(void)
* as a segment-not-present trap.
*
* Here we save the current values from the lwp regs into the pcb
* and set pcb->pcb_rupdate to 1 to tell the rest of the kernel
* that the pcb copy of the segment registers is the current one.
* This ensures the lwp's next trip to user land via update_sregs.
* Finally we set t_post_sys to ensure that no system call fast-path's
* its way out of the kernel via sysret.
* and or PCB_UPDATE_SEGS (1) in pcb->pcb_rupdate to tell the rest
* of the kernel that the pcb copy of the segment registers is the
* current one. This ensures the lwp's next trip to user land via
* update_sregs. Finally we set t_post_sys to ensure that no
* system call fast-path's its way out of the kernel via sysret.
*
* (This means that we need to have interrupts disabled when we test
* t->t_post_sys in the syscall handlers; if the test fails, we need
* to keep interrupts disabled until we return to userland so we can't
* be switched away.)
* (This means that we need to have interrupts disabled when we
* test t->t_post_sys in the syscall handlers; if the test fails,
* we need to keep interrupts disabled until we return to userland
* so we can't be switched away.)
*
* As a result of all this, we don't really have to do a whole lot if
* the thread is just mucking about in the kernel, switching on and
* off the cpu for whatever reason it feels like. And yet we still
* preserve fast syscalls, cause if we -don't- get descheduled,
* we never come here either.
* As a result of all this, we don't really have to do a whole lot
* if the thread is just mucking about in the kernel, switching on
* and off the cpu for whatever reason it feels like. And yet we
* still preserve fast syscalls, cause if we -don't- get
* descheduled, we never come here either.
*/

#define VALID_LWP_DESC(udp) ((udp)->usd_type == SDT_MEMRWA && \
Expand All @@ -468,7 +468,7 @@ lwp_segregs_save(klwp_t *lwp)
ASSERT(VALID_LWP_DESC(&pcb->pcb_fsdesc));
ASSERT(VALID_LWP_DESC(&pcb->pcb_gsdesc));

if (pcb->pcb_rupdate == 0) {
if (!PCB_NEED_UPDATE_SEGS(pcb)) {
rp = lwptoregs(lwp);

/*
Expand All @@ -482,7 +482,7 @@ lwp_segregs_save(klwp_t *lwp)
pcb->pcb_es = rp->r_es;
pcb->pcb_fs = rp->r_fs;
pcb->pcb_gs = rp->r_gs;
pcb->pcb_rupdate = 1;
PCB_SET_UPDATE_SEGS(pcb);
lwp->lwp_thread->t_post_sys = 1;
}
#endif /* __amd64 */
Expand Down Expand Up @@ -833,7 +833,8 @@ lwp_installctx(klwp_t *lwp)
* On the amd64 kernel, the context handlers are responsible for
* virtualizing %ds, %es, %fs, and %gs to the lwp. The register
* values are only ever changed via sys_rtt when the
* pcb->pcb_rupdate == 1. Only sys_rtt gets to clear the bit.
* PCB_UPDATE_SEGS bit (1) is set in pcb->pcb_rupdate. Only
* sys_rtt gets to clear the bit.
*
* On the i386 kernel, the context handlers are responsible for
* virtualizing %gs/%fs to the lwp by updating the per-cpu GDTs
Expand Down Expand Up @@ -964,7 +965,7 @@ setregs(uarg_t *args)

pcb->pcb_ds = rp->r_ds;
pcb->pcb_es = rp->r_es;
pcb->pcb_rupdate = 1;
PCB_SET_UPDATE_SEGS(pcb);

#elif defined(__i386)

Expand All @@ -990,18 +991,16 @@ setregs(uarg_t *args)
lwp->lwp_eosys = JUSTRETURN;
t->t_post_sys = 1;

/*
* Here we initialize minimal fpu state.
* The rest is done at the first floating
* point instruction that a process executes.
*/
pcb->pcb_fpu.fpu_flags = 0;

/*
* Add the lwp context handlers that virtualize segment registers,
* and/or system call stacks etc.
*/
lwp_installctx(lwp);

/*
* Reset the FPU flags and then initialize the FPU for this lwp.
*/
fp_exec();
}

user_desc_t *
Expand Down
2 changes: 1 addition & 1 deletion usr/src/uts/intel/ia32/os/sysi86.c
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ setdscr(struct ssd *ssd)
}

#if defined(__amd64)
if (pcb->pcb_rupdate == 1) {
if (PCB_NEED_UPDATE_SEGS(pcb)) {
if (ssd->sel == pcb->pcb_ds ||
ssd->sel == pcb->pcb_es ||
ssd->sel == pcb->pcb_fs ||
Expand Down
15 changes: 7 additions & 8 deletions usr/src/uts/intel/ia32/syscall/lwp_private.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2018, Joyent, Inc.
*/

#pragma ident "%Z%%M% %I% %E% SMI"

#include <sys/param.h>
#include <sys/types.h>
#include <sys/disp.h>
Expand Down Expand Up @@ -72,12 +71,12 @@ lwp_setprivate(klwp_t *lwp, int which, uintptr_t base)
* of zero for %fs and %gs to use the 64-bit fs_base and gs_base
* respectively.
*/
if (pcb->pcb_rupdate == 0) {
if (!PCB_NEED_UPDATE_SEGS(pcb)) {
pcb->pcb_ds = rp->r_ds;
pcb->pcb_es = rp->r_es;
pcb->pcb_fs = rp->r_fs;
pcb->pcb_gs = rp->r_gs;
pcb->pcb_rupdate = 1;
PCB_SET_UPDATE_SEGS(pcb);
t->t_post_sys = 1;
}
ASSERT(t->t_post_sys);
Expand Down Expand Up @@ -171,15 +170,15 @@ lwp_getprivate(klwp_t *lwp, int which, uintptr_t base)
case _LWP_FSBASE:
if ((sbase = pcb->pcb_fsbase) != 0) {
if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
if (pcb->pcb_rupdate == 1) {
if (PCB_NEED_UPDATE_SEGS(pcb)) {
if (pcb->pcb_fs == 0)
break;
} else {
if (rp->r_fs == 0)
break;
}
} else {
if (pcb->pcb_rupdate == 1) {
if (PCB_NEED_UPDATE_SEGS(pcb)) {
if (pcb->pcb_fs == LWPFS_SEL)
break;
} else {
Expand All @@ -193,15 +192,15 @@ lwp_getprivate(klwp_t *lwp, int which, uintptr_t base)
case _LWP_GSBASE:
if ((sbase = pcb->pcb_gsbase) != 0) {
if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
if (pcb->pcb_rupdate == 1) {
if (PCB_NEED_UPDATE_SEGS(pcb)) {
if (pcb->pcb_gs == 0)
break;
} else {
if (rp->r_gs == 0)
break;
}
} else {
if (pcb->pcb_rupdate == 1) {
if (PCB_NEED_UPDATE_SEGS(pcb)) {
if (pcb->pcb_gs == LWPGS_SEL)
break;
} else {
Expand Down
3 changes: 0 additions & 3 deletions usr/src/uts/intel/sys/archsystm.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,8 @@ extern void mfence_insn(void);
extern uint16_t getgs(void);
extern void setgs(uint16_t);

extern void patch_sse(void);
extern void patch_sse2(void);
#endif

extern void patch_xsave(void);
extern kmem_cache_t *fpsave_cachep;

extern void cli(void);
Expand Down
24 changes: 14 additions & 10 deletions usr/src/uts/intel/sys/fp.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,13 +236,14 @@ struct fxsave_state {
* 13.4.2 of the Intel 64 and IA-32 Architectures Software Developer’s Manual,
* Volume 1 (IASDv1). The extended portion is documented in section 13.4.3.
*
* Our size is at least AVX_XSAVE_SIZE (832 bytes), asserted in fpnoextflt().
* Enabling additional xsave-related CPU features requires an increase in the
* size. We dynamically allocate the per-lwp xsave area at runtime, based on
* the size needed for the CPU-specific features. This xsave_state structure
* simply defines our historical layout for the beginning of the xsave area. The
* locations and size of new, extended, components is determined dynamically by
* querying the CPU. See the xsave_info structure in cpuid.c.
* Our size is at least AVX_XSAVE_SIZE (832 bytes), which is asserted
* statically. Enabling additional xsave-related CPU features requires an
* increase in the size. We dynamically allocate the per-lwp xsave area at
* runtime, based on the size needed for the CPU-specific features. This
* xsave_state structure simply defines our historical layout for the beginning
* of the xsave area. The locations and size of new, extended, components is
* determined dynamically by querying the CPU. See the xsave_info structure in
* cpuid.c.
*
* xsave component usage is tracked using bits in the xs_xstate_bv field. The
* components are documented in section 13.1 of IASDv1. For easy reference,
Expand Down Expand Up @@ -301,7 +302,6 @@ extern uint32_t sse_mxcsr_mask;

extern void fpu_probe(void);
extern uint_t fpu_initial_probe(void);
extern int fpu_probe_pentium_fdivbug(void);

extern void fpu_auxv_info(int *, size_t *);

Expand All @@ -315,6 +315,10 @@ extern void xsaveopt_excp_clr_ctxt(void *);
extern void (*fpsave_ctxt)(void *);
extern void (*xsavep)(struct xsave_state *, uint64_t);

extern void fpxrestore_ctxt(void *);
extern void xrestore_ctxt(void *);
extern void (*fprestore_ctxt)(void *);

extern void fxsave_insn(struct fxsave_state *);
extern void fpsave(struct fnsave_state *);
extern void fprestore(struct fnsave_state *);
Expand All @@ -335,11 +339,11 @@ extern uint32_t fpgetcwsw(void);
extern uint32_t fpgetmxcsr(void);

struct regs;
extern int fpnoextflt(struct regs *);
extern int fpextovrflt(struct regs *);
extern int fpexterrflt(struct regs *);
extern int fpsimderrflt(struct regs *);
extern void fpsetcw(uint16_t, uint32_t);
extern void fp_seed(void);
extern void fp_exec(void);
struct _klwp;
extern void fp_lwp_init(struct _klwp *);
extern void fp_lwp_cleanup(struct _klwp *);
Expand Down
18 changes: 16 additions & 2 deletions usr/src/uts/intel/sys/pcb.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

/*
* Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, Joyent, Inc.
*/

#ifndef _SYS_PCB_H
Expand Down Expand Up @@ -51,15 +52,13 @@ typedef struct pcb {
uint_t pcb_flags; /* state flags; cleared on fork */
greg_t pcb_drstat; /* status debug register (%dr6) */
unsigned char pcb_instr; /* /proc: instruction at stop */
#if defined(__amd64)
unsigned char pcb_rupdate; /* new register values in pcb -> regs */
uintptr_t pcb_fsbase;
uintptr_t pcb_gsbase;
selector_t pcb_ds;
selector_t pcb_es;
selector_t pcb_fs;
selector_t pcb_gs;
#endif /* __amd64 */
user_desc_t pcb_fsdesc; /* private per-lwp %fs descriptors */
user_desc_t pcb_gsdesc; /* private per-lwp %gs descriptors */
} pcb_t;
Expand All @@ -77,6 +76,21 @@ typedef struct pcb {
#define REQUEST_NOSTEP 0x200 /* request pending to disable single-step */
#define ASYNC_HWERR 0x400 /* hardware error has corrupted context */

/* pcb_rupdate values */
#define PCB_UPDATE_SEGS 0x01 /* Update segment registers */
#define PCB_UPDATE_FPU 0x02 /* Update FPU registers */

#define PCB_SET_UPDATE_SEGS(pcb) ((pcb)->pcb_rupdate |= PCB_UPDATE_SEGS)
#define PCB_SET_UPDATE_FPU(pcb) ((pcb)->pcb_rupdate |= PCB_UPDATE_FPU)
#define PCB_NEED_UPDATE_SEGS(pcb) \
(((pcb)->pcb_rupdate & PCB_UPDATE_SEGS) != 0)
#define PCB_NEED_UPDATE_FPU(pcb) \
(((pcb)->pcb_rupdate & PCB_UPDATE_FPU) != 0)
#define PCB_NEED_UPDATE(pcb) \
(PCB_NEED_UPDATE_FPU(pcb) || PCB_NEED_UPDATE_SEGS(pcb))
#define PCB_CLEAR_UPDATE_SEGS(pcb) ((pcb)->pcb_rupdate &= ~PCB_UPDATE_SEGS)
#define PCB_CLEAR_UPDATE_FPU(pcb) ((pcb)->pcb_rupdate &= ~PCB_UPDATE_FPU)

/* fpu_flags */
#define FPU_EN 0x1 /* flag signifying fpu in use */
#define FPU_VALID 0x2 /* fpu_regs has valid fpu state */
Expand Down