blob: cd47930297c65a4adf5e5bc407348dd31854bcf6 [file] [log] [blame]
sewardj5484c142004-08-24 22:43:26 +00001/*
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
sewardjcb59aeb2004-10-21 09:20:46 +000033/* Setting this to 1 creates a very comprehensive test of
34 integer condition codes. */
sewardj08497722006-12-17 14:24:05 +000035#define TEST_INTEGER_VERBOSE 1
sewardj686edb92004-10-15 21:26:24 +000036
sewardj686edb92004-10-15 21:26:24 +000037
sewardj5484c142004-08-24 22:43:26 +000038//#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
sewardj5484c142004-08-24 22:43:26 +0000123#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"
sewardj5484c142004-08-24 22:43:26 +0000130
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 ? */
sewardj5484c142004-08-24 22:43:26 +0000143#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"
sewardj686edb92004-10-15 21:26:24 +0000161
sewardj5484c142004-08-24 22:43:26 +0000162
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);\
sewardj08497722006-12-17 14:24:05 +0000264 { int one = 1; \
sewardj5484c142004-08-24 22:43:26 +0000265 asm("movl $0x12345678, %0\n\t"\
266 "cmpl %2, %1\n\t"\
267 "cmov" JCC "l %3, %0\n\t"\
268 : "=r" (res)\
sewardj08497722006-12-17 14:24:05 +0000269 : "r" (v1), "r" (v2), "m" (one));\
sewardj5484c142004-08-24 22:43:26 +0000270 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);
sewardj04e86f02004-10-16 11:36:34 +0000475
sewardj5484c142004-08-24 22:43:26 +0000476 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);
sewardj04e86f02004-10-16 11:36:34 +0000484
sewardj5484c142004-08-24 22:43:26 +0000485 test_idivl(0, 0x12345678, 12347);
486 test_idivl(0, -233223, -45);
487 test_idivl(0, 0x80000000, -1);
488 test_idivl(0x12343, 0x12345678, 0x81234567);
sewardj04e86f02004-10-16 11:36:34 +0000489
sewardj5484c142004-08-24 22:43:26 +0000490 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);
sewardj04e86f02004-10-16 11:36:34 +0000498
sewardj5484c142004-08-24 22:43:26 +0000499 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;\
sewardj08497722006-12-17 14:24:05 +0000509 asm("xorl %1, %1\n\t"\
510 "movl $0x12345678, %0\n\t"\
511 #op " %" size "2, %" size "0\n\t" \
512 "setz %b1" \
sewardj5484c142004-08-24 22:43:26 +0000513 : "=r" (res), "=q" (resz)\
sewardj08497722006-12-17 14:24:05 +0000514 : "r" (val));\
sewardj5484c142004-08-24 22:43:26 +0000515 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/**********************************************/
sewardjcb59aeb2004-10-21 09:20:46 +0000531
sewardj5484c142004-08-24 22:43:26 +0000532void 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));
sewardjcb59aeb2004-10-21 09:20:46 +0000542 printf("a=%f tan(a)=%f\n", a, tan(a));
sewardj5484c142004-08-24 22:43:26 +0000543 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 */
sewardjcb59aeb2004-10-21 09:20:46 +0000547 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)));
sewardj5484c142004-08-24 22:43:26 +0000550}
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);
sewardjcb59aeb2004-10-21 09:20:46 +0000564 {
sewardj5484c142004-08-24 22:43:26 +0000565 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++) {
sewardj08497722006-12-17 14:24:05 +0000598 int16_t tmp = (fpuc & ~0x0c00) | (i << 10);
599 asm volatile ("fldcw %0" : : "m" (tmp));
sewardj5484c142004-08-24 22:43:26 +0000600 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();
sewardj686edb92004-10-15 21:26:24 +0000749 // REINSTATE (maybe): test_fbcd(1234567890123456);
750 // REINSTATE (maybe): test_fbcd(-123451234567890);
751 // REINSTATE: test_fenv();
sewardjcb59aeb2004-10-21 09:20:46 +0000752 // REINSTATE: test_fcmov();
sewardj5484c142004-08-24 22:43:26 +0000753}
sewardj5484c142004-08-24 22:43:26 +0000754
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}
sewardj2b5b7512004-08-26 11:27:21 +0000825#endif /* 0 */
sewardj5484c142004-08-24 22:43:26 +0000826
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
sewardj2b5b7512004-08-26 11:27:21 +0000861#if 0
sewardj5484c142004-08-24 22:43:26 +0000862 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");
sewardj2b5b7512004-08-26 11:27:21 +0000876#endif
sewardj5484c142004-08-24 22:43:26 +0000877 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);
sewardj2b5b7512004-08-26 11:27:21 +0000892#if 0
sewardj5484c142004-08-24 22:43:26 +0000893 {
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 }
sewardj5484c142004-08-24 22:43:26 +0000913#endif
sewardj2b5b7512004-08-26 11:27:21 +0000914}
sewardj5484c142004-08-24 22:43:26 +0000915
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
sewardj686edb92004-10-15 21:26:24 +00001089#if 0
1090 // REINSTATE
sewardj5484c142004-08-24 22:43:26 +00001091 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);
sewardj686edb92004-10-15 21:26:24 +00001095#endif
sewardj5484c142004-08-24 22:43:26 +00001096#if 0
sewardj686edb92004-10-15 21:26:24 +00001097 // REINSTATE
sewardj5484c142004-08-24 22:43:26 +00001098 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
sewardj686edb92004-10-15 21:26:24 +00001113 // REINSTATE
sewardj5484c142004-08-24 22:43:26 +00001114 /* 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 ");
sewardj686edb92004-10-15 21:26:24 +00001161 // REINSTATE: TEST_STRING(lods, ""); /* to verify stos */
1162 // REINSTATE: TEST_STRING(lods, "rep ");
sewardj5484c142004-08-24 22:43:26 +00001163 TEST_STRING(movs, "");
1164 TEST_STRING(movs, "rep ");
sewardj686edb92004-10-15 21:26:24 +00001165 // REINSTATE: TEST_STRING(lods, ""); /* to verify stos */
sewardj5484c142004-08-24 22:43:26 +00001166
1167 /* XXX: better tests */
1168 TEST_STRING(scas, "");
sewardj686edb92004-10-15 21:26:24 +00001169 // REINSTATE: TEST_STRING(scas, "repz ");
sewardj5484c142004-08-24 22:43:26 +00001170 TEST_STRING(scas, "repnz ");
sewardj686edb92004-10-15 21:26:24 +00001171 // REINSTATE: TEST_STRING(cmps, "");
sewardj5484c142004-08-24 22:43:26 +00001172 TEST_STRING(cmps, "repz ");
sewardj686edb92004-10-15 21:26:24 +00001173 // REINSTATE: TEST_STRING(cmps, "repnz ");
sewardj5484c142004-08-24 22:43:26 +00001174}
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
sewardj686edb92004-10-15 21:26:24 +00001652 test_bsx();
1653 test_mul();
1654 test_jcc();
1655 test_floats();
sewardj5484c142004-08-24 22:43:26 +00001656 //test_bcd();
sewardj2b5b7512004-08-26 11:27:21 +00001657 test_xchg();
sewardj686edb92004-10-15 21:26:24 +00001658 test_string();
sewardja2d37d82005-03-26 11:58:50 +00001659 test_misc(); // REINSTATE
sewardj686edb92004-10-15 21:26:24 +00001660 test_lea();
sewardj5484c142004-08-24 22:43:26 +00001661 // test_segs();
1662 //test_code16();
1663 //test_vm86();
1664 //test_exceptions();
1665 //test_self_modifying_code();
1666 //test_single_step();
1667 return 0;
1668}