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
46typedef  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
65static 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
193void 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 */
293void 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
368void 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
386void 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
447void 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
556void 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
570void 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
590void 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
614void 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
654void 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
666void 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
694void 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
747void 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
773void 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
812void 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
889void 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
967uint8_t seg_data1[4096];
968uint8_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 */
986void 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 */
1081extern char code16_start, code16_end;
1082extern char code16_func1;
1083extern char code16_func2;
1084extern char code16_func3;
1085
1086void 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
1119extern char func_lret32;
1120extern char func_iret32;
1121
1122void 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
1161uint8_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
1194void 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
1218static inline void set_bit(uint8_t *a, unsigned int bit)
1219{
1220    a[bit / 8] |= (1 << (bit % 8));
1221}
1222
1223static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
1224{
1225    return (uint8_t *)((seg << 4) + (reg & 0xffff));
1226}
1227
1228static 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) \
1236do { \
1237	return (type) (res); \
1238} while (0)
1239
1240_syscall2(int, vm86, int, func, struct vm86plus_struct *, v86)
1241
1242extern char vm86_code_start;
1243extern char vm86_code_end;
1244
1245#define VM86_CODE_CS 0x100
1246#define VM86_CODE_IP 0x100
1247
1248void 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
1365jmp_buf jmp_env;
1366int v1;
1367int tab[2];
1368
1369void 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
1387void 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 */
1552void 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
1558const uint8_t sstep_buf1[4] = { 1, 2, 3, 4};
1559uint8_t sstep_buf2[4];
1560
1561void 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 */
1636uint8_t code[] = {
1637    0xb8, 0x1, 0x00, 0x00, 0x00, /* movl $1, %eax */
1638    0xc3, /* ret */
1639};
1640
1641asm("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
1656typedef int FuncType(void);
1657extern int smc_code2(int);
1658void 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
1677static void *call_end __init_call = NULL;
1678#endif
1679
1680int 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