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