Module Name: src Committed By: matt Date: Fri Aug 21 17:50:00 UTC 2009
Modified Files: src/sys/arch/mips/mips [matt-nb5-mips64]: mips_emul.c Log Message: Add sd/sdl/sdr ld/ldr/ldl emulation. Use intptr_t for addresses. To generate a diff of this commit: cvs rdiff -u -r1.14.78.1 -r1.14.78.2 src/sys/arch/mips/mips/mips_emul.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/mips/mips/mips_emul.c diff -u src/sys/arch/mips/mips/mips_emul.c:1.14.78.1 src/sys/arch/mips/mips/mips_emul.c:1.14.78.2 --- src/sys/arch/mips/mips/mips_emul.c:1.14.78.1 Thu Aug 20 04:36:05 2009 +++ src/sys/arch/mips/mips/mips_emul.c Fri Aug 21 17:50:00 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: mips_emul.c,v 1.14.78.1 2009/08/20 04:36:05 uebayasi Exp $ */ +/* $NetBSD: mips_emul.c,v 1.14.78.2 2009/08/21 17:50:00 matt Exp $ */ /* * Copyright (c) 1999 Shuichiro URATA. All rights reserved. @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: mips_emul.c,v 1.14.78.1 2009/08/20 04:36:05 uebayasi Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mips_emul.c,v 1.14.78.2 2009/08/21 17:50:00 matt Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -43,35 +43,45 @@ #include <mips/vmparam.h> /* for VM_MAX_ADDRESS */ #include <mips/trap.h> -void MachEmulateFP(u_int32_t, struct frame *, u_int32_t); +void MachEmulateFP(uint32_t, struct frame *, uint32_t); -static inline void send_sigsegv(vaddr_t, u_int32_t, struct frame *, - u_int32_t); -static inline void update_pc(struct frame *, u_int32_t); +static inline void send_sigsegv(intptr_t, uint32_t, struct frame *, + uint32_t); +static inline void update_pc(struct frame *, uint32_t); vaddr_t MachEmulateBranch(struct frame *, vaddr_t, unsigned, int); -void MachEmulateInst(u_int32_t, u_int32_t, vaddr_t, struct frame *); +void MachEmulateInst(uint32_t, uint32_t, vaddr_t, struct frame *); -void MachEmulateLWC0(u_int32_t inst, struct frame *, u_int32_t); -void MachEmulateSWC0(u_int32_t inst, struct frame *, u_int32_t); -void MachEmulateSpecial(u_int32_t inst, struct frame *, u_int32_t); -void MachEmulateLWC1(u_int32_t inst, struct frame *, u_int32_t); -void MachEmulateLDC1(u_int32_t inst, struct frame *, u_int32_t); -void MachEmulateSWC1(u_int32_t inst, struct frame *, u_int32_t); -void MachEmulateSDC1(u_int32_t inst, struct frame *, u_int32_t); - -void bcemul_lb(u_int32_t inst, struct frame *, u_int32_t); -void bcemul_lbu(u_int32_t inst, struct frame *, u_int32_t); -void bcemul_lh(u_int32_t inst, struct frame *, u_int32_t); -void bcemul_lhu(u_int32_t inst, struct frame *, u_int32_t); -void bcemul_lw(u_int32_t inst, struct frame *, u_int32_t); -void bcemul_lwl(u_int32_t inst, struct frame *, u_int32_t); -void bcemul_lwr(u_int32_t inst, struct frame *, u_int32_t); -void bcemul_sb(u_int32_t inst, struct frame *, u_int32_t); -void bcemul_sh(u_int32_t inst, struct frame *, u_int32_t); -void bcemul_sw(u_int32_t inst, struct frame *, u_int32_t); -void bcemul_swl(u_int32_t inst, struct frame *, u_int32_t); -void bcemul_swr(u_int32_t inst, struct frame *f, u_int32_t); +void MachEmulateLWC0(uint32_t inst, struct frame *, uint32_t); +void MachEmulateSWC0(uint32_t inst, struct frame *, uint32_t); +void MachEmulateSpecial(uint32_t inst, struct frame *, uint32_t); +void MachEmulateLWC1(uint32_t inst, struct frame *, uint32_t); +void MachEmulateLDC1(uint32_t inst, struct frame *, uint32_t); +void MachEmulateSWC1(uint32_t inst, struct frame *, uint32_t); +void MachEmulateSDC1(uint32_t inst, struct frame *, uint32_t); + +void bcemul_lb(uint32_t inst, struct frame *, uint32_t); +void bcemul_lbu(uint32_t inst, struct frame *, uint32_t); +void bcemul_lh(uint32_t inst, struct frame *, uint32_t); +void bcemul_lhu(uint32_t inst, struct frame *, uint32_t); +void bcemul_lw(uint32_t inst, struct frame *, uint32_t); +void bcemul_lwl(uint32_t inst, struct frame *, uint32_t); +void bcemul_lwr(uint32_t inst, struct frame *, uint32_t); +#if defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64) +void bcemul_ld(uint32_t inst, struct frame *, uint32_t); +void bcemul_ldl(uint32_t inst, struct frame *, uint32_t); +void bcemul_ldr(uint32_t inst, struct frame *, uint32_t); +#endif +void bcemul_sb(uint32_t inst, struct frame *, uint32_t); +void bcemul_sh(uint32_t inst, struct frame *, uint32_t); +void bcemul_sw(uint32_t inst, struct frame *, uint32_t); +void bcemul_swl(uint32_t inst, struct frame *, uint32_t); +void bcemul_swr(uint32_t inst, struct frame *f, uint32_t); +#if defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64) +void bcemul_sd(uint32_t inst, struct frame *, uint32_t); +void bcemul_sdl(uint32_t inst, struct frame *, uint32_t); +void bcemul_sdr(uint32_t inst, struct frame *f, uint32_t); +#endif /* * MIPS2 LL instruction emulation state @@ -79,7 +89,7 @@ struct { struct lwp *lwp; vaddr_t addr; - u_int32_t value; + uint32_t value; } llstate; /* @@ -207,22 +217,19 @@ * Emulate instructions (including floating-point instructions) */ void -MachEmulateInst(status, cause, opc, frame) - u_int32_t status; - u_int32_t cause; - vaddr_t opc; - struct frame *frame; +MachEmulateInst(uint32_t status, uint32_t cause, vaddr_t opc, + struct frame *frame) { - u_int32_t inst; + uint32_t inst; ksiginfo_t ksi; /* * Fetch the instruction. */ if (cause & MIPS_CR_BR_DELAY) - inst = fuword((u_int32_t *)opc+1); + inst = fuword((uint32_t *)opc+1); else - inst = fuword((u_int32_t *)opc); + inst = fuword((uint32_t *)opc); switch (((InstFmt)inst).FRType.op) { case OP_LWC0: @@ -265,8 +272,8 @@ } static inline void -send_sigsegv(vaddr_t vaddr, u_int32_t exccode, struct frame *frame, - u_int32_t cause) +send_sigsegv(intptr_t vaddr, uint32_t exccode, struct frame *frame, + uint32_t cause) { ksiginfo_t ksi; cause = (cause & 0xFFFFFF00) | (exccode << MIPS_CR_EXC_CODE_SHIFT); @@ -281,7 +288,7 @@ } static inline void -update_pc(struct frame *frame, u_int32_t cause) +update_pc(struct frame *frame, uint32_t cause) { if (cause & MIPS_CR_BR_DELAY) @@ -296,9 +303,9 @@ * MIPS2 LL instruction */ void -MachEmulateLWC0(u_int32_t inst, struct frame *frame, u_int32_t cause) +MachEmulateLWC0(uint32_t inst, struct frame *frame, uint32_t cause) { - vaddr_t vaddr; + intptr_t vaddr; int16_t offset; void *t; @@ -306,16 +313,8 @@ vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment and alignment check */ - if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) { - ksiginfo_t ksi; - frame->f_regs[_R_CAUSE] = cause; - frame->f_regs[_R_BADVADDR] = vaddr; - KSI_INIT_TRAP(&ksi); - ksi.ksi_signo = SIGBUS; - ksi.ksi_trap = cause; - ksi.ksi_code = (vaddr & 3) ? BUS_ADRALN : BUS_ADRERR; - ksi.ksi_addr = (void *)vaddr; - (*curproc->p_emul->e_trapsignal)(curlwp, &ksi); + if (vaddr < 0 || (vaddr & 3)) { + send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); return; } @@ -328,7 +327,7 @@ llstate.lwp = curlwp; llstate.addr = vaddr; - llstate.value = *((u_int32_t *)t); + llstate.value = *((uint32_t *)t); update_pc(frame, cause); } @@ -337,9 +336,9 @@ * MIPS2 SC instruction */ void -MachEmulateSWC0(u_int32_t inst, struct frame *frame, u_int32_t cause) +MachEmulateSWC0(uint32_t inst, struct frame *frame, uint32_t cause) { - vaddr_t vaddr; + intptr_t vaddr; uint32_t value; int16_t offset; mips_reg_t *t; @@ -348,16 +347,8 @@ vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment and alignment check */ - if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) { - ksiginfo_t ksi; - frame->f_regs[_R_CAUSE] = cause; - frame->f_regs[_R_BADVADDR] = vaddr; - KSI_INIT_TRAP(&ksi); - ksi.ksi_signo = SIGBUS; - ksi.ksi_trap = cause; - ksi.ksi_code = (vaddr & 3) ? BUS_ADRALN : BUS_ADRERR; - ksi.ksi_addr = (void *)vaddr; - (*curproc->p_emul->e_trapsignal)(curlwp, &ksi); + if (vaddr < 0 || (vaddr & 3)) { + send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); return; } @@ -396,7 +387,7 @@ } void -MachEmulateSpecial(u_int32_t inst, struct frame *frame, u_int32_t cause) +MachEmulateSpecial(uint32_t inst, struct frame *frame, uint32_t cause) { ksiginfo_t ksi; switch (((InstFmt)inst).RType.func) { @@ -423,9 +414,9 @@ #define LWSWC1_MAXLOOP 12 void -MachEmulateLWC1(u_int32_t inst, struct frame *frame, u_int32_t cause) +MachEmulateLWC1(uint32_t inst, struct frame *frame, uint32_t cause) { - u_int32_t vaddr; + intptr_t vaddr; int16_t offset; void *t; mips_reg_t pc; @@ -435,11 +426,12 @@ vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment and alignment check */ - if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) { + if (vaddr < 0 || (vaddr & 3)) { send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); return; } + /* NewABI FIXME */ t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]); if (copyin((void *)vaddr, t, 4) != 0) { @@ -458,7 +450,7 @@ return; vaddr = frame->f_regs[_R_PC]; /* XXX truncates to 32 bits */ - inst = fuiword((u_int32_t *)vaddr); + inst = fuiword((uint32_t *)vaddr); if (((InstFmt)inst).FRType.op != OP_LWC1) return; @@ -466,11 +458,12 @@ vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment and alignment check */ - if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) { + if (vaddr < 0 || (vaddr & 3)) { send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); return; } + /* NewABI FIXME */ t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]); if (copyin((void *)vaddr, t, 4) != 0) { @@ -484,9 +477,9 @@ } void -MachEmulateLDC1(u_int32_t inst, struct frame *frame, u_int32_t cause) +MachEmulateLDC1(uint32_t inst, struct frame *frame, uint32_t cause) { - u_int32_t vaddr; + intptr_t vaddr; int16_t offset; void *t; @@ -494,11 +487,12 @@ vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment and alignment check */ - if (vaddr & 0x80000007) { + if (vaddr < 0 || (vaddr & 7)) { send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); return; } + /* NewABI FIXME */ t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1E]); if (copyin((void *)vaddr, t, 8) != 0) { @@ -510,9 +504,9 @@ } void -MachEmulateSWC1(u_int32_t inst, struct frame *frame, u_int32_t cause) +MachEmulateSWC1(uint32_t inst, struct frame *frame, uint32_t cause) { - u_int32_t vaddr; + intptr_t vaddr; int16_t offset; void *t; mips_reg_t pc; @@ -522,11 +516,12 @@ vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment and alignment check */ - if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) { + if (vaddr < 0 || (vaddr & 3)) { send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); return; } + /* NewABI FIXME */ t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]); if (copyout(t, (void *)vaddr, 4) != 0) { @@ -545,7 +540,7 @@ return; vaddr = frame->f_regs[_R_PC]; /* XXX truncates to 32 bits */ - inst = fuiword((u_int32_t *)vaddr); + inst = fuiword((uint32_t *)vaddr); if (((InstFmt)inst).FRType.op != OP_SWC1) return; @@ -553,11 +548,12 @@ vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment and alignment check */ - if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) { + if (vaddr < 0 || (vaddr & 3)) { send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); return; } + /* NewABI FIXME */ t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]); if (copyout(t, (void *)vaddr, 4) != 0) { @@ -571,9 +567,9 @@ } void -MachEmulateSDC1(u_int32_t inst, struct frame *frame, u_int32_t cause) +MachEmulateSDC1(uint32_t inst, struct frame *frame, uint32_t cause) { - u_int32_t vaddr; + intptr_t vaddr; int16_t offset; void *t; @@ -581,11 +577,12 @@ vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment and alignment check */ - if (vaddr & 0x80000007) { + if (vaddr < 0 || (vaddr & 7)) { send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); return; } + /* NewABI FIXME */ t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1E]); if (copyout(t, (void *)vaddr, 8) != 0) { @@ -597,9 +594,9 @@ } void -bcemul_lb(u_int32_t inst, struct frame *frame, u_int32_t cause) +bcemul_lb(uint32_t inst, struct frame *frame, uint32_t cause) { - u_int32_t vaddr; + intptr_t vaddr; int16_t offset; int8_t x; @@ -607,7 +604,7 @@ vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment check */ - if (vaddr & 0x80000000) { + if (vaddr < 0) { send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); return; } @@ -623,17 +620,17 @@ } void -bcemul_lbu(u_int32_t inst, struct frame *frame, u_int32_t cause) +bcemul_lbu(uint32_t inst, struct frame *frame, uint32_t cause) { - u_int32_t vaddr; + intptr_t vaddr; int16_t offset; - u_int8_t x; + uint8_t x; offset = inst & 0xFFFF; vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment check */ - if (vaddr & 0x80000000) { + if (vaddr < 0) { send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); return; } @@ -643,15 +640,15 @@ return; } - frame->f_regs[(inst>>16)&0x1F] = (u_int32_t)x; + frame->f_regs[(inst>>16)&0x1F] = (mips_ureg_t)x; update_pc(frame, cause); } void -bcemul_lh(u_int32_t inst, struct frame *frame, u_int32_t cause) +bcemul_lh(uint32_t inst, struct frame *frame, uint32_t cause) { - u_int32_t vaddr; + intptr_t vaddr; int16_t offset; int16_t x; @@ -659,7 +656,7 @@ vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment and alignment check */ - if (vaddr & 0x80000001) { + if (vaddr < 0 || (vaddr & 1)) { send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); return; } @@ -669,15 +666,15 @@ return; } - frame->f_regs[(inst>>16)&0x1F] = (int32_t)x; + frame->f_regs[(inst>>16)&0x1F] = x; update_pc(frame, cause); } void -bcemul_lhu(u_int32_t inst, struct frame *frame, u_int32_t cause) +bcemul_lhu(uint32_t inst, struct frame *frame, uint32_t cause) { - u_int32_t vaddr; + intptr_t vaddr; int16_t offset; u_int16_t x; @@ -685,7 +682,7 @@ vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment and alignment check */ - if (vaddr & 0x80000001) { + if (vaddr < 0 || (vaddr & 1)) { send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); return; } @@ -695,22 +692,22 @@ return; } - frame->f_regs[(inst>>16)&0x1F] = (u_int32_t)x; + frame->f_regs[(inst>>16)&0x1F] = (mips_ureg_t)x; update_pc(frame, cause); } void -bcemul_lw(u_int32_t inst, struct frame *frame, u_int32_t cause) +bcemul_lw(uint32_t inst, struct frame *frame, uint32_t cause) { - u_int32_t vaddr; + intptr_t vaddr; int16_t offset; offset = inst & 0xFFFF; vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment and alignment check */ - if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) { + if (vaddr < 0 || (vaddr & 3)) { send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); return; } @@ -724,21 +721,22 @@ } void -bcemul_lwl(u_int32_t inst, struct frame *frame, u_int32_t cause) +bcemul_lwl(uint32_t inst, struct frame *frame, uint32_t cause) { - u_int32_t vaddr, a, x, shift; + intptr_t vaddr; + uint32_t a, x, shift; int16_t offset; offset = inst & 0xFFFF; vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment check */ - if (vaddr & 0x80000000) { + if (vaddr < 0) { send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); return; } - if (copyin((void *)(vaddr & ~0x3), &a, 4) != 0) { + if (copyin((void *)(vaddr & ~3), &a, 4) != 0) { send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); return; } @@ -756,9 +754,10 @@ } void -bcemul_lwr(u_int32_t inst, struct frame *frame, u_int32_t cause) +bcemul_lwr(uint32_t inst, struct frame *frame, uint32_t cause) { - u_int32_t vaddr, a, x, shift; + intptr_t vaddr; + uint32_t a, x, shift; int16_t offset; offset = inst & 0xFFFF; @@ -770,7 +769,7 @@ return; } - if (copyin((void *)(vaddr & ~0x3), &a, 4) != 0) { + if (copyin((void *)(vaddr & ~3), &a, 4) != 0) { send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); return; } @@ -787,10 +786,36 @@ update_pc(frame, cause); } +#if defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64) +void +bcemul_ld(uint32_t inst, struct frame *frame, uint32_t cause) +{ + intptr_t vaddr; + int16_t offset; + + offset = inst & 0xFFFF; + vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; + + /* segment and alignment check */ + if (vaddr > VM_MAX_ADDRESS || vaddr & 0x7) { + send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); + return; + } + + if (copyin((void *)vaddr, &(frame->f_regs[(inst>>16)&0x1F]), 8) != 0) { + send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); + return; + } + + update_pc(frame, cause); +} + void -bcemul_sb(u_int32_t inst, struct frame *frame, u_int32_t cause) +bcemul_ldl(uint32_t inst, struct frame *frame, uint32_t cause) { - u_int32_t vaddr; + intptr_t vaddr; + uint64_t a, x; + uint32_t shift; int16_t offset; offset = inst & 0xFFFF; @@ -798,6 +823,73 @@ /* segment check */ if (vaddr & 0x80000000) { + send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); + return; + } + + if (copyin((void *)(vaddr & ~0x7), &a, 8) != 0) { + send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); + return; + } + + x = frame->f_regs[(inst>>16)&0x1F]; + + shift = (7 - (vaddr & 0x7)) * 8; + a <<= shift; + x &= ~(~(uint64_t)0UL << shift); + x |= a; + + frame->f_regs[(inst>>16)&0x1F] = x; + + update_pc(frame, cause); +} + +void +bcemul_ldr(uint32_t inst, struct frame *frame, uint32_t cause) +{ + intptr_t vaddr; + uint64_t a, x; + uint32_t shift; + int16_t offset; + + offset = inst & 0xFFFF; + vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; + + /* segment check */ + if (vaddr < 0) { + send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); + return; + } + + if (copyin((void *)(vaddr & ~0x7), &a, 8) != 0) { + send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); + return; + } + + x = frame->f_regs[(inst>>16)&0x1F]; + + shift = (vaddr & 0x7) * 8; + a >>= shift; + x &= ~(~(uint64_t)0UL >> shift); + x |= a; + + frame->f_regs[(inst>>16)&0x1F] = x; + + update_pc(frame, cause); +} +#endif /* defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64) */ + +void +bcemul_sb(uint32_t inst, struct frame *frame, uint32_t cause) +{ + intptr_t vaddr; + int16_t offset; + + offset = inst & 0xFFFF; + vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; + + /* segment check */ + if (vaddr < 0) { send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); return; } @@ -811,16 +903,16 @@ } void -bcemul_sh(u_int32_t inst, struct frame *frame, u_int32_t cause) +bcemul_sh(uint32_t inst, struct frame *frame, uint32_t cause) { - u_int32_t vaddr; + intptr_t vaddr; int16_t offset; offset = inst & 0xFFFF; vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment and alignment check */ - if (vaddr & 0x80000001) { + if (vaddr < 0 || vaddr & 1) { send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); return; } @@ -834,16 +926,16 @@ } void -bcemul_sw(u_int32_t inst, struct frame *frame, u_int32_t cause) +bcemul_sw(uint32_t inst, struct frame *frame, uint32_t cause) { - u_int32_t vaddr; + intptr_t vaddr; int16_t offset; offset = inst & 0xFFFF; vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment and alignment check */ - if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) { + if (vaddr < 0 || (vaddr & 3)) { send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); return; } @@ -857,28 +949,29 @@ } void -bcemul_swl(u_int32_t inst, struct frame *frame, u_int32_t cause) +bcemul_swl(uint32_t inst, struct frame *frame, uint32_t cause) { - u_int32_t vaddr, a, x, shift; + intptr_t vaddr; + uint32_t a, x, shift; int16_t offset; offset = inst & 0xFFFF; vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment check */ - if (vaddr & 0x80000000) { + if (vaddr < 0) { send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); return; } - if (copyin((void *)(vaddr & ~0x3), &a, 4) != 0) { + if (copyin((void *)(vaddr & ~3), &a, 4) != 0) { send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); return; } x = frame->f_regs[(inst>>16)&0x1F]; - shift = (3 - (vaddr & 0x00000003)) * 8; + shift = (3 - (vaddr & 3)) * 8; x >>= shift; a &= ~(0xFFFFFFFFUL >> shift); a |= x; @@ -892,28 +985,29 @@ } void -bcemul_swr(u_int32_t inst, struct frame *frame, u_int32_t cause) +bcemul_swr(uint32_t inst, struct frame *frame, uint32_t cause) { - u_int32_t vaddr, a, x, shift; + intptr_t vaddr; + uint32_t a, x, shift; int16_t offset; offset = inst & 0xFFFF; vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; /* segment check */ - if (vaddr & 0x80000000) { + if (vaddr < 0) { send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); return; } - if (copyin((void *)(vaddr & ~0x3), &a, 4) != 0) { + if (copyin((void *)(vaddr & ~3), &a, 4) != 0) { send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); return; } x = frame->f_regs[(inst>>16)&0x1F]; - shift = (vaddr & 0x00000003) * 8; + shift = (vaddr & 3) * 8; x <<= shift; a &= ~(0xFFFFFFFFUL << shift); a |= x; @@ -925,4 +1019,103 @@ update_pc(frame, cause); } + +#if defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64) +void +bcemul_sd(uint32_t inst, struct frame *frame, uint32_t cause) +{ + intptr_t vaddr; + int16_t offset; + + offset = inst & 0xFFFF; + vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; + + /* segment and alignment check */ + if (vaddr < 0 || vaddr & 0x7) { + send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); + return; + } + + if (copyout((void *)vaddr, &frame->f_regs[(inst>>16)&0x1F], 8) < 0) { + send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); + return; + } + + update_pc(frame, cause); +} + +void +bcemul_sdl(uint32_t inst, struct frame *frame, uint32_t cause) +{ + intptr_t vaddr; + uint64_t a, x; + uint32_t shift; + int16_t offset; + + offset = inst & 0xFFFF; + vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; + + /* segment check */ + if (vaddr < 0) { + send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); + return; + } + + if (copyin((void *)(vaddr & ~0x7), &a, 8) != 0) { + send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); + return; + } + + x = frame->f_regs[(inst>>16)&0x1F]; + + shift = (7 - (vaddr & 7)) * 8; + x >>= shift; + a &= ~(~(uint64_t)0U >> shift); + a |= x; + + if (copyout((void *)(vaddr & ~0x7), &a, 8) != 0) { + send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); + return; + } + + update_pc(frame, cause); +} + +void +bcemul_sdr(uint32_t inst, struct frame *frame, uint32_t cause) +{ + intptr_t vaddr; + uint64_t a, x; + uint32_t shift; + int16_t offset; + + offset = inst & 0xFFFF; + vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; + + /* segment check */ + if (vaddr < 0) { + send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); + return; + } + + if (copyin((void *)(vaddr & ~0x7), &a, 8) != 0) { + send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); + return; + } + + x = frame->f_regs[(inst>>16)&0x1F]; + + shift = (vaddr & 7) * 8; + x <<= shift; + a &= ~(~(uint64_t)0U << shift); + a |= x; + + if (copyout((void *)(vaddr & ~0x7), &a, 8) != 0) { + send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); + return; + } + + update_pc(frame, cause); +} +#endif /* defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64) */ #endif /* defined(SOFTFLOAT) */