#include <sys/param.h>
#include <sys/types.h>
#include <sys/vmparam.h>
#include <sys/systm.h>
#include <sys/stack.h>
#include <sys/frame.h>
#include <sys/proc.h>
#include <sys/ucontext.h>
#include <sys/cpuvar.h>
#include <sys/asm_linkage.h>
#include <sys/kmem.h>
#include <sys/errno.h>
#include <sys/bootconf.h>
#include <sys/archsystm.h>
#include <sys/fpu/fpusystm.h>
#include <sys/debug.h>
#include <sys/privregs.h>
#include <sys/machpcb.h>
#include <sys/psr_compat.h>
#include <sys/cmn_err.h>
#include <sys/asi.h>
#include <sys/copyops.h>
#include <sys/model.h>
#include <sys/panic.h>
#include <sys/exec.h>
uint_t weakest_mem_model = TSTATE_MM_TSO;
#define SET_LOWER_32(all, lower) \
(((uint64_t)(all) & 0xffffffff00000000) | (uint32_t)(lower))
#define MEMCPY_FPU_EN 2
static uint_t mkpsr(uint64_t tstate, uint32_t fprs);
#ifdef _SYSCALL32_IMPL
static void fpuregset_32ton(const fpregset32_t *src, fpregset_t *dest,
const struct fq32 *sfq, struct _fq *dfq);
#endif
void
setfpregs(klwp_t *lwp, fpregset_t *fp)
{
struct machpcb *mpcb;
kfpu_t *pfp;
uint32_t fprs = (FPRS_FEF|FPRS_DU|FPRS_DL);
model_t model = lwp_getdatamodel(lwp);
mpcb = lwptompcb(lwp);
pfp = lwptofpu(lwp);
if (fp->fpu_en) {
kpreempt_disable();
if (!(pfp->fpu_en) && (!(pfp->fpu_fprs & FPRS_FEF)) &&
fpu_exists) {
pfp->fpu_fprs = (uint32_t)fprs;
}
if (fp->fpu_en == MEMCPY_FPU_EN)
fp->fpu_en = 0;
if (fp->fpu_qcnt > MAXFPQ)
fp->fpu_qcnt = MAXFPQ;
fp->fpu_q_entrysize = sizeof (struct _fq);
(void) kcopy(fp, pfp, sizeof (fp->fpu_fr));
if (model == DATAMODEL_LP64)
pfp->fpu_fsr = fp->fpu_fsr;
else
pfp->fpu_fsr = SET_LOWER_32(pfp->fpu_fsr, fp->fpu_fsr);
pfp->fpu_qcnt = fp->fpu_qcnt;
pfp->fpu_q_entrysize = fp->fpu_q_entrysize;
pfp->fpu_en = fp->fpu_en;
pfp->fpu_q = mpcb->mpcb_fpu_q;
if (fp->fpu_qcnt)
(void) kcopy(fp->fpu_q, pfp->fpu_q,
fp->fpu_qcnt * fp->fpu_q_entrysize);
pfp->fpu_fsr &= ~(FSR_QNE|FSR_FTT);
if (lwp != ttolwp(curthread)) {
pfp->fpu_fprs |= FPRS_FEF;
kpreempt_enable();
return;
}
if (fpu_exists) {
pfp->fpu_fprs = _fp_read_fprs();
if ((pfp->fpu_fprs & FPRS_FEF) != FPRS_FEF) {
_fp_write_fprs(fprs);
pfp->fpu_fprs = (uint32_t)fprs;
#ifdef DEBUG
if (fpdispr)
cmn_err(CE_NOTE,
"setfpregs with fp disabled!\n");
#endif
}
if (model == DATAMODEL_LP64)
fp_restore(pfp);
else
fp_v8_load(pfp);
}
kpreempt_enable();
} else {
if ((pfp->fpu_en) ||
(pfp->fpu_fprs & FPRS_FEF)) {
pfp->fpu_en = 0;
if (fpu_exists) {
fprs = 0;
if (lwp == ttolwp(curthread))
_fp_write_fprs(fprs);
pfp->fpu_fprs = (uint32_t)fprs;
}
}
}
}
#ifdef _SYSCALL32_IMPL
void
setfpregs32(klwp_t *lwp, fpregset32_t *fp)
{
fpregset_t fpregs;
fpuregset_32ton(fp, &fpregs, NULL, NULL);
setfpregs(lwp, &fpregs);
}
#endif
void
run_fpq(klwp_t *lwp, fpregset_t *fp)
{
if (lwp == ttolwp(curthread)) {
if (fpu_exists) {
if (fp->fpu_qcnt)
fp_runq(lwp->lwp_regs);
}
}
}
void
getfpregs(klwp_t *lwp, fpregset_t *fp)
{
kfpu_t *pfp;
model_t model = lwp_getdatamodel(lwp);
pfp = lwptofpu(lwp);
kpreempt_disable();
if (fpu_exists && ttolwp(curthread) == lwp)
pfp->fpu_fprs = _fp_read_fprs();
if (((fp->fpu_en = pfp->fpu_en) != 0) ||
(pfp->fpu_fprs & FPRS_FEF)) {
if (pfp->fpu_en == 0)
fp->fpu_en = MEMCPY_FPU_EN;
if (fpu_exists && ttolwp(curthread) == lwp) {
if ((pfp->fpu_fprs & FPRS_FEF) != FPRS_FEF) {
uint32_t fprs = (FPRS_FEF|FPRS_DU|FPRS_DL);
_fp_write_fprs(fprs);
pfp->fpu_fprs = fprs;
#ifdef DEBUG
if (fpdispr)
cmn_err(CE_NOTE,
"getfpregs with fp disabled!\n");
#endif
}
if (model == DATAMODEL_LP64)
fp_fksave(pfp);
else
fp_v8_fksave(pfp);
}
(void) kcopy(pfp, fp, sizeof (fp->fpu_fr));
fp->fpu_q = pfp->fpu_q;
if (model == DATAMODEL_LP64)
fp->fpu_fsr = pfp->fpu_fsr;
else
fp->fpu_fsr = (uint32_t)pfp->fpu_fsr;
fp->fpu_qcnt = pfp->fpu_qcnt;
fp->fpu_q_entrysize = pfp->fpu_q_entrysize;
} else {
int i;
for (i = 0; i < 32; i++)
((uint32_t *)fp->fpu_fr.fpu_regs)[i] = (uint32_t)-1;
if (model == DATAMODEL_LP64) {
for (i = 16; i < 32; i++)
((uint64_t *)fp->fpu_fr.fpu_dregs)[i] =
(uint64_t)-1;
}
fp->fpu_fsr = 0;
fp->fpu_qcnt = 0;
}
kpreempt_enable();
}
#ifdef _SYSCALL32_IMPL
void
getfpregs32(klwp_t *lwp, fpregset32_t *fp)
{
fpregset_t fpregs;
getfpregs(lwp, &fpregs);
fpuregset_nto32(&fpregs, fp, NULL);
}
#endif
void
setgregs(klwp_t *lwp, gregset_t grp)
{
struct regs *rp = lwptoregs(lwp);
kfpu_t *fp = lwptofpu(lwp);
uint64_t tbits;
int current = (lwp == curthread->t_lwp);
if (current)
(void) save_syscall_args();
tbits = (((grp[REG_CCR] & TSTATE_CCR_MASK) << TSTATE_CCR_SHIFT) |
((grp[REG_ASI] & TSTATE_ASI_MASK) << TSTATE_ASI_SHIFT));
rp->r_tstate &= ~(((uint64_t)TSTATE_CCR_MASK << TSTATE_CCR_SHIFT) |
((uint64_t)TSTATE_ASI_MASK << TSTATE_ASI_SHIFT));
rp->r_tstate |= tbits;
kpreempt_disable();
fp->fpu_fprs = (uint32_t)grp[REG_FPRS];
if (fpu_exists && (current) && (fp->fpu_fprs & FPRS_FEF))
_fp_write_fprs(fp->fpu_fprs);
kpreempt_enable();
rp->r_pc = grp[REG_PC] & ~03L;
rp->r_npc = grp[REG_nPC] & ~03L;
rp->r_y = grp[REG_Y];
rp->r_g1 = grp[REG_G1];
rp->r_g2 = grp[REG_G2];
rp->r_g3 = grp[REG_G3];
rp->r_g4 = grp[REG_G4];
rp->r_g5 = grp[REG_G5];
rp->r_g6 = grp[REG_G6];
rp->r_g7 = grp[REG_G7];
rp->r_o0 = grp[REG_O0];
rp->r_o1 = grp[REG_O1];
rp->r_o2 = grp[REG_O2];
rp->r_o3 = grp[REG_O3];
rp->r_o4 = grp[REG_O4];
rp->r_o5 = grp[REG_O5];
rp->r_o6 = grp[REG_O6];
rp->r_o7 = grp[REG_O7];
if (current) {
lwp->lwp_eosys = JUSTRETURN;
curthread->t_post_sys = 1;
}
}
void
getgregs(klwp_t *lwp, gregset_t grp)
{
struct regs *rp = lwptoregs(lwp);
uint32_t fprs;
kpreempt_disable();
if (fpu_exists && ttolwp(curthread) == lwp) {
fprs = _fp_read_fprs();
} else {
kfpu_t *fp = lwptofpu(lwp);
fprs = fp->fpu_fprs;
}
kpreempt_enable();
grp[REG_CCR] = (rp->r_tstate >> TSTATE_CCR_SHIFT) & TSTATE_CCR_MASK;
grp[REG_PC] = rp->r_pc;
grp[REG_nPC] = rp->r_npc;
grp[REG_Y] = (uint32_t)rp->r_y;
grp[REG_G1] = rp->r_g1;
grp[REG_G2] = rp->r_g2;
grp[REG_G3] = rp->r_g3;
grp[REG_G4] = rp->r_g4;
grp[REG_G5] = rp->r_g5;
grp[REG_G6] = rp->r_g6;
grp[REG_G7] = rp->r_g7;
grp[REG_O0] = rp->r_o0;
grp[REG_O1] = rp->r_o1;
grp[REG_O2] = rp->r_o2;
grp[REG_O3] = rp->r_o3;
grp[REG_O4] = rp->r_o4;
grp[REG_O5] = rp->r_o5;
grp[REG_O6] = rp->r_o6;
grp[REG_O7] = rp->r_o7;
grp[REG_ASI] = (rp->r_tstate >> TSTATE_ASI_SHIFT) & TSTATE_ASI_MASK;
grp[REG_FPRS] = fprs;
}
void
getgregs32(klwp_t *lwp, gregset32_t grp)
{
struct regs *rp = lwptoregs(lwp);
uint32_t fprs;
kpreempt_disable();
if (fpu_exists && ttolwp(curthread) == lwp) {
fprs = _fp_read_fprs();
} else {
kfpu_t *fp = lwptofpu(lwp);
fprs = fp->fpu_fprs;
}
kpreempt_enable();
grp[REG_PSR] = mkpsr(rp->r_tstate, fprs);
grp[REG_PC] = rp->r_pc;
grp[REG_nPC] = rp->r_npc;
grp[REG_Y] = rp->r_y;
grp[REG_G1] = rp->r_g1;
grp[REG_G2] = rp->r_g2;
grp[REG_G3] = rp->r_g3;
grp[REG_G4] = rp->r_g4;
grp[REG_G5] = rp->r_g5;
grp[REG_G6] = rp->r_g6;
grp[REG_G7] = rp->r_g7;
grp[REG_O0] = rp->r_o0;
grp[REG_O1] = rp->r_o1;
grp[REG_O2] = rp->r_o2;
grp[REG_O3] = rp->r_o3;
grp[REG_O4] = rp->r_o4;
grp[REG_O5] = rp->r_o5;
grp[REG_O6] = rp->r_o6;
grp[REG_O7] = rp->r_o7;
}
greg_t
getuserpc()
{
return (lwptoregs(ttolwp(curthread))->r_pc);
}
void
setgwins(klwp_t *lwp, gwindows_t *gwins)
{
struct machpcb *mpcb = lwptompcb(lwp);
int wbcnt = gwins->wbcnt;
caddr_t sp;
int i;
struct rwindow32 *rwp;
int wbuf_rwindow_size;
int is64;
if (mpcb->mpcb_wstate == WSTATE_USER32) {
wbuf_rwindow_size = WINDOWSIZE32;
is64 = 0;
} else {
wbuf_rwindow_size = WINDOWSIZE64;
is64 = 1;
}
ASSERT(wbcnt >= 0 && wbcnt <= SPARC_MAXREGWINDOW);
mpcb->mpcb_wbcnt = 0;
for (i = 0; i < wbcnt; i++) {
sp = (caddr_t)gwins->spbuf[i];
mpcb->mpcb_spbuf[i] = sp;
rwp = (struct rwindow32 *)
(mpcb->mpcb_wbuf + (i * wbuf_rwindow_size));
if (is64 && IS_V9STACK(sp))
bcopy(&gwins->wbuf[i], rwp, sizeof (struct rwindow));
else
rwindow_nto32(&gwins->wbuf[i], rwp);
mpcb->mpcb_wbcnt++;
}
}
void
setgwins32(klwp_t *lwp, gwindows32_t *gwins)
{
struct machpcb *mpcb = lwptompcb(lwp);
int wbcnt = gwins->wbcnt;
caddr_t sp;
int i;
struct rwindow *rwp;
int wbuf_rwindow_size;
int is64;
if (mpcb->mpcb_wstate == WSTATE_USER32) {
wbuf_rwindow_size = WINDOWSIZE32;
is64 = 0;
} else {
wbuf_rwindow_size = WINDOWSIZE64;
is64 = 1;
}
ASSERT(wbcnt >= 0 && wbcnt <= SPARC_MAXREGWINDOW);
mpcb->mpcb_wbcnt = 0;
for (i = 0; i < wbcnt; i++) {
sp = (caddr_t)(uintptr_t)gwins->spbuf[i];
mpcb->mpcb_spbuf[i] = sp;
rwp = (struct rwindow *)
(mpcb->mpcb_wbuf + (i * wbuf_rwindow_size));
if (is64 && IS_V9STACK(sp))
rwindow_32ton(&gwins->wbuf[i], rwp);
else
bcopy(&gwins->wbuf[i], rwp, sizeof (struct rwindow32));
mpcb->mpcb_wbcnt++;
}
}
void
getgwins(klwp_t *lwp, gwindows_t *gwp)
{
struct machpcb *mpcb = lwptompcb(lwp);
int wbcnt = mpcb->mpcb_wbcnt;
caddr_t sp;
int i;
struct rwindow32 *rwp;
int wbuf_rwindow_size;
int is64;
if (mpcb->mpcb_wstate == WSTATE_USER32) {
wbuf_rwindow_size = WINDOWSIZE32;
is64 = 0;
} else {
wbuf_rwindow_size = WINDOWSIZE64;
is64 = 1;
}
ASSERT(wbcnt >= 0 && wbcnt <= SPARC_MAXREGWINDOW);
gwp->wbcnt = wbcnt;
for (i = 0; i < wbcnt; i++) {
sp = mpcb->mpcb_spbuf[i];
gwp->spbuf[i] = (greg_t *)sp;
rwp = (struct rwindow32 *)
(mpcb->mpcb_wbuf + (i * wbuf_rwindow_size));
if (is64 && IS_V9STACK(sp))
bcopy(rwp, &gwp->wbuf[i], sizeof (struct rwindow));
else
rwindow_32ton(rwp, &gwp->wbuf[i]);
}
}
void
getgwins32(klwp_t *lwp, gwindows32_t *gwp)
{
struct machpcb *mpcb = lwptompcb(lwp);
int wbcnt = mpcb->mpcb_wbcnt;
int i;
struct rwindow *rwp;
int wbuf_rwindow_size;
caddr_t sp;
int is64;
if (mpcb->mpcb_wstate == WSTATE_USER32) {
wbuf_rwindow_size = WINDOWSIZE32;
is64 = 0;
} else {
wbuf_rwindow_size = WINDOWSIZE64;
is64 = 1;
}
ASSERT(wbcnt >= 0 && wbcnt <= SPARC_MAXREGWINDOW);
gwp->wbcnt = wbcnt;
for (i = 0; i < wbcnt; i++) {
sp = mpcb->mpcb_spbuf[i];
rwp = (struct rwindow *)
(mpcb->mpcb_wbuf + (i * wbuf_rwindow_size));
gwp->spbuf[i] = (caddr32_t)(uintptr_t)sp;
if (is64 && IS_V9STACK(sp))
rwindow_nto32(rwp, &gwp->wbuf[i]);
else
bcopy(rwp, &gwp->wbuf[i], sizeof (struct rwindow32));
}
}
int
flush_user_windows_to_stack(caddr_t *psp)
{
int j, k;
caddr_t sp;
struct machpcb *mpcb = lwptompcb(ttolwp(curthread));
int err;
int error = 0;
int wbuf_rwindow_size;
int rwindow_size;
int stack_align;
int watched;
flush_user_windows();
if (mpcb->mpcb_wstate != WSTATE_USER32)
wbuf_rwindow_size = WINDOWSIZE64;
else
wbuf_rwindow_size = WINDOWSIZE32;
j = mpcb->mpcb_wbcnt;
while (j > 0) {
sp = mpcb->mpcb_spbuf[--j];
if ((mpcb->mpcb_wstate != WSTATE_USER32) &&
IS_V9STACK(sp)) {
sp += V9BIAS64;
stack_align = STACK_ALIGN64;
rwindow_size = WINDOWSIZE64;
} else {
caddr32_t sp32 = (uint32_t)(uintptr_t)sp;
sp = (caddr_t)(uintptr_t)sp32;
stack_align = STACK_ALIGN32;
rwindow_size = WINDOWSIZE32;
}
if (((uintptr_t)sp & (stack_align - 1)) != 0)
continue;
watched = watch_disable_addr(sp, rwindow_size, S_WRITE);
err = xcopyout(mpcb->mpcb_wbuf +
(j * wbuf_rwindow_size), sp, rwindow_size);
if (err != 0) {
if (psp != NULL) {
uint_t *kaddr = (uint_t *)(mpcb->mpcb_wbuf +
(j * wbuf_rwindow_size));
uint_t *uaddr = (uint_t *)sp;
for (k = 0;
k < rwindow_size / sizeof (int);
k++, kaddr++, uaddr++) {
if (suword32(uaddr, *kaddr))
break;
}
if (k == rwindow_size / sizeof (int))
uaddr = (uint_t *)sp;
*psp = (caddr_t)uaddr;
}
error = err;
} else {
mpcb->mpcb_wbcnt--;
for (k = j; k < mpcb->mpcb_wbcnt; k++) {
mpcb->mpcb_spbuf[k] = mpcb->mpcb_spbuf[k+1];
bcopy(
mpcb->mpcb_wbuf +
((k+1) * wbuf_rwindow_size),
mpcb->mpcb_wbuf +
(k * wbuf_rwindow_size),
wbuf_rwindow_size);
}
}
if (watched)
watch_enable_addr(sp, rwindow_size, S_WRITE);
}
return (error);
}
static int
copy_return_window32(int dotwo)
{
klwp_t *lwp = ttolwp(curthread);
struct machpcb *mpcb = lwptompcb(lwp);
struct rwindow32 rwindow32;
caddr_t sp1;
caddr_t sp2;
(void) flush_user_windows_to_stack(NULL);
if (mpcb->mpcb_rsp[0] == NULL) {
caddr32_t sp1_32 = (uint32_t)lwptoregs(lwp)->r_sp;
sp1 = (caddr_t)(uintptr_t)sp1_32;
if ((copyin_nowatch(sp1, &rwindow32,
sizeof (struct rwindow32))) == 0)
mpcb->mpcb_rsp[0] = sp1;
rwindow_32ton(&rwindow32, &mpcb->mpcb_rwin[0]);
}
mpcb->mpcb_rsp[1] = NULL;
if (dotwo && mpcb->mpcb_rsp[0] != NULL &&
(sp2 = (caddr_t)mpcb->mpcb_rwin[0].rw_fp) != NULL) {
if ((copyin_nowatch(sp2, &rwindow32,
sizeof (struct rwindow32)) == 0))
mpcb->mpcb_rsp[1] = sp2;
rwindow_32ton(&rwindow32, &mpcb->mpcb_rwin[1]);
}
return (mpcb->mpcb_rsp[0] != NULL);
}
int
copy_return_window(int dotwo)
{
proc_t *p = ttoproc(curthread);
klwp_t *lwp;
struct machpcb *mpcb;
caddr_t sp1;
caddr_t sp2;
if (p->p_model == DATAMODEL_ILP32)
return (copy_return_window32(dotwo));
lwp = ttolwp(curthread);
mpcb = lwptompcb(lwp);
(void) flush_user_windows_to_stack(NULL);
if (mpcb->mpcb_rsp[0] == NULL) {
sp1 = (caddr_t)lwptoregs(lwp)->r_sp + STACK_BIAS;
if ((copyin_nowatch(sp1, &mpcb->mpcb_rwin[0],
sizeof (struct rwindow)) == 0))
mpcb->mpcb_rsp[0] = sp1 - STACK_BIAS;
}
mpcb->mpcb_rsp[1] = NULL;
if (dotwo && mpcb->mpcb_rsp[0] != NULL &&
(sp2 = (caddr_t)mpcb->mpcb_rwin[0].rw_fp) != NULL) {
sp2 += STACK_BIAS;
if ((copyin_nowatch(sp2, &mpcb->mpcb_rwin[1],
sizeof (struct rwindow)) == 0))
mpcb->mpcb_rsp[1] = sp2 - STACK_BIAS;
}
return (mpcb->mpcb_rsp[0] != NULL);
}
void
setregs(uarg_t *args)
{
struct regs *rp;
klwp_t *lwp = ttolwp(curthread);
kfpu_t *fpp = lwptofpu(lwp);
struct machpcb *mpcb = lwptompcb(lwp);
proc_t *p = ttoproc(curthread);
(void) save_syscall_args();
rp = lwptoregs(lwp);
rp->r_g1 = rp->r_g2 = rp->r_g3 = rp->r_g4 = rp->r_g5 =
rp->r_g6 = rp->r_o0 = rp->r_o1 = rp->r_o2 =
rp->r_o3 = rp->r_o4 = rp->r_o5 = rp->r_o7 = 0;
if (p->p_model == DATAMODEL_ILP32)
rp->r_tstate = TSTATE_USER32 | weakest_mem_model;
else
rp->r_tstate = TSTATE_USER64 | weakest_mem_model;
if (!fpu_exists)
rp->r_tstate &= ~TSTATE_PEF;
rp->r_g7 = args->thrptr;
rp->r_pc = args->entry;
rp->r_npc = args->entry + 4;
rp->r_y = 0;
curthread->t_post_sys = 1;
lwp->lwp_eosys = JUSTRETURN;
lwp->lwp_pcb.pcb_trap0addr = 0;
p->p_fixalignment = 0;
trash_user_windows();
if (p->p_model == DATAMODEL_LP64 &&
mpcb->mpcb_wstate != WSTATE_USER64) {
ASSERT(mpcb->mpcb_wbcnt == 0);
kmem_cache_free(wbuf32_cache, mpcb->mpcb_wbuf);
mpcb->mpcb_wbuf = kmem_cache_alloc(wbuf64_cache, KM_SLEEP);
ASSERT(((uintptr_t)mpcb->mpcb_wbuf & 7) == 0);
mpcb->mpcb_wstate = WSTATE_USER64;
} else if (p->p_model == DATAMODEL_ILP32 &&
mpcb->mpcb_wstate != WSTATE_USER32) {
ASSERT(mpcb->mpcb_wbcnt == 0);
kmem_cache_free(wbuf64_cache, mpcb->mpcb_wbuf);
mpcb->mpcb_wbuf = kmem_cache_alloc(wbuf32_cache, KM_SLEEP);
mpcb->mpcb_wstate = WSTATE_USER32;
}
mpcb->mpcb_pa = va_to_pa(mpcb);
mpcb->mpcb_wbuf_pa = va_to_pa(mpcb->mpcb_wbuf);
if (fpu_exists) {
extern void _fp_write_fprs(unsigned);
_fp_write_fprs(0);
}
fpp->fpu_en = 0;
fpp->fpu_fprs = 0;
}
void
lwp_swapin(kthread_t *tp)
{
struct machpcb *mpcb = lwptompcb(ttolwp(tp));
mpcb->mpcb_pa = va_to_pa(mpcb);
mpcb->mpcb_wbuf_pa = va_to_pa(mpcb->mpcb_wbuf);
}
int
sendsig(int sig, k_siginfo_t *sip, void (*hdlr)())
{
volatile int minstacksz;
int newstack = 0;
label_t ljb;
caddr_t sp;
struct regs *volatile rp;
klwp_t *lwp = ttolwp(curthread);
proc_t *volatile p = ttoproc(curthread);
int fpq_size = 0;
struct sigframe {
struct frame frwin;
ucontext_t uc;
};
siginfo_t *sip_addr;
struct sigframe *volatile fp;
ucontext_t *volatile tuc = NULL;
char *volatile xregs = NULL;
volatile size_t xregs_size = 0;
gwindows_t *volatile gwp = NULL;
volatile int gwin_size = 0;
kfpu_t *fpp;
struct machpcb *mpcb;
volatile int watched = 0;
volatile int watched2 = 0;
caddr_t tos;
(void) flush_user_windows_to_stack(NULL);
if (lwp->lwp_pcb.pcb_xregstat != XREGNONE)
xregrestore(lwp, 0);
mpcb = lwptompcb(lwp);
rp = lwptoregs(lwp);
mpcb->mpcb_rsp[0] = NULL;
mpcb->mpcb_rsp[1] = NULL;
minstacksz = sizeof (struct sigframe);
if (sip != NULL)
minstacksz += sizeof (siginfo_t);
fpp = lwptofpu(lwp);
fpp->fpu_fprs = _fp_read_fprs();
if ((fpp->fpu_en) || (fpp->fpu_fprs & FPRS_FEF)) {
fpq_size = fpp->fpu_q_entrysize * fpp->fpu_qcnt;
minstacksz += SA(fpq_size);
}
mpcb = lwptompcb(lwp);
if (mpcb->mpcb_wbcnt != 0) {
gwin_size = (mpcb->mpcb_wbcnt * sizeof (struct rwindow)) +
(SPARC_MAXREGWINDOW * sizeof (caddr_t)) + sizeof (long);
minstacksz += SA(gwin_size);
}
minstacksz += SA(xregs_size);
newstack = (sigismember(&PTOU(curproc)->u_sigonstack, sig) &&
!(lwp->lwp_sigaltstack.ss_flags & (SS_ONSTACK|SS_DISABLE)));
tos = (caddr_t)rp->r_sp + STACK_BIAS;
tos = (caddr_t)((uintptr_t)tos & ~(STACK_ALIGN - 1ul));
if (newstack != 0) {
fp = (struct sigframe *)
(SA((uintptr_t)lwp->lwp_sigaltstack.ss_sp) +
SA((int)lwp->lwp_sigaltstack.ss_size) - STACK_ALIGN -
SA(minstacksz));
} else {
if (sig == SIGSEGV &&
mpcb->mpcb_wbcnt != 0 &&
!(lwp->lwp_sigaltstack.ss_flags & SS_ONSTACK))
return (0);
fp = (struct sigframe *)(tos - SA(minstacksz));
}
sp = (caddr_t)fp + sizeof (struct sigframe);
if ((caddr_t)fp >= p->p_usrstack ||
(caddr_t)fp + SA(minstacksz) >= p->p_usrstack) {
#ifdef DEBUG
printf("sendsig: bad signal stack cmd=%s, pid=%d, sig=%d\n",
PTOU(p)->u_comm, p->p_pid, sig);
printf("sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n",
(void *)fp, (void *)hdlr, rp->r_pc);
printf("fp above USRSTACK\n");
#endif
return (0);
}
watched = watch_disable_addr((caddr_t)fp, SA(minstacksz), S_WRITE);
if (on_fault(&ljb))
goto badstack;
tuc = kmem_alloc(sizeof (ucontext_t), KM_SLEEP);
savecontext(tuc, &lwp->lwp_sigoldmask);
if (xregs_size != 0) {
xregs_setptr(lwp, tuc, sp);
xregs = kmem_alloc(xregs_size, KM_SLEEP);
xregs_get(lwp, xregs);
copyout_noerr(xregs, sp, xregs_size);
kmem_free(xregs, xregs_size);
xregs = NULL;
sp += SA(xregs_size);
}
copyout_noerr(tuc, &fp->uc, sizeof (*tuc));
kmem_free(tuc, sizeof (*tuc));
tuc = NULL;
if (sip != NULL) {
zoneid_t zoneid;
uzero(sp, sizeof (siginfo_t));
if (SI_FROMUSER(sip) &&
(zoneid = p->p_zone->zone_id) != GLOBAL_ZONEID &&
zoneid != sip->si_zoneid) {
k_siginfo_t sani_sip = *sip;
sani_sip.si_pid = p->p_zone->zone_zsched->p_pid;
sani_sip.si_uid = 0;
sani_sip.si_ctid = -1;
sani_sip.si_zoneid = zoneid;
copyout_noerr(&sani_sip, sp, sizeof (sani_sip));
} else {
copyout_noerr(sip, sp, sizeof (*sip));
}
sip_addr = (siginfo_t *)sp;
sp += sizeof (siginfo_t);
if (sig == SIGPROF &&
curthread->t_rprof != NULL &&
curthread->t_rprof->rp_anystate) {
int i = sip->si_nsysarg;
while (--i >= 0) {
sulword_noerr(
(ulong_t *)&sip_addr->si_sysarg[i],
(ulong_t)lwp->lwp_arg[i]);
}
copyout_noerr(curthread->t_rprof->rp_state,
sip_addr->si_mstate,
sizeof (curthread->t_rprof->rp_state));
}
} else {
sip_addr = (siginfo_t *)NULL;
}
if (gwin_size != 0) {
gwp = kmem_alloc(gwin_size, KM_SLEEP);
getgwins(lwp, gwp);
sulword_noerr(&fp->uc.uc_mcontext.gwins, (ulong_t)sp);
copyout_noerr(gwp, sp, gwin_size);
kmem_free(gwp, gwin_size);
gwp = NULL;
sp += SA(gwin_size);
} else
sulword_noerr(&fp->uc.uc_mcontext.gwins, (ulong_t)NULL);
if (fpq_size != 0) {
struct _fq *fqp = (struct _fq *)sp;
sulword_noerr(&fp->uc.uc_mcontext.fpregs.fpu_q, (ulong_t)fqp);
copyout_noerr(mpcb->mpcb_fpu_q, fqp, fpq_size);
mpcb->mpcb_fpu->fpu_qcnt = 0;
sp += SA(fpq_size);
mpcb->mpcb_flags |= FP_TRAPPED;
} else {
sulword_noerr(&fp->uc.uc_mcontext.fpregs.fpu_q, (ulong_t)NULL);
suword8_noerr(&fp->uc.uc_mcontext.fpregs.fpu_qcnt, 0);
}
if (mpcb->mpcb_wbcnt == 0) {
watched2 = watch_disable_addr(tos, sizeof (struct rwindow),
S_READ);
ucopy(tos, &fp->frwin, sizeof (struct rwindow));
}
lwp->lwp_oldcontext = (uintptr_t)&fp->uc;
if (newstack != 0) {
lwp->lwp_sigaltstack.ss_flags |= SS_ONSTACK;
if (lwp->lwp_ustack) {
copyout_noerr(&lwp->lwp_sigaltstack,
(stack_t *)lwp->lwp_ustack, sizeof (stack_t));
}
}
no_fault();
mpcb->mpcb_wbcnt = 0;
if (watched2)
watch_enable_addr(tos, sizeof (struct rwindow), S_READ);
if (watched)
watch_enable_addr((caddr_t)fp, SA(minstacksz), S_WRITE);
rp->r_sp = (uintptr_t)fp - STACK_BIAS;
rp->r_pc = (uintptr_t)hdlr;
rp->r_npc = (uintptr_t)hdlr + 4;
rp->r_tstate &= ~((uint64_t)TSTATE_ASI_MASK << TSTATE_ASI_SHIFT);
rp->r_tstate |= ((uint64_t)ASI_PNF << TSTATE_ASI_SHIFT);
rp->r_o0 = sig;
rp->r_o1 = (uintptr_t)sip_addr;
rp->r_o2 = (uintptr_t)&fp->uc;
return (1);
badstack:
no_fault();
if (watched2)
watch_enable_addr(tos, sizeof (struct rwindow), S_READ);
if (watched)
watch_enable_addr((caddr_t)fp, SA(minstacksz), S_WRITE);
if (tuc)
kmem_free(tuc, sizeof (ucontext_t));
if (xregs)
kmem_free(xregs, xregs_size);
if (gwp)
kmem_free(gwp, gwin_size);
#ifdef DEBUG
printf("sendsig: bad signal stack cmd=%s, pid=%d, sig=%d\n",
PTOU(p)->u_comm, p->p_pid, sig);
printf("on fault, sigsp = %p, action = %p, upc = 0x%lx\n",
(void *)fp, (void *)hdlr, rp->r_pc);
#endif
return (0);
}
#ifdef _SYSCALL32_IMPL
int
sendsig32(int sig, k_siginfo_t *sip, void (*hdlr)())
{
volatile int minstacksz;
int newstack = 0;
label_t ljb;
caddr_t sp;
struct regs *volatile rp;
klwp_t *lwp = ttolwp(curthread);
proc_t *volatile p = ttoproc(curthread);
struct fq32 fpu_q[MAXFPQ];
struct fq32 *dfq = NULL;
size_t fpq_size = 0;
struct sigframe32 {
struct frame32 frwin;
ucontext32_t uc;
};
struct sigframe32 *volatile fp;
siginfo32_t *sip_addr;
ucontext32_t *volatile tuc = NULL;
char *volatile xregs = NULL;
volatile int xregs_size = 0;
gwindows32_t *volatile gwp = NULL;
volatile size_t gwin_size = 0;
kfpu_t *fpp;
struct machpcb *mpcb;
volatile int watched = 0;
volatile int watched2 = 0;
caddr_t tos;
(void) flush_user_windows_to_stack(NULL);
if (lwp->lwp_pcb.pcb_xregstat != XREGNONE)
xregrestore(lwp, 0);
mpcb = lwptompcb(lwp);
rp = lwptoregs(lwp);
mpcb->mpcb_rsp[0] = NULL;
mpcb->mpcb_rsp[1] = NULL;
minstacksz = sizeof (struct sigframe32);
if (sip != NULL)
minstacksz += sizeof (siginfo32_t);
fpp = lwptofpu(lwp);
fpp->fpu_fprs = _fp_read_fprs();
if ((fpp->fpu_en) || (fpp->fpu_fprs & FPRS_FEF)) {
fpq_size = sizeof (struct fpq32) * fpp->fpu_qcnt;
minstacksz += fpq_size;
dfq = fpu_q;
}
mpcb = lwptompcb(lwp);
if (mpcb->mpcb_wbcnt != 0) {
gwin_size = (mpcb->mpcb_wbcnt * sizeof (struct rwindow32)) +
(SPARC_MAXREGWINDOW * sizeof (caddr32_t)) +
sizeof (int32_t);
minstacksz += gwin_size;
}
xregs_size = xregs_getsize(p);
minstacksz += SA32(xregs_size);
newstack = (sigismember(&PTOU(curproc)->u_sigonstack, sig) &&
!(lwp->lwp_sigaltstack.ss_flags & (SS_ONSTACK|SS_DISABLE)));
tos = (void *)(uintptr_t)(uint32_t)rp->r_sp;
tos = (caddr_t)((uintptr_t)tos & ~(STACK_ALIGN32 - 1ul));
if (newstack != 0) {
fp = (struct sigframe32 *)
(SA32((uintptr_t)lwp->lwp_sigaltstack.ss_sp) +
SA32((int)lwp->lwp_sigaltstack.ss_size) -
STACK_ALIGN32 -
SA32(minstacksz));
} else {
if (sig == SIGSEGV &&
mpcb->mpcb_wbcnt != 0 &&
!(lwp->lwp_sigaltstack.ss_flags & SS_ONSTACK))
return (0);
fp = (struct sigframe32 *)(tos - SA32(minstacksz));
}
sp = (caddr_t)fp + sizeof (struct sigframe32);
if ((caddr_t)fp >= p->p_usrstack ||
(caddr_t)fp + SA32(minstacksz) >= p->p_usrstack) {
#ifdef DEBUG
printf("sendsig32: bad signal stack cmd=%s, pid=%d, sig=%d\n",
PTOU(p)->u_comm, p->p_pid, sig);
printf("sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n",
(void *)fp, (void *)hdlr, rp->r_pc);
printf("fp above USRSTACK32\n");
#endif
return (0);
}
watched = watch_disable_addr((caddr_t)fp, SA32(minstacksz), S_WRITE);
if (on_fault(&ljb))
goto badstack;
tuc = kmem_alloc(sizeof (ucontext32_t), KM_SLEEP);
savecontext32(tuc, &lwp->lwp_sigoldmask, dfq);
if (xregs_size != 0) {
xregs_setptr32(lwp, tuc, (caddr32_t)(uintptr_t)sp);
xregs = kmem_alloc(xregs_size, KM_SLEEP);
xregs_get(lwp, xregs);
copyout_noerr(xregs, sp, xregs_size);
kmem_free(xregs, xregs_size);
xregs = NULL;
sp += SA32(xregs_size);
}
copyout_noerr(tuc, &fp->uc, sizeof (*tuc));
kmem_free(tuc, sizeof (*tuc));
tuc = NULL;
if (sip != NULL) {
siginfo32_t si32;
zoneid_t zoneid;
siginfo_kto32(sip, &si32);
if (SI_FROMUSER(sip) &&
(zoneid = p->p_zone->zone_id) != GLOBAL_ZONEID &&
zoneid != sip->si_zoneid) {
si32.si_pid = p->p_zone->zone_zsched->p_pid;
si32.si_uid = 0;
si32.si_ctid = -1;
si32.si_zoneid = zoneid;
}
uzero(sp, sizeof (siginfo32_t));
copyout_noerr(&si32, sp, sizeof (siginfo32_t));
sip_addr = (siginfo32_t *)sp;
sp += sizeof (siginfo32_t);
if (sig == SIGPROF &&
curthread->t_rprof != NULL &&
curthread->t_rprof->rp_anystate) {
int i = sip->si_nsysarg;
while (--i >= 0) {
suword32_noerr(&sip_addr->si_sysarg[i],
(uint32_t)lwp->lwp_arg[i]);
}
copyout_noerr(curthread->t_rprof->rp_state,
sip_addr->si_mstate,
sizeof (curthread->t_rprof->rp_state));
}
} else {
sip_addr = NULL;
}
if (gwin_size != 0) {
gwp = kmem_alloc(gwin_size, KM_SLEEP);
getgwins32(lwp, gwp);
suword32_noerr(&fp->uc.uc_mcontext.gwins,
(uint32_t)(uintptr_t)sp);
copyout_noerr(gwp, sp, gwin_size);
kmem_free(gwp, gwin_size);
gwp = NULL;
sp += gwin_size;
} else {
suword32_noerr(&fp->uc.uc_mcontext.gwins, 0);
}
if (fpq_size != 0) {
struct fq32 *fqp = (struct fq32 *)sp;
suword32_noerr(&fp->uc.uc_mcontext.fpregs.fpu_q,
(uint32_t)(uintptr_t)fqp);
copyout_noerr(dfq, fqp, fpq_size);
mpcb->mpcb_fpu->fpu_qcnt = 0;
sp += fpq_size;
mpcb->mpcb_flags |= FP_TRAPPED;
} else {
suword32_noerr(&fp->uc.uc_mcontext.fpregs.fpu_q, 0);
suword8_noerr(&fp->uc.uc_mcontext.fpregs.fpu_qcnt, 0);
}
if (mpcb->mpcb_wbcnt == 0) {
watched2 = watch_disable_addr(tos, sizeof (struct rwindow32),
S_READ);
ucopy(tos, &fp->frwin, sizeof (struct rwindow32));
}
lwp->lwp_oldcontext = (uintptr_t)&fp->uc;
if (newstack != 0) {
lwp->lwp_sigaltstack.ss_flags |= SS_ONSTACK;
if (lwp->lwp_ustack) {
stack32_t stk32;
stk32.ss_sp =
(caddr32_t)(uintptr_t)lwp->lwp_sigaltstack.ss_sp;
stk32.ss_size = (size32_t)lwp->lwp_sigaltstack.ss_size;
stk32.ss_flags = (int32_t)lwp->lwp_sigaltstack.ss_flags;
copyout_noerr(&stk32, (stack32_t *)lwp->lwp_ustack,
sizeof (stack32_t));
}
}
no_fault();
mpcb->mpcb_wbcnt = 0;
if (watched2)
watch_enable_addr(tos, sizeof (struct rwindow32), S_READ);
if (watched)
watch_enable_addr((caddr_t)fp, SA32(minstacksz), S_WRITE);
rp->r_sp = (uintptr_t)fp;
rp->r_pc = (uintptr_t)hdlr;
rp->r_npc = (uintptr_t)hdlr + 4;
rp->r_tstate &= ~((uint64_t)TSTATE_ASI_MASK << TSTATE_ASI_SHIFT);
rp->r_tstate |= ((uint64_t)ASI_PNF << TSTATE_ASI_SHIFT);
rp->r_o0 = sig;
rp->r_o1 = (uintptr_t)sip_addr;
rp->r_o2 = (uintptr_t)&fp->uc;
return (1);
badstack:
no_fault();
if (watched2)
watch_enable_addr(tos, sizeof (struct rwindow32), S_READ);
if (watched)
watch_enable_addr((caddr_t)fp, SA32(minstacksz), S_WRITE);
if (tuc)
kmem_free(tuc, sizeof (*tuc));
if (xregs)
kmem_free(xregs, xregs_size);
if (gwp)
kmem_free(gwp, gwin_size);
#ifdef DEBUG
printf("sendsig32: bad signal stack cmd=%s, pid=%d, sig=%d\n",
PTOU(p)->u_comm, p->p_pid, sig);
printf("on fault, sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n",
(void *)fp, (void *)hdlr, rp->r_pc);
#endif
return (0);
}
#endif
void
lwp_load(klwp_t *lwp, gregset_t grp, uintptr_t thrptr)
{
setgregs(lwp, grp);
if (lwptoproc(lwp)->p_model == DATAMODEL_ILP32)
lwptoregs(lwp)->r_tstate = TSTATE_USER32 | TSTATE_MM_TSO;
else
lwptoregs(lwp)->r_tstate = TSTATE_USER64 | TSTATE_MM_TSO;
if (!fpu_exists)
lwptoregs(lwp)->r_tstate &= ~TSTATE_PEF;
lwp->lwp_eosys = JUSTRETURN;
lwptot(lwp)->t_post_sys = 1;
}
void
lwp_setrval(klwp_t *lwp, int v1, int v2)
{
struct regs *rp = lwptoregs(lwp);
rp->r_tstate &= ~TSTATE_IC;
rp->r_o0 = v1;
rp->r_o1 = v2;
}
void
lwp_setsp(klwp_t *lwp, caddr_t sp)
{
struct regs *rp = lwptoregs(lwp);
rp->r_sp = (uintptr_t)sp;
}
extern void trap_async_hwerr(void);
#pragma weak trap_async_hwerr
void
lwp_pcb_exit(void)
{
klwp_t *lwp = ttolwp(curthread);
if (lwp->lwp_pcb.pcb_flags & ASYNC_HWERR) {
lwp->lwp_pcb.pcb_flags &= ~ASYNC_HWERR;
trap_async_hwerr();
}
}
void
lwp_clear_uwin(void)
{
struct machpcb *m = lwptompcb(ttolwp(curthread));
m->mpcb_wbcnt = 0;
}
static void
mmodel_set_tso(void)
{
struct regs *rp = lwptoregs(ttolwp(curthread));
rp->r_tstate &= ~TSTATE_MM;
rp->r_tstate |= TSTATE_MM_TSO;
}
void
lwp_mmodel_newlwp(void)
{
mmodel_set_tso();
}
void
lwp_mmodel_shared_as(caddr_t addr, size_t sz)
{
mmodel_set_tso();
}
static uint_t
mkpsr(uint64_t tstate, uint_t fprs)
{
uint_t psr, icc;
psr = tstate & TSTATE_CWP_MASK;
if (tstate & TSTATE_PRIV)
psr |= PSR_PS;
if (fprs & FPRS_FEF)
psr |= PSR_EF;
icc = (uint_t)(tstate >> PSR_TSTATE_CC_SHIFT) & PSR_ICC;
psr |= icc;
psr |= V9_PSR_IMPLVER;
return (psr);
}
void
sync_icache(caddr_t va, uint_t len)
{
caddr_t end;
end = va + len;
va = (caddr_t)((uintptr_t)va & -8l);
while (va < end) {
doflush(va);
va += 8;
}
}
#ifdef _SYSCALL32_IMPL
void
fpuregset_nto32(const fpregset_t *src, fpregset32_t *dest, struct fq32 *dfq)
{
int i;
bzero(dest, sizeof (*dest));
for (i = 0; i < 32; i++)
dest->fpu_fr.fpu_regs[i] = src->fpu_fr.fpu_regs[i];
dest->fpu_q = 0;
dest->fpu_fsr = (uint32_t)src->fpu_fsr;
dest->fpu_qcnt = src->fpu_qcnt;
dest->fpu_q_entrysize = sizeof (struct fpq32);
dest->fpu_en = src->fpu_en;
if ((src->fpu_qcnt) && (dfq != NULL)) {
struct _fq *sfq = src->fpu_q;
for (i = 0; i < src->fpu_qcnt; i++, dfq++, sfq++) {
dfq->FQu.fpq.fpq_addr =
(caddr32_t)(uintptr_t)sfq->FQu.fpq.fpq_addr;
dfq->FQu.fpq.fpq_instr = sfq->FQu.fpq.fpq_instr;
}
}
}
static void
fpuregset_32ton(const fpregset32_t *src, fpregset_t *dest,
const struct fq32 *sfq, struct _fq *dfq)
{
int i;
bzero(dest, sizeof (*dest));
for (i = 0; i < 32; i++)
dest->fpu_fr.fpu_regs[i] = src->fpu_fr.fpu_regs[i];
dest->fpu_q = dfq;
dest->fpu_fsr = (uint64_t)src->fpu_fsr;
if ((dest->fpu_qcnt = src->fpu_qcnt) > 0)
dest->fpu_q_entrysize = sizeof (struct _fpq);
else
dest->fpu_q_entrysize = 0;
dest->fpu_en = src->fpu_en;
if ((src->fpu_qcnt) && (sfq) && (dfq)) {
for (i = 0; i < src->fpu_qcnt; i++, dfq++, sfq++) {
dfq->FQu.fpq.fpq_addr =
(unsigned int *)(uintptr_t)sfq->FQu.fpq.fpq_addr;
dfq->FQu.fpq.fpq_instr = sfq->FQu.fpq.fpq_instr;
}
}
}
void
ucontext_32ton(const ucontext32_t *src, ucontext_t *dest,
const struct fq32 *sfq, struct _fq *dfq)
{
int i;
bzero(dest, sizeof (*dest));
dest->uc_flags = src->uc_flags;
dest->uc_link = (ucontext_t *)(uintptr_t)src->uc_link;
for (i = 0; i < 4; i++) {
dest->uc_sigmask.__sigbits[i] = src->uc_sigmask.__sigbits[i];
}
dest->uc_stack.ss_sp = (void *)(uintptr_t)src->uc_stack.ss_sp;
dest->uc_stack.ss_size = (size_t)src->uc_stack.ss_size;
dest->uc_stack.ss_flags = src->uc_stack.ss_flags;
for (i = 1; i < _NGREG32; i++)
dest->uc_mcontext.gregs[i] =
(greg_t)(uint32_t)src->uc_mcontext.gregs[i];
dest->uc_mcontext.gregs[REG_CCR] =
(src->uc_mcontext.gregs[REG_PSR] & PSR_ICC) >> PSR_ICC_SHIFT;
dest->uc_mcontext.gregs[REG_ASI] = ASI_PNF;
if (src->uc_flags & UC_FPU) {
dest->uc_mcontext.gregs[REG_FPRS] =
((src->uc_mcontext.fpregs.fpu_en) ?
(FPRS_DU|FPRS_DL|FPRS_FEF) : 0);
} else {
dest->uc_mcontext.gregs[REG_FPRS] = 0;
}
dest->uc_mcontext.gwins =
(gwindows_t *)(uintptr_t)src->uc_mcontext.gwins;
if (src->uc_flags & UC_FPU) {
fpuregset_32ton(&src->uc_mcontext.fpregs,
&dest->uc_mcontext.fpregs, sfq, dfq);
}
}
void
rwindow_nto32(struct rwindow *src, struct rwindow32 *dest)
{
greg_t *s = (greg_t *)src;
greg32_t *d = (greg32_t *)dest;
int i;
for (i = 0; i < 16; i++)
*d++ = (greg32_t)*s++;
}
void
rwindow_32ton(struct rwindow32 *src, struct rwindow *dest)
{
greg32_t *s = (greg32_t *)src;
greg_t *d = (greg_t *)dest;
int i;
for (i = 0; i < 16; i++)
*d++ = (uint32_t)*s++;
}
#endif
void
panic_saveregs(panic_data_t *pdp, struct regs *rp)
{
panic_nv_t *pnv = PANICNVGET(pdp);
PANICNVADD(pnv, "tstate", rp->r_tstate);
PANICNVADD(pnv, "g1", rp->r_g1);
PANICNVADD(pnv, "g2", rp->r_g2);
PANICNVADD(pnv, "g3", rp->r_g3);
PANICNVADD(pnv, "g4", rp->r_g4);
PANICNVADD(pnv, "g5", rp->r_g5);
PANICNVADD(pnv, "g6", rp->r_g6);
PANICNVADD(pnv, "g7", rp->r_g7);
PANICNVADD(pnv, "o0", rp->r_o0);
PANICNVADD(pnv, "o1", rp->r_o1);
PANICNVADD(pnv, "o2", rp->r_o2);
PANICNVADD(pnv, "o3", rp->r_o3);
PANICNVADD(pnv, "o4", rp->r_o4);
PANICNVADD(pnv, "o5", rp->r_o5);
PANICNVADD(pnv, "o6", rp->r_o6);
PANICNVADD(pnv, "o7", rp->r_o7);
PANICNVADD(pnv, "pc", (ulong_t)rp->r_pc);
PANICNVADD(pnv, "npc", (ulong_t)rp->r_npc);
PANICNVADD(pnv, "y", (uint32_t)rp->r_y);
PANICNVSET(pdp, pnv);
}