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