[BACK]Return to emul.c CVS log [TXT][DIR] Up to [local] / sys / arch / sparc / sparc

Annotation of sys/arch/sparc/sparc/emul.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: emul.c,v 1.3 2002/03/14 01:26:44 millert Exp $        */
                      2: /*     $NetBSD: emul.c,v 1.3 1997/07/29 09:42:01 fair Exp $    */
                      3:
                      4: /*
                      5:  * Copyright (c) 1997 Christos Zoulas.  All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *     This product includes software developed by Christos Zoulas.
                     18:  * 4. The name of the author may not be used to endorse or promote products
                     19:  *    derived from this software without specific prior written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     22:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     23:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     24:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     25:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     26:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     27:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     28:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     29:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     30:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     31:  */
                     32:
                     33: #include <sys/param.h>
                     34: #include <sys/systm.h>
                     35: #include <sys/proc.h>
                     36: #include <machine/reg.h>
                     37: #include <machine/instr.h>
                     38: #include <machine/cpu.h>
                     39: #include <machine/psl.h>
                     40: #include <sparc/sparc/cpuvar.h>
                     41:
                     42: #ifdef DEBUG_EMUL
                     43: # define DPRINTF(a) uprintf a
                     44: #else
                     45: # define DPRINTF(a)
                     46: #endif
                     47:
                     48: #define GPR(tf, i)     ((int32_t *) &tf->tf_global)[i]
                     49: #define IPR(tf, i)     ((int32_t *) tf->tf_out[6])[i - 16]
                     50: #define FPR(p, i)      ((int32_t) p->p_md.md_fpstate->fs_regs[i])
                     51:
                     52: static __inline int readgpreg(struct trapframe *, int, void *);
                     53: static __inline int readfpreg(struct proc *, int, void *);
                     54: static __inline int writegpreg(struct trapframe *, int, const void *);
                     55: static __inline int writefpreg(struct proc *, int, const void *);
                     56: static __inline int decodeaddr(struct trapframe *, union instr *, void *);
                     57: static int muldiv(struct trapframe *, union instr *, int32_t *, int32_t *,
                     58:     int32_t *);
                     59:
                     60: #define        REGNAME(i)      "goli"[i >> 3], i & 7
                     61:
                     62:
                     63: static __inline int
                     64: readgpreg(tf, i, val)
                     65:        struct trapframe *tf;
                     66:        int i;
                     67:        void *val;
                     68: {
                     69:        int error = 0;
                     70:        if (i == 0)
                     71:                *(int32_t *) val = 0;
                     72:        else if (i < 16)
                     73:                *(int32_t *) val = GPR(tf, i);
                     74:        else
                     75:                error = copyin(&IPR(tf, i), val, sizeof(int32_t));
                     76:
                     77:        return error;
                     78: }
                     79:
                     80:
                     81: static __inline int
                     82: writegpreg(tf, i, val)
                     83:        struct trapframe *tf;
                     84:        int i;
                     85:        const void *val;
                     86: {
                     87:        int error = 0;
                     88:
                     89:        if (i == 0)
                     90:                return error;
                     91:        else if (i < 16)
                     92:                GPR(tf, i) = *(int32_t *) val;
                     93:        else
                     94:                /* XXX: Fix copyout prototype */
                     95:                error = copyout((caddr_t) val, &IPR(tf, i), sizeof(int32_t));
                     96:
                     97:        return error;
                     98: }
                     99:
                    100:
                    101: static __inline int
                    102: readfpreg(p, i, val)
                    103:        struct proc *p;
                    104:        int i;
                    105:        void *val;
                    106: {
                    107:        *(int32_t *) val = FPR(p, i);
                    108:        return 0;
                    109: }
                    110:
                    111:
                    112: static __inline int
                    113: writefpreg(p, i, val)
                    114:        struct proc *p;
                    115:        int i;
                    116:        const void *val;
                    117: {
                    118:        FPR(p, i) = *(const int32_t *) val;
                    119:        return 0;
                    120: }
                    121:
                    122: static __inline int
                    123: decodeaddr(tf, code, val)
                    124:        struct trapframe *tf;
                    125:        union instr *code;
                    126:        void *val;
                    127: {
                    128:        if (code->i_simm13.i_i)
                    129:                *((int32_t *) val) = code->i_simm13.i_simm13;
                    130:        else {
                    131:                int error;
                    132:
                    133:                if (code->i_asi.i_asi)
                    134:                        return EINVAL;
                    135:                if ((error = readgpreg(tf, code->i_asi.i_rs2, val)) != 0)
                    136:                        return error;
                    137:        }
                    138:        return 0;
                    139: }
                    140:
                    141:
                    142: static int
                    143: muldiv(tf, code, rd, rs1, rs2)
                    144:        struct trapframe *tf;
                    145:        union instr *code;
                    146:        int32_t *rd, *rs1, *rs2;
                    147: {
                    148:        /*
                    149:         * We check for {S,U}{MUL,DIV}{,cc}
                    150:         *
                    151:         * [c = condition code, s = sign]
                    152:         * Mul = 0c101s
                    153:         * Div = 0c111s
                    154:         */
                    155:        union {
                    156:                struct {
                    157:                        unsigned unused:26;     /* padding */
                    158:                        unsigned zero:1;        /* zero by opcode */
                    159:                        unsigned cc:1;          /* one to send condition code */
                    160:                        unsigned one1:1;        /* one by opcode */
                    161:                        unsigned div:1;         /* one if divide */
                    162:                        unsigned one2:1;        /* one by opcode */
                    163:                        unsigned sgn:1;         /* sign bit */
                    164:                } bits;
                    165:                int num;
                    166:        } op;
                    167:
                    168:        op.num = code->i_op3.i_op3;
                    169:
                    170: #ifdef DEBUG_EMUL
                    171:        uprintf("muldiv 0x%x: %c%s%s %c%d, %c%d, ", code->i_int,
                    172:            "us"[op.bits.sgn], op.bits.div ? "div" : "mul",
                    173:            op.bits.cc ? "cc" : "", REGNAME(code->i_op3.i_rd),
                    174:            REGNAME(code->i_op3.i_rs1));
                    175:        if (code->i_loadstore.i_i)
                    176:                uprintf("0x%x\n", *rs2);
                    177:        else
                    178:                uprintf("%c%d\n", REGNAME(code->i_asi.i_rs2));
                    179: #endif
                    180:
                    181:        if (op.bits.div) {
                    182:                if (*rs2 == 0) {
                    183:                        /*
                    184:                         * XXX: to be 100% correct here, on sunos we need to
                    185:                         *      ignore the error and return *rd = *rs1.
                    186:                         *      It should be easy to fix by passing struct
                    187:                         *      proc in here.
                    188:                         */
                    189:                        DPRINTF(("emulinstr: avoid zerodivide\n"));
                    190:                        return EINVAL;
                    191:                }
                    192:                *rd = *rs1 / *rs2;
                    193:                DPRINTF(("muldiv: %d / %d = %d\n", *rs1, *rs2, *rd));
                    194:        }
                    195:        else {
                    196:                *rd = *rs1 * *rs2;
                    197:                DPRINTF(("muldiv: %d * %d = %d\n", *rs1, *rs2, *rd));
                    198:        }
                    199:
                    200:        if (op.bits.cc) {
                    201:                /* Set condition codes */
                    202:                tf->tf_psr &= ~PSR_ICC;
                    203:
                    204:                if (*rd == 0)
                    205:                        tf->tf_psr |= PSR_Z << 20;
                    206:                else {
                    207:                        if (op.bits.sgn && *rd < 0)
                    208:                                tf->tf_psr |= PSR_N << 20;
                    209:                        if (op.bits.div) {
                    210:                                if (*rd * *rs2 != *rs1)
                    211:                                        tf->tf_psr |= PSR_O << 20;
                    212:                        }
                    213:                        else {
                    214:                                if (*rd / *rs2 != *rs1)
                    215:                                        tf->tf_psr |= PSR_O << 20;
                    216:                        }
                    217:                }
                    218:        }
                    219:
                    220:        return 0;
                    221: }
                    222:
                    223: /*
                    224:  * Code to handle alignment faults on the sparc. This is enabled by sending
                    225:  * a fixalign trap. Such code is generated by compiling with cc -misalign
                    226:  * on SunOS, but we don't have such a feature yet on our gcc.
                    227:  */
                    228:
                    229: int
                    230: fixalign(p, tf)
                    231:        struct proc *p;
                    232:        struct trapframe *tf;
                    233: {
                    234:        static u_char sizedef[] = { 0x4, 0xff, 0x2, 0x8 };
                    235:
                    236:        /*
                    237:         * This is particular to load and store instructions
                    238:         */
                    239:        union {
                    240:                struct {
                    241:                        unsigned unused:26;     /* 26 padding */
                    242:                        unsigned fl:1;          /* 1 bit float flag */
                    243:                        unsigned op:1;          /* 1 bit opcode */
                    244:                        unsigned sgn:1;         /* 1 bit sign */
                    245:                        unsigned st:1;          /* 1 bit load/store */
                    246:                        unsigned sz:2;          /* 2 bit size register */
                    247:                } bits;
                    248:                int num;
                    249:        } op;
                    250:
                    251:        union {
                    252:                double  d;
                    253:                int32_t i[2];
                    254:                int16_t s[4];
                    255:                int8_t  c[8];
                    256:        } data;
                    257:
                    258:        union instr code;
                    259:        size_t size;
                    260:        int32_t rs1, rs2;
                    261:        int error;
                    262:
                    263:        /* fetch and check the instruction that caused the fault */
                    264:        error = copyin((caddr_t) tf->tf_pc, &code.i_int, sizeof(code.i_int));
                    265:        if (error != 0) {
                    266:                DPRINTF(("fixalign: Bad instruction fetch\n"));
                    267:                return EINVAL;
                    268:        }
                    269:
                    270:        /* Only support format 3 */
                    271:        if (code.i_any.i_op != 3) {
                    272:                DPRINTF(("fixalign: Not a load or store\n"));
                    273:                return EINVAL;
                    274:        }
                    275:
                    276:        op.num = code.i_loadstore.i_op3;
                    277:
                    278:        /* Check operand size */
                    279:        if ((size = sizedef[op.bits.sz]) == 0xff) {
                    280:                DPRINTF(("fixalign: Bad operand size\n"));
                    281:                return EINVAL;
                    282:        }
                    283:
                    284:        write_user_windows();
                    285:
                    286:        if ((error = readgpreg(tf, code.i_op3.i_rs1, &rs1)) != 0) {
                    287:                DPRINTF(("emulinstr: read rs1 %d\n", error));
                    288:                return error;
                    289:        }
                    290:
                    291:        if ((error = decodeaddr(tf, &code, &rs2)) != 0) {
                    292:                DPRINTF(("emulinstr: decode addr %d\n", error));
                    293:                return error;
                    294:        }
                    295:
                    296:
                    297:        rs1 += rs2;
                    298:
                    299: #ifdef DEBUG_EMUL
                    300:        uprintf("memalign 0x%x: %s%c%c %c%d, %c%d, ", code.i_int,
                    301:            op.bits.st ? "st" : "ld", "us"[op.bits.sgn],
                    302:            "w*hd"[op.bits.sz], op.bits.fl ? 'f' : REGNAME(code.i_op3.i_rd),
                    303:            REGNAME(code.i_op3.i_rs1));
                    304:        if (code.i_loadstore.i_i)
                    305:                uprintf("0x%x\n", rs2);
                    306:        else
                    307:                uprintf("%c%d\n", REGNAME(code.i_asi.i_rs2));
                    308: #endif
                    309: #ifdef DIAGNOSTIC
                    310:        if (op.bits.fl && p != cpuinfo.fpproc)
                    311:                panic("fp align without being the FP owning process");
                    312: #endif
                    313:
                    314:        if (op.bits.st) {
                    315:                if (op.bits.fl) {
                    316:                        savefpstate(p->p_md.md_fpstate);
                    317:
                    318:                        error = readfpreg(p, code.i_op3.i_rd, &data.i[0]);
                    319:                        if (error)
                    320:                                return error;
                    321:                        if (size == 8) {
                    322:                                error = readfpreg(p, code.i_op3.i_rd + 1,
                    323:                                    &data.i[1]);
                    324:                                if (error)
                    325:                                        return error;
                    326:                        }
                    327:                }
                    328:                else {
                    329:                        error = readgpreg(tf, code.i_op3.i_rd, &data.i[0]);
                    330:                        if (error)
                    331:                                return error;
                    332:                        if (size == 8) {
                    333:                                error = readgpreg(tf, code.i_op3.i_rd + 1,
                    334:                                    &data.i[1]);
                    335:                                if (error)
                    336:                                        return error;
                    337:                        }
                    338:                }
                    339:
                    340:                if (size == 2)
                    341:                        return copyout(&data.s[1], (caddr_t) rs1, size);
                    342:                else
                    343:                        return copyout(&data.d, (caddr_t) rs1, size);
                    344:        }
                    345:        else { /* load */
                    346:                if (size == 2) {
                    347:                        error = copyin((caddr_t) rs1, &data.s[1], size);
                    348:                        if (error)
                    349:                                return error;
                    350:
                    351:                        /* Sign extend if necessary */
                    352:                        if (op.bits.sgn && (data.s[1] & 0x8000) != 0)
                    353:                                data.s[0] = ~0;
                    354:                        else
                    355:                                data.s[0] = 0;
                    356:                }
                    357:                else
                    358:                        error = copyin((caddr_t) rs1, &data.d, size);
                    359:
                    360:                if (error)
                    361:                        return error;
                    362:
                    363:                if (op.bits.fl) {
                    364:                        error = writefpreg(p, code.i_op3.i_rd, &data.i[0]);
                    365:                        if (error)
                    366:                                return error;
                    367:                        if (size == 8) {
                    368:                                error = writefpreg(p, code.i_op3.i_rd + 1,
                    369:                                    &data.i[1]);
                    370:                                if (error)
                    371:                                        return error;
                    372:                        }
                    373:                        loadfpstate(p->p_md.md_fpstate);
                    374:                }
                    375:                else {
                    376:                        error = writegpreg(tf, code.i_op3.i_rd, &data.i[0]);
                    377:                        if (error)
                    378:                                return error;
                    379:                        if (size == 8)
                    380:                                error = writegpreg(tf, code.i_op3.i_rd + 1,
                    381:                                    &data.i[1]);
                    382:                }
                    383:        }
                    384:        return error;
                    385: }
                    386:
                    387: /*
                    388:  * Emulate unimplemented instructions on earlier sparc chips.
                    389:  */
                    390: int
                    391: emulinstr(pc, tf)
                    392:        int pc;
                    393:        struct trapframe *tf;
                    394: {
                    395:        union instr code;
                    396:        int32_t rs1, rs2, rd;
                    397:        int error;
                    398:
                    399:        /* fetch and check the instruction that caused the fault */
                    400:        error = copyin((caddr_t) pc, &code.i_int, sizeof(code.i_int));
                    401:        if (error != 0) {
                    402:                DPRINTF(("emulinstr: Bad instruction fetch\n"));
                    403:                return SIGILL;
                    404:        }
                    405:
                    406:        /* Only support format 2 */
                    407:        if (code.i_any.i_op != 2) {
                    408:                DPRINTF(("emulinstr: Not a format 2 instruction\n"));
                    409:                return SIGILL;
                    410:        }
                    411:
                    412:        write_user_windows();
                    413:
                    414:        if ((error = readgpreg(tf, code.i_op3.i_rs1, &rs1)) != 0) {
                    415:                DPRINTF(("emulinstr: read rs1 %d\n", error));
                    416:                return SIGILL;
                    417:        }
                    418:
                    419:        if ((error = decodeaddr(tf, &code, &rs2)) != 0) {
                    420:                DPRINTF(("emulinstr: decode addr %d\n", error));
                    421:                return SIGILL;
                    422:        }
                    423:
                    424:        switch (code.i_op3.i_op3) {
                    425:        case IOP3_FLUSH:
                    426:                cpuinfo.cache_flush((caddr_t)(rs1 + rs2), 4); /*XXX*/
                    427:                return 0;
                    428:
                    429:        default:
                    430:                if ((code.i_op3.i_op3 & 0x2a) != 0xa) {
                    431:                        DPRINTF(("emulinstr: Unsupported op3 0x%x\n",
                    432:                            code.i_op3.i_op3));
                    433:                        return SIGILL;
                    434:                }
                    435:                else if ((error = muldiv(tf, &code, &rd, &rs1, &rs2)) != 0)
                    436:                        return SIGFPE;
                    437:        }
                    438:
                    439:        if ((error = writegpreg(tf, code.i_op3.i_rd, &rd)) != 0) {
                    440:                DPRINTF(("muldiv: write rd %d\n", error));
                    441:                return SIGILL;
                    442:        }
                    443:
                    444:        return 0;
                    445: }

CVSweb