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 /* We cannot handle emulation in v86-mode */
  66         if (EFLAGS & 0x00020000)
  67                 math_abort(info,SIGILL);
  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:
  85                         math_abort(info,SIGILL);
  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:
  93                         math_abort(info,SIGILL);
  94                 case 0x1e4:
  95                         ftst(PST(0));
  96                         return;
  97                 case 0x1e5:
  98                         printk("fxam not implemented\n\r");
  99                         math_abort(info,SIGILL);
 100                 case 0x1e6: case 0x1e7:
 101                         math_abort(info,SIGILL);
 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:
 131                         math_abort(info,SIGILL);
 132                 case 0x1fa:
 133                         fsqrt(PST(0),&tmp);
 134                         real_to_real(&tmp,&ST(0));
 135                         return;
 136                 case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3:
 137                 case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7:
 138                 case 0x1f8: case 0x1f9: case 0x1fb: case 0x1fd:
 139                 case 0x1fe: case 0x1ff:
 140                         printk("%04x fxxx not implemented\n\r",code + 0xd800);
 141                         math_abort(info,SIGILL);
 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");
 252                         math_abort(info,SIGILL);
 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");
 309                         math_abort(info,SIGILL);
 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);
 484         math_abort(info,SIGFPE);
 485 }
 486 
 487 void math_emulate(long ___false)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 499 {
 500         EIP = ORIG_EIP;
 501         send_sig(signal,current,1);
 502         __asm__("movl %0,%%esp ; ret"::"g" (((long) info)-4));
 503 }
 504 
 505 static void fpop(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 
 543 #include <linux/signal.h>
 544 #include <linux/sched.h>
 545 
 546 void math_emulate(long ___false)
     /* [previous][next][first][last][top][bottom][index][help] */
 547 {
 548         send_sig(SIGFPE,current,1);
 549         schedule();
 550 }
 551 
 552 #endif /* KERNEL_MATH_EMULATION */

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