Annotation of linux/kernel/math/math_emulate.c, revision 1.1.1.2

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

unix.superglobalmegacorp.com