|
|
1.1 ! root 1: /* ! 2: * x86 CPU test ! 3: * ! 4: * Copyright (c) 2003 Fabrice Bellard ! 5: * ! 6: * This program is free software; you can redistribute it and/or modify ! 7: * it under the terms of the GNU General Public License as published by ! 8: * the Free Software Foundation; either version 2 of the License, or ! 9: * (at your option) any later version. ! 10: * ! 11: * This program is distributed in the hope that it will be useful, ! 12: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 14: * GNU General Public License for more details. ! 15: * ! 16: * You should have received a copy of the GNU General Public License ! 17: * along with this program; if not, write to the Free Software ! 18: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 19: */ ! 20: #define _GNU_SOURCE ! 21: #include <stdlib.h> ! 22: #include <stdio.h> ! 23: #include <string.h> ! 24: #include <inttypes.h> ! 25: #include <math.h> ! 26: #include <signal.h> ! 27: #include <setjmp.h> ! 28: #include <errno.h> ! 29: #include <sys/ucontext.h> ! 30: #include <sys/mman.h> ! 31: ! 32: #if !defined(__x86_64__) ! 33: #define TEST_VM86 ! 34: #define TEST_SEGS ! 35: #endif ! 36: //#define LINUX_VM86_IOPL_FIX ! 37: //#define TEST_P4_FLAGS ! 38: #if defined(__x86_64__) ! 39: #define TEST_SSE ! 40: #define TEST_CMOV 1 ! 41: #define TEST_FCOMI 1 ! 42: #else ! 43: //#define TEST_SSE ! 44: #define TEST_CMOV 0 ! 45: #define TEST_FCOMI 0 ! 46: #endif ! 47: ! 48: #if defined(__x86_64__) ! 49: #define FMT64X "%016lx" ! 50: #define FMTLX "%016lx" ! 51: #define X86_64_ONLY(x) x ! 52: #else ! 53: #define FMT64X "%016llx" ! 54: #define FMTLX "%08lx" ! 55: #define X86_64_ONLY(x) ! 56: #endif ! 57: ! 58: #ifdef TEST_VM86 ! 59: #include <asm/vm86.h> ! 60: #endif ! 61: ! 62: #define xglue(x, y) x ## y ! 63: #define glue(x, y) xglue(x, y) ! 64: #define stringify(s) tostring(s) ! 65: #define tostring(s) #s ! 66: ! 67: #define CC_C 0x0001 ! 68: #define CC_P 0x0004 ! 69: #define CC_A 0x0010 ! 70: #define CC_Z 0x0040 ! 71: #define CC_S 0x0080 ! 72: #define CC_O 0x0800 ! 73: ! 74: #define __init_call __attribute__ ((unused,__section__ ("initcall"))) ! 75: ! 76: #define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A) ! 77: ! 78: #if defined(__x86_64__) ! 79: static inline long i2l(long v) ! 80: { ! 81: return v | ((v ^ 0xabcd) << 32); ! 82: } ! 83: #else ! 84: static inline long i2l(long v) ! 85: { ! 86: return v; ! 87: } ! 88: #endif ! 89: ! 90: #define OP add ! 91: #include "test-i386.h" ! 92: ! 93: #define OP sub ! 94: #include "test-i386.h" ! 95: ! 96: #define OP xor ! 97: #include "test-i386.h" ! 98: ! 99: #define OP and ! 100: #include "test-i386.h" ! 101: ! 102: #define OP or ! 103: #include "test-i386.h" ! 104: ! 105: #define OP cmp ! 106: #include "test-i386.h" ! 107: ! 108: #define OP adc ! 109: #define OP_CC ! 110: #include "test-i386.h" ! 111: ! 112: #define OP sbb ! 113: #define OP_CC ! 114: #include "test-i386.h" ! 115: ! 116: #define OP inc ! 117: #define OP_CC ! 118: #define OP1 ! 119: #include "test-i386.h" ! 120: ! 121: #define OP dec ! 122: #define OP_CC ! 123: #define OP1 ! 124: #include "test-i386.h" ! 125: ! 126: #define OP neg ! 127: #define OP_CC ! 128: #define OP1 ! 129: #include "test-i386.h" ! 130: ! 131: #define OP not ! 132: #define OP_CC ! 133: #define OP1 ! 134: #include "test-i386.h" ! 135: ! 136: #undef CC_MASK ! 137: #define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O) ! 138: ! 139: #define OP shl ! 140: #include "test-i386-shift.h" ! 141: ! 142: #define OP shr ! 143: #include "test-i386-shift.h" ! 144: ! 145: #define OP sar ! 146: #include "test-i386-shift.h" ! 147: ! 148: #define OP rol ! 149: #include "test-i386-shift.h" ! 150: ! 151: #define OP ror ! 152: #include "test-i386-shift.h" ! 153: ! 154: #define OP rcr ! 155: #define OP_CC ! 156: #include "test-i386-shift.h" ! 157: ! 158: #define OP rcl ! 159: #define OP_CC ! 160: #include "test-i386-shift.h" ! 161: ! 162: #define OP shld ! 163: #define OP_SHIFTD ! 164: #define OP_NOBYTE ! 165: #include "test-i386-shift.h" ! 166: ! 167: #define OP shrd ! 168: #define OP_SHIFTD ! 169: #define OP_NOBYTE ! 170: #include "test-i386-shift.h" ! 171: ! 172: /* XXX: should be more precise ? */ ! 173: #undef CC_MASK ! 174: #define CC_MASK (CC_C) ! 175: ! 176: #define OP bt ! 177: #define OP_NOBYTE ! 178: #include "test-i386-shift.h" ! 179: ! 180: #define OP bts ! 181: #define OP_NOBYTE ! 182: #include "test-i386-shift.h" ! 183: ! 184: #define OP btr ! 185: #define OP_NOBYTE ! 186: #include "test-i386-shift.h" ! 187: ! 188: #define OP btc ! 189: #define OP_NOBYTE ! 190: #include "test-i386-shift.h" ! 191: ! 192: /* lea test (modrm support) */ ! 193: #define TEST_LEAQ(STR)\ ! 194: {\ ! 195: asm("lea " STR ", %0"\ ! 196: : "=r" (res)\ ! 197: : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\ ! 198: printf("lea %s = " FMTLX "\n", STR, res);\ ! 199: } ! 200: ! 201: #define TEST_LEA(STR)\ ! 202: {\ ! 203: asm("lea " STR ", %0"\ ! 204: : "=r" (res)\ ! 205: : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\ ! 206: printf("lea %s = " FMTLX "\n", STR, res);\ ! 207: } ! 208: ! 209: #define TEST_LEA16(STR)\ ! 210: {\ ! 211: asm(".code16 ; .byte 0x67 ; leal " STR ", %0 ; .code32"\ ! 212: : "=wq" (res)\ ! 213: : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\ ! 214: printf("lea %s = %08lx\n", STR, res);\ ! 215: } ! 216: ! 217: ! 218: void test_lea(void) ! 219: { ! 220: long eax, ebx, ecx, edx, esi, edi, res; ! 221: eax = i2l(0x0001); ! 222: ebx = i2l(0x0002); ! 223: ecx = i2l(0x0004); ! 224: edx = i2l(0x0008); ! 225: esi = i2l(0x0010); ! 226: edi = i2l(0x0020); ! 227: ! 228: TEST_LEA("0x4000"); ! 229: ! 230: TEST_LEA("(%%eax)"); ! 231: TEST_LEA("(%%ebx)"); ! 232: TEST_LEA("(%%ecx)"); ! 233: TEST_LEA("(%%edx)"); ! 234: TEST_LEA("(%%esi)"); ! 235: TEST_LEA("(%%edi)"); ! 236: ! 237: TEST_LEA("0x40(%%eax)"); ! 238: TEST_LEA("0x40(%%ebx)"); ! 239: TEST_LEA("0x40(%%ecx)"); ! 240: TEST_LEA("0x40(%%edx)"); ! 241: TEST_LEA("0x40(%%esi)"); ! 242: TEST_LEA("0x40(%%edi)"); ! 243: ! 244: TEST_LEA("0x4000(%%eax)"); ! 245: TEST_LEA("0x4000(%%ebx)"); ! 246: TEST_LEA("0x4000(%%ecx)"); ! 247: TEST_LEA("0x4000(%%edx)"); ! 248: TEST_LEA("0x4000(%%esi)"); ! 249: TEST_LEA("0x4000(%%edi)"); ! 250: ! 251: TEST_LEA("(%%eax, %%ecx)"); ! 252: TEST_LEA("(%%ebx, %%edx)"); ! 253: TEST_LEA("(%%ecx, %%ecx)"); ! 254: TEST_LEA("(%%edx, %%ecx)"); ! 255: TEST_LEA("(%%esi, %%ecx)"); ! 256: TEST_LEA("(%%edi, %%ecx)"); ! 257: ! 258: TEST_LEA("0x40(%%eax, %%ecx)"); ! 259: TEST_LEA("0x4000(%%ebx, %%edx)"); ! 260: ! 261: TEST_LEA("(%%ecx, %%ecx, 2)"); ! 262: TEST_LEA("(%%edx, %%ecx, 4)"); ! 263: TEST_LEA("(%%esi, %%ecx, 8)"); ! 264: ! 265: TEST_LEA("(,%%eax, 2)"); ! 266: TEST_LEA("(,%%ebx, 4)"); ! 267: TEST_LEA("(,%%ecx, 8)"); ! 268: ! 269: TEST_LEA("0x40(,%%eax, 2)"); ! 270: TEST_LEA("0x40(,%%ebx, 4)"); ! 271: TEST_LEA("0x40(,%%ecx, 8)"); ! 272: ! 273: ! 274: TEST_LEA("-10(%%ecx, %%ecx, 2)"); ! 275: TEST_LEA("-10(%%edx, %%ecx, 4)"); ! 276: TEST_LEA("-10(%%esi, %%ecx, 8)"); ! 277: ! 278: TEST_LEA("0x4000(%%ecx, %%ecx, 2)"); ! 279: TEST_LEA("0x4000(%%edx, %%ecx, 4)"); ! 280: TEST_LEA("0x4000(%%esi, %%ecx, 8)"); ! 281: ! 282: #if defined(__x86_64__) ! 283: TEST_LEAQ("0x4000"); ! 284: TEST_LEAQ("0x4000(%%rip)"); ! 285: ! 286: TEST_LEAQ("(%%rax)"); ! 287: TEST_LEAQ("(%%rbx)"); ! 288: TEST_LEAQ("(%%rcx)"); ! 289: TEST_LEAQ("(%%rdx)"); ! 290: TEST_LEAQ("(%%rsi)"); ! 291: TEST_LEAQ("(%%rdi)"); ! 292: ! 293: TEST_LEAQ("0x40(%%rax)"); ! 294: TEST_LEAQ("0x40(%%rbx)"); ! 295: TEST_LEAQ("0x40(%%rcx)"); ! 296: TEST_LEAQ("0x40(%%rdx)"); ! 297: TEST_LEAQ("0x40(%%rsi)"); ! 298: TEST_LEAQ("0x40(%%rdi)"); ! 299: ! 300: TEST_LEAQ("0x4000(%%rax)"); ! 301: TEST_LEAQ("0x4000(%%rbx)"); ! 302: TEST_LEAQ("0x4000(%%rcx)"); ! 303: TEST_LEAQ("0x4000(%%rdx)"); ! 304: TEST_LEAQ("0x4000(%%rsi)"); ! 305: TEST_LEAQ("0x4000(%%rdi)"); ! 306: ! 307: TEST_LEAQ("(%%rax, %%rcx)"); ! 308: TEST_LEAQ("(%%rbx, %%rdx)"); ! 309: TEST_LEAQ("(%%rcx, %%rcx)"); ! 310: TEST_LEAQ("(%%rdx, %%rcx)"); ! 311: TEST_LEAQ("(%%rsi, %%rcx)"); ! 312: TEST_LEAQ("(%%rdi, %%rcx)"); ! 313: ! 314: TEST_LEAQ("0x40(%%rax, %%rcx)"); ! 315: TEST_LEAQ("0x4000(%%rbx, %%rdx)"); ! 316: ! 317: TEST_LEAQ("(%%rcx, %%rcx, 2)"); ! 318: TEST_LEAQ("(%%rdx, %%rcx, 4)"); ! 319: TEST_LEAQ("(%%rsi, %%rcx, 8)"); ! 320: ! 321: TEST_LEAQ("(,%%rax, 2)"); ! 322: TEST_LEAQ("(,%%rbx, 4)"); ! 323: TEST_LEAQ("(,%%rcx, 8)"); ! 324: ! 325: TEST_LEAQ("0x40(,%%rax, 2)"); ! 326: TEST_LEAQ("0x40(,%%rbx, 4)"); ! 327: TEST_LEAQ("0x40(,%%rcx, 8)"); ! 328: ! 329: ! 330: TEST_LEAQ("-10(%%rcx, %%rcx, 2)"); ! 331: TEST_LEAQ("-10(%%rdx, %%rcx, 4)"); ! 332: TEST_LEAQ("-10(%%rsi, %%rcx, 8)"); ! 333: ! 334: TEST_LEAQ("0x4000(%%rcx, %%rcx, 2)"); ! 335: TEST_LEAQ("0x4000(%%rdx, %%rcx, 4)"); ! 336: TEST_LEAQ("0x4000(%%rsi, %%rcx, 8)"); ! 337: #else ! 338: /* limited 16 bit addressing test */ ! 339: TEST_LEA16("0x4000"); ! 340: TEST_LEA16("(%%bx)"); ! 341: TEST_LEA16("(%%si)"); ! 342: TEST_LEA16("(%%di)"); ! 343: TEST_LEA16("0x40(%%bx)"); ! 344: TEST_LEA16("0x40(%%si)"); ! 345: TEST_LEA16("0x40(%%di)"); ! 346: TEST_LEA16("0x4000(%%bx)"); ! 347: TEST_LEA16("0x4000(%%si)"); ! 348: TEST_LEA16("(%%bx,%%si)"); ! 349: TEST_LEA16("(%%bx,%%di)"); ! 350: TEST_LEA16("0x40(%%bx,%%si)"); ! 351: TEST_LEA16("0x40(%%bx,%%di)"); ! 352: TEST_LEA16("0x4000(%%bx,%%si)"); ! 353: TEST_LEA16("0x4000(%%bx,%%di)"); ! 354: #endif ! 355: } ! 356: ! 357: #define TEST_JCC(JCC, v1, v2)\ ! 358: {\ ! 359: int res;\ ! 360: asm("movl $1, %0\n\t"\ ! 361: "cmpl %2, %1\n\t"\ ! 362: "j" JCC " 1f\n\t"\ ! 363: "movl $0, %0\n\t"\ ! 364: "1:\n\t"\ ! 365: : "=r" (res)\ ! 366: : "r" (v1), "r" (v2));\ ! 367: printf("%-10s %d\n", "j" JCC, res);\ ! 368: \ ! 369: asm("movl $0, %0\n\t"\ ! 370: "cmpl %2, %1\n\t"\ ! 371: "set" JCC " %b0\n\t"\ ! 372: : "=r" (res)\ ! 373: : "r" (v1), "r" (v2));\ ! 374: printf("%-10s %d\n", "set" JCC, res);\ ! 375: if (TEST_CMOV) {\ ! 376: long val = i2l(1);\ ! 377: long res = i2l(0x12345678);\ ! 378: X86_64_ONLY(\ ! 379: asm("cmpl %2, %1\n\t"\ ! 380: "cmov" JCC "q %3, %0\n\t"\ ! 381: : "=r" (res)\ ! 382: : "r" (v1), "r" (v2), "m" (val), "0" (res));\ ! 383: printf("%-10s R=" FMTLX "\n", "cmov" JCC "q", res);)\ ! 384: asm("cmpl %2, %1\n\t"\ ! 385: "cmov" JCC "l %k3, %k0\n\t"\ ! 386: : "=r" (res)\ ! 387: : "r" (v1), "r" (v2), "m" (val), "0" (res));\ ! 388: printf("%-10s R=" FMTLX "\n", "cmov" JCC "l", res);\ ! 389: asm("cmpl %2, %1\n\t"\ ! 390: "cmov" JCC "w %w3, %w0\n\t"\ ! 391: : "=r" (res)\ ! 392: : "r" (v1), "r" (v2), "r" (1), "0" (res));\ ! 393: printf("%-10s R=" FMTLX "\n", "cmov" JCC "w", res);\ ! 394: } \ ! 395: } ! 396: ! 397: /* various jump tests */ ! 398: void test_jcc(void) ! 399: { ! 400: TEST_JCC("ne", 1, 1); ! 401: TEST_JCC("ne", 1, 0); ! 402: ! 403: TEST_JCC("e", 1, 1); ! 404: TEST_JCC("e", 1, 0); ! 405: ! 406: TEST_JCC("l", 1, 1); ! 407: TEST_JCC("l", 1, 0); ! 408: TEST_JCC("l", 1, -1); ! 409: ! 410: TEST_JCC("le", 1, 1); ! 411: TEST_JCC("le", 1, 0); ! 412: TEST_JCC("le", 1, -1); ! 413: ! 414: TEST_JCC("ge", 1, 1); ! 415: TEST_JCC("ge", 1, 0); ! 416: TEST_JCC("ge", -1, 1); ! 417: ! 418: TEST_JCC("g", 1, 1); ! 419: TEST_JCC("g", 1, 0); ! 420: TEST_JCC("g", 1, -1); ! 421: ! 422: TEST_JCC("b", 1, 1); ! 423: TEST_JCC("b", 1, 0); ! 424: TEST_JCC("b", 1, -1); ! 425: ! 426: TEST_JCC("be", 1, 1); ! 427: TEST_JCC("be", 1, 0); ! 428: TEST_JCC("be", 1, -1); ! 429: ! 430: TEST_JCC("ae", 1, 1); ! 431: TEST_JCC("ae", 1, 0); ! 432: TEST_JCC("ae", 1, -1); ! 433: ! 434: TEST_JCC("a", 1, 1); ! 435: TEST_JCC("a", 1, 0); ! 436: TEST_JCC("a", 1, -1); ! 437: ! 438: ! 439: TEST_JCC("p", 1, 1); ! 440: TEST_JCC("p", 1, 0); ! 441: ! 442: TEST_JCC("np", 1, 1); ! 443: TEST_JCC("np", 1, 0); ! 444: ! 445: TEST_JCC("o", 0x7fffffff, 0); ! 446: TEST_JCC("o", 0x7fffffff, -1); ! 447: ! 448: TEST_JCC("no", 0x7fffffff, 0); ! 449: TEST_JCC("no", 0x7fffffff, -1); ! 450: ! 451: TEST_JCC("s", 0, 1); ! 452: TEST_JCC("s", 0, -1); ! 453: TEST_JCC("s", 0, 0); ! 454: ! 455: TEST_JCC("ns", 0, 1); ! 456: TEST_JCC("ns", 0, -1); ! 457: TEST_JCC("ns", 0, 0); ! 458: } ! 459: ! 460: #undef CC_MASK ! 461: #ifdef TEST_P4_FLAGS ! 462: #define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A) ! 463: #else ! 464: #define CC_MASK (CC_O | CC_C) ! 465: #endif ! 466: ! 467: #define OP mul ! 468: #include "test-i386-muldiv.h" ! 469: ! 470: #define OP imul ! 471: #include "test-i386-muldiv.h" ! 472: ! 473: void test_imulw2(long op0, long op1) ! 474: { ! 475: long res, s1, s0, flags; ! 476: s0 = op0; ! 477: s1 = op1; ! 478: res = s0; ! 479: flags = 0; ! 480: asm volatile ("push %4\n\t" ! 481: "popf\n\t" ! 482: "imulw %w2, %w0\n\t" ! 483: "pushf\n\t" ! 484: "pop %1\n\t" ! 485: : "=q" (res), "=g" (flags) ! 486: : "q" (s1), "0" (res), "1" (flags)); ! 487: printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n", ! 488: "imulw", s0, s1, res, flags & CC_MASK); ! 489: } ! 490: ! 491: void test_imull2(long op0, long op1) ! 492: { ! 493: long res, s1, s0, flags; ! 494: s0 = op0; ! 495: s1 = op1; ! 496: res = s0; ! 497: flags = 0; ! 498: asm volatile ("push %4\n\t" ! 499: "popf\n\t" ! 500: "imull %k2, %k0\n\t" ! 501: "pushf\n\t" ! 502: "pop %1\n\t" ! 503: : "=q" (res), "=g" (flags) ! 504: : "q" (s1), "0" (res), "1" (flags)); ! 505: printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n", ! 506: "imull", s0, s1, res, flags & CC_MASK); ! 507: } ! 508: ! 509: #if defined(__x86_64__) ! 510: void test_imulq2(long op0, long op1) ! 511: { ! 512: long res, s1, s0, flags; ! 513: s0 = op0; ! 514: s1 = op1; ! 515: res = s0; ! 516: flags = 0; ! 517: asm volatile ("push %4\n\t" ! 518: "popf\n\t" ! 519: "imulq %2, %0\n\t" ! 520: "pushf\n\t" ! 521: "pop %1\n\t" ! 522: : "=q" (res), "=g" (flags) ! 523: : "q" (s1), "0" (res), "1" (flags)); ! 524: printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n", ! 525: "imulq", s0, s1, res, flags & CC_MASK); ! 526: } ! 527: #endif ! 528: ! 529: #define TEST_IMUL_IM(size, rsize, op0, op1)\ ! 530: {\ ! 531: long res, flags, s1;\ ! 532: flags = 0;\ ! 533: res = 0;\ ! 534: s1 = op1;\ ! 535: asm volatile ("push %3\n\t"\ ! 536: "popf\n\t"\ ! 537: "imul" size " $" #op0 ", %" rsize "2, %" rsize "0\n\t" \ ! 538: "pushf\n\t"\ ! 539: "pop %1\n\t"\ ! 540: : "=r" (res), "=g" (flags)\ ! 541: : "r" (s1), "1" (flags), "0" (res));\ ! 542: printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n",\ ! 543: "imul" size " im", (long)op0, (long)op1, res, flags & CC_MASK);\ ! 544: } ! 545: ! 546: ! 547: #undef CC_MASK ! 548: #define CC_MASK (0) ! 549: ! 550: #define OP div ! 551: #include "test-i386-muldiv.h" ! 552: ! 553: #define OP idiv ! 554: #include "test-i386-muldiv.h" ! 555: ! 556: void test_mul(void) ! 557: { ! 558: test_imulb(0x1234561d, 4); ! 559: test_imulb(3, -4); ! 560: test_imulb(0x80, 0x80); ! 561: test_imulb(0x10, 0x10); ! 562: ! 563: test_imulw(0, 0x1234001d, 45); ! 564: test_imulw(0, 23, -45); ! 565: test_imulw(0, 0x8000, 0x8000); ! 566: test_imulw(0, 0x100, 0x100); ! 567: ! 568: test_imull(0, 0x1234001d, 45); ! 569: test_imull(0, 23, -45); ! 570: test_imull(0, 0x80000000, 0x80000000); ! 571: test_imull(0, 0x10000, 0x10000); ! 572: ! 573: test_mulb(0x1234561d, 4); ! 574: test_mulb(3, -4); ! 575: test_mulb(0x80, 0x80); ! 576: test_mulb(0x10, 0x10); ! 577: ! 578: test_mulw(0, 0x1234001d, 45); ! 579: test_mulw(0, 23, -45); ! 580: test_mulw(0, 0x8000, 0x8000); ! 581: test_mulw(0, 0x100, 0x100); ! 582: ! 583: test_mull(0, 0x1234001d, 45); ! 584: test_mull(0, 23, -45); ! 585: test_mull(0, 0x80000000, 0x80000000); ! 586: test_mull(0, 0x10000, 0x10000); ! 587: ! 588: test_imulw2(0x1234001d, 45); ! 589: test_imulw2(23, -45); ! 590: test_imulw2(0x8000, 0x8000); ! 591: test_imulw2(0x100, 0x100); ! 592: ! 593: test_imull2(0x1234001d, 45); ! 594: test_imull2(23, -45); ! 595: test_imull2(0x80000000, 0x80000000); ! 596: test_imull2(0x10000, 0x10000); ! 597: ! 598: TEST_IMUL_IM("w", "w", 45, 0x1234); ! 599: TEST_IMUL_IM("w", "w", -45, 23); ! 600: TEST_IMUL_IM("w", "w", 0x8000, 0x80000000); ! 601: TEST_IMUL_IM("w", "w", 0x7fff, 0x1000); ! 602: ! 603: TEST_IMUL_IM("l", "k", 45, 0x1234); ! 604: TEST_IMUL_IM("l", "k", -45, 23); ! 605: TEST_IMUL_IM("l", "k", 0x8000, 0x80000000); ! 606: TEST_IMUL_IM("l", "k", 0x7fff, 0x1000); ! 607: ! 608: test_idivb(0x12341678, 0x127e); ! 609: test_idivb(0x43210123, -5); ! 610: test_idivb(0x12340004, -1); ! 611: ! 612: test_idivw(0, 0x12345678, 12347); ! 613: test_idivw(0, -23223, -45); ! 614: test_idivw(0, 0x12348000, -1); ! 615: test_idivw(0x12343, 0x12345678, 0x81238567); ! 616: ! 617: test_idivl(0, 0x12345678, 12347); ! 618: test_idivl(0, -233223, -45); ! 619: test_idivl(0, 0x80000000, -1); ! 620: test_idivl(0x12343, 0x12345678, 0x81234567); ! 621: ! 622: test_divb(0x12341678, 0x127e); ! 623: test_divb(0x43210123, -5); ! 624: test_divb(0x12340004, -1); ! 625: ! 626: test_divw(0, 0x12345678, 12347); ! 627: test_divw(0, -23223, -45); ! 628: test_divw(0, 0x12348000, -1); ! 629: test_divw(0x12343, 0x12345678, 0x81238567); ! 630: ! 631: test_divl(0, 0x12345678, 12347); ! 632: test_divl(0, -233223, -45); ! 633: test_divl(0, 0x80000000, -1); ! 634: test_divl(0x12343, 0x12345678, 0x81234567); ! 635: ! 636: #if defined(__x86_64__) ! 637: test_imulq(0, 0x1234001d1234001d, 45); ! 638: test_imulq(0, 23, -45); ! 639: test_imulq(0, 0x8000000000000000, 0x8000000000000000); ! 640: test_imulq(0, 0x100000000, 0x100000000); ! 641: ! 642: test_mulq(0, 0x1234001d1234001d, 45); ! 643: test_mulq(0, 23, -45); ! 644: test_mulq(0, 0x8000000000000000, 0x8000000000000000); ! 645: test_mulq(0, 0x100000000, 0x100000000); ! 646: ! 647: test_imulq2(0x1234001d1234001d, 45); ! 648: test_imulq2(23, -45); ! 649: test_imulq2(0x8000000000000000, 0x8000000000000000); ! 650: test_imulq2(0x100000000, 0x100000000); ! 651: ! 652: TEST_IMUL_IM("q", "", 45, 0x12341234); ! 653: TEST_IMUL_IM("q", "", -45, 23); ! 654: TEST_IMUL_IM("q", "", 0x8000, 0x8000000000000000); ! 655: TEST_IMUL_IM("q", "", 0x7fff, 0x10000000); ! 656: ! 657: test_idivq(0, 0x12345678abcdef, 12347); ! 658: test_idivq(0, -233223, -45); ! 659: test_idivq(0, 0x8000000000000000, -1); ! 660: test_idivq(0x12343, 0x12345678, 0x81234567); ! 661: ! 662: test_divq(0, 0x12345678abcdef, 12347); ! 663: test_divq(0, -233223, -45); ! 664: test_divq(0, 0x8000000000000000, -1); ! 665: test_divq(0x12343, 0x12345678, 0x81234567); ! 666: #endif ! 667: } ! 668: ! 669: #define TEST_BSX(op, size, op0)\ ! 670: {\ ! 671: long res, val, resz;\ ! 672: val = op0;\ ! 673: asm("xor %1, %1\n"\ ! 674: "mov $0x12345678, %0\n"\ ! 675: #op " %" size "2, %" size "0 ; setz %b1" \ ! 676: : "=r" (res), "=q" (resz)\ ! 677: : "g" (val));\ ! 678: printf("%-10s A=" FMTLX " R=" FMTLX " %ld\n", #op, val, res, resz);\ ! 679: } ! 680: ! 681: void test_bsx(void) ! 682: { ! 683: TEST_BSX(bsrw, "w", 0); ! 684: TEST_BSX(bsrw, "w", 0x12340128); ! 685: TEST_BSX(bsfw, "w", 0); ! 686: TEST_BSX(bsfw, "w", 0x12340128); ! 687: TEST_BSX(bsrl, "k", 0); ! 688: TEST_BSX(bsrl, "k", 0x00340128); ! 689: TEST_BSX(bsfl, "k", 0); ! 690: TEST_BSX(bsfl, "k", 0x00340128); ! 691: #if defined(__x86_64__) ! 692: TEST_BSX(bsrq, "", 0); ! 693: TEST_BSX(bsrq, "", 0x003401281234); ! 694: TEST_BSX(bsfq, "", 0); ! 695: TEST_BSX(bsfq, "", 0x003401281234); ! 696: #endif ! 697: } ! 698: ! 699: /**********************************************/ ! 700: ! 701: union float64u { ! 702: double d; ! 703: uint64_t l; ! 704: }; ! 705: ! 706: union float64u q_nan = { .l = 0xFFF8000000000000 }; ! 707: union float64u s_nan = { .l = 0xFFF0000000000000 }; ! 708: ! 709: void test_fops(double a, double b) ! 710: { ! 711: printf("a=%f b=%f a+b=%f\n", a, b, a + b); ! 712: printf("a=%f b=%f a-b=%f\n", a, b, a - b); ! 713: printf("a=%f b=%f a*b=%f\n", a, b, a * b); ! 714: printf("a=%f b=%f a/b=%f\n", a, b, a / b); ! 715: printf("a=%f b=%f fmod(a, b)=%f\n", a, b, fmod(a, b)); ! 716: printf("a=%f sqrt(a)=%f\n", a, sqrt(a)); ! 717: printf("a=%f sin(a)=%f\n", a, sin(a)); ! 718: printf("a=%f cos(a)=%f\n", a, cos(a)); ! 719: printf("a=%f tan(a)=%f\n", a, tan(a)); ! 720: printf("a=%f log(a)=%f\n", a, log(a)); ! 721: printf("a=%f exp(a)=%f\n", a, exp(a)); ! 722: printf("a=%f b=%f atan2(a, b)=%f\n", a, b, atan2(a, b)); ! 723: /* just to test some op combining */ ! 724: printf("a=%f asin(sin(a))=%f\n", a, asin(sin(a))); ! 725: printf("a=%f acos(cos(a))=%f\n", a, acos(cos(a))); ! 726: printf("a=%f atan(tan(a))=%f\n", a, atan(tan(a))); ! 727: ! 728: } ! 729: ! 730: void fpu_clear_exceptions(void) ! 731: { ! 732: struct __attribute__((packed)) { ! 733: uint16_t fpuc; ! 734: uint16_t dummy1; ! 735: uint16_t fpus; ! 736: uint16_t dummy2; ! 737: uint16_t fptag; ! 738: uint16_t dummy3; ! 739: uint32_t ignored[4]; ! 740: long double fpregs[8]; ! 741: } float_env32; ! 742: ! 743: asm volatile ("fnstenv %0\n" : : "m" (float_env32)); ! 744: float_env32.fpus &= ~0x7f; ! 745: asm volatile ("fldenv %0\n" : : "m" (float_env32)); ! 746: } ! 747: ! 748: /* XXX: display exception bits when supported */ ! 749: #define FPUS_EMASK 0x0000 ! 750: //#define FPUS_EMASK 0x007f ! 751: ! 752: void test_fcmp(double a, double b) ! 753: { ! 754: long eflags, fpus; ! 755: ! 756: fpu_clear_exceptions(); ! 757: asm("fcom %2\n" ! 758: "fstsw %%ax\n" ! 759: : "=a" (fpus) ! 760: : "t" (a), "u" (b)); ! 761: printf("fcom(%f %f)=%04lx \n", ! 762: a, b, fpus & (0x4500 | FPUS_EMASK)); ! 763: fpu_clear_exceptions(); ! 764: asm("fucom %2\n" ! 765: "fstsw %%ax\n" ! 766: : "=a" (fpus) ! 767: : "t" (a), "u" (b)); ! 768: printf("fucom(%f %f)=%04lx\n", ! 769: a, b, fpus & (0x4500 | FPUS_EMASK)); ! 770: if (TEST_FCOMI) { ! 771: /* test f(u)comi instruction */ ! 772: fpu_clear_exceptions(); ! 773: asm("fcomi %3, %2\n" ! 774: "fstsw %%ax\n" ! 775: "pushf\n" ! 776: "pop %0\n" ! 777: : "=r" (eflags), "=a" (fpus) ! 778: : "t" (a), "u" (b)); ! 779: printf("fcomi(%f %f)=%04lx %02lx\n", ! 780: a, b, fpus & FPUS_EMASK, eflags & (CC_Z | CC_P | CC_C)); ! 781: fpu_clear_exceptions(); ! 782: asm("fucomi %3, %2\n" ! 783: "fstsw %%ax\n" ! 784: "pushf\n" ! 785: "pop %0\n" ! 786: : "=r" (eflags), "=a" (fpus) ! 787: : "t" (a), "u" (b)); ! 788: printf("fucomi(%f %f)=%04lx %02lx\n", ! 789: a, b, fpus & FPUS_EMASK, eflags & (CC_Z | CC_P | CC_C)); ! 790: } ! 791: fpu_clear_exceptions(); ! 792: } ! 793: ! 794: void test_fcvt(double a) ! 795: { ! 796: float fa; ! 797: long double la; ! 798: int16_t fpuc; ! 799: int i; ! 800: int64_t lla; ! 801: int ia; ! 802: int16_t wa; ! 803: double ra; ! 804: ! 805: fa = a; ! 806: la = a; ! 807: printf("(float)%f = %f\n", a, fa); ! 808: printf("(long double)%f = %Lf\n", a, la); ! 809: printf("a=" FMT64X "\n", *(uint64_t *)&a); ! 810: printf("la=" FMT64X " %04x\n", *(uint64_t *)&la, ! 811: *(unsigned short *)((char *)(&la) + 8)); ! 812: ! 813: /* test all roundings */ ! 814: asm volatile ("fstcw %0" : "=m" (fpuc)); ! 815: for(i=0;i<4;i++) { ! 816: asm volatile ("fldcw %0" : : "m" ((fpuc & ~0x0c00) | (i << 10))); ! 817: asm volatile ("fist %0" : "=m" (wa) : "t" (a)); ! 818: asm volatile ("fistl %0" : "=m" (ia) : "t" (a)); ! 819: asm volatile ("fistpll %0" : "=m" (lla) : "t" (a) : "st"); ! 820: asm volatile ("frndint ; fstl %0" : "=m" (ra) : "t" (a)); ! 821: asm volatile ("fldcw %0" : : "m" (fpuc)); ! 822: printf("(short)a = %d\n", wa); ! 823: printf("(int)a = %d\n", ia); ! 824: printf("(int64_t)a = " FMT64X "\n", lla); ! 825: printf("rint(a) = %f\n", ra); ! 826: } ! 827: } ! 828: ! 829: #define TEST(N) \ ! 830: asm("fld" #N : "=t" (a)); \ ! 831: printf("fld" #N "= %f\n", a); ! 832: ! 833: void test_fconst(void) ! 834: { ! 835: double a; ! 836: TEST(1); ! 837: TEST(l2t); ! 838: TEST(l2e); ! 839: TEST(pi); ! 840: TEST(lg2); ! 841: TEST(ln2); ! 842: TEST(z); ! 843: } ! 844: ! 845: void test_fbcd(double a) ! 846: { ! 847: unsigned short bcd[5]; ! 848: double b; ! 849: ! 850: asm("fbstp %0" : "=m" (bcd[0]) : "t" (a) : "st"); ! 851: asm("fbld %1" : "=t" (b) : "m" (bcd[0])); ! 852: printf("a=%f bcd=%04x%04x%04x%04x%04x b=%f\n", ! 853: a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b); ! 854: } ! 855: ! 856: #define TEST_ENV(env, save, restore)\ ! 857: {\ ! 858: memset((env), 0xaa, sizeof(*(env)));\ ! 859: for(i=0;i<5;i++)\ ! 860: asm volatile ("fldl %0" : : "m" (dtab[i]));\ ! 861: asm volatile (save " %0\n" : : "m" (*(env)));\ ! 862: asm volatile (restore " %0\n": : "m" (*(env)));\ ! 863: for(i=0;i<5;i++)\ ! 864: asm volatile ("fstpl %0" : "=m" (rtab[i]));\ ! 865: for(i=0;i<5;i++)\ ! 866: printf("res[%d]=%f\n", i, rtab[i]);\ ! 867: printf("fpuc=%04x fpus=%04x fptag=%04x\n",\ ! 868: (env)->fpuc,\ ! 869: (env)->fpus & 0xff00,\ ! 870: (env)->fptag);\ ! 871: } ! 872: ! 873: void test_fenv(void) ! 874: { ! 875: struct __attribute__((packed)) { ! 876: uint16_t fpuc; ! 877: uint16_t dummy1; ! 878: uint16_t fpus; ! 879: uint16_t dummy2; ! 880: uint16_t fptag; ! 881: uint16_t dummy3; ! 882: uint32_t ignored[4]; ! 883: long double fpregs[8]; ! 884: } float_env32; ! 885: struct __attribute__((packed)) { ! 886: uint16_t fpuc; ! 887: uint16_t fpus; ! 888: uint16_t fptag; ! 889: uint16_t ignored[4]; ! 890: long double fpregs[8]; ! 891: } float_env16; ! 892: double dtab[8]; ! 893: double rtab[8]; ! 894: int i; ! 895: ! 896: for(i=0;i<8;i++) ! 897: dtab[i] = i + 1; ! 898: ! 899: TEST_ENV(&float_env16, "data16 fnstenv", "data16 fldenv"); ! 900: TEST_ENV(&float_env16, "data16 fnsave", "data16 frstor"); ! 901: TEST_ENV(&float_env32, "fnstenv", "fldenv"); ! 902: TEST_ENV(&float_env32, "fnsave", "frstor"); ! 903: ! 904: /* test for ffree */ ! 905: for(i=0;i<5;i++) ! 906: asm volatile ("fldl %0" : : "m" (dtab[i])); ! 907: asm volatile("ffree %st(2)"); ! 908: asm volatile ("fnstenv %0\n" : : "m" (float_env32)); ! 909: asm volatile ("fninit"); ! 910: printf("fptag=%04x\n", float_env32.fptag); ! 911: } ! 912: ! 913: ! 914: #define TEST_FCMOV(a, b, eflags, CC)\ ! 915: {\ ! 916: double res;\ ! 917: asm("push %3\n"\ ! 918: "popf\n"\ ! 919: "fcmov" CC " %2, %0\n"\ ! 920: : "=t" (res)\ ! 921: : "0" (a), "u" (b), "g" (eflags));\ ! 922: printf("fcmov%s eflags=0x%04lx-> %f\n", \ ! 923: CC, (long)eflags, res);\ ! 924: } ! 925: ! 926: void test_fcmov(void) ! 927: { ! 928: double a, b; ! 929: long eflags, i; ! 930: ! 931: a = 1.0; ! 932: b = 2.0; ! 933: for(i = 0; i < 4; i++) { ! 934: eflags = 0; ! 935: if (i & 1) ! 936: eflags |= CC_C; ! 937: if (i & 2) ! 938: eflags |= CC_Z; ! 939: TEST_FCMOV(a, b, eflags, "b"); ! 940: TEST_FCMOV(a, b, eflags, "e"); ! 941: TEST_FCMOV(a, b, eflags, "be"); ! 942: TEST_FCMOV(a, b, eflags, "nb"); ! 943: TEST_FCMOV(a, b, eflags, "ne"); ! 944: TEST_FCMOV(a, b, eflags, "nbe"); ! 945: } ! 946: TEST_FCMOV(a, b, 0, "u"); ! 947: TEST_FCMOV(a, b, CC_P, "u"); ! 948: TEST_FCMOV(a, b, 0, "nu"); ! 949: TEST_FCMOV(a, b, CC_P, "nu"); ! 950: } ! 951: ! 952: void test_floats(void) ! 953: { ! 954: test_fops(2, 3); ! 955: test_fops(1.4, -5); ! 956: test_fcmp(2, -1); ! 957: test_fcmp(2, 2); ! 958: test_fcmp(2, 3); ! 959: test_fcmp(2, q_nan.d); ! 960: test_fcmp(q_nan.d, -1); ! 961: test_fcvt(0.5); ! 962: test_fcvt(-0.5); ! 963: test_fcvt(1.0/7.0); ! 964: test_fcvt(-1.0/9.0); ! 965: test_fcvt(32768); ! 966: test_fcvt(-1e20); ! 967: test_fconst(); ! 968: test_fbcd(1234567890123456); ! 969: test_fbcd(-123451234567890); ! 970: test_fenv(); ! 971: if (TEST_CMOV) { ! 972: test_fcmov(); ! 973: } ! 974: } ! 975: ! 976: /**********************************************/ ! 977: #if !defined(__x86_64__) ! 978: ! 979: #define TEST_BCD(op, op0, cc_in, cc_mask)\ ! 980: {\ ! 981: int res, flags;\ ! 982: res = op0;\ ! 983: flags = cc_in;\ ! 984: asm ("push %3\n\t"\ ! 985: "popf\n\t"\ ! 986: #op "\n\t"\ ! 987: "pushf\n\t"\ ! 988: "pop %1\n\t"\ ! 989: : "=a" (res), "=g" (flags)\ ! 990: : "0" (res), "1" (flags));\ ! 991: printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n",\ ! 992: #op, op0, res, cc_in, flags & cc_mask);\ ! 993: } ! 994: ! 995: void test_bcd(void) ! 996: { ! 997: TEST_BCD(daa, 0x12340503, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 998: TEST_BCD(daa, 0x12340506, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 999: TEST_BCD(daa, 0x12340507, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1000: TEST_BCD(daa, 0x12340559, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1001: TEST_BCD(daa, 0x12340560, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1002: TEST_BCD(daa, 0x1234059f, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1003: TEST_BCD(daa, 0x123405a0, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1004: TEST_BCD(daa, 0x12340503, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1005: TEST_BCD(daa, 0x12340506, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1006: TEST_BCD(daa, 0x12340503, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1007: TEST_BCD(daa, 0x12340506, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1008: TEST_BCD(daa, 0x12340503, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1009: TEST_BCD(daa, 0x12340506, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1010: ! 1011: TEST_BCD(das, 0x12340503, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1012: TEST_BCD(das, 0x12340506, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1013: TEST_BCD(das, 0x12340507, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1014: TEST_BCD(das, 0x12340559, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1015: TEST_BCD(das, 0x12340560, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1016: TEST_BCD(das, 0x1234059f, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1017: TEST_BCD(das, 0x123405a0, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1018: TEST_BCD(das, 0x12340503, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1019: TEST_BCD(das, 0x12340506, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1020: TEST_BCD(das, 0x12340503, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1021: TEST_BCD(das, 0x12340506, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1022: TEST_BCD(das, 0x12340503, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1023: TEST_BCD(das, 0x12340506, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); ! 1024: ! 1025: TEST_BCD(aaa, 0x12340205, CC_A, (CC_C | CC_A)); ! 1026: TEST_BCD(aaa, 0x12340306, CC_A, (CC_C | CC_A)); ! 1027: TEST_BCD(aaa, 0x1234040a, CC_A, (CC_C | CC_A)); ! 1028: TEST_BCD(aaa, 0x123405fa, CC_A, (CC_C | CC_A)); ! 1029: TEST_BCD(aaa, 0x12340205, 0, (CC_C | CC_A)); ! 1030: TEST_BCD(aaa, 0x12340306, 0, (CC_C | CC_A)); ! 1031: TEST_BCD(aaa, 0x1234040a, 0, (CC_C | CC_A)); ! 1032: TEST_BCD(aaa, 0x123405fa, 0, (CC_C | CC_A)); ! 1033: ! 1034: TEST_BCD(aas, 0x12340205, CC_A, (CC_C | CC_A)); ! 1035: TEST_BCD(aas, 0x12340306, CC_A, (CC_C | CC_A)); ! 1036: TEST_BCD(aas, 0x1234040a, CC_A, (CC_C | CC_A)); ! 1037: TEST_BCD(aas, 0x123405fa, CC_A, (CC_C | CC_A)); ! 1038: TEST_BCD(aas, 0x12340205, 0, (CC_C | CC_A)); ! 1039: TEST_BCD(aas, 0x12340306, 0, (CC_C | CC_A)); ! 1040: TEST_BCD(aas, 0x1234040a, 0, (CC_C | CC_A)); ! 1041: TEST_BCD(aas, 0x123405fa, 0, (CC_C | CC_A)); ! 1042: ! 1043: TEST_BCD(aam, 0x12340547, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)); ! 1044: TEST_BCD(aad, 0x12340407, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)); ! 1045: } ! 1046: #endif ! 1047: ! 1048: #define TEST_XCHG(op, size, opconst)\ ! 1049: {\ ! 1050: long op0, op1;\ ! 1051: op0 = i2l(0x12345678);\ ! 1052: op1 = i2l(0xfbca7654);\ ! 1053: asm(#op " %" size "0, %" size "1" \ ! 1054: : "=q" (op0), opconst (op1) \ ! 1055: : "0" (op0), "1" (op1));\ ! 1056: printf("%-10s A=" FMTLX " B=" FMTLX "\n",\ ! 1057: #op, op0, op1);\ ! 1058: } ! 1059: ! 1060: #define TEST_CMPXCHG(op, size, opconst, eax)\ ! 1061: {\ ! 1062: long op0, op1, op2;\ ! 1063: op0 = i2l(0x12345678);\ ! 1064: op1 = i2l(0xfbca7654);\ ! 1065: op2 = i2l(eax);\ ! 1066: asm(#op " %" size "0, %" size "1" \ ! 1067: : "=q" (op0), opconst (op1) \ ! 1068: : "0" (op0), "1" (op1), "a" (op2));\ ! 1069: printf("%-10s EAX=" FMTLX " A=" FMTLX " C=" FMTLX "\n",\ ! 1070: #op, op2, op0, op1);\ ! 1071: } ! 1072: ! 1073: void test_xchg(void) ! 1074: { ! 1075: #if defined(__x86_64__) ! 1076: TEST_XCHG(xchgq, "", "=q"); ! 1077: #endif ! 1078: TEST_XCHG(xchgl, "k", "=q"); ! 1079: TEST_XCHG(xchgw, "w", "=q"); ! 1080: TEST_XCHG(xchgb, "b", "=q"); ! 1081: ! 1082: #if defined(__x86_64__) ! 1083: TEST_XCHG(xchgq, "", "=m"); ! 1084: #endif ! 1085: TEST_XCHG(xchgl, "k", "=m"); ! 1086: TEST_XCHG(xchgw, "w", "=m"); ! 1087: TEST_XCHG(xchgb, "b", "=m"); ! 1088: ! 1089: #if defined(__x86_64__) ! 1090: TEST_XCHG(xaddq, "", "=q"); ! 1091: #endif ! 1092: TEST_XCHG(xaddl, "k", "=q"); ! 1093: TEST_XCHG(xaddw, "w", "=q"); ! 1094: TEST_XCHG(xaddb, "b", "=q"); ! 1095: ! 1096: { ! 1097: int res; ! 1098: res = 0x12345678; ! 1099: asm("xaddl %1, %0" : "=r" (res) : "0" (res)); ! 1100: printf("xaddl same res=%08x\n", res); ! 1101: } ! 1102: ! 1103: #if defined(__x86_64__) ! 1104: TEST_XCHG(xaddq, "", "=m"); ! 1105: #endif ! 1106: TEST_XCHG(xaddl, "k", "=m"); ! 1107: TEST_XCHG(xaddw, "w", "=m"); ! 1108: TEST_XCHG(xaddb, "b", "=m"); ! 1109: ! 1110: #if defined(__x86_64__) ! 1111: TEST_CMPXCHG(cmpxchgq, "", "=q", 0xfbca7654); ! 1112: #endif ! 1113: TEST_CMPXCHG(cmpxchgl, "k", "=q", 0xfbca7654); ! 1114: TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfbca7654); ! 1115: TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfbca7654); ! 1116: ! 1117: #if defined(__x86_64__) ! 1118: TEST_CMPXCHG(cmpxchgq, "", "=q", 0xfffefdfc); ! 1119: #endif ! 1120: TEST_CMPXCHG(cmpxchgl, "k", "=q", 0xfffefdfc); ! 1121: TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfffefdfc); ! 1122: TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfffefdfc); ! 1123: ! 1124: #if defined(__x86_64__) ! 1125: TEST_CMPXCHG(cmpxchgq, "", "=m", 0xfbca7654); ! 1126: #endif ! 1127: TEST_CMPXCHG(cmpxchgl, "k", "=m", 0xfbca7654); ! 1128: TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfbca7654); ! 1129: TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfbca7654); ! 1130: ! 1131: #if defined(__x86_64__) ! 1132: TEST_CMPXCHG(cmpxchgq, "", "=m", 0xfffefdfc); ! 1133: #endif ! 1134: TEST_CMPXCHG(cmpxchgl, "k", "=m", 0xfffefdfc); ! 1135: TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfffefdfc); ! 1136: TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfffefdfc); ! 1137: ! 1138: { ! 1139: uint64_t op0, op1, op2; ! 1140: long i, eflags; ! 1141: ! 1142: for(i = 0; i < 2; i++) { ! 1143: op0 = 0x123456789abcd; ! 1144: if (i == 0) ! 1145: op1 = 0xfbca765423456; ! 1146: else ! 1147: op1 = op0; ! 1148: op2 = 0x6532432432434; ! 1149: asm("cmpxchg8b %1\n" ! 1150: "pushf\n" ! 1151: "pop %2\n" ! 1152: : "=A" (op0), "=m" (op1), "=g" (eflags) ! 1153: : "0" (op0), "m" (op1), "b" ((int)op2), "c" ((int)(op2 >> 32))); ! 1154: printf("cmpxchg8b: op0=" FMT64X " op1=" FMT64X " CC=%02lx\n", ! 1155: op0, op1, eflags & CC_Z); ! 1156: } ! 1157: } ! 1158: } ! 1159: ! 1160: #ifdef TEST_SEGS ! 1161: /**********************************************/ ! 1162: /* segmentation tests */ ! 1163: ! 1164: #include <asm/ldt.h> ! 1165: #include <linux/unistd.h> ! 1166: #include <linux/version.h> ! 1167: ! 1168: _syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount) ! 1169: ! 1170: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66) ! 1171: #define modify_ldt_ldt_s user_desc ! 1172: #endif ! 1173: ! 1174: #define MK_SEL(n) (((n) << 3) | 7) ! 1175: ! 1176: uint8_t seg_data1[4096]; ! 1177: uint8_t seg_data2[4096]; ! 1178: ! 1179: #define TEST_LR(op, size, seg, mask)\ ! 1180: {\ ! 1181: int res, res2;\ ! 1182: res = 0x12345678;\ ! 1183: asm (op " %" size "2, %" size "0\n" \ ! 1184: "movl $0, %1\n"\ ! 1185: "jnz 1f\n"\ ! 1186: "movl $1, %1\n"\ ! 1187: "1:\n"\ ! 1188: : "=r" (res), "=r" (res2) : "m" (seg), "0" (res));\ ! 1189: printf(op ": Z=%d %08x\n", res2, res & ~(mask));\ ! 1190: } ! 1191: ! 1192: /* NOTE: we use Linux modify_ldt syscall */ ! 1193: void test_segs(void) ! 1194: { ! 1195: struct modify_ldt_ldt_s ldt; ! 1196: long long ldt_table[3]; ! 1197: int res, res2; ! 1198: char tmp; ! 1199: struct { ! 1200: uint32_t offset; ! 1201: uint16_t seg; ! 1202: } __attribute__((packed)) segoff; ! 1203: ! 1204: ldt.entry_number = 1; ! 1205: ldt.base_addr = (unsigned long)&seg_data1; ! 1206: ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12; ! 1207: ldt.seg_32bit = 1; ! 1208: ldt.contents = MODIFY_LDT_CONTENTS_DATA; ! 1209: ldt.read_exec_only = 0; ! 1210: ldt.limit_in_pages = 1; ! 1211: ldt.seg_not_present = 0; ! 1212: ldt.useable = 1; ! 1213: modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ ! 1214: ! 1215: ldt.entry_number = 2; ! 1216: ldt.base_addr = (unsigned long)&seg_data2; ! 1217: ldt.limit = (sizeof(seg_data2) + 0xfff) >> 12; ! 1218: ldt.seg_32bit = 1; ! 1219: ldt.contents = MODIFY_LDT_CONTENTS_DATA; ! 1220: ldt.read_exec_only = 0; ! 1221: ldt.limit_in_pages = 1; ! 1222: ldt.seg_not_present = 0; ! 1223: ldt.useable = 1; ! 1224: modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ ! 1225: ! 1226: modify_ldt(0, &ldt_table, sizeof(ldt_table)); /* read ldt entries */ ! 1227: #if 0 ! 1228: { ! 1229: int i; ! 1230: for(i=0;i<3;i++) ! 1231: printf("%d: %016Lx\n", i, ldt_table[i]); ! 1232: } ! 1233: #endif ! 1234: /* do some tests with fs or gs */ ! 1235: asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1))); ! 1236: ! 1237: seg_data1[1] = 0xaa; ! 1238: seg_data2[1] = 0x55; ! 1239: ! 1240: asm volatile ("fs movzbl 0x1, %0" : "=r" (res)); ! 1241: printf("FS[1] = %02x\n", res); ! 1242: ! 1243: asm volatile ("pushl %%gs\n" ! 1244: "movl %1, %%gs\n" ! 1245: "gs movzbl 0x1, %0\n" ! 1246: "popl %%gs\n" ! 1247: : "=r" (res) ! 1248: : "r" (MK_SEL(2))); ! 1249: printf("GS[1] = %02x\n", res); ! 1250: ! 1251: /* tests with ds/ss (implicit segment case) */ ! 1252: tmp = 0xa5; ! 1253: asm volatile ("pushl %%ebp\n\t" ! 1254: "pushl %%ds\n\t" ! 1255: "movl %2, %%ds\n\t" ! 1256: "movl %3, %%ebp\n\t" ! 1257: "movzbl 0x1, %0\n\t" ! 1258: "movzbl (%%ebp), %1\n\t" ! 1259: "popl %%ds\n\t" ! 1260: "popl %%ebp\n\t" ! 1261: : "=r" (res), "=r" (res2) ! 1262: : "r" (MK_SEL(1)), "r" (&tmp)); ! 1263: printf("DS[1] = %02x\n", res); ! 1264: printf("SS[tmp] = %02x\n", res2); ! 1265: ! 1266: segoff.seg = MK_SEL(2); ! 1267: segoff.offset = 0xabcdef12; ! 1268: asm volatile("lfs %2, %0\n\t" ! 1269: "movl %%fs, %1\n\t" ! 1270: : "=r" (res), "=g" (res2) ! 1271: : "m" (segoff)); ! 1272: printf("FS:reg = %04x:%08x\n", res2, res); ! 1273: ! 1274: TEST_LR("larw", "w", MK_SEL(2), 0x0100); ! 1275: TEST_LR("larl", "", MK_SEL(2), 0x0100); ! 1276: TEST_LR("lslw", "w", MK_SEL(2), 0); ! 1277: TEST_LR("lsll", "", MK_SEL(2), 0); ! 1278: ! 1279: TEST_LR("larw", "w", 0xfff8, 0); ! 1280: TEST_LR("larl", "", 0xfff8, 0); ! 1281: TEST_LR("lslw", "w", 0xfff8, 0); ! 1282: TEST_LR("lsll", "", 0xfff8, 0); ! 1283: } ! 1284: ! 1285: /* 16 bit code test */ ! 1286: extern char code16_start, code16_end; ! 1287: extern char code16_func1; ! 1288: extern char code16_func2; ! 1289: extern char code16_func3; ! 1290: ! 1291: void test_code16(void) ! 1292: { ! 1293: struct modify_ldt_ldt_s ldt; ! 1294: int res, res2; ! 1295: ! 1296: /* build a code segment */ ! 1297: ldt.entry_number = 1; ! 1298: ldt.base_addr = (unsigned long)&code16_start; ! 1299: ldt.limit = &code16_end - &code16_start; ! 1300: ldt.seg_32bit = 0; ! 1301: ldt.contents = MODIFY_LDT_CONTENTS_CODE; ! 1302: ldt.read_exec_only = 0; ! 1303: ldt.limit_in_pages = 0; ! 1304: ldt.seg_not_present = 0; ! 1305: ldt.useable = 1; ! 1306: modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ ! 1307: ! 1308: /* call the first function */ ! 1309: asm volatile ("lcall %1, %2" ! 1310: : "=a" (res) ! 1311: : "i" (MK_SEL(1)), "i" (&code16_func1): "memory", "cc"); ! 1312: printf("func1() = 0x%08x\n", res); ! 1313: asm volatile ("lcall %2, %3" ! 1314: : "=a" (res), "=c" (res2) ! 1315: : "i" (MK_SEL(1)), "i" (&code16_func2): "memory", "cc"); ! 1316: printf("func2() = 0x%08x spdec=%d\n", res, res2); ! 1317: asm volatile ("lcall %1, %2" ! 1318: : "=a" (res) ! 1319: : "i" (MK_SEL(1)), "i" (&code16_func3): "memory", "cc"); ! 1320: printf("func3() = 0x%08x\n", res); ! 1321: } ! 1322: #endif ! 1323: ! 1324: #if defined(__x86_64__) ! 1325: asm(".globl func_lret\n" ! 1326: "func_lret:\n" ! 1327: "movl $0x87654641, %eax\n" ! 1328: "lretq\n"); ! 1329: #else ! 1330: asm(".globl func_lret\n" ! 1331: "func_lret:\n" ! 1332: "movl $0x87654321, %eax\n" ! 1333: "lret\n" ! 1334: ! 1335: ".globl func_iret\n" ! 1336: "func_iret:\n" ! 1337: "movl $0xabcd4321, %eax\n" ! 1338: "iret\n"); ! 1339: #endif ! 1340: ! 1341: extern char func_lret; ! 1342: extern char func_iret; ! 1343: ! 1344: void test_misc(void) ! 1345: { ! 1346: char table[256]; ! 1347: long res, i; ! 1348: ! 1349: for(i=0;i<256;i++) table[i] = 256 - i; ! 1350: res = 0x12345678; ! 1351: asm ("xlat" : "=a" (res) : "b" (table), "0" (res)); ! 1352: printf("xlat: EAX=" FMTLX "\n", res); ! 1353: ! 1354: #if defined(__x86_64__) ! 1355: { ! 1356: static struct __attribute__((packed)) { ! 1357: uint32_t offset; ! 1358: uint16_t seg; ! 1359: } desc; ! 1360: long cs_sel; ! 1361: ! 1362: asm volatile ("mov %%cs, %0" : "=r" (cs_sel)); ! 1363: ! 1364: asm volatile ("push %1\n" ! 1365: "call func_lret\n" ! 1366: : "=a" (res) ! 1367: : "r" (cs_sel) : "memory", "cc"); ! 1368: printf("func_lret=" FMTLX "\n", res); ! 1369: ! 1370: /* NOTE: we assume that &func_lret < 4GB */ ! 1371: desc.offset = (long)&func_lret; ! 1372: desc.seg = cs_sel; ! 1373: ! 1374: asm volatile ("xor %%rax, %%rax\n" ! 1375: "rex64 lcall %1\n" ! 1376: : "=a" (res) ! 1377: : "m" (desc) ! 1378: : "memory", "cc"); ! 1379: printf("func_lret2=" FMTLX "\n", res); ! 1380: ! 1381: asm volatile ("push %2\n" ! 1382: "mov $ 1f, %%rax\n" ! 1383: "push %%rax\n" ! 1384: "ljmp %1\n" ! 1385: "1:\n" ! 1386: : "=a" (res) ! 1387: : "m" (desc), "b" (cs_sel) ! 1388: : "memory", "cc"); ! 1389: printf("func_lret3=" FMTLX "\n", res); ! 1390: } ! 1391: #else ! 1392: asm volatile ("push %%cs ; call %1" ! 1393: : "=a" (res) ! 1394: : "m" (func_lret): "memory", "cc"); ! 1395: printf("func_lret=" FMTLX "\n", res); ! 1396: ! 1397: asm volatile ("pushf ; push %%cs ; call %1" ! 1398: : "=a" (res) ! 1399: : "m" (func_iret): "memory", "cc"); ! 1400: printf("func_iret=" FMTLX "\n", res); ! 1401: #endif ! 1402: ! 1403: #if defined(__x86_64__) ! 1404: /* specific popl test */ ! 1405: asm volatile ("push $12345432 ; push $0x9abcdef ; pop (%%rsp) ; pop %0" ! 1406: : "=g" (res)); ! 1407: printf("popl esp=" FMTLX "\n", res); ! 1408: #else ! 1409: /* specific popl test */ ! 1410: asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popl (%%esp) ; popl %0" ! 1411: : "=g" (res)); ! 1412: printf("popl esp=" FMTLX "\n", res); ! 1413: ! 1414: /* specific popw test */ ! 1415: asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popw (%%esp) ; addl $2, %%esp ; popl %0" ! 1416: : "=g" (res)); ! 1417: printf("popw esp=" FMTLX "\n", res); ! 1418: #endif ! 1419: } ! 1420: ! 1421: uint8_t str_buffer[4096]; ! 1422: ! 1423: #define TEST_STRING1(OP, size, DF, REP)\ ! 1424: {\ ! 1425: long esi, edi, eax, ecx, eflags;\ ! 1426: \ ! 1427: esi = (long)(str_buffer + sizeof(str_buffer) / 2);\ ! 1428: edi = (long)(str_buffer + sizeof(str_buffer) / 2) + 16;\ ! 1429: eax = i2l(0x12345678);\ ! 1430: ecx = 17;\ ! 1431: \ ! 1432: asm volatile ("push $0\n\t"\ ! 1433: "popf\n\t"\ ! 1434: DF "\n\t"\ ! 1435: REP #OP size "\n\t"\ ! 1436: "cld\n\t"\ ! 1437: "pushf\n\t"\ ! 1438: "pop %4\n\t"\ ! 1439: : "=S" (esi), "=D" (edi), "=a" (eax), "=c" (ecx), "=g" (eflags)\ ! 1440: : "0" (esi), "1" (edi), "2" (eax), "3" (ecx));\ ! 1441: printf("%-10s ESI=" FMTLX " EDI=" FMTLX " EAX=" FMTLX " ECX=" FMTLX " EFL=%04x\n",\ ! 1442: REP #OP size, esi, edi, eax, ecx,\ ! 1443: (int)(eflags & (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)));\ ! 1444: } ! 1445: ! 1446: #define TEST_STRING(OP, REP)\ ! 1447: TEST_STRING1(OP, "b", "", REP);\ ! 1448: TEST_STRING1(OP, "w", "", REP);\ ! 1449: TEST_STRING1(OP, "l", "", REP);\ ! 1450: X86_64_ONLY(TEST_STRING1(OP, "q", "", REP));\ ! 1451: TEST_STRING1(OP, "b", "std", REP);\ ! 1452: TEST_STRING1(OP, "w", "std", REP);\ ! 1453: TEST_STRING1(OP, "l", "std", REP);\ ! 1454: X86_64_ONLY(TEST_STRING1(OP, "q", "std", REP)) ! 1455: ! 1456: void test_string(void) ! 1457: { ! 1458: int i; ! 1459: for(i = 0;i < sizeof(str_buffer); i++) ! 1460: str_buffer[i] = i + 0x56; ! 1461: TEST_STRING(stos, ""); ! 1462: TEST_STRING(stos, "rep "); ! 1463: TEST_STRING(lods, ""); /* to verify stos */ ! 1464: TEST_STRING(lods, "rep "); ! 1465: TEST_STRING(movs, ""); ! 1466: TEST_STRING(movs, "rep "); ! 1467: TEST_STRING(lods, ""); /* to verify stos */ ! 1468: ! 1469: /* XXX: better tests */ ! 1470: TEST_STRING(scas, ""); ! 1471: TEST_STRING(scas, "repz "); ! 1472: TEST_STRING(scas, "repnz "); ! 1473: TEST_STRING(cmps, ""); ! 1474: TEST_STRING(cmps, "repz "); ! 1475: TEST_STRING(cmps, "repnz "); ! 1476: } ! 1477: ! 1478: #ifdef TEST_VM86 ! 1479: /* VM86 test */ ! 1480: ! 1481: static inline void set_bit(uint8_t *a, unsigned int bit) ! 1482: { ! 1483: a[bit / 8] |= (1 << (bit % 8)); ! 1484: } ! 1485: ! 1486: static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg) ! 1487: { ! 1488: return (uint8_t *)((seg << 4) + (reg & 0xffff)); ! 1489: } ! 1490: ! 1491: static inline void pushw(struct vm86_regs *r, int val) ! 1492: { ! 1493: r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff); ! 1494: *(uint16_t *)seg_to_linear(r->ss, r->esp) = val; ! 1495: } ! 1496: ! 1497: #undef __syscall_return ! 1498: #define __syscall_return(type, res) \ ! 1499: do { \ ! 1500: return (type) (res); \ ! 1501: } while (0) ! 1502: ! 1503: _syscall2(int, vm86, int, func, struct vm86plus_struct *, v86) ! 1504: ! 1505: extern char vm86_code_start; ! 1506: extern char vm86_code_end; ! 1507: ! 1508: #define VM86_CODE_CS 0x100 ! 1509: #define VM86_CODE_IP 0x100 ! 1510: ! 1511: void test_vm86(void) ! 1512: { ! 1513: struct vm86plus_struct ctx; ! 1514: struct vm86_regs *r; ! 1515: uint8_t *vm86_mem; ! 1516: int seg, ret; ! 1517: ! 1518: vm86_mem = mmap((void *)0x00000000, 0x110000, ! 1519: PROT_WRITE | PROT_READ | PROT_EXEC, ! 1520: MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); ! 1521: if (vm86_mem == MAP_FAILED) { ! 1522: printf("ERROR: could not map vm86 memory"); ! 1523: return; ! 1524: } ! 1525: memset(&ctx, 0, sizeof(ctx)); ! 1526: ! 1527: /* init basic registers */ ! 1528: r = &ctx.regs; ! 1529: r->eip = VM86_CODE_IP; ! 1530: r->esp = 0xfffe; ! 1531: seg = VM86_CODE_CS; ! 1532: r->cs = seg; ! 1533: r->ss = seg; ! 1534: r->ds = seg; ! 1535: r->es = seg; ! 1536: r->fs = seg; ! 1537: r->gs = seg; ! 1538: r->eflags = VIF_MASK; ! 1539: ! 1540: /* move code to proper address. We use the same layout as a .com ! 1541: dos program. */ ! 1542: memcpy(vm86_mem + (VM86_CODE_CS << 4) + VM86_CODE_IP, ! 1543: &vm86_code_start, &vm86_code_end - &vm86_code_start); ! 1544: ! 1545: /* mark int 0x21 as being emulated */ ! 1546: set_bit((uint8_t *)&ctx.int_revectored, 0x21); ! 1547: ! 1548: for(;;) { ! 1549: ret = vm86(VM86_ENTER, &ctx); ! 1550: switch(VM86_TYPE(ret)) { ! 1551: case VM86_INTx: ! 1552: { ! 1553: int int_num, ah, v; ! 1554: ! 1555: int_num = VM86_ARG(ret); ! 1556: if (int_num != 0x21) ! 1557: goto unknown_int; ! 1558: ah = (r->eax >> 8) & 0xff; ! 1559: switch(ah) { ! 1560: case 0x00: /* exit */ ! 1561: goto the_end; ! 1562: case 0x02: /* write char */ ! 1563: { ! 1564: uint8_t c = r->edx; ! 1565: putchar(c); ! 1566: } ! 1567: break; ! 1568: case 0x09: /* write string */ ! 1569: { ! 1570: uint8_t c, *ptr; ! 1571: ptr = seg_to_linear(r->ds, r->edx); ! 1572: for(;;) { ! 1573: c = *ptr++; ! 1574: if (c == '$') ! 1575: break; ! 1576: putchar(c); ! 1577: } ! 1578: r->eax = (r->eax & ~0xff) | '$'; ! 1579: } ! 1580: break; ! 1581: case 0xff: /* extension: write eflags number in edx */ ! 1582: v = (int)r->edx; ! 1583: #ifndef LINUX_VM86_IOPL_FIX ! 1584: v &= ~0x3000; ! 1585: #endif ! 1586: printf("%08x\n", v); ! 1587: break; ! 1588: default: ! 1589: unknown_int: ! 1590: printf("unsupported int 0x%02x\n", int_num); ! 1591: goto the_end; ! 1592: } ! 1593: } ! 1594: break; ! 1595: case VM86_SIGNAL: ! 1596: /* a signal came, we just ignore that */ ! 1597: break; ! 1598: case VM86_STI: ! 1599: break; ! 1600: default: ! 1601: printf("ERROR: unhandled vm86 return code (0x%x)\n", ret); ! 1602: goto the_end; ! 1603: } ! 1604: } ! 1605: the_end: ! 1606: printf("VM86 end\n"); ! 1607: munmap(vm86_mem, 0x110000); ! 1608: } ! 1609: #endif ! 1610: ! 1611: /* exception tests */ ! 1612: #if defined(__i386__) && !defined(REG_EAX) ! 1613: #define REG_EAX EAX ! 1614: #define REG_EBX EBX ! 1615: #define REG_ECX ECX ! 1616: #define REG_EDX EDX ! 1617: #define REG_ESI ESI ! 1618: #define REG_EDI EDI ! 1619: #define REG_EBP EBP ! 1620: #define REG_ESP ESP ! 1621: #define REG_EIP EIP ! 1622: #define REG_EFL EFL ! 1623: #define REG_TRAPNO TRAPNO ! 1624: #define REG_ERR ERR ! 1625: #endif ! 1626: ! 1627: #if defined(__x86_64__) ! 1628: #define REG_EIP REG_RIP ! 1629: #endif ! 1630: ! 1631: jmp_buf jmp_env; ! 1632: int v1; ! 1633: int tab[2]; ! 1634: ! 1635: void sig_handler(int sig, siginfo_t *info, void *puc) ! 1636: { ! 1637: struct ucontext *uc = puc; ! 1638: ! 1639: printf("si_signo=%d si_errno=%d si_code=%d", ! 1640: info->si_signo, info->si_errno, info->si_code); ! 1641: printf(" si_addr=0x%08lx", ! 1642: (unsigned long)info->si_addr); ! 1643: printf("\n"); ! 1644: ! 1645: printf("trapno=" FMTLX " err=" FMTLX, ! 1646: (long)uc->uc_mcontext.gregs[REG_TRAPNO], ! 1647: (long)uc->uc_mcontext.gregs[REG_ERR]); ! 1648: printf(" EIP=" FMTLX, (long)uc->uc_mcontext.gregs[REG_EIP]); ! 1649: printf("\n"); ! 1650: longjmp(jmp_env, 1); ! 1651: } ! 1652: ! 1653: void test_exceptions(void) ! 1654: { ! 1655: struct sigaction act; ! 1656: volatile int val; ! 1657: ! 1658: act.sa_sigaction = sig_handler; ! 1659: sigemptyset(&act.sa_mask); ! 1660: act.sa_flags = SA_SIGINFO | SA_NODEFER; ! 1661: sigaction(SIGFPE, &act, NULL); ! 1662: sigaction(SIGILL, &act, NULL); ! 1663: sigaction(SIGSEGV, &act, NULL); ! 1664: sigaction(SIGBUS, &act, NULL); ! 1665: sigaction(SIGTRAP, &act, NULL); ! 1666: ! 1667: /* test division by zero reporting */ ! 1668: printf("DIVZ exception:\n"); ! 1669: if (setjmp(jmp_env) == 0) { ! 1670: /* now divide by zero */ ! 1671: v1 = 0; ! 1672: v1 = 2 / v1; ! 1673: } ! 1674: ! 1675: #if !defined(__x86_64__) ! 1676: printf("BOUND exception:\n"); ! 1677: if (setjmp(jmp_env) == 0) { ! 1678: /* bound exception */ ! 1679: tab[0] = 1; ! 1680: tab[1] = 10; ! 1681: asm volatile ("bound %0, %1" : : "r" (11), "m" (tab[0])); ! 1682: } ! 1683: #endif ! 1684: ! 1685: #ifdef TEST_SEGS ! 1686: printf("segment exceptions:\n"); ! 1687: if (setjmp(jmp_env) == 0) { ! 1688: /* load an invalid segment */ ! 1689: asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 1)); ! 1690: } ! 1691: if (setjmp(jmp_env) == 0) { ! 1692: /* null data segment is valid */ ! 1693: asm volatile ("movl %0, %%fs" : : "r" (3)); ! 1694: /* null stack segment */ ! 1695: asm volatile ("movl %0, %%ss" : : "r" (3)); ! 1696: } ! 1697: ! 1698: { ! 1699: struct modify_ldt_ldt_s ldt; ! 1700: ldt.entry_number = 1; ! 1701: ldt.base_addr = (unsigned long)&seg_data1; ! 1702: ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12; ! 1703: ldt.seg_32bit = 1; ! 1704: ldt.contents = MODIFY_LDT_CONTENTS_DATA; ! 1705: ldt.read_exec_only = 0; ! 1706: ldt.limit_in_pages = 1; ! 1707: ldt.seg_not_present = 1; ! 1708: ldt.useable = 1; ! 1709: modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ ! 1710: ! 1711: if (setjmp(jmp_env) == 0) { ! 1712: /* segment not present */ ! 1713: asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1))); ! 1714: } ! 1715: } ! 1716: #endif ! 1717: ! 1718: /* test SEGV reporting */ ! 1719: printf("PF exception:\n"); ! 1720: if (setjmp(jmp_env) == 0) { ! 1721: val = 1; ! 1722: /* we add a nop to test a weird PC retrieval case */ ! 1723: asm volatile ("nop"); ! 1724: /* now store in an invalid address */ ! 1725: *(char *)0x1234 = 1; ! 1726: } ! 1727: ! 1728: /* test SEGV reporting */ ! 1729: printf("PF exception:\n"); ! 1730: if (setjmp(jmp_env) == 0) { ! 1731: val = 1; ! 1732: /* read from an invalid address */ ! 1733: v1 = *(char *)0x1234; ! 1734: } ! 1735: ! 1736: /* test illegal instruction reporting */ ! 1737: printf("UD2 exception:\n"); ! 1738: if (setjmp(jmp_env) == 0) { ! 1739: /* now execute an invalid instruction */ ! 1740: asm volatile("ud2"); ! 1741: } ! 1742: printf("lock nop exception:\n"); ! 1743: if (setjmp(jmp_env) == 0) { ! 1744: /* now execute an invalid instruction */ ! 1745: asm volatile("lock nop"); ! 1746: } ! 1747: ! 1748: printf("INT exception:\n"); ! 1749: if (setjmp(jmp_env) == 0) { ! 1750: asm volatile ("int $0xfd"); ! 1751: } ! 1752: if (setjmp(jmp_env) == 0) { ! 1753: asm volatile ("int $0x01"); ! 1754: } ! 1755: if (setjmp(jmp_env) == 0) { ! 1756: asm volatile (".byte 0xcd, 0x03"); ! 1757: } ! 1758: if (setjmp(jmp_env) == 0) { ! 1759: asm volatile ("int $0x04"); ! 1760: } ! 1761: if (setjmp(jmp_env) == 0) { ! 1762: asm volatile ("int $0x05"); ! 1763: } ! 1764: ! 1765: printf("INT3 exception:\n"); ! 1766: if (setjmp(jmp_env) == 0) { ! 1767: asm volatile ("int3"); ! 1768: } ! 1769: ! 1770: printf("CLI exception:\n"); ! 1771: if (setjmp(jmp_env) == 0) { ! 1772: asm volatile ("cli"); ! 1773: } ! 1774: ! 1775: printf("STI exception:\n"); ! 1776: if (setjmp(jmp_env) == 0) { ! 1777: asm volatile ("cli"); ! 1778: } ! 1779: ! 1780: #if !defined(__x86_64__) ! 1781: printf("INTO exception:\n"); ! 1782: if (setjmp(jmp_env) == 0) { ! 1783: /* overflow exception */ ! 1784: asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff)); ! 1785: } ! 1786: #endif ! 1787: ! 1788: printf("OUTB exception:\n"); ! 1789: if (setjmp(jmp_env) == 0) { ! 1790: asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0)); ! 1791: } ! 1792: ! 1793: printf("INB exception:\n"); ! 1794: if (setjmp(jmp_env) == 0) { ! 1795: asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321)); ! 1796: } ! 1797: ! 1798: printf("REP OUTSB exception:\n"); ! 1799: if (setjmp(jmp_env) == 0) { ! 1800: asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1)); ! 1801: } ! 1802: ! 1803: printf("REP INSB exception:\n"); ! 1804: if (setjmp(jmp_env) == 0) { ! 1805: asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1)); ! 1806: } ! 1807: ! 1808: printf("HLT exception:\n"); ! 1809: if (setjmp(jmp_env) == 0) { ! 1810: asm volatile ("hlt"); ! 1811: } ! 1812: ! 1813: printf("single step exception:\n"); ! 1814: val = 0; ! 1815: if (setjmp(jmp_env) == 0) { ! 1816: asm volatile ("pushf\n" ! 1817: "orl $0x00100, (%%esp)\n" ! 1818: "popf\n" ! 1819: "movl $0xabcd, %0\n" ! 1820: "movl $0x0, %0\n" : "=m" (val) : : "cc", "memory"); ! 1821: } ! 1822: printf("val=0x%x\n", val); ! 1823: } ! 1824: ! 1825: #if !defined(__x86_64__) ! 1826: /* specific precise single step test */ ! 1827: void sig_trap_handler(int sig, siginfo_t *info, void *puc) ! 1828: { ! 1829: struct ucontext *uc = puc; ! 1830: printf("EIP=" FMTLX "\n", (long)uc->uc_mcontext.gregs[REG_EIP]); ! 1831: } ! 1832: ! 1833: const uint8_t sstep_buf1[4] = { 1, 2, 3, 4}; ! 1834: uint8_t sstep_buf2[4]; ! 1835: ! 1836: void test_single_step(void) ! 1837: { ! 1838: struct sigaction act; ! 1839: volatile int val; ! 1840: int i; ! 1841: ! 1842: val = 0; ! 1843: act.sa_sigaction = sig_trap_handler; ! 1844: sigemptyset(&act.sa_mask); ! 1845: act.sa_flags = SA_SIGINFO; ! 1846: sigaction(SIGTRAP, &act, NULL); ! 1847: asm volatile ("pushf\n" ! 1848: "orl $0x00100, (%%esp)\n" ! 1849: "popf\n" ! 1850: "movl $0xabcd, %0\n" ! 1851: ! 1852: /* jmp test */ ! 1853: "movl $3, %%ecx\n" ! 1854: "1:\n" ! 1855: "addl $1, %0\n" ! 1856: "decl %%ecx\n" ! 1857: "jnz 1b\n" ! 1858: ! 1859: /* movsb: the single step should stop at each movsb iteration */ ! 1860: "movl $sstep_buf1, %%esi\n" ! 1861: "movl $sstep_buf2, %%edi\n" ! 1862: "movl $0, %%ecx\n" ! 1863: "rep movsb\n" ! 1864: "movl $3, %%ecx\n" ! 1865: "rep movsb\n" ! 1866: "movl $1, %%ecx\n" ! 1867: "rep movsb\n" ! 1868: ! 1869: /* cmpsb: the single step should stop at each cmpsb iteration */ ! 1870: "movl $sstep_buf1, %%esi\n" ! 1871: "movl $sstep_buf2, %%edi\n" ! 1872: "movl $0, %%ecx\n" ! 1873: "rep cmpsb\n" ! 1874: "movl $4, %%ecx\n" ! 1875: "rep cmpsb\n" ! 1876: ! 1877: /* getpid() syscall: single step should skip one ! 1878: instruction */ ! 1879: "movl $20, %%eax\n" ! 1880: "int $0x80\n" ! 1881: "movl $0, %%eax\n" ! 1882: ! 1883: /* when modifying SS, trace is not done on the next ! 1884: instruction */ ! 1885: "movl %%ss, %%ecx\n" ! 1886: "movl %%ecx, %%ss\n" ! 1887: "addl $1, %0\n" ! 1888: "movl $1, %%eax\n" ! 1889: "movl %%ecx, %%ss\n" ! 1890: "jmp 1f\n" ! 1891: "addl $1, %0\n" ! 1892: "1:\n" ! 1893: "movl $1, %%eax\n" ! 1894: "pushl %%ecx\n" ! 1895: "popl %%ss\n" ! 1896: "addl $1, %0\n" ! 1897: "movl $1, %%eax\n" ! 1898: ! 1899: "pushf\n" ! 1900: "andl $~0x00100, (%%esp)\n" ! 1901: "popf\n" ! 1902: : "=m" (val) ! 1903: : ! 1904: : "cc", "memory", "eax", "ecx", "esi", "edi"); ! 1905: printf("val=%d\n", val); ! 1906: for(i = 0; i < 4; i++) ! 1907: printf("sstep_buf2[%d] = %d\n", i, sstep_buf2[i]); ! 1908: } ! 1909: ! 1910: /* self modifying code test */ ! 1911: uint8_t code[] = { ! 1912: 0xb8, 0x1, 0x00, 0x00, 0x00, /* movl $1, %eax */ ! 1913: 0xc3, /* ret */ ! 1914: }; ! 1915: ! 1916: asm("smc_code2:\n" ! 1917: "movl 4(%esp), %eax\n" ! 1918: "movl %eax, smc_patch_addr2 + 1\n" ! 1919: "nop\n" ! 1920: "nop\n" ! 1921: "nop\n" ! 1922: "nop\n" ! 1923: "nop\n" ! 1924: "nop\n" ! 1925: "nop\n" ! 1926: "nop\n" ! 1927: "smc_patch_addr2:\n" ! 1928: "movl $1, %eax\n" ! 1929: "ret\n"); ! 1930: ! 1931: typedef int FuncType(void); ! 1932: extern int smc_code2(int); ! 1933: void test_self_modifying_code(void) ! 1934: { ! 1935: int i; ! 1936: ! 1937: printf("self modifying code:\n"); ! 1938: printf("func1 = 0x%x\n", ((FuncType *)code)()); ! 1939: for(i = 2; i <= 4; i++) { ! 1940: code[1] = i; ! 1941: printf("func%d = 0x%x\n", i, ((FuncType *)code)()); ! 1942: } ! 1943: ! 1944: /* more difficult test : the modified code is just after the ! 1945: modifying instruction. It is forbidden in Intel specs, but it ! 1946: is used by old DOS programs */ ! 1947: for(i = 2; i <= 4; i++) { ! 1948: printf("smc_code2(%d) = %d\n", i, smc_code2(i)); ! 1949: } ! 1950: } ! 1951: #endif ! 1952: ! 1953: long enter_stack[4096]; ! 1954: ! 1955: #if defined(__x86_64__) ! 1956: #define RSP "%%rsp" ! 1957: #define RBP "%%rbp" ! 1958: #else ! 1959: #define RSP "%%esp" ! 1960: #define RBP "%%ebp" ! 1961: #endif ! 1962: ! 1963: #define TEST_ENTER(size, stack_type, level)\ ! 1964: {\ ! 1965: long esp_save, esp_val, ebp_val, ebp_save, i;\ ! 1966: stack_type *ptr, *stack_end, *stack_ptr;\ ! 1967: memset(enter_stack, 0, sizeof(enter_stack));\ ! 1968: stack_end = stack_ptr = (stack_type *)(enter_stack + 4096);\ ! 1969: ebp_val = (long)stack_ptr;\ ! 1970: for(i=1;i<=32;i++)\ ! 1971: *--stack_ptr = i;\ ! 1972: esp_val = (long)stack_ptr;\ ! 1973: asm("mov " RSP ", %[esp_save]\n"\ ! 1974: "mov " RBP ", %[ebp_save]\n"\ ! 1975: "mov %[esp_val], " RSP "\n"\ ! 1976: "mov %[ebp_val], " RBP "\n"\ ! 1977: "enter" size " $8, $" #level "\n"\ ! 1978: "mov " RSP ", %[esp_val]\n"\ ! 1979: "mov " RBP ", %[ebp_val]\n"\ ! 1980: "mov %[esp_save], " RSP "\n"\ ! 1981: "mov %[ebp_save], " RBP "\n"\ ! 1982: : [esp_save] "=r" (esp_save),\ ! 1983: [ebp_save] "=r" (ebp_save),\ ! 1984: [esp_val] "=r" (esp_val),\ ! 1985: [ebp_val] "=r" (ebp_val)\ ! 1986: : "[esp_val]" (esp_val),\ ! 1987: "[ebp_val]" (ebp_val));\ ! 1988: printf("level=%d:\n", level);\ ! 1989: printf("esp_val=" FMTLX "\n", esp_val - (long)stack_end);\ ! 1990: printf("ebp_val=" FMTLX "\n", ebp_val - (long)stack_end);\ ! 1991: for(ptr = (stack_type *)esp_val; ptr < stack_end; ptr++)\ ! 1992: printf(FMTLX "\n", (long)ptr[0]);\ ! 1993: } ! 1994: ! 1995: static void test_enter(void) ! 1996: { ! 1997: #if defined(__x86_64__) ! 1998: TEST_ENTER("q", uint64_t, 0); ! 1999: TEST_ENTER("q", uint64_t, 1); ! 2000: TEST_ENTER("q", uint64_t, 2); ! 2001: TEST_ENTER("q", uint64_t, 31); ! 2002: #else ! 2003: TEST_ENTER("l", uint32_t, 0); ! 2004: TEST_ENTER("l", uint32_t, 1); ! 2005: TEST_ENTER("l", uint32_t, 2); ! 2006: TEST_ENTER("l", uint32_t, 31); ! 2007: #endif ! 2008: ! 2009: TEST_ENTER("w", uint16_t, 0); ! 2010: TEST_ENTER("w", uint16_t, 1); ! 2011: TEST_ENTER("w", uint16_t, 2); ! 2012: TEST_ENTER("w", uint16_t, 31); ! 2013: } ! 2014: ! 2015: #ifdef TEST_SSE ! 2016: ! 2017: typedef int __m64 __attribute__ ((__mode__ (__V2SI__))); ! 2018: typedef int __m128 __attribute__ ((__mode__(__V4SF__))); ! 2019: ! 2020: typedef union { ! 2021: double d[2]; ! 2022: float s[4]; ! 2023: uint32_t l[4]; ! 2024: uint64_t q[2]; ! 2025: __m128 dq; ! 2026: } XMMReg; ! 2027: ! 2028: static uint64_t __attribute__((aligned(16))) test_values[4][2] = { ! 2029: { 0x456723c698694873, 0xdc515cff944a58ec }, ! 2030: { 0x1f297ccd58bad7ab, 0x41f21efba9e3e146 }, ! 2031: { 0x007c62c2085427f8, 0x231be9e8cde7438d }, ! 2032: { 0x0f76255a085427f8, 0xc233e9e8c4c9439a }, ! 2033: }; ! 2034: ! 2035: #define SSE_OP(op)\ ! 2036: {\ ! 2037: asm volatile (#op " %2, %0" : "=x" (r.dq) : "0" (a.dq), "x" (b.dq));\ ! 2038: printf("%-9s: a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X " r=" FMT64X "" FMT64X "\n",\ ! 2039: #op,\ ! 2040: a.q[1], a.q[0],\ ! 2041: b.q[1], b.q[0],\ ! 2042: r.q[1], r.q[0]);\ ! 2043: } ! 2044: ! 2045: #define SSE_OP2(op)\ ! 2046: {\ ! 2047: int i;\ ! 2048: for(i=0;i<2;i++) {\ ! 2049: a.q[0] = test_values[2*i][0];\ ! 2050: a.q[1] = test_values[2*i][1];\ ! 2051: b.q[0] = test_values[2*i+1][0];\ ! 2052: b.q[1] = test_values[2*i+1][1];\ ! 2053: SSE_OP(op);\ ! 2054: }\ ! 2055: } ! 2056: ! 2057: #define MMX_OP2(op)\ ! 2058: {\ ! 2059: int i;\ ! 2060: for(i=0;i<2;i++) {\ ! 2061: a.q[0] = test_values[2*i][0];\ ! 2062: b.q[0] = test_values[2*i+1][0];\ ! 2063: asm volatile (#op " %2, %0" : "=y" (r.q[0]) : "0" (a.q[0]), "y" (b.q[0]));\ ! 2064: printf("%-9s: a=" FMT64X " b=" FMT64X " r=" FMT64X "\n",\ ! 2065: #op,\ ! 2066: a.q[0],\ ! 2067: b.q[0],\ ! 2068: r.q[0]);\ ! 2069: }\ ! 2070: SSE_OP2(op);\ ! 2071: } ! 2072: ! 2073: #define SHUF_OP(op, ib)\ ! 2074: {\ ! 2075: a.q[0] = test_values[0][0];\ ! 2076: a.q[1] = test_values[0][1];\ ! 2077: b.q[0] = test_values[1][0];\ ! 2078: b.q[1] = test_values[1][1];\ ! 2079: asm volatile (#op " $" #ib ", %2, %0" : "=x" (r.dq) : "0" (a.dq), "x" (b.dq));\ ! 2080: printf("%-9s: a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X " ib=%02x r=" FMT64X "" FMT64X "\n",\ ! 2081: #op,\ ! 2082: a.q[1], a.q[0],\ ! 2083: b.q[1], b.q[0],\ ! 2084: ib,\ ! 2085: r.q[1], r.q[0]);\ ! 2086: } ! 2087: ! 2088: #define PSHUF_OP(op, ib)\ ! 2089: {\ ! 2090: int i;\ ! 2091: for(i=0;i<2;i++) {\ ! 2092: a.q[0] = test_values[2*i][0];\ ! 2093: a.q[1] = test_values[2*i][1];\ ! 2094: asm volatile (#op " $" #ib ", %1, %0" : "=x" (r.dq) : "x" (a.dq));\ ! 2095: printf("%-9s: a=" FMT64X "" FMT64X " ib=%02x r=" FMT64X "" FMT64X "\n",\ ! 2096: #op,\ ! 2097: a.q[1], a.q[0],\ ! 2098: ib,\ ! 2099: r.q[1], r.q[0]);\ ! 2100: }\ ! 2101: } ! 2102: ! 2103: #define SHIFT_IM(op, ib)\ ! 2104: {\ ! 2105: int i;\ ! 2106: for(i=0;i<2;i++) {\ ! 2107: a.q[0] = test_values[2*i][0];\ ! 2108: a.q[1] = test_values[2*i][1];\ ! 2109: asm volatile (#op " $" #ib ", %0" : "=x" (r.dq) : "0" (a.dq));\ ! 2110: printf("%-9s: a=" FMT64X "" FMT64X " ib=%02x r=" FMT64X "" FMT64X "\n",\ ! 2111: #op,\ ! 2112: a.q[1], a.q[0],\ ! 2113: ib,\ ! 2114: r.q[1], r.q[0]);\ ! 2115: }\ ! 2116: } ! 2117: ! 2118: #define SHIFT_OP(op, ib)\ ! 2119: {\ ! 2120: int i;\ ! 2121: SHIFT_IM(op, ib);\ ! 2122: for(i=0;i<2;i++) {\ ! 2123: a.q[0] = test_values[2*i][0];\ ! 2124: a.q[1] = test_values[2*i][1];\ ! 2125: b.q[0] = ib;\ ! 2126: b.q[1] = 0;\ ! 2127: asm volatile (#op " %2, %0" : "=x" (r.dq) : "0" (a.dq), "x" (b.dq));\ ! 2128: printf("%-9s: a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X " r=" FMT64X "" FMT64X "\n",\ ! 2129: #op,\ ! 2130: a.q[1], a.q[0],\ ! 2131: b.q[1], b.q[0],\ ! 2132: r.q[1], r.q[0]);\ ! 2133: }\ ! 2134: } ! 2135: ! 2136: #define MOVMSK(op)\ ! 2137: {\ ! 2138: int i, reg;\ ! 2139: for(i=0;i<2;i++) {\ ! 2140: a.q[0] = test_values[2*i][0];\ ! 2141: a.q[1] = test_values[2*i][1];\ ! 2142: asm volatile (#op " %1, %0" : "=r" (reg) : "x" (a.dq));\ ! 2143: printf("%-9s: a=" FMT64X "" FMT64X " r=%08x\n",\ ! 2144: #op,\ ! 2145: a.q[1], a.q[0],\ ! 2146: reg);\ ! 2147: }\ ! 2148: } ! 2149: ! 2150: #define SSE_OPS(a) \ ! 2151: SSE_OP(a ## ps);\ ! 2152: SSE_OP(a ## ss); ! 2153: ! 2154: #define SSE_OPD(a) \ ! 2155: SSE_OP(a ## pd);\ ! 2156: SSE_OP(a ## sd); ! 2157: ! 2158: #define SSE_COMI(op, field)\ ! 2159: {\ ! 2160: unsigned int eflags;\ ! 2161: XMMReg a, b;\ ! 2162: a.field[0] = a1;\ ! 2163: b.field[0] = b1;\ ! 2164: asm volatile (#op " %2, %1\n"\ ! 2165: "pushf\n"\ ! 2166: "pop %0\n"\ ! 2167: : "=m" (eflags)\ ! 2168: : "x" (a.dq), "x" (b.dq));\ ! 2169: printf("%-9s: a=%f b=%f cc=%04x\n",\ ! 2170: #op, a1, b1,\ ! 2171: eflags & (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));\ ! 2172: } ! 2173: ! 2174: void test_sse_comi(double a1, double b1) ! 2175: { ! 2176: SSE_COMI(ucomiss, s); ! 2177: SSE_COMI(ucomisd, d); ! 2178: SSE_COMI(comiss, s); ! 2179: SSE_COMI(comisd, d); ! 2180: } ! 2181: ! 2182: #define CVT_OP_XMM(op)\ ! 2183: {\ ! 2184: asm volatile (#op " %1, %0" : "=x" (r.dq) : "x" (a.dq));\ ! 2185: printf("%-9s: a=" FMT64X "" FMT64X " r=" FMT64X "" FMT64X "\n",\ ! 2186: #op,\ ! 2187: a.q[1], a.q[0],\ ! 2188: r.q[1], r.q[0]);\ ! 2189: } ! 2190: ! 2191: #define CVT_OP_XMM2MMX(op)\ ! 2192: {\ ! 2193: asm volatile (#op " %1, %0" : "=y" (r.q[0]) : "x" (a.dq));\ ! 2194: printf("%-9s: a=" FMT64X "" FMT64X " r=" FMT64X "\n",\ ! 2195: #op,\ ! 2196: a.q[1], a.q[0],\ ! 2197: r.q[0]);\ ! 2198: } ! 2199: ! 2200: #define CVT_OP_MMX2XMM(op)\ ! 2201: {\ ! 2202: asm volatile (#op " %1, %0" : "=x" (r.dq) : "y" (a.q[0]));\ ! 2203: printf("%-9s: a=" FMT64X " r=" FMT64X "" FMT64X "\n",\ ! 2204: #op,\ ! 2205: a.q[0],\ ! 2206: r.q[1], r.q[0]);\ ! 2207: } ! 2208: ! 2209: #define CVT_OP_REG2XMM(op)\ ! 2210: {\ ! 2211: asm volatile (#op " %1, %0" : "=x" (r.dq) : "r" (a.l[0]));\ ! 2212: printf("%-9s: a=%08x r=" FMT64X "" FMT64X "\n",\ ! 2213: #op,\ ! 2214: a.l[0],\ ! 2215: r.q[1], r.q[0]);\ ! 2216: } ! 2217: ! 2218: #define CVT_OP_XMM2REG(op)\ ! 2219: {\ ! 2220: asm volatile (#op " %1, %0" : "=r" (r.l[0]) : "x" (a.dq));\ ! 2221: printf("%-9s: a=" FMT64X "" FMT64X " r=%08x\n",\ ! 2222: #op,\ ! 2223: a.q[1], a.q[0],\ ! 2224: r.l[0]);\ ! 2225: } ! 2226: ! 2227: struct fpxstate { ! 2228: uint16_t fpuc; ! 2229: uint16_t fpus; ! 2230: uint16_t fptag; ! 2231: uint16_t fop; ! 2232: uint32_t fpuip; ! 2233: uint16_t cs_sel; ! 2234: uint16_t dummy0; ! 2235: uint32_t fpudp; ! 2236: uint16_t ds_sel; ! 2237: uint16_t dummy1; ! 2238: uint32_t mxcsr; ! 2239: uint32_t mxcsr_mask; ! 2240: uint8_t fpregs1[8 * 16]; ! 2241: uint8_t xmm_regs[8 * 16]; ! 2242: uint8_t dummy2[224]; ! 2243: }; ! 2244: ! 2245: static struct fpxstate fpx_state __attribute__((aligned(16))); ! 2246: static struct fpxstate fpx_state2 __attribute__((aligned(16))); ! 2247: ! 2248: void test_fxsave(void) ! 2249: { ! 2250: struct fpxstate *fp = &fpx_state; ! 2251: struct fpxstate *fp2 = &fpx_state2; ! 2252: int i, nb_xmm; ! 2253: XMMReg a, b; ! 2254: a.q[0] = test_values[0][0]; ! 2255: a.q[1] = test_values[0][1]; ! 2256: b.q[0] = test_values[1][0]; ! 2257: b.q[1] = test_values[1][1]; ! 2258: ! 2259: asm("movdqa %2, %%xmm0\n" ! 2260: "movdqa %3, %%xmm7\n" ! 2261: #if defined(__x86_64__) ! 2262: "movdqa %2, %%xmm15\n" ! 2263: #endif ! 2264: " fld1\n" ! 2265: " fldpi\n" ! 2266: " fldln2\n" ! 2267: " fxsave %0\n" ! 2268: " fxrstor %0\n" ! 2269: " fxsave %1\n" ! 2270: " fninit\n" ! 2271: : "=m" (*(uint32_t *)fp2), "=m" (*(uint32_t *)fp) ! 2272: : "m" (a), "m" (b)); ! 2273: printf("fpuc=%04x\n", fp->fpuc); ! 2274: printf("fpus=%04x\n", fp->fpus); ! 2275: printf("fptag=%04x\n", fp->fptag); ! 2276: for(i = 0; i < 3; i++) { ! 2277: printf("ST%d: " FMT64X " %04x\n", ! 2278: i, ! 2279: *(uint64_t *)&fp->fpregs1[i * 16], ! 2280: *(uint16_t *)&fp->fpregs1[i * 16 + 8]); ! 2281: } ! 2282: printf("mxcsr=%08x\n", fp->mxcsr & 0x1f80); ! 2283: #if defined(__x86_64__) ! 2284: nb_xmm = 16; ! 2285: #else ! 2286: nb_xmm = 8; ! 2287: #endif ! 2288: for(i = 0; i < nb_xmm; i++) { ! 2289: printf("xmm%d: " FMT64X "" FMT64X "\n", ! 2290: i, ! 2291: *(uint64_t *)&fp->xmm_regs[i * 16], ! 2292: *(uint64_t *)&fp->xmm_regs[i * 16 + 8]); ! 2293: } ! 2294: } ! 2295: ! 2296: void test_sse(void) ! 2297: { ! 2298: XMMReg r, a, b; ! 2299: int i; ! 2300: ! 2301: MMX_OP2(punpcklbw); ! 2302: MMX_OP2(punpcklwd); ! 2303: MMX_OP2(punpckldq); ! 2304: MMX_OP2(packsswb); ! 2305: MMX_OP2(pcmpgtb); ! 2306: MMX_OP2(pcmpgtw); ! 2307: MMX_OP2(pcmpgtd); ! 2308: MMX_OP2(packuswb); ! 2309: MMX_OP2(punpckhbw); ! 2310: MMX_OP2(punpckhwd); ! 2311: MMX_OP2(punpckhdq); ! 2312: MMX_OP2(packssdw); ! 2313: MMX_OP2(pcmpeqb); ! 2314: MMX_OP2(pcmpeqw); ! 2315: MMX_OP2(pcmpeqd); ! 2316: ! 2317: MMX_OP2(paddq); ! 2318: MMX_OP2(pmullw); ! 2319: MMX_OP2(psubusb); ! 2320: MMX_OP2(psubusw); ! 2321: MMX_OP2(pminub); ! 2322: MMX_OP2(pand); ! 2323: MMX_OP2(paddusb); ! 2324: MMX_OP2(paddusw); ! 2325: MMX_OP2(pmaxub); ! 2326: MMX_OP2(pandn); ! 2327: ! 2328: MMX_OP2(pmulhuw); ! 2329: MMX_OP2(pmulhw); ! 2330: ! 2331: MMX_OP2(psubsb); ! 2332: MMX_OP2(psubsw); ! 2333: MMX_OP2(pminsw); ! 2334: MMX_OP2(por); ! 2335: MMX_OP2(paddsb); ! 2336: MMX_OP2(paddsw); ! 2337: MMX_OP2(pmaxsw); ! 2338: MMX_OP2(pxor); ! 2339: MMX_OP2(pmuludq); ! 2340: MMX_OP2(pmaddwd); ! 2341: MMX_OP2(psadbw); ! 2342: MMX_OP2(psubb); ! 2343: MMX_OP2(psubw); ! 2344: MMX_OP2(psubd); ! 2345: MMX_OP2(psubq); ! 2346: MMX_OP2(paddb); ! 2347: MMX_OP2(paddw); ! 2348: MMX_OP2(paddd); ! 2349: ! 2350: MMX_OP2(pavgb); ! 2351: MMX_OP2(pavgw); ! 2352: ! 2353: asm volatile ("pinsrw $1, %1, %0" : "=y" (r.q[0]) : "r" (0x12345678)); ! 2354: printf("%-9s: r=" FMT64X "\n", "pinsrw", r.q[0]); ! 2355: ! 2356: asm volatile ("pinsrw $5, %1, %0" : "=x" (r.dq) : "r" (0x12345678)); ! 2357: printf("%-9s: r=" FMT64X "" FMT64X "\n", "pinsrw", r.q[1], r.q[0]); ! 2358: ! 2359: a.q[0] = test_values[0][0]; ! 2360: a.q[1] = test_values[0][1]; ! 2361: asm volatile ("pextrw $1, %1, %0" : "=r" (r.l[0]) : "y" (a.q[0])); ! 2362: printf("%-9s: r=%08x\n", "pextrw", r.l[0]); ! 2363: ! 2364: asm volatile ("pextrw $5, %1, %0" : "=r" (r.l[0]) : "x" (a.dq)); ! 2365: printf("%-9s: r=%08x\n", "pextrw", r.l[0]); ! 2366: ! 2367: asm volatile ("pmovmskb %1, %0" : "=r" (r.l[0]) : "y" (a.q[0])); ! 2368: printf("%-9s: r=%08x\n", "pmovmskb", r.l[0]); ! 2369: ! 2370: asm volatile ("pmovmskb %1, %0" : "=r" (r.l[0]) : "x" (a.dq)); ! 2371: printf("%-9s: r=%08x\n", "pmovmskb", r.l[0]); ! 2372: ! 2373: { ! 2374: r.q[0] = -1; ! 2375: r.q[1] = -1; ! 2376: ! 2377: a.q[0] = test_values[0][0]; ! 2378: a.q[1] = test_values[0][1]; ! 2379: b.q[0] = test_values[1][0]; ! 2380: b.q[1] = test_values[1][1]; ! 2381: asm volatile("maskmovq %1, %0" : ! 2382: : "y" (a.q[0]), "y" (b.q[0]), "D" (&r) ! 2383: : "memory"); ! 2384: printf("%-9s: r=" FMT64X " a=" FMT64X " b=" FMT64X "\n", ! 2385: "maskmov", ! 2386: r.q[0], ! 2387: a.q[0], ! 2388: b.q[0]); ! 2389: asm volatile("maskmovdqu %1, %0" : ! 2390: : "x" (a.dq), "x" (b.dq), "D" (&r) ! 2391: : "memory"); ! 2392: printf("%-9s: r=" FMT64X "" FMT64X " a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X "\n", ! 2393: "maskmov", ! 2394: r.q[1], r.q[0], ! 2395: a.q[1], a.q[0], ! 2396: b.q[1], b.q[0]); ! 2397: } ! 2398: ! 2399: asm volatile ("emms"); ! 2400: ! 2401: SSE_OP2(punpcklqdq); ! 2402: SSE_OP2(punpckhqdq); ! 2403: SSE_OP2(andps); ! 2404: SSE_OP2(andpd); ! 2405: SSE_OP2(andnps); ! 2406: SSE_OP2(andnpd); ! 2407: SSE_OP2(orps); ! 2408: SSE_OP2(orpd); ! 2409: SSE_OP2(xorps); ! 2410: SSE_OP2(xorpd); ! 2411: ! 2412: SSE_OP2(unpcklps); ! 2413: SSE_OP2(unpcklpd); ! 2414: SSE_OP2(unpckhps); ! 2415: SSE_OP2(unpckhpd); ! 2416: ! 2417: SHUF_OP(shufps, 0x78); ! 2418: SHUF_OP(shufpd, 0x02); ! 2419: ! 2420: PSHUF_OP(pshufd, 0x78); ! 2421: PSHUF_OP(pshuflw, 0x78); ! 2422: PSHUF_OP(pshufhw, 0x78); ! 2423: ! 2424: SHIFT_OP(psrlw, 7); ! 2425: SHIFT_OP(psrlw, 16); ! 2426: SHIFT_OP(psraw, 7); ! 2427: SHIFT_OP(psraw, 16); ! 2428: SHIFT_OP(psllw, 7); ! 2429: SHIFT_OP(psllw, 16); ! 2430: ! 2431: SHIFT_OP(psrld, 7); ! 2432: SHIFT_OP(psrld, 32); ! 2433: SHIFT_OP(psrad, 7); ! 2434: SHIFT_OP(psrad, 32); ! 2435: SHIFT_OP(pslld, 7); ! 2436: SHIFT_OP(pslld, 32); ! 2437: ! 2438: SHIFT_OP(psrlq, 7); ! 2439: SHIFT_OP(psrlq, 32); ! 2440: SHIFT_OP(psllq, 7); ! 2441: SHIFT_OP(psllq, 32); ! 2442: ! 2443: SHIFT_IM(psrldq, 16); ! 2444: SHIFT_IM(psrldq, 7); ! 2445: SHIFT_IM(pslldq, 16); ! 2446: SHIFT_IM(pslldq, 7); ! 2447: ! 2448: MOVMSK(movmskps); ! 2449: MOVMSK(movmskpd); ! 2450: ! 2451: /* FPU specific ops */ ! 2452: ! 2453: { ! 2454: uint32_t mxcsr; ! 2455: asm volatile("stmxcsr %0" : "=m" (mxcsr)); ! 2456: printf("mxcsr=%08x\n", mxcsr & 0x1f80); ! 2457: asm volatile("ldmxcsr %0" : : "m" (mxcsr)); ! 2458: } ! 2459: ! 2460: test_sse_comi(2, -1); ! 2461: test_sse_comi(2, 2); ! 2462: test_sse_comi(2, 3); ! 2463: test_sse_comi(2, q_nan.d); ! 2464: test_sse_comi(q_nan.d, -1); ! 2465: ! 2466: for(i = 0; i < 2; i++) { ! 2467: a.s[0] = 2.7; ! 2468: a.s[1] = 3.4; ! 2469: a.s[2] = 4; ! 2470: a.s[3] = -6.3; ! 2471: b.s[0] = 45.7; ! 2472: b.s[1] = 353.4; ! 2473: b.s[2] = 4; ! 2474: b.s[3] = 56.3; ! 2475: if (i == 1) { ! 2476: a.s[0] = q_nan.d; ! 2477: b.s[3] = q_nan.d; ! 2478: } ! 2479: ! 2480: SSE_OPS(add); ! 2481: SSE_OPS(mul); ! 2482: SSE_OPS(sub); ! 2483: SSE_OPS(min); ! 2484: SSE_OPS(div); ! 2485: SSE_OPS(max); ! 2486: SSE_OPS(sqrt); ! 2487: SSE_OPS(cmpeq); ! 2488: SSE_OPS(cmplt); ! 2489: SSE_OPS(cmple); ! 2490: SSE_OPS(cmpunord); ! 2491: SSE_OPS(cmpneq); ! 2492: SSE_OPS(cmpnlt); ! 2493: SSE_OPS(cmpnle); ! 2494: SSE_OPS(cmpord); ! 2495: ! 2496: ! 2497: a.d[0] = 2.7; ! 2498: a.d[1] = -3.4; ! 2499: b.d[0] = 45.7; ! 2500: b.d[1] = -53.4; ! 2501: if (i == 1) { ! 2502: a.d[0] = q_nan.d; ! 2503: b.d[1] = q_nan.d; ! 2504: } ! 2505: SSE_OPD(add); ! 2506: SSE_OPD(mul); ! 2507: SSE_OPD(sub); ! 2508: SSE_OPD(min); ! 2509: SSE_OPD(div); ! 2510: SSE_OPD(max); ! 2511: SSE_OPD(sqrt); ! 2512: SSE_OPD(cmpeq); ! 2513: SSE_OPD(cmplt); ! 2514: SSE_OPD(cmple); ! 2515: SSE_OPD(cmpunord); ! 2516: SSE_OPD(cmpneq); ! 2517: SSE_OPD(cmpnlt); ! 2518: SSE_OPD(cmpnle); ! 2519: SSE_OPD(cmpord); ! 2520: } ! 2521: ! 2522: /* float to float/int */ ! 2523: a.s[0] = 2.7; ! 2524: a.s[1] = 3.4; ! 2525: a.s[2] = 4; ! 2526: a.s[3] = -6.3; ! 2527: CVT_OP_XMM(cvtps2pd); ! 2528: CVT_OP_XMM(cvtss2sd); ! 2529: CVT_OP_XMM2MMX(cvtps2pi); ! 2530: CVT_OP_XMM2MMX(cvttps2pi); ! 2531: CVT_OP_XMM2REG(cvtss2si); ! 2532: CVT_OP_XMM2REG(cvttss2si); ! 2533: CVT_OP_XMM(cvtps2dq); ! 2534: CVT_OP_XMM(cvttps2dq); ! 2535: ! 2536: a.d[0] = 2.6; ! 2537: a.d[1] = -3.4; ! 2538: CVT_OP_XMM(cvtpd2ps); ! 2539: CVT_OP_XMM(cvtsd2ss); ! 2540: CVT_OP_XMM2MMX(cvtpd2pi); ! 2541: CVT_OP_XMM2MMX(cvttpd2pi); ! 2542: CVT_OP_XMM2REG(cvtsd2si); ! 2543: CVT_OP_XMM2REG(cvttsd2si); ! 2544: CVT_OP_XMM(cvtpd2dq); ! 2545: CVT_OP_XMM(cvttpd2dq); ! 2546: ! 2547: /* int to float */ ! 2548: a.l[0] = -6; ! 2549: a.l[1] = 2; ! 2550: a.l[2] = 100; ! 2551: a.l[3] = -60000; ! 2552: CVT_OP_MMX2XMM(cvtpi2ps); ! 2553: CVT_OP_MMX2XMM(cvtpi2pd); ! 2554: CVT_OP_REG2XMM(cvtsi2ss); ! 2555: CVT_OP_REG2XMM(cvtsi2sd); ! 2556: CVT_OP_XMM(cvtdq2ps); ! 2557: CVT_OP_XMM(cvtdq2pd); ! 2558: ! 2559: /* XXX: test PNI insns */ ! 2560: #if 0 ! 2561: SSE_OP2(movshdup); ! 2562: #endif ! 2563: asm volatile ("emms"); ! 2564: } ! 2565: ! 2566: #endif ! 2567: ! 2568: extern void *__start_initcall; ! 2569: extern void *__stop_initcall; ! 2570: ! 2571: ! 2572: int main(int argc, char **argv) ! 2573: { ! 2574: void **ptr; ! 2575: void (*func)(void); ! 2576: ! 2577: ptr = &__start_initcall; ! 2578: while (ptr != &__stop_initcall) { ! 2579: func = *ptr++; ! 2580: func(); ! 2581: } ! 2582: test_bsx(); ! 2583: test_mul(); ! 2584: test_jcc(); ! 2585: test_floats(); ! 2586: #if !defined(__x86_64__) ! 2587: test_bcd(); ! 2588: #endif ! 2589: test_xchg(); ! 2590: test_string(); ! 2591: test_misc(); ! 2592: test_lea(); ! 2593: #ifdef TEST_SEGS ! 2594: test_segs(); ! 2595: test_code16(); ! 2596: #endif ! 2597: #ifdef TEST_VM86 ! 2598: test_vm86(); ! 2599: #endif ! 2600: test_exceptions(); ! 2601: #if !defined(__x86_64__) ! 2602: test_self_modifying_code(); ! 2603: test_single_step(); ! 2604: #endif ! 2605: test_enter(); ! 2606: #ifdef TEST_SSE ! 2607: test_sse(); ! 2608: test_fxsave(); ! 2609: #endif ! 2610: return 0; ! 2611: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.