1 
2 /* To build:
3 
4      gcc -g -o test-amd64 test-amd64.c -lm
5 
6  */
7 
8 /* Contrary to what the next comment says, this is now an amd64 CPU
9    test. */
10 
11 /*
12  *  x86 CPU test
13  *
14  *  Copyright (c) 2003 Fabrice Bellard
15  *
16  *  This program is free software; you can redistribute it and/or modify
17  *  it under the terms of the GNU General Public License as published by
18  *  the Free Software Foundation; either version 2 of the License, or
19  *  (at your option) any later version.
20  *
21  *  This program is distributed in the hope that it will be useful,
22  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
23  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  *  GNU General Public License for more details.
25  *
26  *  You should have received a copy of the GNU General Public License
27  *  along with this program; if not, write to the Free Software
28  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29  */
30 #define _GNU_SOURCE
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <inttypes.h>
35 #include <math.h>
36 #include <signal.h>
37 #include <setjmp.h>
38 #include <errno.h>
39 #include <sys/ucontext.h>
40 #include <sys/mman.h>
41 
42 /* Setting this to 1 creates a very comprehensive test of
43    integer condition codes. */
44 #define TEST_INTEGER_VERBOSE 1
45 
46 typedef  long long int  int64;
47 
48 //#define LINUX_VM86_IOPL_FIX
49 //#define TEST_P4_FLAGS
50 
51 #define xglue(x, y) x ## y
52 #define glue(x, y) xglue(x, y)
53 #define stringify(s)	tostring(s)
54 #define tostring(s)	#s
55 
56 #define CC_C   	0x0001
57 #define CC_P 	0x0004
58 #define CC_A	0x0010
59 #define CC_Z	0x0040
60 #define CC_S    0x0080
61 #define CC_O    0x0800
62 
63 #define __init_call	__attribute__ ((unused,__section__ (".initcall.init")))
64 
65 static void *call_start __init_call = NULL;
66 
67 #define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)
68 
69 #define OP add
70 #include "test-amd64.h"
71 
72 #define OP sub
73 #include "test-amd64.h"
74 
75 #define OP xor
76 #include "test-amd64.h"
77 
78 #define OP and
79 #include "test-amd64.h"
80 
81 #define OP or
82 #include "test-amd64.h"
83 
84 #define OP cmp
85 #include "test-amd64.h"
86 
87 #define OP adc
88 #define OP_CC
89 #include "test-amd64.h"
90 
91 #define OP sbb
92 #define OP_CC
93 #include "test-amd64.h"
94 
95 #define OP inc
96 #define OP_CC
97 #define OP1
98 #include "test-amd64.h"
99 
100 #define OP dec
101 #define OP_CC
102 #define OP1
103 #include "test-amd64.h"
104 
105 #define OP neg
106 #define OP_CC
107 #define OP1
108 #include "test-amd64.h"
109 
110 #define OP not
111 #define OP_CC
112 #define OP1
113 #include "test-amd64.h"
114 
115 #undef CC_MASK
116 #define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O)
117 
118 #define OP shl
119 #include "test-amd64-shift.h"
120 
121 #define OP shr
122 #include "test-amd64-shift.h"
123 
124 #define OP sar
125 #include "test-amd64-shift.h"
126 
127 #define OP rol
128 #include "test-amd64-shift.h"
129 
130 #define OP ror
131 #include "test-amd64-shift.h"
132 
133 #define OP rcr
134 #define OP_CC
135 #include "test-amd64-shift.h"
136 
137 #define OP rcl
138 #define OP_CC
139 #include "test-amd64-shift.h"
140 
141 #if 0
142 #define OP shld
143 #define OP_SHIFTD
144 #define OP_NOBYTE
145 #include "test-amd64-shift.h"
146 
147 #define OP shrd
148 #define OP_SHIFTD
149 #define OP_NOBYTE
150 #include "test-amd64-shift.h"
151 #endif
152 
153 /* XXX: should be more precise ? */
154 #undef CC_MASK
155 #define CC_MASK (CC_C)
156 
157 #if 0
158 #define OP bt
159 #define OP_NOBYTE
160 #include "test-amd64-shift.h"
161 
162 #define OP bts
163 #define OP_NOBYTE
164 #include "test-amd64-shift.h"
165 
166 #define OP btr
167 #define OP_NOBYTE
168 #include "test-amd64-shift.h"
169 
170 #define OP btc
171 #define OP_NOBYTE
172 #include "test-amd64-shift.h"
173 #endif
174 
175 /* lea test (modrm support) */
176 #define TEST_LEA(STR)\
177 {\
178     asm("leaq " STR ", %0"\
179         : "=r" (res)\
180         : "a" (rax), "b" (rbx), "c" (rcx), "d" (rdx), "S" (rsi), "D" (rdi));\
181     printf("lea %s = %016llx\n", STR, res);\
182 }
183 
184 #define TEST_LEA16(STR)\
185 {\
186     asm(".code16 ; .byte 0x67 ; leal " STR ", %0 ; .code32"\
187         : "=wq" (res)\
188         : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\
189     printf("lea %s = %08x\n", STR, res);\
190 }
191 
192 
test_lea(void)193 void test_lea(void)
194 {
195     int64 rax, rbx, rcx, rdx, rsi, rdi, res;
196     rax = 0x0001;
197     rbx = 0x0002;
198     rcx = 0x0004;
199     rdx = 0x0008;
200     rsi = 0x0010;
201     rdi = 0x0020;
202 
203     TEST_LEA("0x4000");
204 
205     TEST_LEA("(%%rax)");
206     TEST_LEA("(%%rbx)");
207     TEST_LEA("(%%rcx)");
208     TEST_LEA("(%%rdx)");
209     TEST_LEA("(%%rsi)");
210     TEST_LEA("(%%rdi)");
211 
212     TEST_LEA("0x40(%%rax)");
213     TEST_LEA("0x40(%%rbx)");
214     TEST_LEA("0x40(%%rcx)");
215     TEST_LEA("0x40(%%rdx)");
216     TEST_LEA("0x40(%%rsi)");
217     TEST_LEA("0x40(%%rdi)");
218 
219     TEST_LEA("0x4000(%%rax)");
220     TEST_LEA("0x4000(%%rbx)");
221     TEST_LEA("0x4000(%%rcx)");
222     TEST_LEA("0x4000(%%rdx)");
223     TEST_LEA("0x4000(%%rsi)");
224     TEST_LEA("0x4000(%%rdi)");
225 
226     TEST_LEA("(%%rax, %%rcx)");
227     TEST_LEA("(%%rbx, %%rdx)");
228     TEST_LEA("(%%rcx, %%rcx)");
229     TEST_LEA("(%%rdx, %%rcx)");
230     TEST_LEA("(%%rsi, %%rcx)");
231     TEST_LEA("(%%rdi, %%rcx)");
232 
233     TEST_LEA("0x40(%%rax, %%rcx)");
234     TEST_LEA("0x4000(%%rbx, %%rdx)");
235 
236     TEST_LEA("(%%rcx, %%rcx, 2)");
237     TEST_LEA("(%%rdx, %%rcx, 4)");
238     TEST_LEA("(%%rsi, %%rcx, 8)");
239 
240     TEST_LEA("(,%%rax, 2)");
241     TEST_LEA("(,%%rbx, 4)");
242     TEST_LEA("(,%%rcx, 8)");
243 
244     TEST_LEA("0x40(,%%rax, 2)");
245     TEST_LEA("0x40(,%%rbx, 4)");
246     TEST_LEA("0x40(,%%rcx, 8)");
247 
248 
249     TEST_LEA("-10(%%rcx, %%rcx, 2)");
250     TEST_LEA("-10(%%rdx, %%rcx, 4)");
251     TEST_LEA("-10(%%rsi, %%rcx, 8)");
252 
253     TEST_LEA("0x4000(%%rcx, %%rcx, 2)");
254     TEST_LEA("0x4000(%%rdx, %%rcx, 4)");
255     TEST_LEA("0x4000(%%rsi, %%rcx, 8)");
256 }
257 
258 #define TEST_JCC(JCC, v1, v2)\
259 {   int one = 1; \
260     int res;\
261     asm("movl $1, %0\n\t"\
262         "cmpl %2, %1\n\t"\
263         "j" JCC " 1f\n\t"\
264         "movl $0, %0\n\t"\
265         "1:\n\t"\
266         : "=r" (res)\
267         : "r" (v1), "r" (v2));\
268     printf("%-10s %d\n", "j" JCC, res);\
269 \
270     asm("movl $0, %0\n\t"\
271         "cmpl %2, %1\n\t"\
272         "set" JCC " %b0\n\t"\
273         : "=r" (res)\
274         : "r" (v1), "r" (v2));\
275     printf("%-10s %d\n", "set" JCC, res);\
276  {\
277     asm("movl $0x12345678, %0\n\t"\
278         "cmpl %2, %1\n\t"\
279         "cmov" JCC "l %3, %0\n\t"\
280         : "=r" (res)\
281         : "r" (v1), "r" (v2), "m" (one));\
282         printf("%-10s R=0x%08x\n", "cmov" JCC "l", res);\
283     asm("movl $0x12345678, %0\n\t"\
284         "cmpl %2, %1\n\t"\
285         "cmov" JCC "w %w3, %w0\n\t"\
286         : "=r" (res)\
287         : "r" (v1), "r" (v2), "r" (one));\
288         printf("%-10s R=0x%08x\n", "cmov" JCC "w", res);\
289  } \
290 }
291 
292 /* various jump tests */
test_jcc(void)293 void test_jcc(void)
294 {
295     TEST_JCC("ne", 1, 1);
296     TEST_JCC("ne", 1, 0);
297 
298     TEST_JCC("e", 1, 1);
299     TEST_JCC("e", 1, 0);
300 
301     TEST_JCC("l", 1, 1);
302     TEST_JCC("l", 1, 0);
303     TEST_JCC("l", 1, -1);
304 
305     TEST_JCC("le", 1, 1);
306     TEST_JCC("le", 1, 0);
307     TEST_JCC("le", 1, -1);
308 
309     TEST_JCC("ge", 1, 1);
310     TEST_JCC("ge", 1, 0);
311     TEST_JCC("ge", -1, 1);
312 
313     TEST_JCC("g", 1, 1);
314     TEST_JCC("g", 1, 0);
315     TEST_JCC("g", 1, -1);
316 
317     TEST_JCC("b", 1, 1);
318     TEST_JCC("b", 1, 0);
319     TEST_JCC("b", 1, -1);
320 
321     TEST_JCC("be", 1, 1);
322     TEST_JCC("be", 1, 0);
323     TEST_JCC("be", 1, -1);
324 
325     TEST_JCC("ae", 1, 1);
326     TEST_JCC("ae", 1, 0);
327     TEST_JCC("ae", 1, -1);
328 
329     TEST_JCC("a", 1, 1);
330     TEST_JCC("a", 1, 0);
331     TEST_JCC("a", 1, -1);
332 
333 
334     TEST_JCC("p", 1, 1);
335     TEST_JCC("p", 1, 0);
336 
337     TEST_JCC("np", 1, 1);
338     TEST_JCC("np", 1, 0);
339 
340     TEST_JCC("o", 0x7fffffff, 0);
341     TEST_JCC("o", 0x7fffffff, -1);
342 
343     TEST_JCC("no", 0x7fffffff, 0);
344     TEST_JCC("no", 0x7fffffff, -1);
345 
346     TEST_JCC("s", 0, 1);
347     TEST_JCC("s", 0, -1);
348     TEST_JCC("s", 0, 0);
349 
350     TEST_JCC("ns", 0, 1);
351     TEST_JCC("ns", 0, -1);
352     TEST_JCC("ns", 0, 0);
353 }
354 
355 #undef CC_MASK
356 #ifdef TEST_P4_FLAGS
357 #define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)
358 #else
359 #define CC_MASK (CC_O | CC_C)
360 #endif
361 
362 #define OP mul
363 #include "test-amd64-muldiv.h"
364 
365 #define OP imul
366 #include "test-amd64-muldiv.h"
367 
test_imulw2(int64 op0,int64 op1)368 void test_imulw2(int64 op0, int64 op1)
369 {
370     int64 res, s1, s0, flags;
371     s0 = op0;
372     s1 = op1;
373     res = s0;
374     flags = 0;
375     asm ("pushq %4\n\t"
376          "popfq\n\t"
377          "imulw %w2, %w0\n\t"
378          "pushfq\n\t"
379          "popq %1\n\t"
380          : "=q" (res), "=g" (flags)
381          : "q" (s1), "0" (res), "1" (flags));
382     printf("%-10s A=%016llx B=%016llx R=%016llx CC=%04llx\n",
383            "imulw", s0, s1, res, flags & CC_MASK);
384 }
385 
test_imull2(int64 op0,int64 op1)386 void test_imull2(int64 op0, int64 op1)
387 {
388     int res, s1;
389     int64 s0, flags;
390     s0 = op0;
391     s1 = op1;
392     res = s0;
393     flags = 0;
394     asm ("pushq %4\n\t"
395          "popfq\n\t"
396          "imull %2, %0\n\t"
397          "pushfq\n\t"
398          "popq %1\n\t"
399          : "=q" (res), "=g" (flags)
400          : "q" (s1), "0" (res), "1" (flags));
401     printf("%-10s A=%016llx B=%08x R=%08x CC=%04llx\n",
402            "imull", s0, s1, res, flags & CC_MASK);
403 }
404 
405 #define TEST_IMUL_IM(size, size1, op0, op1)\
406 {\
407     int64 res, flags;\
408     flags = 0;\
409     res = 0;\
410     asm ("pushq %3\n\t"\
411          "popfq\n\t"\
412          "imul" size " $" #op0 ", %" size1 "2, %" size1 "0\n\t" \
413          "pushfq\n\t"\
414          "popq %1\n\t"\
415          : "=r" (res), "=g" (flags)\
416          : "r" (op1), "1" (flags), "0" (res));\
417     printf("%-10s A=%08x B=%08x R=%016llx CC=%04llx\n",\
418            "imul" size, op0, op1, res, flags & CC_MASK);\
419 }
420 
421 #define TEST_IMUL_IM_L(op0, op1)\
422 {\
423     int64 flags = 0;\
424     int res = 0;\
425     int res64 = 0;\
426     asm ("pushq %3\n\t"\
427          "popfq\n\t"\
428          "imul $" #op0 ", %2, %0\n\t" \
429          "pushfq\n\t"\
430          "popq %1\n\t"\
431          : "=r" (res64), "=g" (flags)\
432          : "r" (op1), "1" (flags), "0" (res));\
433     printf("%-10s A=%08x B=%08x R=%08x CC=%04llx\n",\
434            "imull", op0, op1, res, flags & CC_MASK);\
435 }
436 
437 
438 #undef CC_MASK
439 #define CC_MASK (0)
440 
441 #define OP div
442 #include "test-amd64-muldiv.h"
443 
444 #define OP idiv
445 #include "test-amd64-muldiv.h"
446 
test_mul(void)447 void test_mul(void)
448 {
449     test_imulb(0x1234561d, 4);
450     test_imulb(3, -4);
451     test_imulb(0x80, 0x80);
452     test_imulb(0x10, 0x10);
453 
454     test_imulw(0, 0, 0);
455     test_imulw(0, 0xFF, 0xFF);
456     test_imulw(0, 0xFF, 0x100);
457     test_imulw(0, 0x1234001d, 45);
458     test_imulw(0, 23, -45);
459     test_imulw(0, 0x8000, 0x8000);
460     test_imulw(0, 0x100, 0x100);
461 
462     test_imull(0, 0, 0);
463     test_imull(0, 0xFFFF, 0xFFFF);
464     test_imull(0, 0xFFFF, 0x10000);
465     test_imull(0, 0x1234001d, 45);
466     test_imull(0, 23, -45);
467     test_imull(0, 0x80000000, 0x80000000);
468     test_imull(0, 0x10000, 0x10000);
469 
470     test_mulb(0x1234561d, 4);
471     test_mulb(3, -4);
472     test_mulb(0x80, 0x80);
473     test_mulb(0x10, 0x10);
474 
475     test_mulw(0, 0x1234001d, 45);
476     test_mulw(0, 23, -45);
477     test_mulw(0, 0x8000, 0x8000);
478     test_mulw(0, 0x100, 0x100);
479 
480     test_mull(0, 0x1234001d, 45);
481     test_mull(0, 23, -45);
482     test_mull(0, 0x80000000, 0x80000000);
483     test_mull(0, 0x10000, 0x10000);
484 
485     test_imulw2(0x1234001d, 45);
486     test_imulw2(23, -45);
487     test_imulw2(0x8000, 0x8000);
488     test_imulw2(0x100, 0x100);
489 
490     test_imull2(0x1234001d, 45);
491     test_imull2(23, -45);
492     test_imull2(0x80000000, 0x80000000);
493     test_imull2(0x10000, 0x10000);
494 
495     TEST_IMUL_IM("w", "w", 45, 0x1234);
496     TEST_IMUL_IM("w", "w", -45, 23);
497     TEST_IMUL_IM("w", "w", 0x8000, 0x80000000);
498     TEST_IMUL_IM("w", "w", 0x7fff, 0x1000);
499 
500     TEST_IMUL_IM_L(45, 0x1234);
501     TEST_IMUL_IM_L(-45, 23);
502     TEST_IMUL_IM_L(0x8000, 0x80000000);
503     TEST_IMUL_IM_L(0x7fff, 0x1000);
504 
505     test_idivb(0x12341678, 0x127e);
506     test_idivb(0x43210123, -5);
507     test_idivb(0x12340004, -1);
508 
509     test_idivw(0, 0x12345678, 12347);
510     test_idivw(0, -23223, -45);
511     test_idivw(0, 0x12348000, -1);
512     test_idivw(0x12343, 0x12345678, 0x81238567);
513 
514     test_idivl(0, 0x12345678, 12347);
515     test_idivl(0, -233223, -45);
516     test_idivl(0, 0x80000000, -1);
517     test_idivl(0x12343, 0x12345678, 0x81234567);
518 
519     test_idivq(0, 0x12345678, 12347);
520     test_idivq(0, -233223, -45);
521     test_idivq(0, 0x80000000, -1);
522     test_idivq(0x12343, 0x12345678, 0x81234567);
523 
524     test_divb(0x12341678, 0x127e);
525     test_divb(0x43210123, -5);
526     test_divb(0x12340004, -1);
527 
528     test_divw(0, 0x12345678, 12347);
529     test_divw(0, -23223, -45);
530     test_divw(0, 0x12348000, -1);
531     test_divw(0x12343, 0x12345678, 0x81238567);
532 
533     test_divl(0, 0x12345678, 12347);
534     test_divl(0, -233223, -45);
535     test_divl(0, 0x80000000, -1);
536     test_divl(0x12343, 0x12345678, 0x81234567);
537 
538     test_divq(0, 0x12345678, 12347);
539     test_divq(0, -233223, -45);
540     test_divq(0, 0x80000000, -1);
541     test_divq(0x12343, 0x12345678, 0x81234567);
542 }
543 
544 #define TEST_BSX(op, size, op0)\
545 {\
546     int res, val, resz;\
547     val = op0;\
548     asm("xorl %1, %1\n"\
549         "movl $0x12345678, %0\n"\
550         #op " %" size "2, %" size "0 ; setz %b1" \
551         : "=r" (res), "=q" (resz)\
552         : "r" (val));\
553     printf("%-10s A=%08x R=%08x %d\n", #op, val, res, resz);\
554 }
555 
test_bsx(void)556 void test_bsx(void)
557 {
558     TEST_BSX(bsrw, "w", 0);
559     TEST_BSX(bsrw, "w", 0x12340128);
560     TEST_BSX(bsrl, "", 0);
561     TEST_BSX(bsrl, "", 0x00340128);
562     TEST_BSX(bsfw, "w", 0);
563     TEST_BSX(bsfw, "w", 0x12340128);
564     TEST_BSX(bsfl, "", 0);
565     TEST_BSX(bsfl, "", 0x00340128);
566 }
567 
568 /**********************************************/
569 
test_fops(double a,double b)570 void test_fops(double a, double b)
571 {
572     printf("a=%f b=%f a+b=%f\n", a, b, a + b);
573     printf("a=%f b=%f a-b=%f\n", a, b, a - b);
574     printf("a=%f b=%f a*b=%f\n", a, b, a * b);
575     printf("a=%f b=%f a/b=%f\n", a, b, a / b);
576     printf("a=%f b=%f fmod(a, b)=%f\n", a, b, fmod(a, b));
577     printf("a=%f sqrt(a)=%f\n", a, sqrt(a));
578     printf("a=%f sin(a)=%f\n", a, sin(a));
579     printf("a=%f cos(a)=%f\n", a, cos(a));
580     printf("a=%f tan(a)=%f\n", a, tan(a));
581     printf("a=%f log(a)=%f\n", a, log(a));
582     printf("a=%f exp(a)=%f\n", a, exp(a));
583     printf("a=%f b=%f atan2(a, b)=%f\n", a, b, atan2(a, b));
584     /* just to test some op combining */
585     printf("a=%f asin(sin(a))=%f\n", a, asin(sin(a)));
586     printf("a=%f acos(cos(a))=%f\n", a, acos(cos(a)));
587     printf("a=%f atan(tan(a))=%f\n", a, atan(tan(a)));
588 }
589 
test_fcmp(double a,double b)590 void test_fcmp(double a, double b)
591 {
592     printf("(%f<%f)=%d\n",
593            a, b, a < b);
594     printf("(%f<=%f)=%d\n",
595            a, b, a <= b);
596     printf("(%f==%f)=%d\n",
597            a, b, a == b);
598     printf("(%f>%f)=%d\n",
599            a, b, a > b);
600     printf("(%f<=%f)=%d\n",
601            a, b, a >= b);
602     {
603         unsigned long long int rflags;
604         /* test f(u)comi instruction */
605         asm("fcomi %2, %1\n"
606             "pushfq\n"
607             "popq %0\n"
608             : "=r" (rflags)
609             : "t" (a), "u" (b));
610         printf("fcomi(%f %f)=%016llx\n", a, b, rflags & (CC_Z | CC_P | CC_C));
611     }
612 }
613 
test_fcvt(double a)614 void test_fcvt(double a)
615 {
616     float fa;
617     long double la;
618     int16_t fpuc;
619     int i;
620     int64 lla;
621     int ia;
622     int16_t wa;
623     double ra;
624 
625     fa = a;
626     la = a;
627     printf("(float)%f = %f\n", a, fa);
628     printf("(long double)%f = %Lf\n", a, la);
629     printf("a=%016Lx\n", *(long long *)&a);
630     printf("la=%016Lx %04x\n", *(long long *)&la,
631            *(unsigned short *)((char *)(&la) + 8));
632 
633     /* test all roundings */
634     asm volatile ("fstcw %0" : "=m" (fpuc));
635     for(i=0;i<4;i++) {
636         short zz = (fpuc & ~0x0c00) | (i << 10);
637         asm volatile ("fldcw %0" : : "m" (zz));
638         asm volatile ("fist %0" : "=m" (wa) : "t" (a));
639         asm volatile ("fistl %0" : "=m" (ia) : "t" (a));
640         asm volatile ("fistpll %0" : "=m" (lla) : "t" (a) : "st");
641         asm volatile ("frndint ; fstl %0" : "=m" (ra) : "t" (a));
642         asm volatile ("fldcw %0" : : "m" (fpuc));
643         printf("(short)a = %d\n", wa);
644         printf("(int)a = %d\n", ia);
645         printf("(int64_t)a = %Ld\n", lla);
646         printf("rint(a) = %f\n", ra);
647     }
648 }
649 
650 #define TEST(N) \
651     asm("fld" #N : "=t" (a)); \
652     printf("fld" #N "= %f\n", a);
653 
test_fconst(void)654 void test_fconst(void)
655 {
656     double a;
657     TEST(1);
658     TEST(l2t);
659     TEST(l2e);
660     TEST(pi);
661     TEST(lg2);
662     TEST(ln2);
663     TEST(z);
664 }
665 
test_fbcd(double a)666 void test_fbcd(double a)
667 {
668     unsigned short bcd[5];
669     double b;
670 
671     asm("fbstp %0" : "=m" (bcd[0]) : "t" (a) : "st");
672     asm("fbld %1" : "=t" (b) : "m" (bcd[0]));
673     printf("a=%f bcd=%04x%04x%04x%04x%04x b=%f\n",
674            a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b);
675 }
676 
677 #define TEST_ENV(env, save, restore)\
678 {\
679     memset((env), 0xaa, sizeof(*(env)));\
680     for(i=0;i<5;i++)\
681         asm volatile ("fldl %0" : : "m" (dtab[i]));\
682     asm(save " %0\n" : : "m" (*(env)));\
683     asm(restore " %0\n": : "m" (*(env)));\
684     for(i=0;i<5;i++)\
685         asm volatile ("fstpl %0" : "=m" (rtab[i]));\
686     for(i=0;i<5;i++)\
687         printf("res[%d]=%f\n", i, rtab[i]);\
688     printf("fpuc=%04x fpus=%04x fptag=%04x\n",\
689            (env)->fpuc,\
690            (env)->fpus & 0xff00,\
691            (env)->fptag);\
692 }
693 
test_fenv(void)694 void test_fenv(void)
695 {
696     struct __attribute__((packed)) {
697         uint16_t fpuc;
698         uint16_t dummy1;
699         uint16_t fpus;
700         uint16_t dummy2;
701         uint16_t fptag;
702         uint16_t dummy3;
703         uint32_t ignored[4];
704         long double fpregs[8];
705     } float_env32;
706     struct __attribute__((packed)) {
707         uint16_t fpuc;
708         uint16_t fpus;
709         uint16_t fptag;
710         uint16_t ignored[4];
711         long double fpregs[8];
712     } float_env16;
713     double dtab[8];
714     double rtab[8];
715     int i;
716 
717     for(i=0;i<8;i++)
718         dtab[i] = i + 1;
719 
720     TEST_ENV(&float_env16, "data16 fnstenv", "data16 fldenv");
721     TEST_ENV(&float_env16, "data16 fnsave", "data16 frstor");
722     TEST_ENV(&float_env32, "fnstenv", "fldenv");
723     TEST_ENV(&float_env32, "fnsave", "frstor");
724 
725     /* test for ffree */
726     for(i=0;i<5;i++)
727         asm volatile ("fldl %0" : : "m" (dtab[i]));
728     asm volatile("ffree %st(2)");
729     asm volatile ("fnstenv %0\n" : : "m" (float_env32));
730     asm volatile ("fninit");
731     printf("fptag=%04x\n", float_env32.fptag);
732 }
733 
734 
735 #define TEST_FCMOV(a, b, rflags, CC)\
736 {\
737     double res;\
738     asm("pushq %3\n"\
739         "popfq\n"\
740         "fcmov" CC " %2, %0\n"\
741         : "=t" (res)\
742         : "0" (a), "u" (b), "g" (rflags));\
743     printf("fcmov%s rflags=0x%04llx-> %f\n", \
744            CC, rflags, res);\
745 }
746 
test_fcmov(void)747 void test_fcmov(void)
748 {
749     double a, b;
750     int64 rflags, i;
751 
752     a = 1.0;
753     b = 2.0;
754     for(i = 0; i < 4; i++) {
755         rflags = 0;
756         if (i & 1)
757             rflags |= CC_C;
758         if (i & 2)
759             rflags |= CC_Z;
760         TEST_FCMOV(a, b, rflags, "b");
761         TEST_FCMOV(a, b, rflags, "e");
762         TEST_FCMOV(a, b, rflags, "be");
763         TEST_FCMOV(a, b, rflags, "nb");
764         TEST_FCMOV(a, b, rflags, "ne");
765         TEST_FCMOV(a, b, rflags, "nbe");
766     }
767     TEST_FCMOV(a, b, (int64)0, "u");
768     TEST_FCMOV(a, b, (int64)CC_P, "u");
769     TEST_FCMOV(a, b, (int64)0, "nu");
770     TEST_FCMOV(a, b, (int64)CC_P, "nu");
771 }
772 
test_floats(void)773 void test_floats(void)
774 {
775     test_fops(2, 3);
776     test_fops(1.4, -5);
777     test_fcmp(2, -1);
778     test_fcmp(2, 2);
779     test_fcmp(2, 3);
780     test_fcvt(0.5);
781     test_fcvt(-0.5);
782     test_fcvt(1.0/7.0);
783     test_fcvt(-1.0/9.0);
784     test_fcvt(32768);
785     test_fcvt(-1e20);
786     test_fconst();
787     // REINSTATE (maybe): test_fbcd(1234567890123456);
788     // REINSTATE (maybe): test_fbcd(-123451234567890);
789     // REINSTATE: test_fenv();
790     // REINSTATE: test_fcmov();
791 }
792 
793 /**********************************************/
794 #if 0
795 
796 #define TEST_BCD(op, op0, cc_in, cc_mask)\
797 {\
798     int res, flags;\
799     res = op0;\
800     flags = cc_in;\
801     asm ("push %3\n\t"\
802          "popf\n\t"\
803          #op "\n\t"\
804          "pushf\n\t"\
805          "popl %1\n\t"\
806         : "=a" (res), "=g" (flags)\
807         : "0" (res), "1" (flags));\
808     printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n",\
809            #op, op0, res, cc_in, flags & cc_mask);\
810 }
811 
812 void test_bcd(void)
813 {
814     TEST_BCD(daa, 0x12340503, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
815     TEST_BCD(daa, 0x12340506, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
816     TEST_BCD(daa, 0x12340507, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
817     TEST_BCD(daa, 0x12340559, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
818     TEST_BCD(daa, 0x12340560, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
819     TEST_BCD(daa, 0x1234059f, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
820     TEST_BCD(daa, 0x123405a0, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
821     TEST_BCD(daa, 0x12340503, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A));
822     TEST_BCD(daa, 0x12340506, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A));
823     TEST_BCD(daa, 0x12340503, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A));
824     TEST_BCD(daa, 0x12340506, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A));
825     TEST_BCD(daa, 0x12340503, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
826     TEST_BCD(daa, 0x12340506, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
827 
828     TEST_BCD(das, 0x12340503, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
829     TEST_BCD(das, 0x12340506, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
830     TEST_BCD(das, 0x12340507, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
831     TEST_BCD(das, 0x12340559, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
832     TEST_BCD(das, 0x12340560, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
833     TEST_BCD(das, 0x1234059f, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
834     TEST_BCD(das, 0x123405a0, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
835     TEST_BCD(das, 0x12340503, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A));
836     TEST_BCD(das, 0x12340506, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A));
837     TEST_BCD(das, 0x12340503, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A));
838     TEST_BCD(das, 0x12340506, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A));
839     TEST_BCD(das, 0x12340503, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
840     TEST_BCD(das, 0x12340506, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
841 
842     TEST_BCD(aaa, 0x12340205, CC_A, (CC_C | CC_A));
843     TEST_BCD(aaa, 0x12340306, CC_A, (CC_C | CC_A));
844     TEST_BCD(aaa, 0x1234040a, CC_A, (CC_C | CC_A));
845     TEST_BCD(aaa, 0x123405fa, CC_A, (CC_C | CC_A));
846     TEST_BCD(aaa, 0x12340205, 0, (CC_C | CC_A));
847     TEST_BCD(aaa, 0x12340306, 0, (CC_C | CC_A));
848     TEST_BCD(aaa, 0x1234040a, 0, (CC_C | CC_A));
849     TEST_BCD(aaa, 0x123405fa, 0, (CC_C | CC_A));
850 
851     TEST_BCD(aas, 0x12340205, CC_A, (CC_C | CC_A));
852     TEST_BCD(aas, 0x12340306, CC_A, (CC_C | CC_A));
853     TEST_BCD(aas, 0x1234040a, CC_A, (CC_C | CC_A));
854     TEST_BCD(aas, 0x123405fa, CC_A, (CC_C | CC_A));
855     TEST_BCD(aas, 0x12340205, 0, (CC_C | CC_A));
856     TEST_BCD(aas, 0x12340306, 0, (CC_C | CC_A));
857     TEST_BCD(aas, 0x1234040a, 0, (CC_C | CC_A));
858     TEST_BCD(aas, 0x123405fa, 0, (CC_C | CC_A));
859 
860     TEST_BCD(aam, 0x12340547, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));
861     TEST_BCD(aad, 0x12340407, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));
862 }
863 #endif /* 0 */
864 
865 #define TEST_XCHG(op, size, opconst)\
866 {\
867     int op0, op1;\
868     op0 = 0x12345678;\
869     op1 = 0xfbca7654;\
870     asm(#op " %" size "0, %" size "1" \
871         : "=q" (op0), opconst (op1) \
872         : "0" (op0), "1" (op1));\
873     printf("%-10s A=%08x B=%08x\n",\
874            #op, op0, op1);\
875 }
876 
877 #define TEST_CMPXCHG(op, size, opconst, eax)\
878 {\
879     int op0, op1;\
880     op0 = 0x12345678;\
881     op1 = 0xfbca7654;\
882     asm(#op " %" size "0, %" size "1" \
883         : "=q" (op0), opconst (op1) \
884         : "0" (op0), "1" (op1), "a" (eax));\
885     printf("%-10s EAX=%08x A=%08x C=%08x\n",\
886            #op, eax, op0, op1);\
887 }
888 
test_xchg(void)889 void test_xchg(void)
890 {
891     TEST_XCHG(xchgl, "", "=q");
892     TEST_XCHG(xchgw, "w", "=q");
893     TEST_XCHG(xchgb, "b", "=q");
894 
895     TEST_XCHG(xchgl, "", "=m");
896     TEST_XCHG(xchgw, "w", "=m");
897     TEST_XCHG(xchgb, "b", "=m");
898 
899 #if 0
900     TEST_XCHG(xaddl, "", "=q");
901     TEST_XCHG(xaddw, "w", "=q");
902     TEST_XCHG(xaddb, "b", "=q");
903 
904     {
905         int res;
906         res = 0x12345678;
907         asm("xaddl %1, %0" : "=r" (res) : "0" (res));
908         printf("xaddl same res=%08x\n", res);
909     }
910 
911     TEST_XCHG(xaddl, "", "=m");
912     TEST_XCHG(xaddw, "w", "=m");
913     TEST_XCHG(xaddb, "b", "=m");
914 #endif
915     TEST_CMPXCHG(cmpxchgl, "", "=q", 0xfbca7654);
916     TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfbca7654);
917     TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfbca7654);
918 
919     TEST_CMPXCHG(cmpxchgl, "", "=q", 0xfffefdfc);
920     TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfffefdfc);
921     TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfffefdfc);
922 
923     TEST_CMPXCHG(cmpxchgl, "", "=m", 0xfbca7654);
924     TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfbca7654);
925     TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfbca7654);
926 
927     TEST_CMPXCHG(cmpxchgl, "", "=m", 0xfffefdfc);
928     TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfffefdfc);
929     TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfffefdfc);
930 #if 0
931     {
932         uint64_t op0, op1, op2;
933         int i, eflags;
934 
935         for(i = 0; i < 2; i++) {
936             op0 = 0x123456789abcd;
937             if (i == 0)
938                 op1 = 0xfbca765423456;
939             else
940                 op1 = op0;
941             op2 = 0x6532432432434;
942             asm("cmpxchg8b %1\n"
943                 "pushf\n"
944                 "popl %2\n"
945                 : "=A" (op0), "=m" (op1), "=g" (eflags)
946                 : "0" (op0), "m" (op1), "b" ((int)op2), "c" ((int)(op2 >> 32)));
947             printf("cmpxchg8b: op0=%016llx op1=%016llx CC=%02x\n",
948                     op0, op1, eflags & CC_Z);
949         }
950     }
951 #endif
952 }
953 
954 /**********************************************/
955 /* segmentation tests */
956 #if 0
957 #include <asm/ldt.h>
958 #include <linux/unistd.h>
959 #include <linux/version.h>
960 
961 _syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount)
962 
963 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66)
964 #define modify_ldt_ldt_s user_desc
965 #endif
966 
967 uint8_t seg_data1[4096];
968 uint8_t seg_data2[4096];
969 
970 #define MK_SEL(n) (((n) << 3) | 7)
971 
972 #define TEST_LR(op, size, seg, mask)\
973 {\
974     int res, res2;\
975     res = 0x12345678;\
976     asm (op " %" size "2, %" size "0\n" \
977          "movl $0, %1\n"\
978          "jnz 1f\n"\
979          "movl $1, %1\n"\
980          "1:\n"\
981          : "=r" (res), "=r" (res2) : "m" (seg), "0" (res));\
982     printf(op ": Z=%d %08x\n", res2, res & ~(mask));\
983 }
984 
985 /* NOTE: we use Linux modify_ldt syscall */
986 void test_segs(void)
987 {
988     struct modify_ldt_ldt_s ldt;
989     long long ldt_table[3];
990     int res, res2;
991     char tmp;
992     struct {
993         uint32_t offset;
994         uint16_t seg;
995     } __attribute__((packed)) segoff;
996 
997     ldt.entry_number = 1;
998     ldt.base_addr = (unsigned long)&seg_data1;
999     ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12;
1000     ldt.seg_32bit = 1;
1001     ldt.contents = MODIFY_LDT_CONTENTS_DATA;
1002     ldt.read_exec_only = 0;
1003     ldt.limit_in_pages = 1;
1004     ldt.seg_not_present = 0;
1005     ldt.useable = 1;
1006     modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
1007 
1008     ldt.entry_number = 2;
1009     ldt.base_addr = (unsigned long)&seg_data2;
1010     ldt.limit = (sizeof(seg_data2) + 0xfff) >> 12;
1011     ldt.seg_32bit = 1;
1012     ldt.contents = MODIFY_LDT_CONTENTS_DATA;
1013     ldt.read_exec_only = 0;
1014     ldt.limit_in_pages = 1;
1015     ldt.seg_not_present = 0;
1016     ldt.useable = 1;
1017     modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
1018 
1019     modify_ldt(0, &ldt_table, sizeof(ldt_table)); /* read ldt entries */
1020 #if 0
1021     {
1022         int i;
1023         for(i=0;i<3;i++)
1024             printf("%d: %016Lx\n", i, ldt_table[i]);
1025     }
1026 #endif
1027     /* do some tests with fs or gs */
1028     asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1)));
1029 
1030     seg_data1[1] = 0xaa;
1031     seg_data2[1] = 0x55;
1032 
1033     asm volatile ("fs movzbl 0x1, %0" : "=r" (res));
1034     printf("FS[1] = %02x\n", res);
1035 
1036     asm volatile ("pushl %%gs\n"
1037                   "movl %1, %%gs\n"
1038                   "gs movzbl 0x1, %0\n"
1039                   "popl %%gs\n"
1040                   : "=r" (res)
1041                   : "r" (MK_SEL(2)));
1042     printf("GS[1] = %02x\n", res);
1043 
1044     /* tests with ds/ss (implicit segment case) */
1045     tmp = 0xa5;
1046     asm volatile ("pushl %%ebp\n\t"
1047                   "pushl %%ds\n\t"
1048                   "movl %2, %%ds\n\t"
1049                   "movl %3, %%ebp\n\t"
1050                   "movzbl 0x1, %0\n\t"
1051                   "movzbl (%%ebp), %1\n\t"
1052                   "popl %%ds\n\t"
1053                   "popl %%ebp\n\t"
1054                   : "=r" (res), "=r" (res2)
1055                   : "r" (MK_SEL(1)), "r" (&tmp));
1056     printf("DS[1] = %02x\n", res);
1057     printf("SS[tmp] = %02x\n", res2);
1058 
1059     segoff.seg = MK_SEL(2);
1060     segoff.offset = 0xabcdef12;
1061     asm volatile("lfs %2, %0\n\t"
1062                  "movl %%fs, %1\n\t"
1063                  : "=r" (res), "=g" (res2)
1064                  : "m" (segoff));
1065     printf("FS:reg = %04x:%08x\n", res2, res);
1066 
1067     TEST_LR("larw", "w", MK_SEL(2), 0x0100);
1068     TEST_LR("larl", "", MK_SEL(2), 0x0100);
1069     TEST_LR("lslw", "w", MK_SEL(2), 0);
1070     TEST_LR("lsll", "", MK_SEL(2), 0);
1071 
1072     TEST_LR("larw", "w", 0xfff8, 0);
1073     TEST_LR("larl", "", 0xfff8, 0);
1074     TEST_LR("lslw", "w", 0xfff8, 0);
1075     TEST_LR("lsll", "", 0xfff8, 0);
1076 }
1077 #endif
1078 
1079 #if 0
1080 /* 16 bit code test */
1081 extern char code16_start, code16_end;
1082 extern char code16_func1;
1083 extern char code16_func2;
1084 extern char code16_func3;
1085 
1086 void test_code16(void)
1087 {
1088     struct modify_ldt_ldt_s ldt;
1089     int res, res2;
1090 
1091     /* build a code segment */
1092     ldt.entry_number = 1;
1093     ldt.base_addr = (unsigned long)&code16_start;
1094     ldt.limit = &code16_end - &code16_start;
1095     ldt.seg_32bit = 0;
1096     ldt.contents = MODIFY_LDT_CONTENTS_CODE;
1097     ldt.read_exec_only = 0;
1098     ldt.limit_in_pages = 0;
1099     ldt.seg_not_present = 0;
1100     ldt.useable = 1;
1101     modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
1102 
1103     /* call the first function */
1104     asm volatile ("lcall %1, %2"
1105                   : "=a" (res)
1106                   : "i" (MK_SEL(1)), "i" (&code16_func1): "memory", "cc");
1107     printf("func1() = 0x%08x\n", res);
1108     asm volatile ("lcall %2, %3"
1109                   : "=a" (res), "=c" (res2)
1110                   : "i" (MK_SEL(1)), "i" (&code16_func2): "memory", "cc");
1111     printf("func2() = 0x%08x spdec=%d\n", res, res2);
1112     asm volatile ("lcall %1, %2"
1113                   : "=a" (res)
1114                   : "i" (MK_SEL(1)), "i" (&code16_func3): "memory", "cc");
1115     printf("func3() = 0x%08x\n", res);
1116 }
1117 #endif
1118 
1119 extern char func_lret32;
1120 extern char func_iret32;
1121 
test_misc(void)1122 void test_misc(void)
1123 {
1124   //    char table[256];
1125   //  int res, i;
1126 
1127 #if 0
1128     // REINSTATE
1129     for(i=0;i<256;i++) table[i] = 256 - i;
1130     res = 0x12345678;
1131     asm ("xlat" : "=a" (res) : "b" (table), "0" (res));
1132     printf("xlat: EAX=%08x\n", res);
1133 #endif
1134 #if 0
1135     // REINSTATE
1136     asm volatile ("pushl %%cs ; call %1"
1137                   : "=a" (res)
1138                   : "m" (func_lret32): "memory", "cc");
1139     printf("func_lret32=%x\n", res);
1140 
1141     asm volatile ("pushfl ; pushl %%cs ; call %1"
1142                   : "=a" (res)
1143                   : "m" (func_iret32): "memory", "cc");
1144     printf("func_iret32=%x\n", res);
1145 #endif
1146 #if 0
1147     /* specific popl test */
1148     asm volatile ("pushq $0x9abcdef12345678 ; popl (%%rsp) ; addq $4,%%rsp"
1149                   : "=g" (res));
1150     printf("popl esp=%x\n", res);
1151 #endif
1152 #if 0
1153     // REINSTATE
1154     /* specific popw test */
1155     asm volatile ("pushq $12345432 ; pushq $0x9abcdef ; popw (%%rsp) ; addl $2, %%rsp ; popq %0"
1156                   : "=g" (res));
1157     printf("popw rsp=%x\n", res);
1158 #endif
1159 }
1160 
1161 uint8_t str_buffer[4096];
1162 
1163 #define TEST_STRING1(OP, size, DF, REP)\
1164 {\
1165     int64 rsi, rdi, rax, rcx, rflags;\
1166 \
1167     rsi = (long)(str_buffer + sizeof(str_buffer) / 2);\
1168     rdi = (long)(str_buffer + sizeof(str_buffer) / 2) + 16;\
1169     rax = 0x12345678;\
1170     rcx = 17;\
1171 \
1172     asm volatile ("pushq $0\n\t"\
1173                   "popfq\n\t"\
1174                   DF "\n\t"\
1175                   REP #OP size "\n\t"\
1176                   "cld\n\t"\
1177                   "pushfq\n\t"\
1178                   "popq %4\n\t"\
1179                   : "=S" (rsi), "=D" (rdi), "=a" (rax), "=c" (rcx), "=g" (rflags)\
1180                   : "0" (rsi), "1" (rdi), "2" (rax), "3" (rcx));\
1181     printf("%-10s ESI=%016llx EDI=%016llx EAX=%016llx ECX=%016llx EFL=%04llx\n",\
1182            REP #OP size, rsi, rdi, rax, rcx,\
1183            rflags & (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));\
1184 }
1185 
1186 #define TEST_STRING(OP, REP)\
1187     TEST_STRING1(OP, "b", "", REP);\
1188     TEST_STRING1(OP, "w", "", REP);\
1189     TEST_STRING1(OP, "l", "", REP);\
1190     TEST_STRING1(OP, "b", "std", REP);\
1191     TEST_STRING1(OP, "w", "std", REP);\
1192     TEST_STRING1(OP, "l", "std", REP)
1193 
test_string(void)1194 void test_string(void)
1195 {
1196     int64 i;
1197     for(i = 0;i < sizeof(str_buffer); i++)
1198         str_buffer[i] = i + 0x56;
1199    TEST_STRING(stos, "");
1200    TEST_STRING(stos, "rep ");
1201    // REINSTATE: TEST_STRING(lods, ""); /* to verify stos */
1202    // REINSTATE: TEST_STRING(lods, "rep ");
1203    TEST_STRING(movs, "");
1204    TEST_STRING(movs, "rep ");
1205    // REINSTATE: TEST_STRING(lods, ""); /* to verify stos */
1206 
1207    /* XXX: better tests */
1208    TEST_STRING(scas, "");
1209    // REINSTATE: TEST_STRING(scas, "repz ");
1210    TEST_STRING(scas, "repnz ");
1211    // REINSTATE: TEST_STRING(cmps, "");
1212    TEST_STRING(cmps, "repz ");
1213    // REINSTATE: TEST_STRING(cmps, "repnz ");
1214 }
1215 
1216 /* VM86 test */
1217 #if 0
1218 static inline void set_bit(uint8_t *a, unsigned int bit)
1219 {
1220     a[bit / 8] |= (1 << (bit % 8));
1221 }
1222 
1223 static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
1224 {
1225     return (uint8_t *)((seg << 4) + (reg & 0xffff));
1226 }
1227 
1228 static inline void pushw(struct vm86_regs *r, int val)
1229 {
1230     r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff);
1231     *(uint16_t *)seg_to_linear(r->ss, r->esp) = val;
1232 }
1233 
1234 #undef __syscall_return
1235 #define __syscall_return(type, res) \
1236 do { \
1237 	return (type) (res); \
1238 } while (0)
1239 
1240 _syscall2(int, vm86, int, func, struct vm86plus_struct *, v86)
1241 
1242 extern char vm86_code_start;
1243 extern char vm86_code_end;
1244 
1245 #define VM86_CODE_CS 0x100
1246 #define VM86_CODE_IP 0x100
1247 
1248 void test_vm86(void)
1249 {
1250     struct vm86plus_struct ctx;
1251     struct vm86_regs *r;
1252     uint8_t *vm86_mem;
1253     int seg, ret;
1254 
1255     vm86_mem = mmap((void *)0x00000000, 0x110000,
1256                     PROT_WRITE | PROT_READ | PROT_EXEC,
1257                     MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
1258     if (vm86_mem == MAP_FAILED) {
1259         printf("ERROR: could not map vm86 memory");
1260         return;
1261     }
1262     memset(&ctx, 0, sizeof(ctx));
1263 
1264     /* init basic registers */
1265     r = &ctx.regs;
1266     r->eip = VM86_CODE_IP;
1267     r->esp = 0xfffe;
1268     seg = VM86_CODE_CS;
1269     r->cs = seg;
1270     r->ss = seg;
1271     r->ds = seg;
1272     r->es = seg;
1273     r->fs = seg;
1274     r->gs = seg;
1275     r->eflags = VIF_MASK;
1276 
1277     /* move code to proper address. We use the same layout as a .com
1278        dos program. */
1279     memcpy(vm86_mem + (VM86_CODE_CS << 4) + VM86_CODE_IP,
1280            &vm86_code_start, &vm86_code_end - &vm86_code_start);
1281 
1282     /* mark int 0x21 as being emulated */
1283     set_bit((uint8_t *)&ctx.int_revectored, 0x21);
1284 
1285     for(;;) {
1286         ret = vm86(VM86_ENTER, &ctx);
1287         switch(VM86_TYPE(ret)) {
1288         case VM86_INTx:
1289             {
1290                 int int_num, ah, v;
1291 
1292                 int_num = VM86_ARG(ret);
1293                 if (int_num != 0x21)
1294                     goto unknown_int;
1295                 ah = (r->eax >> 8) & 0xff;
1296                 switch(ah) {
1297                 case 0x00: /* exit */
1298                     goto the_end;
1299                 case 0x02: /* write char */
1300                     {
1301                         uint8_t c = r->edx;
1302                         putchar(c);
1303                     }
1304                     break;
1305                 case 0x09: /* write string */
1306                     {
1307                         uint8_t c, *ptr;
1308                         ptr = seg_to_linear(r->ds, r->edx);
1309                         for(;;) {
1310                             c = *ptr++;
1311                             if (c == '$')
1312                                 break;
1313                             putchar(c);
1314                         }
1315                         r->eax = (r->eax & ~0xff) | '$';
1316                     }
1317                     break;
1318                 case 0xff: /* extension: write eflags number in edx */
1319                     v = (int)r->edx;
1320 #ifndef LINUX_VM86_IOPL_FIX
1321                     v &= ~0x3000;
1322 #endif
1323                     printf("%08x\n", v);
1324                     break;
1325                 default:
1326                 unknown_int:
1327                     printf("unsupported int 0x%02x\n", int_num);
1328                     goto the_end;
1329                 }
1330             }
1331             break;
1332         case VM86_SIGNAL:
1333             /* a signal came, we just ignore that */
1334             break;
1335         case VM86_STI:
1336             break;
1337         default:
1338             printf("ERROR: unhandled vm86 return code (0x%x)\n", ret);
1339             goto the_end;
1340         }
1341     }
1342  the_end:
1343     printf("VM86 end\n");
1344     munmap(vm86_mem, 0x110000);
1345 }
1346 #endif
1347 
1348 /* exception tests */
1349 #if 0
1350 #ifndef REG_EAX
1351 #define REG_EAX EAX
1352 #define REG_EBX EBX
1353 #define REG_ECX ECX
1354 #define REG_EDX EDX
1355 #define REG_ESI ESI
1356 #define REG_EDI EDI
1357 #define REG_EBP EBP
1358 #define REG_ESP ESP
1359 #define REG_EIP EIP
1360 #define REG_EFL EFL
1361 #define REG_TRAPNO TRAPNO
1362 #define REG_ERR ERR
1363 #endif
1364 
1365 jmp_buf jmp_env;
1366 int v1;
1367 int tab[2];
1368 
1369 void sig_handler(int sig, siginfo_t *info, void *puc)
1370 {
1371     struct ucontext *uc = puc;
1372 
1373     printf("si_signo=%d si_errno=%d si_code=%d",
1374            info->si_signo, info->si_errno, info->si_code);
1375     printf(" si_addr=0x%08lx",
1376            (unsigned long)info->si_addr);
1377     printf("\n");
1378 
1379     printf("trapno=0x%02x err=0x%08x",
1380            uc->uc_mcontext.gregs[REG_TRAPNO],
1381            uc->uc_mcontext.gregs[REG_ERR]);
1382     printf(" EIP=0x%08x", uc->uc_mcontext.gregs[REG_EIP]);
1383     printf("\n");
1384     longjmp(jmp_env, 1);
1385 }
1386 
1387 void test_exceptions(void)
1388 {
1389     struct modify_ldt_ldt_s ldt;
1390     struct sigaction act;
1391     volatile int val;
1392 
1393     act.sa_sigaction = sig_handler;
1394     sigemptyset(&act.sa_mask);
1395     act.sa_flags = SA_SIGINFO;
1396     sigaction(SIGFPE, &act, NULL);
1397     sigaction(SIGILL, &act, NULL);
1398     sigaction(SIGSEGV, &act, NULL);
1399     sigaction(SIGBUS, &act, NULL);
1400     sigaction(SIGTRAP, &act, NULL);
1401 
1402     /* test division by zero reporting */
1403     printf("DIVZ exception:\n");
1404     if (setjmp(jmp_env) == 0) {
1405         /* now divide by zero */
1406         v1 = 0;
1407         v1 = 2 / v1;
1408     }
1409 
1410     printf("BOUND exception:\n");
1411     if (setjmp(jmp_env) == 0) {
1412         /* bound exception */
1413         tab[0] = 1;
1414         tab[1] = 10;
1415         asm volatile ("bound %0, %1" : : "r" (11), "m" (tab));
1416     }
1417 
1418     printf("segment exceptions:\n");
1419     if (setjmp(jmp_env) == 0) {
1420         /* load an invalid segment */
1421         asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 1));
1422     }
1423     if (setjmp(jmp_env) == 0) {
1424         /* null data segment is valid */
1425         asm volatile ("movl %0, %%fs" : : "r" (3));
1426         /* null stack segment */
1427         asm volatile ("movl %0, %%ss" : : "r" (3));
1428     }
1429 
1430     ldt.entry_number = 1;
1431     ldt.base_addr = (unsigned long)&seg_data1;
1432     ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12;
1433     ldt.seg_32bit = 1;
1434     ldt.contents = MODIFY_LDT_CONTENTS_DATA;
1435     ldt.read_exec_only = 0;
1436     ldt.limit_in_pages = 1;
1437     ldt.seg_not_present = 1;
1438     ldt.useable = 1;
1439     modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
1440 
1441     if (setjmp(jmp_env) == 0) {
1442         /* segment not present */
1443         asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1)));
1444     }
1445 
1446     /* test SEGV reporting */
1447     printf("PF exception:\n");
1448     if (setjmp(jmp_env) == 0) {
1449         val = 1;
1450         /* we add a nop to test a weird PC retrieval case */
1451         asm volatile ("nop");
1452         /* now store in an invalid address */
1453         *(char *)0x1234 = 1;
1454     }
1455 
1456     /* test SEGV reporting */
1457     printf("PF exception:\n");
1458     if (setjmp(jmp_env) == 0) {
1459         val = 1;
1460         /* read from an invalid address */
1461         v1 = *(char *)0x1234;
1462     }
1463 
1464     /* test illegal instruction reporting */
1465     printf("UD2 exception:\n");
1466     if (setjmp(jmp_env) == 0) {
1467         /* now execute an invalid instruction */
1468         asm volatile("ud2");
1469     }
1470     printf("lock nop exception:\n");
1471     if (setjmp(jmp_env) == 0) {
1472         /* now execute an invalid instruction */
1473         asm volatile("lock nop");
1474     }
1475 
1476     printf("INT exception:\n");
1477     if (setjmp(jmp_env) == 0) {
1478         asm volatile ("int $0xfd");
1479     }
1480     if (setjmp(jmp_env) == 0) {
1481         asm volatile ("int $0x01");
1482     }
1483     if (setjmp(jmp_env) == 0) {
1484         asm volatile (".byte 0xcd, 0x03");
1485     }
1486     if (setjmp(jmp_env) == 0) {
1487         asm volatile ("int $0x04");
1488     }
1489     if (setjmp(jmp_env) == 0) {
1490         asm volatile ("int $0x05");
1491     }
1492 
1493     printf("INT3 exception:\n");
1494     if (setjmp(jmp_env) == 0) {
1495         asm volatile ("int3");
1496     }
1497 
1498     printf("CLI exception:\n");
1499     if (setjmp(jmp_env) == 0) {
1500         asm volatile ("cli");
1501     }
1502 
1503     printf("STI exception:\n");
1504     if (setjmp(jmp_env) == 0) {
1505         asm volatile ("cli");
1506     }
1507 
1508     printf("INTO exception:\n");
1509     if (setjmp(jmp_env) == 0) {
1510         /* overflow exception */
1511         asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff));
1512     }
1513 
1514     printf("OUTB exception:\n");
1515     if (setjmp(jmp_env) == 0) {
1516         asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0));
1517     }
1518 
1519     printf("INB exception:\n");
1520     if (setjmp(jmp_env) == 0) {
1521         asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321));
1522     }
1523 
1524     printf("REP OUTSB exception:\n");
1525     if (setjmp(jmp_env) == 0) {
1526         asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1));
1527     }
1528 
1529     printf("REP INSB exception:\n");
1530     if (setjmp(jmp_env) == 0) {
1531         asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1));
1532     }
1533 
1534     printf("HLT exception:\n");
1535     if (setjmp(jmp_env) == 0) {
1536         asm volatile ("hlt");
1537     }
1538 
1539     printf("single step exception:\n");
1540     val = 0;
1541     if (setjmp(jmp_env) == 0) {
1542         asm volatile ("pushf\n"
1543                       "orl $0x00100, (%%esp)\n"
1544                       "popf\n"
1545                       "movl $0xabcd, %0\n"
1546                       "movl $0x0, %0\n" : "=m" (val) : : "cc", "memory");
1547     }
1548     printf("val=0x%x\n", val);
1549 }
1550 
1551 /* specific precise single step test */
1552 void sig_trap_handler(int sig, siginfo_t *info, void *puc)
1553 {
1554     struct ucontext *uc = puc;
1555     printf("EIP=0x%08x\n", uc->uc_mcontext.gregs[REG_EIP]);
1556 }
1557 
1558 const uint8_t sstep_buf1[4] = { 1, 2, 3, 4};
1559 uint8_t sstep_buf2[4];
1560 
1561 void test_single_step(void)
1562 {
1563     struct sigaction act;
1564     volatile int val;
1565     int i;
1566 
1567     val = 0;
1568     act.sa_sigaction = sig_trap_handler;
1569     sigemptyset(&act.sa_mask);
1570     act.sa_flags = SA_SIGINFO;
1571     sigaction(SIGTRAP, &act, NULL);
1572     asm volatile ("pushf\n"
1573                   "orl $0x00100, (%%esp)\n"
1574                   "popf\n"
1575                   "movl $0xabcd, %0\n"
1576 
1577                   /* jmp test */
1578                   "movl $3, %%ecx\n"
1579                   "1:\n"
1580                   "addl $1, %0\n"
1581                   "decl %%ecx\n"
1582                   "jnz 1b\n"
1583 
1584                   /* movsb: the single step should stop at each movsb iteration */
1585                   "movl $sstep_buf1, %%esi\n"
1586                   "movl $sstep_buf2, %%edi\n"
1587                   "movl $0, %%ecx\n"
1588                   "rep movsb\n"
1589                   "movl $3, %%ecx\n"
1590                   "rep movsb\n"
1591                   "movl $1, %%ecx\n"
1592                   "rep movsb\n"
1593 
1594                   /* cmpsb: the single step should stop at each cmpsb iteration */
1595                   "movl $sstep_buf1, %%esi\n"
1596                   "movl $sstep_buf2, %%edi\n"
1597                   "movl $0, %%ecx\n"
1598                   "rep cmpsb\n"
1599                   "movl $4, %%ecx\n"
1600                   "rep cmpsb\n"
1601 
1602                   /* getpid() syscall: single step should skip one
1603                      instruction */
1604                   "movl $20, %%eax\n"
1605                   "int $0x80\n"
1606                   "movl $0, %%eax\n"
1607 
1608                   /* when modifying SS, trace is not done on the next
1609                      instruction */
1610                   "movl %%ss, %%ecx\n"
1611                   "movl %%ecx, %%ss\n"
1612                   "addl $1, %0\n"
1613                   "movl $1, %%eax\n"
1614                   "movl %%ecx, %%ss\n"
1615                   "jmp 1f\n"
1616                   "addl $1, %0\n"
1617                   "1:\n"
1618                   "movl $1, %%eax\n"
1619                   "pushl %%ecx\n"
1620                   "popl %%ss\n"
1621                   "addl $1, %0\n"
1622                   "movl $1, %%eax\n"
1623 
1624                   "pushf\n"
1625                   "andl $~0x00100, (%%esp)\n"
1626                   "popf\n"
1627                   : "=m" (val)
1628                   :
1629                   : "cc", "memory", "eax", "ecx", "esi", "edi");
1630     printf("val=%d\n", val);
1631     for(i = 0; i < 4; i++)
1632         printf("sstep_buf2[%d] = %d\n", i, sstep_buf2[i]);
1633 }
1634 
1635 /* self modifying code test */
1636 uint8_t code[] = {
1637     0xb8, 0x1, 0x00, 0x00, 0x00, /* movl $1, %eax */
1638     0xc3, /* ret */
1639 };
1640 
1641 asm("smc_code2:\n"
1642     "movl 4(%esp), %eax\n"
1643     "movl %eax, smc_patch_addr2 + 1\n"
1644     "nop\n"
1645     "nop\n"
1646     "nop\n"
1647     "nop\n"
1648     "nop\n"
1649     "nop\n"
1650     "nop\n"
1651     "nop\n"
1652     "smc_patch_addr2:\n"
1653     "movl $1, %eax\n"
1654     "ret\n");
1655 
1656 typedef int FuncType(void);
1657 extern int smc_code2(int);
1658 void test_self_modifying_code(void)
1659 {
1660     int i;
1661 
1662     printf("self modifying code:\n");
1663     printf("func1 = 0x%x\n", ((FuncType *)code)());
1664     for(i = 2; i <= 4; i++) {
1665         code[1] = i;
1666         printf("func%d = 0x%x\n", i, ((FuncType *)code)());
1667     }
1668 
1669     /* more difficult test : the modified code is just after the
1670        modifying instruction. It is forbidden in Intel specs, but it
1671        is used by old DOS programs */
1672     for(i = 2; i <= 4; i++) {
1673         printf("smc_code2(%d) = %d\n", i, smc_code2(i));
1674     }
1675 }
1676 
1677 static void *call_end __init_call = NULL;
1678 #endif
1679 
main(int argc,char ** argv)1680 int main(int argc, char **argv)
1681 {
1682     void **ptr;
1683     void (*func)(void);
1684 
1685 #if 1
1686     ptr = &call_start + 1;
1687     while (*ptr != NULL) {
1688         func = *ptr++;
1689         func();
1690     }
1691 #endif
1692     test_bsx();  //REINSTATE64
1693     test_mul();
1694     test_jcc();
1695     //    test_floats();  REINSTATE64
1696     //test_bcd();
1697     //test_xchg();   REINSTATE64
1698     test_string();
1699     //test_misc(); // REINSTATE
1700     test_lea();
1701     //    test_segs();
1702     //test_code16();
1703     //test_vm86();
1704     //test_exceptions();
1705     //test_self_modifying_code();
1706     //test_single_step();
1707     printf("bye\n");
1708     return 0;
1709 }
1710