#include <sys/param.h>
#include <sys/types.h>
#include <sys/disp.h>
#include <sys/sysmacros.h>
#include <sys/cpuvar.h>
#include <sys/systm.h>
#include <sys/thread.h>
#include <sys/lwp.h>
#include <sys/segments.h>
#include <sys/privregs.h>
#include <sys/cmn_err.h>
int
lwp_setprivate(klwp_t *lwp, int which, uintptr_t base)
{
pcb_t *pcb = &lwp->lwp_pcb;
struct regs *rp = lwptoregs(lwp);
kthread_t *t = lwptot(lwp);
int thisthread = t == curthread;
int rval;
if (thisthread)
kpreempt_disable();
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_SET_UPDATE_SEGS(pcb);
t->t_post_sys = 1;
}
ASSERT(t->t_post_sys);
switch (which) {
case _LWP_FSBASE:
if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
set_usegd(&pcb->pcb_fsdesc, SDP_LONG, 0, 0,
SDT_MEMRWA, SEL_UPL, SDP_BYTES, SDP_OP32);
rval = pcb->pcb_fs = 0;
} else {
set_usegd(&pcb->pcb_fsdesc, SDP_SHORT, (void *)base, -1,
SDT_MEMRWA, SEL_UPL, SDP_PAGES, SDP_OP32);
rval = pcb->pcb_fs = LWPFS_SEL;
}
if (thisthread)
gdt_update_usegd(GDT_LWPFS, &pcb->pcb_fsdesc);
pcb->pcb_fsbase = base;
break;
case _LWP_GSBASE:
if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
set_usegd(&pcb->pcb_gsdesc, SDP_LONG, 0, 0,
SDT_MEMRWA, SEL_UPL, SDP_BYTES, SDP_OP32);
rval = pcb->pcb_gs = 0;
} else {
set_usegd(&pcb->pcb_gsdesc, SDP_SHORT, (void *)base, -1,
SDT_MEMRWA, SEL_UPL, SDP_PAGES, SDP_OP32);
rval = pcb->pcb_gs = LWPGS_SEL;
}
if (thisthread)
gdt_update_usegd(GDT_LWPGS, &pcb->pcb_gsdesc);
pcb->pcb_gsbase = base;
break;
default:
rval = -1;
break;
}
if (thisthread)
kpreempt_enable();
return (rval);
}
static int
lwp_getprivate(klwp_t *lwp, int which, uintptr_t base)
{
pcb_t *pcb = &lwp->lwp_pcb;
struct regs *rp = lwptoregs(lwp);
uintptr_t sbase;
int error = 0;
ASSERT(lwptot(lwp) == curthread);
kpreempt_disable();
switch (which) {
case _LWP_FSBASE:
if ((sbase = pcb->pcb_fsbase) != 0) {
if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
if (PCB_NEED_UPDATE_SEGS(pcb)) {
if (pcb->pcb_fs == 0)
break;
} else {
if (rp->r_fs == 0)
break;
}
} else {
if (PCB_NEED_UPDATE_SEGS(pcb)) {
if (pcb->pcb_fs == LWPFS_SEL)
break;
} else {
if (rp->r_fs == LWPFS_SEL)
break;
}
}
}
error = EINVAL;
break;
case _LWP_GSBASE:
if ((sbase = pcb->pcb_gsbase) != 0) {
if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
if (PCB_NEED_UPDATE_SEGS(pcb)) {
if (pcb->pcb_gs == 0)
break;
} else {
if (rp->r_gs == 0)
break;
}
} else {
if (PCB_NEED_UPDATE_SEGS(pcb)) {
if (pcb->pcb_gs == LWPGS_SEL)
break;
} else {
if (rp->r_gs == LWPGS_SEL)
break;
}
}
}
error = EINVAL;
break;
default:
error = ENOTSUP;
break;
}
kpreempt_enable();
if (error != 0)
return (error);
if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
if (sulword((void *)base, sbase) == -1)
error = EFAULT;
#if defined(_SYSCALL32_IMPL)
} else {
if (suword32((void *)base, (uint32_t)sbase) == -1)
error = EFAULT;
#endif
}
return (error);
}
int
syslwp_private(int cmd, int which, uintptr_t base)
{
klwp_t *lwp = ttolwp(curthread);
int res, error;
switch (cmd) {
case _LWP_SETPRIVATE:
res = lwp_setprivate(lwp, which, base);
return (res < 0 ? set_errno(ENOTSUP) : res);
case _LWP_GETPRIVATE:
error = lwp_getprivate(lwp, which, base);
return (error != 0 ? set_errno(error) : error);
default:
return (set_errno(ENOTSUP));
}
}