root/kernel/math/emulate.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. do_emu
  2. math_emulate
  3. __math_abort
  4. fpop
  5. fpush
  6. fxchg
  7. __st
  8. math_emulate

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

/* [previous][next][first][last][top][bottom][index][help] */