Annotation of linux/kernel/math/emulate.c, revision 1.1.1.5

1.1       root        1: /*
                      2:  * linux/kernel/math/emulate.c
                      3:  *
1.1.1.4   root        4:  * Copyright (C) 1991, 1992 Linus Torvalds
1.1       root        5:  */
                      6: 
                      7: /*
                      8:  * Limited emulation 27.12.91 - mostly loads/stores, which gcc wants
                      9:  * even for soft-float, unless you use bruce evans' patches. The patches
                     10:  * are great, but they have to be re-applied for every version, and the
                     11:  * library is different for soft-float and 80387. So emulation is more
                     12:  * practical, even though it's slower.
                     13:  *
                     14:  * 28.12.91 - loads/stores work, even BCD. I'll have to start thinking
                     15:  * about add/sub/mul/div. Urgel. I should find some good source, but I'll
                     16:  * just fake up something.
                     17:  *
                     18:  * 30.12.91 - add/sub/mul/div/com seem to work mostly. I should really
                     19:  * test every possible combination.
                     20:  */
                     21: 
                     22: /*
                     23:  * This file is full of ugly macros etc: one problem was that gcc simply
                     24:  * didn't want to make the structures as they should be: it has to try to
                     25:  * align them. Sickening code, but at least I've hidden the ugly things
                     26:  * in this one file: the other files don't need to know about these things.
                     27:  *
                     28:  * The other files also don't care about ST(x) etc - they just get addresses
                     29:  * to 80-bit temporary reals, and do with them as they please. I wanted to
                     30:  * hide most of the 387-specific things here.
                     31:  */
                     32: 
                     33: #ifdef KERNEL_MATH_EMULATION
                     34: 
1.1.1.4   root       35: #include <linux/signal.h>
1.1       root       36: 
                     37: #define __ALIGNED_TEMP_REAL 1
                     38: #include <linux/math_emu.h>
                     39: #include <linux/kernel.h>
                     40: #include <asm/segment.h>
                     41: 
                     42: #define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
                     43: #define ST(x) (*__st((x)))
                     44: #define PST(x) ((const temp_real *) __st((x)))
                     45: 
                     46: /*
                     47:  * We don't want these inlined - it gets too messy in the machine-code.
                     48:  */
                     49: static void fpop(void);
                     50: static void fpush(void);
                     51: static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b);
                     52: static temp_real_unaligned * __st(int i);
                     53: 
                     54: static void do_emu(struct info * info)
                     55: {
                     56:        unsigned short code;
                     57:        temp_real tmp;
                     58:        char * address;
                     59: 
                     60:        if (I387.cwd & I387.swd & 0x3f)
                     61:                I387.swd |= 0x8000;
                     62:        else
                     63:                I387.swd &= 0x7fff;
                     64:        ORIG_EIP = EIP;
1.1.1.5 ! root       65: /* We cannot handle emulation in v86-mode */
        !            66:        if (EFLAGS & 0x00020000)
        !            67:                math_abort(info,SIGILL);
1.1       root       68: /* 0x0007 means user code space */
                     69:        if (CS != 0x000F) {
                     70:                printk("math_emulate: %04x:%08x\n\r",CS,EIP);
                     71:                panic("Math emulation needed in kernel");
                     72:        }
                     73:        code = get_fs_word((unsigned short *) EIP);
                     74:        bswapw(code);
                     75:        code &= 0x7ff;
                     76:        I387.fip = EIP;
                     77:        *(unsigned short *) &I387.fcs = CS;
                     78:        *(1+(unsigned short *) &I387.fcs) = code;
                     79:        EIP += 2;
                     80:        switch (code) {
                     81:                case 0x1d0: /* fnop */
                     82:                        return;
                     83:                case 0x1d1: case 0x1d2: case 0x1d3:
                     84:                case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7:
1.1.1.3   root       85:                        math_abort(info,SIGILL);
1.1       root       86:                case 0x1e0:
                     87:                        ST(0).exponent ^= 0x8000;
                     88:                        return;
                     89:                case 0x1e1:
                     90:                        ST(0).exponent &= 0x7fff;
                     91:                        return;
                     92:                case 0x1e2: case 0x1e3:
1.1.1.3   root       93:                        math_abort(info,SIGILL);
1.1       root       94:                case 0x1e4:
                     95:                        ftst(PST(0));
                     96:                        return;
                     97:                case 0x1e5:
                     98:                        printk("fxam not implemented\n\r");
1.1.1.3   root       99:                        math_abort(info,SIGILL);
1.1       root      100:                case 0x1e6: case 0x1e7:
1.1.1.3   root      101:                        math_abort(info,SIGILL);
1.1       root      102:                case 0x1e8:
                    103:                        fpush();
                    104:                        ST(0) = CONST1;
                    105:                        return;
                    106:                case 0x1e9:
                    107:                        fpush();
                    108:                        ST(0) = CONSTL2T;
                    109:                        return;
                    110:                case 0x1ea:
                    111:                        fpush();
                    112:                        ST(0) = CONSTL2E;
                    113:                        return;
                    114:                case 0x1eb:
                    115:                        fpush();
                    116:                        ST(0) = CONSTPI;
                    117:                        return;
                    118:                case 0x1ec:
                    119:                        fpush();
                    120:                        ST(0) = CONSTLG2;
                    121:                        return;
                    122:                case 0x1ed:
                    123:                        fpush();
                    124:                        ST(0) = CONSTLN2;
                    125:                        return;
                    126:                case 0x1ee:
                    127:                        fpush();
                    128:                        ST(0) = CONSTZ;
                    129:                        return;
                    130:                case 0x1ef:
1.1.1.3   root      131:                        math_abort(info,SIGILL);
1.1.1.2   root      132:                case 0x1fa:
                    133:                        fsqrt(PST(0),&tmp);
                    134:                        real_to_real(&tmp,&ST(0));
                    135:                        return;
1.1       root      136:                case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3:
                    137:                case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7:
1.1.1.2   root      138:                case 0x1f8: case 0x1f9: case 0x1fb: case 0x1fd:
                    139:                case 0x1fe: case 0x1ff:
1.1       root      140:                        printk("%04x fxxx not implemented\n\r",code + 0xd800);
1.1.1.3   root      141:                        math_abort(info,SIGILL);
1.1       root      142:                case 0x1fc:
                    143:                        frndint(PST(0),&tmp);
                    144:                        real_to_real(&tmp,&ST(0));
                    145:                        return;
                    146:                case 0x2e9:
                    147:                        fucom(PST(1),PST(0));
                    148:                        fpop(); fpop();
                    149:                        return;
                    150:                case 0x3d0: case 0x3d1:
                    151:                        return;
                    152:                case 0x3e2:
                    153:                        I387.swd &= 0x7f00;
                    154:                        return;
                    155:                case 0x3e3:
                    156:                        I387.cwd = 0x037f;
                    157:                        I387.swd = 0x0000;
                    158:                        I387.twd = 0x0000;
                    159:                        return;
                    160:                case 0x3e4:
                    161:                        return;
                    162:                case 0x6d9:
                    163:                        fcom(PST(1),PST(0));
                    164:                        fpop(); fpop();
                    165:                        return;
                    166:                case 0x7e0:
                    167:                        *(short *) &EAX = I387.swd;
                    168:                        return;
                    169:        }
                    170:        switch (code >> 3) {
                    171:                case 0x18:
                    172:                        fadd(PST(0),PST(code & 7),&tmp);
                    173:                        real_to_real(&tmp,&ST(0));
                    174:                        return;
                    175:                case 0x19:
                    176:                        fmul(PST(0),PST(code & 7),&tmp);
                    177:                        real_to_real(&tmp,&ST(0));
                    178:                        return;
                    179:                case 0x1a:
                    180:                        fcom(PST(code & 7),PST(0));
                    181:                        return;
                    182:                case 0x1b:
                    183:                        fcom(PST(code & 7),PST(0));
                    184:                        fpop();
                    185:                        return;
                    186:                case 0x1c:
                    187:                        real_to_real(&ST(code & 7),&tmp);
                    188:                        tmp.exponent ^= 0x8000;
                    189:                        fadd(PST(0),&tmp,&tmp);
                    190:                        real_to_real(&tmp,&ST(0));
                    191:                        return;
                    192:                case 0x1d:
                    193:                        ST(0).exponent ^= 0x8000;
                    194:                        fadd(PST(0),PST(code & 7),&tmp);
                    195:                        real_to_real(&tmp,&ST(0));
                    196:                        return;
                    197:                case 0x1e:
                    198:                        fdiv(PST(0),PST(code & 7),&tmp);
                    199:                        real_to_real(&tmp,&ST(0));
                    200:                        return;
                    201:                case 0x1f:
                    202:                        fdiv(PST(code & 7),PST(0),&tmp);
                    203:                        real_to_real(&tmp,&ST(0));
                    204:                        return;
                    205:                case 0x38:
                    206:                        fpush();
                    207:                        ST(0) = ST((code+1) & 7);
                    208:                        return;
                    209:                case 0x39:
                    210:                        fxchg(&ST(0),&ST(code & 7));
                    211:                        return;
                    212:                case 0x3b:
                    213:                        ST(code & 7) = ST(0);
                    214:                        fpop();
                    215:                        return;
                    216:                case 0x98:
                    217:                        fadd(PST(0),PST(code & 7),&tmp);
                    218:                        real_to_real(&tmp,&ST(code & 7));
                    219:                        return;
                    220:                case 0x99:
                    221:                        fmul(PST(0),PST(code & 7),&tmp);
                    222:                        real_to_real(&tmp,&ST(code & 7));
                    223:                        return;
                    224:                case 0x9a:
                    225:                        fcom(PST(code & 7),PST(0));
                    226:                        return;
                    227:                case 0x9b:
                    228:                        fcom(PST(code & 7),PST(0));
                    229:                        fpop();
                    230:                        return;                 
                    231:                case 0x9c:
                    232:                        ST(code & 7).exponent ^= 0x8000;
                    233:                        fadd(PST(0),PST(code & 7),&tmp);
                    234:                        real_to_real(&tmp,&ST(code & 7));
                    235:                        return;
                    236:                case 0x9d:
                    237:                        real_to_real(&ST(0),&tmp);
                    238:                        tmp.exponent ^= 0x8000;
                    239:                        fadd(PST(code & 7),&tmp,&tmp);
                    240:                        real_to_real(&tmp,&ST(code & 7));
                    241:                        return;
                    242:                case 0x9e:
                    243:                        fdiv(PST(0),PST(code & 7),&tmp);
                    244:                        real_to_real(&tmp,&ST(code & 7));
                    245:                        return;
                    246:                case 0x9f:
                    247:                        fdiv(PST(code & 7),PST(0),&tmp);
                    248:                        real_to_real(&tmp,&ST(code & 7));
                    249:                        return;
                    250:                case 0xb8:
                    251:                        printk("ffree not implemented\n\r");
1.1.1.3   root      252:                        math_abort(info,SIGILL);
1.1       root      253:                case 0xb9:
                    254:                        fxchg(&ST(0),&ST(code & 7));
                    255:                        return;
                    256:                case 0xba:
                    257:                        ST(code & 7) = ST(0);
                    258:                        return;
                    259:                case 0xbb:
                    260:                        ST(code & 7) = ST(0);
                    261:                        fpop();
                    262:                        return;
                    263:                case 0xbc:
                    264:                        fucom(PST(code & 7),PST(0));
                    265:                        return;
                    266:                case 0xbd:
                    267:                        fucom(PST(code & 7),PST(0));
                    268:                        fpop();
                    269:                        return;
                    270:                case 0xd8:
                    271:                        fadd(PST(code & 7),PST(0),&tmp);
                    272:                        real_to_real(&tmp,&ST(code & 7));
                    273:                        fpop();
                    274:                        return;
                    275:                case 0xd9:
                    276:                        fmul(PST(code & 7),PST(0),&tmp);
                    277:                        real_to_real(&tmp,&ST(code & 7));
                    278:                        fpop();
                    279:                        return;
                    280:                case 0xda:
                    281:                        fcom(PST(code & 7),PST(0));
                    282:                        fpop();
                    283:                        return;
                    284:                case 0xdc:
                    285:                        ST(code & 7).exponent ^= 0x8000;
                    286:                        fadd(PST(0),PST(code & 7),&tmp);
                    287:                        real_to_real(&tmp,&ST(code & 7));
                    288:                        fpop();
                    289:                        return;
                    290:                case 0xdd:
                    291:                        real_to_real(&ST(0),&tmp);
                    292:                        tmp.exponent ^= 0x8000;
                    293:                        fadd(PST(code & 7),&tmp,&tmp);
                    294:                        real_to_real(&tmp,&ST(code & 7));
                    295:                        fpop();
                    296:                        return;
                    297:                case 0xde:
                    298:                        fdiv(PST(0),PST(code & 7),&tmp);
                    299:                        real_to_real(&tmp,&ST(code & 7));
                    300:                        fpop();
                    301:                        return;
                    302:                case 0xdf:
                    303:                        fdiv(PST(code & 7),PST(0),&tmp);
                    304:                        real_to_real(&tmp,&ST(code & 7));
                    305:                        fpop();
                    306:                        return;
                    307:                case 0xf8:
                    308:                        printk("ffree not implemented\n\r");
1.1.1.3   root      309:                        math_abort(info,SIGILL);
1.1       root      310:                        fpop();
                    311:                        return;
                    312:                case 0xf9:
                    313:                        fxchg(&ST(0),&ST(code & 7));
                    314:                        return;
                    315:                case 0xfa:
                    316:                case 0xfb:
                    317:                        ST(code & 7) = ST(0);
                    318:                        fpop();
                    319:                        return;
                    320:        }
                    321:        switch ((code>>3) & 0xe7) {
                    322:                case 0x22:
                    323:                        put_short_real(PST(0),info,code);
                    324:                        return;
                    325:                case 0x23:
                    326:                        put_short_real(PST(0),info,code);
                    327:                        fpop();
                    328:                        return;
                    329:                case 0x24:
                    330:                        address = ea(info,code);
                    331:                        for (code = 0 ; code < 7 ; code++) {
                    332:                                ((long *) & I387)[code] =
                    333:                                   get_fs_long((unsigned long *) address);
                    334:                                address += 4;
                    335:                        }
                    336:                        return;
                    337:                case 0x25:
                    338:                        address = ea(info,code);
                    339:                        *(unsigned short *) &I387.cwd =
                    340:                                get_fs_word((unsigned short *) address);
                    341:                        return;
                    342:                case 0x26:
                    343:                        address = ea(info,code);
                    344:                        verify_area(address,28);
                    345:                        for (code = 0 ; code < 7 ; code++) {
                    346:                                put_fs_long( ((long *) & I387)[code],
                    347:                                        (unsigned long *) address);
                    348:                                address += 4;
                    349:                        }
                    350:                        return;
                    351:                case 0x27:
                    352:                        address = ea(info,code);
                    353:                        verify_area(address,2);
                    354:                        put_fs_word(I387.cwd,(short *) address);
                    355:                        return;
                    356:                case 0x62:
                    357:                        put_long_int(PST(0),info,code);
                    358:                        return;
                    359:                case 0x63:
                    360:                        put_long_int(PST(0),info,code);
                    361:                        fpop();
                    362:                        return;
                    363:                case 0x65:
                    364:                        fpush();
                    365:                        get_temp_real(&tmp,info,code);
                    366:                        real_to_real(&tmp,&ST(0));
                    367:                        return;
                    368:                case 0x67:
                    369:                        put_temp_real(PST(0),info,code);
                    370:                        fpop();
                    371:                        return;
                    372:                case 0xa2:
                    373:                        put_long_real(PST(0),info,code);
                    374:                        return;
                    375:                case 0xa3:
                    376:                        put_long_real(PST(0),info,code);
                    377:                        fpop();
                    378:                        return;
                    379:                case 0xa4:
                    380:                        address = ea(info,code);
                    381:                        for (code = 0 ; code < 27 ; code++) {
                    382:                                ((long *) & I387)[code] =
                    383:                                   get_fs_long((unsigned long *) address);
                    384:                                address += 4;
                    385:                        }
                    386:                        return;
                    387:                case 0xa6:
                    388:                        address = ea(info,code);
                    389:                        verify_area(address,108);
                    390:                        for (code = 0 ; code < 27 ; code++) {
                    391:                                put_fs_long( ((long *) & I387)[code],
                    392:                                        (unsigned long *) address);
                    393:                                address += 4;
                    394:                        }
                    395:                        I387.cwd = 0x037f;
                    396:                        I387.swd = 0x0000;
                    397:                        I387.twd = 0x0000;
                    398:                        return;
                    399:                case 0xa7:
                    400:                        address = ea(info,code);
                    401:                        verify_area(address,2);
                    402:                        put_fs_word(I387.swd,(short *) address);
                    403:                        return;
                    404:                case 0xe2:
                    405:                        put_short_int(PST(0),info,code);
                    406:                        return;
                    407:                case 0xe3:
                    408:                        put_short_int(PST(0),info,code);
                    409:                        fpop();
                    410:                        return;
                    411:                case 0xe4:
                    412:                        fpush();
                    413:                        get_BCD(&tmp,info,code);
                    414:                        real_to_real(&tmp,&ST(0));
                    415:                        return;
                    416:                case 0xe5:
                    417:                        fpush();
                    418:                        get_longlong_int(&tmp,info,code);
                    419:                        real_to_real(&tmp,&ST(0));
                    420:                        return;
                    421:                case 0xe6:
                    422:                        put_BCD(PST(0),info,code);
                    423:                        fpop();
                    424:                        return;
                    425:                case 0xe7:
                    426:                        put_longlong_int(PST(0),info,code);
                    427:                        fpop();
                    428:                        return;
                    429:        }
                    430:        switch (code >> 9) {
                    431:                case 0:
                    432:                        get_short_real(&tmp,info,code);
                    433:                        break;
                    434:                case 1:
                    435:                        get_long_int(&tmp,info,code);
                    436:                        break;
                    437:                case 2:
                    438:                        get_long_real(&tmp,info,code);
                    439:                        break;
                    440:                case 4:
                    441:                        get_short_int(&tmp,info,code);
                    442:        }
                    443:        switch ((code>>3) & 0x27) {
                    444:                case 0:
                    445:                        fadd(&tmp,PST(0),&tmp);
                    446:                        real_to_real(&tmp,&ST(0));
                    447:                        return;
                    448:                case 1:
                    449:                        fmul(&tmp,PST(0),&tmp);
                    450:                        real_to_real(&tmp,&ST(0));
                    451:                        return;
                    452:                case 2:
                    453:                        fcom(&tmp,PST(0));
                    454:                        return;
                    455:                case 3:
                    456:                        fcom(&tmp,PST(0));
                    457:                        fpop();
                    458:                        return;
                    459:                case 4:
                    460:                        tmp.exponent ^= 0x8000;
                    461:                        fadd(&tmp,PST(0),&tmp);
                    462:                        real_to_real(&tmp,&ST(0));
                    463:                        return;
                    464:                case 5:
                    465:                        ST(0).exponent ^= 0x8000;
                    466:                        fadd(&tmp,PST(0),&tmp);
                    467:                        real_to_real(&tmp,&ST(0));
                    468:                        return;
                    469:                case 6:
                    470:                        fdiv(PST(0),&tmp,&tmp);
                    471:                        real_to_real(&tmp,&ST(0));
                    472:                        return;
                    473:                case 7:
                    474:                        fdiv(&tmp,PST(0),&tmp);
                    475:                        real_to_real(&tmp,&ST(0));
                    476:                        return;
                    477:        }
                    478:        if ((code & 0x138) == 0x100) {
                    479:                        fpush();
                    480:                        real_to_real(&tmp,&ST(0));
                    481:                        return;
                    482:        }
                    483:        printk("Unknown math-insns: %04x:%08x %04x\n\r",CS,EIP,code);
1.1.1.3   root      484:        math_abort(info,SIGFPE);
1.1       root      485: }
                    486: 
                    487: void math_emulate(long ___false)
                    488: {
                    489:        if (!current->used_math) {
                    490:                current->used_math = 1;
                    491:                I387.cwd = 0x037f;
                    492:                I387.swd = 0x0000;
                    493:                I387.twd = 0x0000;
                    494:        }
                    495:        do_emu((struct info *) &___false);
                    496: }
                    497: 
                    498: void __math_abort(struct info * info, unsigned int signal)
                    499: {
                    500:        EIP = ORIG_EIP;
1.1.1.3   root      501:        send_sig(signal,current,1);
1.1       root      502:        __asm__("movl %0,%%esp ; ret"::"g" (((long) info)-4));
                    503: }
                    504: 
                    505: static void fpop(void)
                    506: {
                    507:        unsigned long tmp;
                    508: 
                    509:        tmp = I387.swd & 0xffffc7ff;
                    510:        I387.swd += 0x00000800;
                    511:        I387.swd &= 0x00003800;
                    512:        I387.swd |= tmp;
                    513: }
                    514: 
                    515: static void fpush(void)
                    516: {
                    517:        unsigned long tmp;
                    518: 
                    519:        tmp = I387.swd & 0xffffc7ff;
                    520:        I387.swd += 0x00003800;
                    521:        I387.swd &= 0x00003800;
                    522:        I387.swd |= tmp;
                    523: }
                    524: 
                    525: static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b)
                    526: {
                    527:        temp_real_unaligned c;
                    528: 
                    529:        c = *a;
                    530:        *a = *b;
                    531:        *b = c;
                    532: }
                    533: 
                    534: static temp_real_unaligned * __st(int i)
                    535: {
                    536:        i += I387.swd >> 11;
                    537:        i &= 7;
                    538:        return (temp_real_unaligned *) (i*10 + (char *)(I387.st_space));
                    539: }
                    540: 
                    541: #else /* no math emulation */
                    542: 
1.1.1.4   root      543: #include <linux/signal.h>
1.1       root      544: #include <linux/sched.h>
                    545: 
                    546: void math_emulate(long ___false)
                    547: {
1.1.1.3   root      548:        send_sig(SIGFPE,current,1);
1.1       root      549:        schedule();
                    550: }
                    551: 
                    552: #endif /* KERNEL_MATH_EMULATION */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.