#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <sys/t_lock.h>
#include <sys/klwp.h>
#include <sys/ucontext.h>
#include <sys/procfs.h>
#include <sys/privregs.h>
#include <sys/cpuvar.h>
#include <sys/cmn_err.h>
#include <sys/systm.h>
#include <sys/archsystm.h>
#include <sys/machsystm.h>
#include <sys/fpu/fpusystm.h>
void
xregs_clrptr(klwp_id_t lwp, ucontext_t *uc)
{
uc->uc_mcontext.xrs.xrs_id = 0;
uc->uc_mcontext.xrs.xrs_ptr = NULL;
}
int
xregs_hasptr(klwp_id_t lwp, ucontext_t *uc)
{
return (uc->uc_mcontext.xrs.xrs_id == XRS_ID);
}
caddr_t
xregs_getptr(klwp_id_t lwp, ucontext_t *uc)
{
if (uc->uc_mcontext.xrs.xrs_id == XRS_ID)
return (uc->uc_mcontext.xrs.xrs_ptr);
return (NULL);
}
void
xregs_setptr(klwp_id_t lwp, ucontext_t *uc, caddr_t xrp)
{
uc->uc_mcontext.xrs.xrs_id = XRS_ID;
uc->uc_mcontext.xrs.xrs_ptr = xrp;
}
#ifdef _SYSCALL32_IMPL
void
xregs_clrptr32(klwp_id_t lwp, ucontext32_t *uc)
{
uc->uc_mcontext.xrs.xrs_id = 0;
uc->uc_mcontext.xrs.xrs_ptr = 0;
}
int
xregs_hasptr32(klwp_id_t lwp, ucontext32_t *uc)
{
return (uc->uc_mcontext.xrs.xrs_id == XRS_ID);
}
caddr32_t
xregs_getptr32(klwp_id_t lwp, ucontext32_t *uc)
{
if (uc->uc_mcontext.xrs.xrs_id == XRS_ID)
return (uc->uc_mcontext.xrs.xrs_ptr);
return (0);
}
void
xregs_setptr32(klwp_id_t lwp, ucontext32_t *uc, caddr32_t xrp)
{
uc->uc_mcontext.xrs.xrs_id = XRS_ID;
uc->uc_mcontext.xrs.xrs_ptr = xrp;
}
#endif
int xregs_exists = 1;
#define GET_UPPER_32(all) (uint32_t)((uint64_t)(all) >> 32)
#define SET_ALL_64(upper, lower) \
(((uint64_t)(upper) << 32) | (uint32_t)(lower))
void
xregs_getgregs(klwp_id_t lwp, caddr_t xrp)
{
prxregset_t *xregs = (prxregset_t *)xrp;
struct regs *rp = lwptoregs(lwp);
if (xregs == NULL)
return;
xregs->pr_type = XR_TYPE_V8P;
xregs->pr_un.pr_v8p.pr_xg[XR_G0] = 0;
xregs->pr_un.pr_v8p.pr_xg[XR_G1] = GET_UPPER_32(rp->r_g1);
xregs->pr_un.pr_v8p.pr_xg[XR_G2] = GET_UPPER_32(rp->r_g2);
xregs->pr_un.pr_v8p.pr_xg[XR_G3] = GET_UPPER_32(rp->r_g3);
xregs->pr_un.pr_v8p.pr_xg[XR_G4] = GET_UPPER_32(rp->r_g4);
xregs->pr_un.pr_v8p.pr_xg[XR_G5] = GET_UPPER_32(rp->r_g5);
xregs->pr_un.pr_v8p.pr_xg[XR_G6] = GET_UPPER_32(rp->r_g6);
xregs->pr_un.pr_v8p.pr_xg[XR_G7] = GET_UPPER_32(rp->r_g7);
xregs->pr_un.pr_v8p.pr_xo[XR_O0] = GET_UPPER_32(rp->r_o0);
xregs->pr_un.pr_v8p.pr_xo[XR_O1] = GET_UPPER_32(rp->r_o1);
xregs->pr_un.pr_v8p.pr_xo[XR_O2] = GET_UPPER_32(rp->r_o2);
xregs->pr_un.pr_v8p.pr_xo[XR_O3] = GET_UPPER_32(rp->r_o3);
xregs->pr_un.pr_v8p.pr_xo[XR_O4] = GET_UPPER_32(rp->r_o4);
xregs->pr_un.pr_v8p.pr_xo[XR_O5] = GET_UPPER_32(rp->r_o5);
xregs->pr_un.pr_v8p.pr_xo[XR_O6] = GET_UPPER_32(rp->r_o6);
xregs->pr_un.pr_v8p.pr_xo[XR_O7] = GET_UPPER_32(rp->r_o7);
xregs->pr_un.pr_v8p.pr_tstate = rp->r_tstate;
xregs_getgfiller(lwp, xrp);
}
void
xregs_getfpregs(klwp_id_t lwp, caddr_t xrp)
{
prxregset_t *xregs = (prxregset_t *)xrp;
kfpu_t *fp = lwptofpu(lwp);
if (xregs == NULL)
return;
kpreempt_disable();
xregs->pr_type = XR_TYPE_V8P;
if (ttolwp(curthread) == lwp)
fp->fpu_fprs = _fp_read_fprs();
if ((fp->fpu_en) || (fp->fpu_fprs & FPRS_FEF)) {
if (fpu_exists && (ttolwp(curthread) == lwp)) {
if ((fp->fpu_fprs & FPRS_FEF) != FPRS_FEF) {
uint32_t fprs = (FPRS_FEF|FPRS_DU|FPRS_DL);
_fp_write_fprs(fprs);
fp->fpu_fprs = fprs;
#ifdef DEBUG
if (fpdispr) {
cmn_err(CE_NOTE, "xregs_getfpregs "
"with fp disabled!");
}
#endif
}
fp_v8p_fksave(fp);
}
(void) kcopy(&fp->fpu_fr.fpu_dregs[16],
&xregs->pr_un.pr_v8p.pr_xfr,
sizeof (xregs->pr_un.pr_v8p.pr_xfr));
xregs->pr_un.pr_v8p.pr_xfsr = GET_UPPER_32(fp->fpu_fsr);
xregs->pr_un.pr_v8p.pr_fprs = fp->fpu_fprs;
xregs_getfpfiller(lwp, xrp);
} else {
int i;
for (i = 0; i < 32; i++)
xregs->pr_un.pr_v8p.pr_xfr.pr_regs[i] = (uint32_t)-1;
}
kpreempt_enable();
}
void
xregs_get(klwp_id_t lwp, caddr_t xrp)
{
if (xrp != NULL) {
bzero(xrp, sizeof (prxregset_t));
xregs_getgregs(lwp, xrp);
xregs_getfpregs(lwp, xrp);
}
}
void
xregs_setgregs(klwp_id_t lwp, caddr_t xrp)
{
prxregset_t *xregs = (prxregset_t *)xrp;
struct regs *rp = lwptoregs(lwp);
int current = (lwp == curthread->t_lwp);
if (xregs == NULL)
return;
#ifdef DEBUG
if (xregs->pr_type != XR_TYPE_V8P) {
cmn_err(CE_WARN,
"xregs_setgregs: pr_type is %d and should be %d",
xregs->pr_type, XR_TYPE_V8P);
}
#endif
if (current) {
(void) save_syscall_args();
}
rp->r_g1 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xg[XR_G1], rp->r_g1);
rp->r_g2 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xg[XR_G2], rp->r_g2);
rp->r_g3 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xg[XR_G3], rp->r_g3);
rp->r_g4 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xg[XR_G4], rp->r_g4);
rp->r_g5 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xg[XR_G5], rp->r_g5);
rp->r_g6 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xg[XR_G6], rp->r_g6);
rp->r_g7 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xg[XR_G7], rp->r_g7);
rp->r_o0 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xo[XR_O0], rp->r_o0);
rp->r_o1 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xo[XR_O1], rp->r_o1);
rp->r_o2 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xo[XR_O2], rp->r_o2);
rp->r_o3 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xo[XR_O3], rp->r_o3);
rp->r_o4 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xo[XR_O4], rp->r_o4);
rp->r_o5 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xo[XR_O5], rp->r_o5);
rp->r_o6 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xo[XR_O6], rp->r_o6);
rp->r_o7 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xo[XR_O7], rp->r_o7);
rp->r_tstate &= ~((uint64_t)CCR_XCC << TSTATE_CCR_SHIFT);
rp->r_tstate |= xregs->pr_un.pr_v8p.pr_tstate &
((uint64_t)CCR_XCC << TSTATE_CCR_SHIFT);
rp->r_tstate &= ~((uint64_t)TSTATE_ASI_MASK << TSTATE_ASI_SHIFT);
rp->r_tstate |= xregs->pr_un.pr_v8p.pr_tstate &
((uint64_t)TSTATE_ASI_MASK << TSTATE_ASI_SHIFT);
xregs_setgfiller(lwp, xrp);
if (current) {
lwp->lwp_eosys = JUSTRETURN;
curthread->t_post_sys = 1;
}
}
void
xregs_setfpregs(klwp_id_t lwp, caddr_t xrp)
{
prxregset_t *xregs = (prxregset_t *)xrp;
kfpu_t *fp = lwptofpu(lwp);
if (xregs == NULL)
return;
#ifdef DEBUG
if (xregs->pr_type != XR_TYPE_V8P) {
cmn_err(CE_WARN,
"xregs_setfpregs: pr_type is %d and should be %d",
xregs->pr_type, XR_TYPE_V8P);
}
#endif
if ((fp->fpu_en) || (xregs->pr_un.pr_v8p.pr_fprs & FPRS_FEF)) {
kpreempt_disable();
(void) kcopy(&xregs->pr_un.pr_v8p.pr_xfr,
&fp->fpu_fr.fpu_dregs[16],
sizeof (xregs->pr_un.pr_v8p.pr_xfr));
fp->fpu_fprs = xregs->pr_un.pr_v8p.pr_fprs;
fp->fpu_fsr = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xfsr,
fp->fpu_fsr);
xregs_setfpfiller(lwp, xrp);
if (lwp != ttolwp(curthread)) {
kpreempt_enable();
return;
}
if (fpu_exists) {
fp->fpu_fprs = _fp_read_fprs();
if ((fp->fpu_fprs & FPRS_FEF) != FPRS_FEF) {
uint32_t fprs = (FPRS_FEF|FPRS_DU|FPRS_DL);
_fp_write_fprs(fprs);
fp->fpu_fprs = (V9_FPU_FPRS_TYPE)fprs;
#ifdef DEBUG
if (fpdispr) {
cmn_err(CE_NOTE, "xregs_setfpregs "
"with fp disabled!");
}
#endif
}
fp_v8p_load(fp);
}
kpreempt_enable();
}
}
void
xregs_set(klwp_id_t lwp, caddr_t xrp)
{
if (xrp != NULL) {
xregs_setgregs(lwp, xrp);
xregs_setfpregs(lwp, xrp);
}
}
int
xregs_getsize(proc_t *p)
{
if (!xregs_exists || p->p_model == DATAMODEL_LP64)
return (0);
return (sizeof (prxregset_t));
}