14132431fSAlex Bennée /*
24132431fSAlex Bennée * x86 CPU test
34132431fSAlex Bennée *
44132431fSAlex Bennée * Copyright (c) 2003 Fabrice Bellard
54132431fSAlex Bennée *
64132431fSAlex Bennée * This program is free software; you can redistribute it and/or modify
74132431fSAlex Bennée * it under the terms of the GNU General Public License as published by
84132431fSAlex Bennée * the Free Software Foundation; either version 2 of the License, or
94132431fSAlex Bennée * (at your option) any later version.
104132431fSAlex Bennée *
114132431fSAlex Bennée * This program is distributed in the hope that it will be useful,
124132431fSAlex Bennée * but WITHOUT ANY WARRANTY; without even the implied warranty of
134132431fSAlex Bennée * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
144132431fSAlex Bennée * GNU General Public License for more details.
154132431fSAlex Bennée *
164132431fSAlex Bennée * You should have received a copy of the GNU General Public License
174132431fSAlex Bennée * along with this program; if not, see <http://www.gnu.org/licenses/>.
184132431fSAlex Bennée */
194132431fSAlex Bennée #define _GNU_SOURCE
204132431fSAlex Bennée #include <stdlib.h>
214132431fSAlex Bennée #include <stdio.h>
224132431fSAlex Bennée #include <string.h>
234132431fSAlex Bennée #include <inttypes.h>
244132431fSAlex Bennée #include <math.h>
254132431fSAlex Bennée #include <signal.h>
264132431fSAlex Bennée #include <setjmp.h>
274132431fSAlex Bennée #include <errno.h>
284132431fSAlex Bennée #include <sys/ucontext.h>
294132431fSAlex Bennée #include <sys/mman.h>
304132431fSAlex Bennée
314132431fSAlex Bennée #if !defined(__x86_64__)
324132431fSAlex Bennée //#define TEST_VM86
334132431fSAlex Bennée #define TEST_SEGS
344132431fSAlex Bennée #endif
354132431fSAlex Bennée //#define LINUX_VM86_IOPL_FIX
364132431fSAlex Bennée //#define TEST_P4_FLAGS
374132431fSAlex Bennée #define TEST_CMOV 1
384132431fSAlex Bennée #define TEST_FCOMI 1
394132431fSAlex Bennée
404132431fSAlex Bennée #if defined(__x86_64__)
414132431fSAlex Bennée #define FMT64X "%016lx"
424132431fSAlex Bennée #define FMTLX "%016lx"
434132431fSAlex Bennée #define X86_64_ONLY(x) x
444132431fSAlex Bennée #else
454132431fSAlex Bennée #define FMT64X "%016" PRIx64
464132431fSAlex Bennée #define FMTLX "%08lx"
474132431fSAlex Bennée #define X86_64_ONLY(x)
484132431fSAlex Bennée #endif
494132431fSAlex Bennée
504132431fSAlex Bennée #ifdef TEST_VM86
514132431fSAlex Bennée #include <asm/vm86.h>
524132431fSAlex Bennée #endif
534132431fSAlex Bennée
544132431fSAlex Bennée #define xglue(x, y) x ## y
554132431fSAlex Bennée #define glue(x, y) xglue(x, y)
564132431fSAlex Bennée #define stringify(s) tostring(s)
574132431fSAlex Bennée #define tostring(s) #s
584132431fSAlex Bennée
594132431fSAlex Bennée #define CC_C 0x0001
604132431fSAlex Bennée #define CC_P 0x0004
614132431fSAlex Bennée #define CC_A 0x0010
624132431fSAlex Bennée #define CC_Z 0x0040
634132431fSAlex Bennée #define CC_S 0x0080
644132431fSAlex Bennée #define CC_O 0x0800
654132431fSAlex Bennée
664132431fSAlex Bennée #define __init_call __attribute__ ((unused,__section__ ("initcall")))
674132431fSAlex Bennée
684132431fSAlex Bennée #define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)
694132431fSAlex Bennée
704132431fSAlex Bennée #if defined(__x86_64__)
i2l(long v)714132431fSAlex Bennée static inline long i2l(long v)
724132431fSAlex Bennée {
734132431fSAlex Bennée return v | ((v ^ 0xabcd) << 32);
744132431fSAlex Bennée }
754132431fSAlex Bennée #else
i2l(long v)764132431fSAlex Bennée static inline long i2l(long v)
774132431fSAlex Bennée {
784132431fSAlex Bennée return v;
794132431fSAlex Bennée }
804132431fSAlex Bennée #endif
814132431fSAlex Bennée
824132431fSAlex Bennée #define OP add
834132431fSAlex Bennée #include "test-i386.h"
844132431fSAlex Bennée
854132431fSAlex Bennée #define OP sub
864132431fSAlex Bennée #include "test-i386.h"
874132431fSAlex Bennée
884132431fSAlex Bennée #define OP xor
894132431fSAlex Bennée #include "test-i386.h"
904132431fSAlex Bennée
914132431fSAlex Bennée #define OP and
924132431fSAlex Bennée #include "test-i386.h"
934132431fSAlex Bennée
944132431fSAlex Bennée #define OP or
954132431fSAlex Bennée #include "test-i386.h"
964132431fSAlex Bennée
974132431fSAlex Bennée #define OP cmp
984132431fSAlex Bennée #include "test-i386.h"
994132431fSAlex Bennée
1004132431fSAlex Bennée #define OP adc
1014132431fSAlex Bennée #define OP_CC
1024132431fSAlex Bennée #include "test-i386.h"
1034132431fSAlex Bennée
1044132431fSAlex Bennée #define OP sbb
1054132431fSAlex Bennée #define OP_CC
1064132431fSAlex Bennée #include "test-i386.h"
1074132431fSAlex Bennée
1084132431fSAlex Bennée #define OP inc
1094132431fSAlex Bennée #define OP_CC
1104132431fSAlex Bennée #define OP1
1114132431fSAlex Bennée #include "test-i386.h"
1124132431fSAlex Bennée
1134132431fSAlex Bennée #define OP dec
1144132431fSAlex Bennée #define OP_CC
1154132431fSAlex Bennée #define OP1
1164132431fSAlex Bennée #include "test-i386.h"
1174132431fSAlex Bennée
1184132431fSAlex Bennée #define OP neg
1194132431fSAlex Bennée #define OP_CC
1204132431fSAlex Bennée #define OP1
1214132431fSAlex Bennée #include "test-i386.h"
1224132431fSAlex Bennée
1234132431fSAlex Bennée #define OP not
1244132431fSAlex Bennée #define OP_CC
1254132431fSAlex Bennée #define OP1
1264132431fSAlex Bennée #include "test-i386.h"
1274132431fSAlex Bennée
1284132431fSAlex Bennée #undef CC_MASK
1294132431fSAlex Bennée #define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O)
1304132431fSAlex Bennée
1314132431fSAlex Bennée #define OP shl
1324132431fSAlex Bennée #include "test-i386-shift.h"
1334132431fSAlex Bennée
1344132431fSAlex Bennée #define OP shr
1354132431fSAlex Bennée #include "test-i386-shift.h"
1364132431fSAlex Bennée
1374132431fSAlex Bennée #define OP sar
1384132431fSAlex Bennée #include "test-i386-shift.h"
1394132431fSAlex Bennée
1404132431fSAlex Bennée #define OP rol
1414132431fSAlex Bennée #include "test-i386-shift.h"
1424132431fSAlex Bennée
1434132431fSAlex Bennée #define OP ror
1444132431fSAlex Bennée #include "test-i386-shift.h"
1454132431fSAlex Bennée
1464132431fSAlex Bennée #define OP rcr
1474132431fSAlex Bennée #define OP_CC
1484132431fSAlex Bennée #include "test-i386-shift.h"
1494132431fSAlex Bennée
1504132431fSAlex Bennée #define OP rcl
1514132431fSAlex Bennée #define OP_CC
1524132431fSAlex Bennée #include "test-i386-shift.h"
1534132431fSAlex Bennée
1544132431fSAlex Bennée #define OP shld
1554132431fSAlex Bennée #define OP_SHIFTD
1564132431fSAlex Bennée #define OP_NOBYTE
1574132431fSAlex Bennée #include "test-i386-shift.h"
1584132431fSAlex Bennée
1594132431fSAlex Bennée #define OP shrd
1604132431fSAlex Bennée #define OP_SHIFTD
1614132431fSAlex Bennée #define OP_NOBYTE
1624132431fSAlex Bennée #include "test-i386-shift.h"
1634132431fSAlex Bennée
1644132431fSAlex Bennée /* XXX: should be more precise ? */
1654132431fSAlex Bennée #undef CC_MASK
1664132431fSAlex Bennée #define CC_MASK (CC_C)
1674132431fSAlex Bennée
1684132431fSAlex Bennée #define OP bt
1694132431fSAlex Bennée #define OP_NOBYTE
1704132431fSAlex Bennée #include "test-i386-shift.h"
1714132431fSAlex Bennée
1724132431fSAlex Bennée #define OP bts
1734132431fSAlex Bennée #define OP_NOBYTE
1744132431fSAlex Bennée #include "test-i386-shift.h"
1754132431fSAlex Bennée
1764132431fSAlex Bennée #define OP btr
1774132431fSAlex Bennée #define OP_NOBYTE
1784132431fSAlex Bennée #include "test-i386-shift.h"
1794132431fSAlex Bennée
1804132431fSAlex Bennée #define OP btc
1814132431fSAlex Bennée #define OP_NOBYTE
1824132431fSAlex Bennée #include "test-i386-shift.h"
1834132431fSAlex Bennée
1844132431fSAlex Bennée /* lea test (modrm support) */
1854132431fSAlex Bennée #define TEST_LEAQ(STR)\
1864132431fSAlex Bennée {\
1874132431fSAlex Bennée asm("lea " STR ", %0"\
1884132431fSAlex Bennée : "=r" (res)\
1894132431fSAlex Bennée : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\
1904132431fSAlex Bennée printf("lea %s = " FMTLX "\n", STR, res);\
1914132431fSAlex Bennée }
1924132431fSAlex Bennée
1934132431fSAlex Bennée #define TEST_LEA(STR)\
1944132431fSAlex Bennée {\
1954132431fSAlex Bennée asm("lea " STR ", %0"\
1964132431fSAlex Bennée : "=r" (res)\
1974132431fSAlex Bennée : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\
1984132431fSAlex Bennée printf("lea %s = " FMTLX "\n", STR, res);\
1994132431fSAlex Bennée }
2004132431fSAlex Bennée
2014132431fSAlex Bennée #define TEST_LEA16(STR)\
2024132431fSAlex Bennée {\
2034132431fSAlex Bennée asm(".code16 ; .byte 0x67 ; leal " STR ", %0 ; .code32"\
2044132431fSAlex Bennée : "=r" (res)\
2054132431fSAlex Bennée : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\
2064132431fSAlex Bennée printf("lea %s = %08lx\n", STR, res);\
2074132431fSAlex Bennée }
2084132431fSAlex Bennée
2094132431fSAlex Bennée
test_lea(void)2104132431fSAlex Bennée void test_lea(void)
2114132431fSAlex Bennée {
2124132431fSAlex Bennée long eax, ebx, ecx, edx, esi, edi, res;
2134132431fSAlex Bennée eax = i2l(0x0001);
2144132431fSAlex Bennée ebx = i2l(0x0002);
2154132431fSAlex Bennée ecx = i2l(0x0004);
2164132431fSAlex Bennée edx = i2l(0x0008);
2174132431fSAlex Bennée esi = i2l(0x0010);
2184132431fSAlex Bennée edi = i2l(0x0020);
2194132431fSAlex Bennée
2204132431fSAlex Bennée TEST_LEA("0x4000");
2214132431fSAlex Bennée
2224132431fSAlex Bennée TEST_LEA("(%%eax)");
2234132431fSAlex Bennée TEST_LEA("(%%ebx)");
2244132431fSAlex Bennée TEST_LEA("(%%ecx)");
2254132431fSAlex Bennée TEST_LEA("(%%edx)");
2264132431fSAlex Bennée TEST_LEA("(%%esi)");
2274132431fSAlex Bennée TEST_LEA("(%%edi)");
2284132431fSAlex Bennée
2294132431fSAlex Bennée TEST_LEA("0x40(%%eax)");
2304132431fSAlex Bennée TEST_LEA("0x40(%%ebx)");
2314132431fSAlex Bennée TEST_LEA("0x40(%%ecx)");
2324132431fSAlex Bennée TEST_LEA("0x40(%%edx)");
2334132431fSAlex Bennée TEST_LEA("0x40(%%esi)");
2344132431fSAlex Bennée TEST_LEA("0x40(%%edi)");
2354132431fSAlex Bennée
2364132431fSAlex Bennée TEST_LEA("0x4000(%%eax)");
2374132431fSAlex Bennée TEST_LEA("0x4000(%%ebx)");
2384132431fSAlex Bennée TEST_LEA("0x4000(%%ecx)");
2394132431fSAlex Bennée TEST_LEA("0x4000(%%edx)");
2404132431fSAlex Bennée TEST_LEA("0x4000(%%esi)");
2414132431fSAlex Bennée TEST_LEA("0x4000(%%edi)");
2424132431fSAlex Bennée
2434132431fSAlex Bennée TEST_LEA("(%%eax, %%ecx)");
2444132431fSAlex Bennée TEST_LEA("(%%ebx, %%edx)");
2454132431fSAlex Bennée TEST_LEA("(%%ecx, %%ecx)");
2464132431fSAlex Bennée TEST_LEA("(%%edx, %%ecx)");
2474132431fSAlex Bennée TEST_LEA("(%%esi, %%ecx)");
2484132431fSAlex Bennée TEST_LEA("(%%edi, %%ecx)");
2494132431fSAlex Bennée
2504132431fSAlex Bennée TEST_LEA("0x40(%%eax, %%ecx)");
2514132431fSAlex Bennée TEST_LEA("0x4000(%%ebx, %%edx)");
2524132431fSAlex Bennée
2534132431fSAlex Bennée TEST_LEA("(%%ecx, %%ecx, 2)");
2544132431fSAlex Bennée TEST_LEA("(%%edx, %%ecx, 4)");
2554132431fSAlex Bennée TEST_LEA("(%%esi, %%ecx, 8)");
2564132431fSAlex Bennée
2574132431fSAlex Bennée TEST_LEA("(,%%eax, 2)");
2584132431fSAlex Bennée TEST_LEA("(,%%ebx, 4)");
2594132431fSAlex Bennée TEST_LEA("(,%%ecx, 8)");
2604132431fSAlex Bennée
2614132431fSAlex Bennée TEST_LEA("0x40(,%%eax, 2)");
2624132431fSAlex Bennée TEST_LEA("0x40(,%%ebx, 4)");
2634132431fSAlex Bennée TEST_LEA("0x40(,%%ecx, 8)");
2644132431fSAlex Bennée
2654132431fSAlex Bennée
2664132431fSAlex Bennée TEST_LEA("-10(%%ecx, %%ecx, 2)");
2674132431fSAlex Bennée TEST_LEA("-10(%%edx, %%ecx, 4)");
2684132431fSAlex Bennée TEST_LEA("-10(%%esi, %%ecx, 8)");
2694132431fSAlex Bennée
2704132431fSAlex Bennée TEST_LEA("0x4000(%%ecx, %%ecx, 2)");
2714132431fSAlex Bennée TEST_LEA("0x4000(%%edx, %%ecx, 4)");
2724132431fSAlex Bennée TEST_LEA("0x4000(%%esi, %%ecx, 8)");
2734132431fSAlex Bennée
2744132431fSAlex Bennée #if defined(__x86_64__)
2754132431fSAlex Bennée TEST_LEAQ("0x4000");
2764132431fSAlex Bennée TEST_LEAQ("0x4000(%%rip)");
2774132431fSAlex Bennée
2784132431fSAlex Bennée TEST_LEAQ("(%%rax)");
2794132431fSAlex Bennée TEST_LEAQ("(%%rbx)");
2804132431fSAlex Bennée TEST_LEAQ("(%%rcx)");
2814132431fSAlex Bennée TEST_LEAQ("(%%rdx)");
2824132431fSAlex Bennée TEST_LEAQ("(%%rsi)");
2834132431fSAlex Bennée TEST_LEAQ("(%%rdi)");
2844132431fSAlex Bennée
2854132431fSAlex Bennée TEST_LEAQ("0x40(%%rax)");
2864132431fSAlex Bennée TEST_LEAQ("0x40(%%rbx)");
2874132431fSAlex Bennée TEST_LEAQ("0x40(%%rcx)");
2884132431fSAlex Bennée TEST_LEAQ("0x40(%%rdx)");
2894132431fSAlex Bennée TEST_LEAQ("0x40(%%rsi)");
2904132431fSAlex Bennée TEST_LEAQ("0x40(%%rdi)");
2914132431fSAlex Bennée
2924132431fSAlex Bennée TEST_LEAQ("0x4000(%%rax)");
2934132431fSAlex Bennée TEST_LEAQ("0x4000(%%rbx)");
2944132431fSAlex Bennée TEST_LEAQ("0x4000(%%rcx)");
2954132431fSAlex Bennée TEST_LEAQ("0x4000(%%rdx)");
2964132431fSAlex Bennée TEST_LEAQ("0x4000(%%rsi)");
2974132431fSAlex Bennée TEST_LEAQ("0x4000(%%rdi)");
2984132431fSAlex Bennée
2994132431fSAlex Bennée TEST_LEAQ("(%%rax, %%rcx)");
3004132431fSAlex Bennée TEST_LEAQ("(%%rbx, %%rdx)");
3014132431fSAlex Bennée TEST_LEAQ("(%%rcx, %%rcx)");
3024132431fSAlex Bennée TEST_LEAQ("(%%rdx, %%rcx)");
3034132431fSAlex Bennée TEST_LEAQ("(%%rsi, %%rcx)");
3044132431fSAlex Bennée TEST_LEAQ("(%%rdi, %%rcx)");
3054132431fSAlex Bennée
3064132431fSAlex Bennée TEST_LEAQ("0x40(%%rax, %%rcx)");
3074132431fSAlex Bennée TEST_LEAQ("0x4000(%%rbx, %%rdx)");
3084132431fSAlex Bennée
3094132431fSAlex Bennée TEST_LEAQ("(%%rcx, %%rcx, 2)");
3104132431fSAlex Bennée TEST_LEAQ("(%%rdx, %%rcx, 4)");
3114132431fSAlex Bennée TEST_LEAQ("(%%rsi, %%rcx, 8)");
3124132431fSAlex Bennée
3134132431fSAlex Bennée TEST_LEAQ("(,%%rax, 2)");
3144132431fSAlex Bennée TEST_LEAQ("(,%%rbx, 4)");
3154132431fSAlex Bennée TEST_LEAQ("(,%%rcx, 8)");
3164132431fSAlex Bennée
3174132431fSAlex Bennée TEST_LEAQ("0x40(,%%rax, 2)");
3184132431fSAlex Bennée TEST_LEAQ("0x40(,%%rbx, 4)");
3194132431fSAlex Bennée TEST_LEAQ("0x40(,%%rcx, 8)");
3204132431fSAlex Bennée
3214132431fSAlex Bennée
3224132431fSAlex Bennée TEST_LEAQ("-10(%%rcx, %%rcx, 2)");
3234132431fSAlex Bennée TEST_LEAQ("-10(%%rdx, %%rcx, 4)");
3244132431fSAlex Bennée TEST_LEAQ("-10(%%rsi, %%rcx, 8)");
3254132431fSAlex Bennée
3264132431fSAlex Bennée TEST_LEAQ("0x4000(%%rcx, %%rcx, 2)");
3274132431fSAlex Bennée TEST_LEAQ("0x4000(%%rdx, %%rcx, 4)");
3284132431fSAlex Bennée TEST_LEAQ("0x4000(%%rsi, %%rcx, 8)");
3294132431fSAlex Bennée #else
3304132431fSAlex Bennée /* limited 16 bit addressing test */
3314132431fSAlex Bennée TEST_LEA16("0x4000");
3324132431fSAlex Bennée TEST_LEA16("(%%bx)");
3334132431fSAlex Bennée TEST_LEA16("(%%si)");
3344132431fSAlex Bennée TEST_LEA16("(%%di)");
3354132431fSAlex Bennée TEST_LEA16("0x40(%%bx)");
3364132431fSAlex Bennée TEST_LEA16("0x40(%%si)");
3374132431fSAlex Bennée TEST_LEA16("0x40(%%di)");
3384132431fSAlex Bennée TEST_LEA16("0x4000(%%bx)");
3394132431fSAlex Bennée TEST_LEA16("0x4000(%%si)");
3404132431fSAlex Bennée TEST_LEA16("(%%bx,%%si)");
3414132431fSAlex Bennée TEST_LEA16("(%%bx,%%di)");
3424132431fSAlex Bennée TEST_LEA16("0x40(%%bx,%%si)");
3434132431fSAlex Bennée TEST_LEA16("0x40(%%bx,%%di)");
3444132431fSAlex Bennée TEST_LEA16("0x4000(%%bx,%%si)");
3454132431fSAlex Bennée TEST_LEA16("0x4000(%%bx,%%di)");
3464132431fSAlex Bennée #endif
3474132431fSAlex Bennée }
3484132431fSAlex Bennée
3494132431fSAlex Bennée #define TEST_JCC(JCC, v1, v2)\
3504132431fSAlex Bennée {\
3514132431fSAlex Bennée int res;\
3524132431fSAlex Bennée asm("movl $1, %0\n\t"\
3534132431fSAlex Bennée "cmpl %2, %1\n\t"\
3544132431fSAlex Bennée "j" JCC " 1f\n\t"\
3554132431fSAlex Bennée "movl $0, %0\n\t"\
3564132431fSAlex Bennée "1:\n\t"\
3574132431fSAlex Bennée : "=r" (res)\
3584132431fSAlex Bennée : "r" (v1), "r" (v2));\
3594132431fSAlex Bennée printf("%-10s %d\n", "j" JCC, res);\
3604132431fSAlex Bennée \
3614132431fSAlex Bennée asm("movl $0, %0\n\t"\
3624132431fSAlex Bennée "cmpl %2, %1\n\t"\
3634132431fSAlex Bennée "set" JCC " %b0\n\t"\
3644132431fSAlex Bennée : "=r" (res)\
3654132431fSAlex Bennée : "r" (v1), "r" (v2));\
3664132431fSAlex Bennée printf("%-10s %d\n", "set" JCC, res);\
3674132431fSAlex Bennée if (TEST_CMOV) {\
3684132431fSAlex Bennée long val = i2l(1);\
3694132431fSAlex Bennée long res = i2l(0x12345678);\
3704132431fSAlex Bennée X86_64_ONLY(\
3714132431fSAlex Bennée asm("cmpl %2, %1\n\t"\
3724132431fSAlex Bennée "cmov" JCC "q %3, %0\n\t"\
3734132431fSAlex Bennée : "=r" (res)\
3744132431fSAlex Bennée : "r" (v1), "r" (v2), "m" (val), "0" (res));\
3754132431fSAlex Bennée printf("%-10s R=" FMTLX "\n", "cmov" JCC "q", res);)\
3764132431fSAlex Bennée asm("cmpl %2, %1\n\t"\
3774132431fSAlex Bennée "cmov" JCC "l %k3, %k0\n\t"\
3784132431fSAlex Bennée : "=r" (res)\
3794132431fSAlex Bennée : "r" (v1), "r" (v2), "m" (val), "0" (res));\
3804132431fSAlex Bennée printf("%-10s R=" FMTLX "\n", "cmov" JCC "l", res);\
3814132431fSAlex Bennée asm("cmpl %2, %1\n\t"\
3824132431fSAlex Bennée "cmov" JCC "w %w3, %w0\n\t"\
3834132431fSAlex Bennée : "=r" (res)\
3844132431fSAlex Bennée : "r" (v1), "r" (v2), "r" (1), "0" (res));\
3854132431fSAlex Bennée printf("%-10s R=" FMTLX "\n", "cmov" JCC "w", res);\
3864132431fSAlex Bennée } \
3874132431fSAlex Bennée }
3884132431fSAlex Bennée
3894132431fSAlex Bennée /* various jump tests */
test_jcc(void)3904132431fSAlex Bennée void test_jcc(void)
3914132431fSAlex Bennée {
3924132431fSAlex Bennée TEST_JCC("ne", 1, 1);
3934132431fSAlex Bennée TEST_JCC("ne", 1, 0);
3944132431fSAlex Bennée
3954132431fSAlex Bennée TEST_JCC("e", 1, 1);
3964132431fSAlex Bennée TEST_JCC("e", 1, 0);
3974132431fSAlex Bennée
3984132431fSAlex Bennée TEST_JCC("l", 1, 1);
3994132431fSAlex Bennée TEST_JCC("l", 1, 0);
4004132431fSAlex Bennée TEST_JCC("l", 1, -1);
4014132431fSAlex Bennée
4024132431fSAlex Bennée TEST_JCC("le", 1, 1);
4034132431fSAlex Bennée TEST_JCC("le", 1, 0);
4044132431fSAlex Bennée TEST_JCC("le", 1, -1);
4054132431fSAlex Bennée
4064132431fSAlex Bennée TEST_JCC("ge", 1, 1);
4074132431fSAlex Bennée TEST_JCC("ge", 1, 0);
4084132431fSAlex Bennée TEST_JCC("ge", -1, 1);
4094132431fSAlex Bennée
4104132431fSAlex Bennée TEST_JCC("g", 1, 1);
4114132431fSAlex Bennée TEST_JCC("g", 1, 0);
4124132431fSAlex Bennée TEST_JCC("g", 1, -1);
4134132431fSAlex Bennée
4144132431fSAlex Bennée TEST_JCC("b", 1, 1);
4154132431fSAlex Bennée TEST_JCC("b", 1, 0);
4164132431fSAlex Bennée TEST_JCC("b", 1, -1);
4174132431fSAlex Bennée
4184132431fSAlex Bennée TEST_JCC("be", 1, 1);
4194132431fSAlex Bennée TEST_JCC("be", 1, 0);
4204132431fSAlex Bennée TEST_JCC("be", 1, -1);
4214132431fSAlex Bennée
4224132431fSAlex Bennée TEST_JCC("ae", 1, 1);
4234132431fSAlex Bennée TEST_JCC("ae", 1, 0);
4244132431fSAlex Bennée TEST_JCC("ae", 1, -1);
4254132431fSAlex Bennée
4264132431fSAlex Bennée TEST_JCC("a", 1, 1);
4274132431fSAlex Bennée TEST_JCC("a", 1, 0);
4284132431fSAlex Bennée TEST_JCC("a", 1, -1);
4294132431fSAlex Bennée
4304132431fSAlex Bennée
4314132431fSAlex Bennée TEST_JCC("p", 1, 1);
4324132431fSAlex Bennée TEST_JCC("p", 1, 0);
4334132431fSAlex Bennée
4344132431fSAlex Bennée TEST_JCC("np", 1, 1);
4354132431fSAlex Bennée TEST_JCC("np", 1, 0);
4364132431fSAlex Bennée
4374132431fSAlex Bennée TEST_JCC("o", 0x7fffffff, 0);
4384132431fSAlex Bennée TEST_JCC("o", 0x7fffffff, -1);
4394132431fSAlex Bennée
4404132431fSAlex Bennée TEST_JCC("no", 0x7fffffff, 0);
4414132431fSAlex Bennée TEST_JCC("no", 0x7fffffff, -1);
4424132431fSAlex Bennée
4434132431fSAlex Bennée TEST_JCC("s", 0, 1);
4444132431fSAlex Bennée TEST_JCC("s", 0, -1);
4454132431fSAlex Bennée TEST_JCC("s", 0, 0);
4464132431fSAlex Bennée
4474132431fSAlex Bennée TEST_JCC("ns", 0, 1);
4484132431fSAlex Bennée TEST_JCC("ns", 0, -1);
4494132431fSAlex Bennée TEST_JCC("ns", 0, 0);
4504132431fSAlex Bennée }
4514132431fSAlex Bennée
4524132431fSAlex Bennée #define TEST_LOOP(insn) \
4534132431fSAlex Bennée {\
4544132431fSAlex Bennée for(i = 0; i < sizeof(ecx_vals) / sizeof(long); i++) {\
4554132431fSAlex Bennée ecx = ecx_vals[i];\
4564132431fSAlex Bennée for(zf = 0; zf < 2; zf++) {\
4574132431fSAlex Bennée asm("test %2, %2\n\t"\
4584132431fSAlex Bennée "movl $1, %0\n\t"\
4594132431fSAlex Bennée insn " 1f\n\t" \
4604132431fSAlex Bennée "movl $0, %0\n\t"\
4614132431fSAlex Bennée "1:\n\t"\
4624132431fSAlex Bennée : "=a" (res)\
4634132431fSAlex Bennée : "c" (ecx), "b" (!zf)); \
4644132431fSAlex Bennée printf("%-10s ECX=" FMTLX " ZF=%ld r=%d\n", insn, ecx, zf, res); \
4654132431fSAlex Bennée }\
4664132431fSAlex Bennée }\
4674132431fSAlex Bennée }
4684132431fSAlex Bennée
test_loop(void)4694132431fSAlex Bennée void test_loop(void)
4704132431fSAlex Bennée {
4714132431fSAlex Bennée long ecx, zf;
4724132431fSAlex Bennée const long ecx_vals[] = {
4734132431fSAlex Bennée 0,
4744132431fSAlex Bennée 1,
4754132431fSAlex Bennée 0x10000,
4764132431fSAlex Bennée 0x10001,
4774132431fSAlex Bennée #if defined(__x86_64__)
4784132431fSAlex Bennée 0x100000000L,
4794132431fSAlex Bennée 0x100000001L,
4804132431fSAlex Bennée #endif
4814132431fSAlex Bennée };
4824132431fSAlex Bennée int i, res;
4834132431fSAlex Bennée
4844132431fSAlex Bennée #if !defined(__x86_64__)
4854132431fSAlex Bennée TEST_LOOP("jcxz");
4864132431fSAlex Bennée TEST_LOOP("loopw");
4874132431fSAlex Bennée TEST_LOOP("loopzw");
4884132431fSAlex Bennée TEST_LOOP("loopnzw");
4894132431fSAlex Bennée #endif
4904132431fSAlex Bennée
4914132431fSAlex Bennée TEST_LOOP("jecxz");
4924132431fSAlex Bennée TEST_LOOP("loopl");
4934132431fSAlex Bennée TEST_LOOP("loopzl");
4944132431fSAlex Bennée TEST_LOOP("loopnzl");
4954132431fSAlex Bennée }
4964132431fSAlex Bennée
4974132431fSAlex Bennée #undef CC_MASK
4984132431fSAlex Bennée #ifdef TEST_P4_FLAGS
4994132431fSAlex Bennée #define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)
5004132431fSAlex Bennée #else
5014132431fSAlex Bennée #define CC_MASK (CC_O | CC_C)
5024132431fSAlex Bennée #endif
5034132431fSAlex Bennée
5044132431fSAlex Bennée #define OP mul
5054132431fSAlex Bennée #include "test-i386-muldiv.h"
5064132431fSAlex Bennée
5074132431fSAlex Bennée #define OP imul
5084132431fSAlex Bennée #include "test-i386-muldiv.h"
5094132431fSAlex Bennée
test_imulw2(long op0,long op1)5104132431fSAlex Bennée void test_imulw2(long op0, long op1)
5114132431fSAlex Bennée {
5124132431fSAlex Bennée long res, s1, s0, flags;
5134132431fSAlex Bennée s0 = op0;
5144132431fSAlex Bennée s1 = op1;
5154132431fSAlex Bennée res = s0;
5164132431fSAlex Bennée flags = 0;
5174132431fSAlex Bennée asm volatile ("push %4\n\t"
5184132431fSAlex Bennée "popf\n\t"
5194132431fSAlex Bennée "imulw %w2, %w0\n\t"
5204132431fSAlex Bennée "pushf\n\t"
5214132431fSAlex Bennée "pop %1\n\t"
5224132431fSAlex Bennée : "=q" (res), "=g" (flags)
5234132431fSAlex Bennée : "q" (s1), "0" (res), "1" (flags));
5244132431fSAlex Bennée printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n",
5254132431fSAlex Bennée "imulw", s0, s1, res, flags & CC_MASK);
5264132431fSAlex Bennée }
5274132431fSAlex Bennée
test_imull2(long op0,long op1)5284132431fSAlex Bennée void test_imull2(long op0, long op1)
5294132431fSAlex Bennée {
5304132431fSAlex Bennée long res, s1, s0, flags;
5314132431fSAlex Bennée s0 = op0;
5324132431fSAlex Bennée s1 = op1;
5334132431fSAlex Bennée res = s0;
5344132431fSAlex Bennée flags = 0;
5354132431fSAlex Bennée asm volatile ("push %4\n\t"
5364132431fSAlex Bennée "popf\n\t"
5374132431fSAlex Bennée "imull %k2, %k0\n\t"
5384132431fSAlex Bennée "pushf\n\t"
5394132431fSAlex Bennée "pop %1\n\t"
5404132431fSAlex Bennée : "=q" (res), "=g" (flags)
5414132431fSAlex Bennée : "q" (s1), "0" (res), "1" (flags));
5424132431fSAlex Bennée printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n",
5434132431fSAlex Bennée "imull", s0, s1, res, flags & CC_MASK);
5444132431fSAlex Bennée }
5454132431fSAlex Bennée
5464132431fSAlex Bennée #if defined(__x86_64__)
test_imulq2(long op0,long op1)5474132431fSAlex Bennée void test_imulq2(long op0, long op1)
5484132431fSAlex Bennée {
5494132431fSAlex Bennée long res, s1, s0, flags;
5504132431fSAlex Bennée s0 = op0;
5514132431fSAlex Bennée s1 = op1;
5524132431fSAlex Bennée res = s0;
5534132431fSAlex Bennée flags = 0;
5544132431fSAlex Bennée asm volatile ("push %4\n\t"
5554132431fSAlex Bennée "popf\n\t"
5564132431fSAlex Bennée "imulq %2, %0\n\t"
5574132431fSAlex Bennée "pushf\n\t"
5584132431fSAlex Bennée "pop %1\n\t"
5594132431fSAlex Bennée : "=q" (res), "=g" (flags)
5604132431fSAlex Bennée : "q" (s1), "0" (res), "1" (flags));
5614132431fSAlex Bennée printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n",
5624132431fSAlex Bennée "imulq", s0, s1, res, flags & CC_MASK);
5634132431fSAlex Bennée }
5644132431fSAlex Bennée #endif
5654132431fSAlex Bennée
5664132431fSAlex Bennée #define TEST_IMUL_IM(size, rsize, op0, op1)\
5674132431fSAlex Bennée {\
5684132431fSAlex Bennée long res, flags, s1;\
5694132431fSAlex Bennée flags = 0;\
5704132431fSAlex Bennée res = 0;\
5714132431fSAlex Bennée s1 = op1;\
5724132431fSAlex Bennée asm volatile ("push %3\n\t"\
5734132431fSAlex Bennée "popf\n\t"\
5744132431fSAlex Bennée "imul" size " $" #op0 ", %" rsize "2, %" rsize "0\n\t" \
5754132431fSAlex Bennée "pushf\n\t"\
5764132431fSAlex Bennée "pop %1\n\t"\
5774132431fSAlex Bennée : "=r" (res), "=g" (flags)\
5784132431fSAlex Bennée : "r" (s1), "1" (flags), "0" (res));\
5794132431fSAlex Bennée printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n",\
5804132431fSAlex Bennée "imul" size " im", (long)op0, (long)op1, res, flags & CC_MASK);\
5814132431fSAlex Bennée }
5824132431fSAlex Bennée
5834132431fSAlex Bennée
5844132431fSAlex Bennée #undef CC_MASK
5854132431fSAlex Bennée #define CC_MASK (0)
5864132431fSAlex Bennée
5874132431fSAlex Bennée #define OP div
5884132431fSAlex Bennée #include "test-i386-muldiv.h"
5894132431fSAlex Bennée
5904132431fSAlex Bennée #define OP idiv
5914132431fSAlex Bennée #include "test-i386-muldiv.h"
5924132431fSAlex Bennée
test_mul(void)5934132431fSAlex Bennée void test_mul(void)
5944132431fSAlex Bennée {
5954132431fSAlex Bennée test_imulb(0x1234561d, 4);
5964132431fSAlex Bennée test_imulb(3, -4);
5974132431fSAlex Bennée test_imulb(0x80, 0x80);
5984132431fSAlex Bennée test_imulb(0x10, 0x10);
5994132431fSAlex Bennée
6004132431fSAlex Bennée test_imulw(0, 0x1234001d, 45);
6014132431fSAlex Bennée test_imulw(0, 23, -45);
6024132431fSAlex Bennée test_imulw(0, 0x8000, 0x8000);
6034132431fSAlex Bennée test_imulw(0, 0x100, 0x100);
6044132431fSAlex Bennée
6054132431fSAlex Bennée test_imull(0, 0x1234001d, 45);
6064132431fSAlex Bennée test_imull(0, 23, -45);
6074132431fSAlex Bennée test_imull(0, 0x80000000, 0x80000000);
6084132431fSAlex Bennée test_imull(0, 0x10000, 0x10000);
6094132431fSAlex Bennée
6104132431fSAlex Bennée test_mulb(0x1234561d, 4);
6114132431fSAlex Bennée test_mulb(3, -4);
6124132431fSAlex Bennée test_mulb(0x80, 0x80);
6134132431fSAlex Bennée test_mulb(0x10, 0x10);
6144132431fSAlex Bennée
6154132431fSAlex Bennée test_mulw(0, 0x1234001d, 45);
6164132431fSAlex Bennée test_mulw(0, 23, -45);
6174132431fSAlex Bennée test_mulw(0, 0x8000, 0x8000);
6184132431fSAlex Bennée test_mulw(0, 0x100, 0x100);
6194132431fSAlex Bennée
6204132431fSAlex Bennée test_mull(0, 0x1234001d, 45);
6214132431fSAlex Bennée test_mull(0, 23, -45);
6224132431fSAlex Bennée test_mull(0, 0x80000000, 0x80000000);
6234132431fSAlex Bennée test_mull(0, 0x10000, 0x10000);
6244132431fSAlex Bennée
6254132431fSAlex Bennée test_imulw2(0x1234001d, 45);
6264132431fSAlex Bennée test_imulw2(23, -45);
6274132431fSAlex Bennée test_imulw2(0x8000, 0x8000);
6284132431fSAlex Bennée test_imulw2(0x100, 0x100);
6294132431fSAlex Bennée
6304132431fSAlex Bennée test_imull2(0x1234001d, 45);
6314132431fSAlex Bennée test_imull2(23, -45);
6324132431fSAlex Bennée test_imull2(0x80000000, 0x80000000);
6334132431fSAlex Bennée test_imull2(0x10000, 0x10000);
6344132431fSAlex Bennée
6354132431fSAlex Bennée TEST_IMUL_IM("w", "w", 45, 0x1234);
6364132431fSAlex Bennée TEST_IMUL_IM("w", "w", -45, 23);
6374132431fSAlex Bennée TEST_IMUL_IM("w", "w", 0x8000, 0x80000000);
6384132431fSAlex Bennée TEST_IMUL_IM("w", "w", 0x7fff, 0x1000);
6394132431fSAlex Bennée
6404132431fSAlex Bennée TEST_IMUL_IM("l", "k", 45, 0x1234);
6414132431fSAlex Bennée TEST_IMUL_IM("l", "k", -45, 23);
6424132431fSAlex Bennée TEST_IMUL_IM("l", "k", 0x8000, 0x80000000);
6434132431fSAlex Bennée TEST_IMUL_IM("l", "k", 0x7fff, 0x1000);
6444132431fSAlex Bennée
6454132431fSAlex Bennée test_idivb(0x12341678, 0x127e);
6464132431fSAlex Bennée test_idivb(0x43210123, -5);
6474132431fSAlex Bennée test_idivb(0x12340004, -1);
6484132431fSAlex Bennée
6494132431fSAlex Bennée test_idivw(0, 0x12345678, 12347);
6504132431fSAlex Bennée test_idivw(0, -23223, -45);
6514132431fSAlex Bennée test_idivw(0, 0x12348000, -1);
6524132431fSAlex Bennée test_idivw(0x12343, 0x12345678, 0x81238567);
6534132431fSAlex Bennée
6544132431fSAlex Bennée test_idivl(0, 0x12345678, 12347);
6554132431fSAlex Bennée test_idivl(0, -233223, -45);
6564132431fSAlex Bennée test_idivl(0, 0x80000000, -1);
6574132431fSAlex Bennée test_idivl(0x12343, 0x12345678, 0x81234567);
6584132431fSAlex Bennée
6594132431fSAlex Bennée test_divb(0x12341678, 0x127e);
6604132431fSAlex Bennée test_divb(0x43210123, -5);
6614132431fSAlex Bennée test_divb(0x12340004, -1);
6624132431fSAlex Bennée
6634132431fSAlex Bennée test_divw(0, 0x12345678, 12347);
6644132431fSAlex Bennée test_divw(0, -23223, -45);
6654132431fSAlex Bennée test_divw(0, 0x12348000, -1);
6664132431fSAlex Bennée test_divw(0x12343, 0x12345678, 0x81238567);
6674132431fSAlex Bennée
6684132431fSAlex Bennée test_divl(0, 0x12345678, 12347);
6694132431fSAlex Bennée test_divl(0, -233223, -45);
6704132431fSAlex Bennée test_divl(0, 0x80000000, -1);
6714132431fSAlex Bennée test_divl(0x12343, 0x12345678, 0x81234567);
6724132431fSAlex Bennée
6734132431fSAlex Bennée #if defined(__x86_64__)
6744132431fSAlex Bennée test_imulq(0, 0x1234001d1234001d, 45);
6754132431fSAlex Bennée test_imulq(0, 23, -45);
6764132431fSAlex Bennée test_imulq(0, 0x8000000000000000, 0x8000000000000000);
6774132431fSAlex Bennée test_imulq(0, 0x100000000, 0x100000000);
6784132431fSAlex Bennée
6794132431fSAlex Bennée test_mulq(0, 0x1234001d1234001d, 45);
6804132431fSAlex Bennée test_mulq(0, 23, -45);
6814132431fSAlex Bennée test_mulq(0, 0x8000000000000000, 0x8000000000000000);
6824132431fSAlex Bennée test_mulq(0, 0x100000000, 0x100000000);
6834132431fSAlex Bennée
6844132431fSAlex Bennée test_imulq2(0x1234001d1234001d, 45);
6854132431fSAlex Bennée test_imulq2(23, -45);
6864132431fSAlex Bennée test_imulq2(0x8000000000000000, 0x8000000000000000);
6874132431fSAlex Bennée test_imulq2(0x100000000, 0x100000000);
6884132431fSAlex Bennée
6894132431fSAlex Bennée TEST_IMUL_IM("q", "", 45, 0x12341234);
6904132431fSAlex Bennée TEST_IMUL_IM("q", "", -45, 23);
6914132431fSAlex Bennée TEST_IMUL_IM("q", "", 0x8000, 0x8000000000000000);
6924132431fSAlex Bennée TEST_IMUL_IM("q", "", 0x7fff, 0x10000000);
6934132431fSAlex Bennée
6944132431fSAlex Bennée test_idivq(0, 0x12345678abcdef, 12347);
6954132431fSAlex Bennée test_idivq(0, -233223, -45);
6964132431fSAlex Bennée test_idivq(0, 0x8000000000000000, -1);
6974132431fSAlex Bennée test_idivq(0x12343, 0x12345678, 0x81234567);
6984132431fSAlex Bennée
6994132431fSAlex Bennée test_divq(0, 0x12345678abcdef, 12347);
7004132431fSAlex Bennée test_divq(0, -233223, -45);
7014132431fSAlex Bennée test_divq(0, 0x8000000000000000, -1);
7024132431fSAlex Bennée test_divq(0x12343, 0x12345678, 0x81234567);
7034132431fSAlex Bennée #endif
7044132431fSAlex Bennée }
7054132431fSAlex Bennée
7064132431fSAlex Bennée #define TEST_BSX(op, size, op0)\
7074132431fSAlex Bennée {\
7084132431fSAlex Bennée long res, val, resz;\
7094132431fSAlex Bennée val = op0;\
7104132431fSAlex Bennée asm("xor %1, %1\n"\
7114132431fSAlex Bennée "mov $0x12345678, %0\n"\
7124132431fSAlex Bennée #op " %" size "2, %" size "0 ; setz %b1" \
7134132431fSAlex Bennée : "=&r" (res), "=&q" (resz)\
7144132431fSAlex Bennée : "r" (val));\
7154132431fSAlex Bennée printf("%-10s A=" FMTLX " R=" FMTLX " %ld\n", #op, val, res, resz);\
7164132431fSAlex Bennée }
7174132431fSAlex Bennée
test_xcnt(void)718*ff5b5739SPaolo Bonzini void test_xcnt(void)
719*ff5b5739SPaolo Bonzini {
720*ff5b5739SPaolo Bonzini TEST_BSX(tzcntw, "w", 0);
721*ff5b5739SPaolo Bonzini TEST_BSX(tzcntw, "w", 0x12340128);
722*ff5b5739SPaolo Bonzini TEST_BSX(lzcntw, "w", 0);
723*ff5b5739SPaolo Bonzini TEST_BSX(lzcntw, "w", 0x12340128);
724*ff5b5739SPaolo Bonzini TEST_BSX(popcntw, "w", 0);
725*ff5b5739SPaolo Bonzini TEST_BSX(popcntw, "w", 0x12340128);
726*ff5b5739SPaolo Bonzini TEST_BSX(tzcntl, "k", 0);
727*ff5b5739SPaolo Bonzini TEST_BSX(tzcntl, "k", 0x00340128);
728*ff5b5739SPaolo Bonzini TEST_BSX(lzcntl, "k", 0);
729*ff5b5739SPaolo Bonzini TEST_BSX(lzcntl, "k", 0x00340128);
730*ff5b5739SPaolo Bonzini TEST_BSX(popcntl, "k", 0);
731*ff5b5739SPaolo Bonzini TEST_BSX(popcntl, "k", 0x00340128);
732*ff5b5739SPaolo Bonzini #if defined(__x86_64__)
733*ff5b5739SPaolo Bonzini TEST_BSX(tzcntq, "", 0);
734*ff5b5739SPaolo Bonzini TEST_BSX(tzcntq, "", 0x003401281234);
735*ff5b5739SPaolo Bonzini TEST_BSX(lzcntq, "", 0);
736*ff5b5739SPaolo Bonzini TEST_BSX(lzcntq, "", 0x003401281234);
737*ff5b5739SPaolo Bonzini TEST_BSX(popcntq, "", 0);
738*ff5b5739SPaolo Bonzini TEST_BSX(popcntq, "", 0x003401281234);
739*ff5b5739SPaolo Bonzini #endif
740*ff5b5739SPaolo Bonzini }
741*ff5b5739SPaolo Bonzini
test_bsx(void)7424132431fSAlex Bennée void test_bsx(void)
7434132431fSAlex Bennée {
7444132431fSAlex Bennée TEST_BSX(bsrw, "w", 0);
7454132431fSAlex Bennée TEST_BSX(bsrw, "w", 0x12340128);
7464132431fSAlex Bennée TEST_BSX(bsfw, "w", 0);
7474132431fSAlex Bennée TEST_BSX(bsfw, "w", 0x12340128);
7484132431fSAlex Bennée TEST_BSX(bsrl, "k", 0);
7494132431fSAlex Bennée TEST_BSX(bsrl, "k", 0x00340128);
7504132431fSAlex Bennée TEST_BSX(bsfl, "k", 0);
7514132431fSAlex Bennée TEST_BSX(bsfl, "k", 0x00340128);
7524132431fSAlex Bennée #if defined(__x86_64__)
7534132431fSAlex Bennée TEST_BSX(bsrq, "", 0);
7544132431fSAlex Bennée TEST_BSX(bsrq, "", 0x003401281234);
7554132431fSAlex Bennée TEST_BSX(bsfq, "", 0);
7564132431fSAlex Bennée TEST_BSX(bsfq, "", 0x003401281234);
7574132431fSAlex Bennée #endif
7584132431fSAlex Bennée }
7594132431fSAlex Bennée
7604132431fSAlex Bennée /**********************************************/
7614132431fSAlex Bennée
7624132431fSAlex Bennée union float64u {
7634132431fSAlex Bennée double d;
7644132431fSAlex Bennée uint64_t l;
7654132431fSAlex Bennée };
7664132431fSAlex Bennée
7674132431fSAlex Bennée union float64u q_nan = { .l = 0xFFF8000000000000LL };
7684132431fSAlex Bennée union float64u s_nan = { .l = 0xFFF0000000000000LL };
7694132431fSAlex Bennée
test_fops(double a,double b)7704132431fSAlex Bennée void test_fops(double a, double b)
7714132431fSAlex Bennée {
7724132431fSAlex Bennée printf("a=%f b=%f a+b=%f\n", a, b, a + b);
7734132431fSAlex Bennée printf("a=%f b=%f a-b=%f\n", a, b, a - b);
7744132431fSAlex Bennée printf("a=%f b=%f a*b=%f\n", a, b, a * b);
7754132431fSAlex Bennée printf("a=%f b=%f a/b=%f\n", a, b, a / b);
7764132431fSAlex Bennée printf("a=%f b=%f fmod(a, b)=%f\n", a, b, fmod(a, b));
7774132431fSAlex Bennée printf("a=%f sqrt(a)=%f\n", a, sqrt(a));
7784132431fSAlex Bennée printf("a=%f sin(a)=%f\n", a, sin(a));
7794132431fSAlex Bennée printf("a=%f cos(a)=%f\n", a, cos(a));
7804132431fSAlex Bennée printf("a=%f tan(a)=%f\n", a, tan(a));
7814132431fSAlex Bennée printf("a=%f log(a)=%f\n", a, log(a));
7824132431fSAlex Bennée printf("a=%f exp(a)=%f\n", a, exp(a));
7834132431fSAlex Bennée printf("a=%f b=%f atan2(a, b)=%f\n", a, b, atan2(a, b));
7844132431fSAlex Bennée /* just to test some op combining */
7854132431fSAlex Bennée printf("a=%f asin(sin(a))=%f\n", a, asin(sin(a)));
7864132431fSAlex Bennée printf("a=%f acos(cos(a))=%f\n", a, acos(cos(a)));
7874132431fSAlex Bennée printf("a=%f atan(tan(a))=%f\n", a, atan(tan(a)));
7884132431fSAlex Bennée
7894132431fSAlex Bennée }
7904132431fSAlex Bennée
fpu_clear_exceptions(void)7914132431fSAlex Bennée void fpu_clear_exceptions(void)
7924132431fSAlex Bennée {
7934132431fSAlex Bennée struct QEMU_PACKED {
7944132431fSAlex Bennée uint16_t fpuc;
7954132431fSAlex Bennée uint16_t dummy1;
7964132431fSAlex Bennée uint16_t fpus;
7974132431fSAlex Bennée uint16_t dummy2;
7984132431fSAlex Bennée uint16_t fptag;
7994132431fSAlex Bennée uint16_t dummy3;
8004132431fSAlex Bennée uint32_t ignored[4];
8014132431fSAlex Bennée long double fpregs[8];
8024132431fSAlex Bennée } float_env32;
8034132431fSAlex Bennée
8044132431fSAlex Bennée asm volatile ("fnstenv %0\n" : "=m" (float_env32));
8054132431fSAlex Bennée float_env32.fpus &= ~0x7f;
8064132431fSAlex Bennée asm volatile ("fldenv %0\n" : : "m" (float_env32));
8074132431fSAlex Bennée }
8084132431fSAlex Bennée
8094132431fSAlex Bennée /* XXX: display exception bits when supported */
8104132431fSAlex Bennée #define FPUS_EMASK 0x0000
8114132431fSAlex Bennée //#define FPUS_EMASK 0x007f
8124132431fSAlex Bennée
test_fcmp(double a,double b)8134132431fSAlex Bennée void test_fcmp(double a, double b)
8144132431fSAlex Bennée {
8154132431fSAlex Bennée long eflags, fpus;
8164132431fSAlex Bennée
8174132431fSAlex Bennée fpu_clear_exceptions();
8184132431fSAlex Bennée asm("fcom %2\n"
8194132431fSAlex Bennée "fstsw %%ax\n"
8204132431fSAlex Bennée : "=a" (fpus)
8214132431fSAlex Bennée : "t" (a), "u" (b));
8224132431fSAlex Bennée printf("fcom(%f %f)=%04lx\n",
8234132431fSAlex Bennée a, b, fpus & (0x4500 | FPUS_EMASK));
8244132431fSAlex Bennée fpu_clear_exceptions();
8254132431fSAlex Bennée asm("fucom %2\n"
8264132431fSAlex Bennée "fstsw %%ax\n"
8274132431fSAlex Bennée : "=a" (fpus)
8284132431fSAlex Bennée : "t" (a), "u" (b));
8294132431fSAlex Bennée printf("fucom(%f %f)=%04lx\n",
8304132431fSAlex Bennée a, b, fpus & (0x4500 | FPUS_EMASK));
8314132431fSAlex Bennée if (TEST_FCOMI) {
8324132431fSAlex Bennée /* test f(u)comi instruction */
8334132431fSAlex Bennée fpu_clear_exceptions();
8344132431fSAlex Bennée asm("fcomi %3, %2\n"
8354132431fSAlex Bennée "fstsw %%ax\n"
8364132431fSAlex Bennée "pushf\n"
8374132431fSAlex Bennée "pop %0\n"
8384132431fSAlex Bennée : "=r" (eflags), "=a" (fpus)
8394132431fSAlex Bennée : "t" (a), "u" (b));
8404132431fSAlex Bennée printf("fcomi(%f %f)=%04lx %02lx\n",
8414132431fSAlex Bennée a, b, fpus & FPUS_EMASK, eflags & (CC_Z | CC_P | CC_C));
8424132431fSAlex Bennée fpu_clear_exceptions();
8434132431fSAlex Bennée asm("fucomi %3, %2\n"
8444132431fSAlex Bennée "fstsw %%ax\n"
8454132431fSAlex Bennée "pushf\n"
8464132431fSAlex Bennée "pop %0\n"
8474132431fSAlex Bennée : "=r" (eflags), "=a" (fpus)
8484132431fSAlex Bennée : "t" (a), "u" (b));
8494132431fSAlex Bennée printf("fucomi(%f %f)=%04lx %02lx\n",
8504132431fSAlex Bennée a, b, fpus & FPUS_EMASK, eflags & (CC_Z | CC_P | CC_C));
8514132431fSAlex Bennée }
8524132431fSAlex Bennée fpu_clear_exceptions();
8534132431fSAlex Bennée asm volatile("fxam\n"
8544132431fSAlex Bennée "fstsw %%ax\n"
8554132431fSAlex Bennée : "=a" (fpus)
8564132431fSAlex Bennée : "t" (a));
8574132431fSAlex Bennée printf("fxam(%f)=%04lx\n", a, fpus & 0x4700);
8584132431fSAlex Bennée fpu_clear_exceptions();
8594132431fSAlex Bennée }
8604132431fSAlex Bennée
test_fcvt(double a)8614132431fSAlex Bennée void test_fcvt(double a)
8624132431fSAlex Bennée {
8634132431fSAlex Bennée float fa;
8644132431fSAlex Bennée long double la;
8654132431fSAlex Bennée int16_t fpuc;
8664132431fSAlex Bennée int i;
8674132431fSAlex Bennée int64_t lla;
8684132431fSAlex Bennée int ia;
8694132431fSAlex Bennée int16_t wa;
8704132431fSAlex Bennée double ra;
8714132431fSAlex Bennée
8724132431fSAlex Bennée fa = a;
8734132431fSAlex Bennée la = a;
8744132431fSAlex Bennée printf("(float)%f = %f\n", a, fa);
8754132431fSAlex Bennée printf("(long double)%f = %Lf\n", a, la);
8764132431fSAlex Bennée printf("a=" FMT64X "\n", *(uint64_t *)&a);
8774132431fSAlex Bennée printf("la=" FMT64X " %04x\n", *(uint64_t *)&la,
8784132431fSAlex Bennée *(unsigned short *)((char *)(&la) + 8));
8794132431fSAlex Bennée
8804132431fSAlex Bennée /* test all roundings */
8814132431fSAlex Bennée asm volatile ("fstcw %0" : "=m" (fpuc));
8824132431fSAlex Bennée for(i=0;i<4;i++) {
8834132431fSAlex Bennée uint16_t val16;
8844132431fSAlex Bennée val16 = (fpuc & ~0x0c00) | (i << 10);
8854132431fSAlex Bennée asm volatile ("fldcw %0" : : "m" (val16));
8866012d963SRichard Henderson asm volatile ("fists %0" : "=m" (wa) : "t" (a));
8874132431fSAlex Bennée asm volatile ("fistl %0" : "=m" (ia) : "t" (a));
8884132431fSAlex Bennée asm volatile ("fistpll %0" : "=m" (lla) : "t" (a) : "st");
8894132431fSAlex Bennée asm volatile ("frndint ; fstl %0" : "=m" (ra) : "t" (a));
8904132431fSAlex Bennée asm volatile ("fldcw %0" : : "m" (fpuc));
8914132431fSAlex Bennée printf("(short)a = %d\n", wa);
8924132431fSAlex Bennée printf("(int)a = %d\n", ia);
8934132431fSAlex Bennée printf("(int64_t)a = " FMT64X "\n", lla);
8944132431fSAlex Bennée printf("rint(a) = %f\n", ra);
8954132431fSAlex Bennée }
8964132431fSAlex Bennée }
8974132431fSAlex Bennée
8984132431fSAlex Bennée #define TEST(N) \
8994132431fSAlex Bennée asm("fld" #N : "=t" (a)); \
9004132431fSAlex Bennée printf("fld" #N "= %f\n", a);
9014132431fSAlex Bennée
test_fconst(void)9024132431fSAlex Bennée void test_fconst(void)
9034132431fSAlex Bennée {
9044132431fSAlex Bennée double a;
9054132431fSAlex Bennée TEST(1);
9064132431fSAlex Bennée TEST(l2t);
9074132431fSAlex Bennée TEST(l2e);
9084132431fSAlex Bennée TEST(pi);
9094132431fSAlex Bennée TEST(lg2);
9104132431fSAlex Bennée TEST(ln2);
9114132431fSAlex Bennée TEST(z);
9124132431fSAlex Bennée }
9134132431fSAlex Bennée
test_fbcd(double a)9144132431fSAlex Bennée void test_fbcd(double a)
9154132431fSAlex Bennée {
9164132431fSAlex Bennée unsigned short bcd[5];
9174132431fSAlex Bennée double b;
9184132431fSAlex Bennée
9194132431fSAlex Bennée asm("fbstp %0" : "=m" (bcd[0]) : "t" (a) : "st");
9204132431fSAlex Bennée asm("fbld %1" : "=t" (b) : "m" (bcd[0]));
9214132431fSAlex Bennée printf("a=%f bcd=%04x%04x%04x%04x%04x b=%f\n",
9224132431fSAlex Bennée a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b);
9234132431fSAlex Bennée }
9244132431fSAlex Bennée
9254132431fSAlex Bennée #define TEST_ENV(env, save, restore)\
9264132431fSAlex Bennée {\
9274132431fSAlex Bennée memset((env), 0xaa, sizeof(*(env)));\
9284132431fSAlex Bennée for(i=0;i<5;i++)\
9294132431fSAlex Bennée asm volatile ("fldl %0" : : "m" (dtab[i]));\
9304132431fSAlex Bennée asm volatile (save " %0\n" : : "m" (*(env)));\
9314132431fSAlex Bennée asm volatile (restore " %0\n": : "m" (*(env)));\
9324132431fSAlex Bennée for(i=0;i<5;i++)\
9334132431fSAlex Bennée asm volatile ("fstpl %0" : "=m" (rtab[i]));\
9344132431fSAlex Bennée for(i=0;i<5;i++)\
9354132431fSAlex Bennée printf("res[%d]=%f\n", i, rtab[i]);\
9364132431fSAlex Bennée printf("fpuc=%04x fpus=%04x fptag=%04x\n",\
9374132431fSAlex Bennée (env)->fpuc,\
9384132431fSAlex Bennée (env)->fpus & 0xff00,\
9394132431fSAlex Bennée (env)->fptag);\
9404132431fSAlex Bennée }
9414132431fSAlex Bennée
test_fenv(void)9424132431fSAlex Bennée void test_fenv(void)
9434132431fSAlex Bennée {
9444132431fSAlex Bennée struct __attribute__((__packed__)) {
9454132431fSAlex Bennée uint16_t fpuc;
9464132431fSAlex Bennée uint16_t dummy1;
9474132431fSAlex Bennée uint16_t fpus;
9484132431fSAlex Bennée uint16_t dummy2;
9494132431fSAlex Bennée uint16_t fptag;
9504132431fSAlex Bennée uint16_t dummy3;
9514132431fSAlex Bennée uint32_t ignored[4];
9524132431fSAlex Bennée long double fpregs[8];
9534132431fSAlex Bennée } float_env32;
9544132431fSAlex Bennée struct __attribute__((__packed__)) {
9554132431fSAlex Bennée uint16_t fpuc;
9564132431fSAlex Bennée uint16_t fpus;
9574132431fSAlex Bennée uint16_t fptag;
9584132431fSAlex Bennée uint16_t ignored[4];
9594132431fSAlex Bennée long double fpregs[8];
9604132431fSAlex Bennée } float_env16;
9614132431fSAlex Bennée double dtab[8];
9624132431fSAlex Bennée double rtab[8];
9634132431fSAlex Bennée int i;
9644132431fSAlex Bennée
9654132431fSAlex Bennée for(i=0;i<8;i++)
9664132431fSAlex Bennée dtab[i] = i + 1;
9674132431fSAlex Bennée
9684132431fSAlex Bennée TEST_ENV(&float_env16, "data16 fnstenv", "data16 fldenv");
9694132431fSAlex Bennée TEST_ENV(&float_env16, "data16 fnsave", "data16 frstor");
9704132431fSAlex Bennée TEST_ENV(&float_env32, "fnstenv", "fldenv");
9714132431fSAlex Bennée TEST_ENV(&float_env32, "fnsave", "frstor");
9724132431fSAlex Bennée
9734132431fSAlex Bennée /* test for ffree */
9744132431fSAlex Bennée for(i=0;i<5;i++)
9754132431fSAlex Bennée asm volatile ("fldl %0" : : "m" (dtab[i]));
9764132431fSAlex Bennée asm volatile("ffree %st(2)");
9774132431fSAlex Bennée asm volatile ("fnstenv %0\n" : : "m" (float_env32));
9784132431fSAlex Bennée asm volatile ("fninit");
9794132431fSAlex Bennée printf("fptag=%04x\n", float_env32.fptag);
9804132431fSAlex Bennée }
9814132431fSAlex Bennée
9824132431fSAlex Bennée
9834132431fSAlex Bennée #define TEST_FCMOV(a, b, eflags, CC)\
9844132431fSAlex Bennée {\
9854132431fSAlex Bennée double res;\
9864132431fSAlex Bennée asm("push %3\n"\
9874132431fSAlex Bennée "popf\n"\
9884132431fSAlex Bennée "fcmov" CC " %2, %0\n"\
9894132431fSAlex Bennée : "=t" (res)\
9904132431fSAlex Bennée : "0" (a), "u" (b), "g" (eflags));\
9914132431fSAlex Bennée printf("fcmov%s eflags=0x%04lx-> %f\n", \
9924132431fSAlex Bennée CC, (long)eflags, res);\
9934132431fSAlex Bennée }
9944132431fSAlex Bennée
test_fcmov(void)9954132431fSAlex Bennée void test_fcmov(void)
9964132431fSAlex Bennée {
9974132431fSAlex Bennée double a, b;
9984132431fSAlex Bennée long eflags, i;
9994132431fSAlex Bennée
10004132431fSAlex Bennée a = 1.0;
10014132431fSAlex Bennée b = 2.0;
10024132431fSAlex Bennée for(i = 0; i < 4; i++) {
10034132431fSAlex Bennée eflags = 0;
10044132431fSAlex Bennée if (i & 1)
10054132431fSAlex Bennée eflags |= CC_C;
10064132431fSAlex Bennée if (i & 2)
10074132431fSAlex Bennée eflags |= CC_Z;
10084132431fSAlex Bennée TEST_FCMOV(a, b, eflags, "b");
10094132431fSAlex Bennée TEST_FCMOV(a, b, eflags, "e");
10104132431fSAlex Bennée TEST_FCMOV(a, b, eflags, "be");
10114132431fSAlex Bennée TEST_FCMOV(a, b, eflags, "nb");
10124132431fSAlex Bennée TEST_FCMOV(a, b, eflags, "ne");
10134132431fSAlex Bennée TEST_FCMOV(a, b, eflags, "nbe");
10144132431fSAlex Bennée }
10154132431fSAlex Bennée TEST_FCMOV(a, b, 0, "u");
10164132431fSAlex Bennée TEST_FCMOV(a, b, CC_P, "u");
10174132431fSAlex Bennée TEST_FCMOV(a, b, 0, "nu");
10184132431fSAlex Bennée TEST_FCMOV(a, b, CC_P, "nu");
10194132431fSAlex Bennée }
10204132431fSAlex Bennée
test_floats(void)10214132431fSAlex Bennée void test_floats(void)
10224132431fSAlex Bennée {
10234132431fSAlex Bennée test_fops(2, 3);
10244132431fSAlex Bennée test_fops(1.4, -5);
10254132431fSAlex Bennée test_fcmp(2, -1);
10264132431fSAlex Bennée test_fcmp(2, 2);
10274132431fSAlex Bennée test_fcmp(2, 3);
10284132431fSAlex Bennée test_fcmp(2, q_nan.d);
10294132431fSAlex Bennée test_fcmp(q_nan.d, -1);
10304132431fSAlex Bennée test_fcmp(-1.0/0.0, -1);
10314132431fSAlex Bennée test_fcmp(1.0/0.0, -1);
10324132431fSAlex Bennée test_fcvt(0.5);
10334132431fSAlex Bennée test_fcvt(-0.5);
10344132431fSAlex Bennée test_fcvt(1.0/7.0);
10354132431fSAlex Bennée test_fcvt(-1.0/9.0);
10364132431fSAlex Bennée test_fcvt(32768);
10374132431fSAlex Bennée test_fcvt(-1e20);
10384132431fSAlex Bennée test_fcvt(-1.0/0.0);
10394132431fSAlex Bennée test_fcvt(1.0/0.0);
10404132431fSAlex Bennée test_fcvt(q_nan.d);
10414132431fSAlex Bennée test_fconst();
10424132431fSAlex Bennée test_fbcd(1234567890123456.0);
10434132431fSAlex Bennée test_fbcd(-123451234567890.0);
10444132431fSAlex Bennée test_fenv();
10454132431fSAlex Bennée if (TEST_CMOV) {
10464132431fSAlex Bennée test_fcmov();
10474132431fSAlex Bennée }
10484132431fSAlex Bennée }
10494132431fSAlex Bennée
10504132431fSAlex Bennée /**********************************************/
10514132431fSAlex Bennée #if !defined(__x86_64__)
10524132431fSAlex Bennée
10534132431fSAlex Bennée #define TEST_BCD(op, op0, cc_in, cc_mask)\
10544132431fSAlex Bennée {\
10554132431fSAlex Bennée int res, flags;\
10564132431fSAlex Bennée res = op0;\
10574132431fSAlex Bennée flags = cc_in;\
10584132431fSAlex Bennée asm ("push %3\n\t"\
10594132431fSAlex Bennée "popf\n\t"\
10604132431fSAlex Bennée #op "\n\t"\
10614132431fSAlex Bennée "pushf\n\t"\
10624132431fSAlex Bennée "pop %1\n\t"\
10634132431fSAlex Bennée : "=a" (res), "=g" (flags)\
10644132431fSAlex Bennée : "0" (res), "1" (flags));\
10654132431fSAlex Bennée printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n",\
10664132431fSAlex Bennée #op, op0, res, cc_in, flags & cc_mask);\
10674132431fSAlex Bennée }
10684132431fSAlex Bennée
test_bcd(void)10694132431fSAlex Bennée void test_bcd(void)
10704132431fSAlex Bennée {
10714132431fSAlex Bennée TEST_BCD(daa, 0x12340503, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10724132431fSAlex Bennée TEST_BCD(daa, 0x12340506, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10734132431fSAlex Bennée TEST_BCD(daa, 0x12340507, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10744132431fSAlex Bennée TEST_BCD(daa, 0x12340559, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10754132431fSAlex Bennée TEST_BCD(daa, 0x12340560, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10764132431fSAlex Bennée TEST_BCD(daa, 0x1234059f, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10774132431fSAlex Bennée TEST_BCD(daa, 0x123405a0, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10784132431fSAlex Bennée TEST_BCD(daa, 0x12340503, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10794132431fSAlex Bennée TEST_BCD(daa, 0x12340506, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10804132431fSAlex Bennée TEST_BCD(daa, 0x12340503, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10814132431fSAlex Bennée TEST_BCD(daa, 0x12340506, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10824132431fSAlex Bennée TEST_BCD(daa, 0x12340503, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10834132431fSAlex Bennée TEST_BCD(daa, 0x12340506, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10844132431fSAlex Bennée
10854132431fSAlex Bennée TEST_BCD(das, 0x12340503, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10864132431fSAlex Bennée TEST_BCD(das, 0x12340506, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10874132431fSAlex Bennée TEST_BCD(das, 0x12340507, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10884132431fSAlex Bennée TEST_BCD(das, 0x12340559, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10894132431fSAlex Bennée TEST_BCD(das, 0x12340560, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10904132431fSAlex Bennée TEST_BCD(das, 0x1234059f, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10914132431fSAlex Bennée TEST_BCD(das, 0x123405a0, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10924132431fSAlex Bennée TEST_BCD(das, 0x12340503, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10934132431fSAlex Bennée TEST_BCD(das, 0x12340506, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10944132431fSAlex Bennée TEST_BCD(das, 0x12340503, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10954132431fSAlex Bennée TEST_BCD(das, 0x12340506, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10964132431fSAlex Bennée TEST_BCD(das, 0x12340503, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10974132431fSAlex Bennée TEST_BCD(das, 0x12340506, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A));
10984132431fSAlex Bennée
10994132431fSAlex Bennée TEST_BCD(aaa, 0x12340205, CC_A, (CC_C | CC_A));
11004132431fSAlex Bennée TEST_BCD(aaa, 0x12340306, CC_A, (CC_C | CC_A));
11014132431fSAlex Bennée TEST_BCD(aaa, 0x1234040a, CC_A, (CC_C | CC_A));
11024132431fSAlex Bennée TEST_BCD(aaa, 0x123405fa, CC_A, (CC_C | CC_A));
11034132431fSAlex Bennée TEST_BCD(aaa, 0x12340205, 0, (CC_C | CC_A));
11044132431fSAlex Bennée TEST_BCD(aaa, 0x12340306, 0, (CC_C | CC_A));
11054132431fSAlex Bennée TEST_BCD(aaa, 0x1234040a, 0, (CC_C | CC_A));
11064132431fSAlex Bennée TEST_BCD(aaa, 0x123405fa, 0, (CC_C | CC_A));
11074132431fSAlex Bennée
11084132431fSAlex Bennée TEST_BCD(aas, 0x12340205, CC_A, (CC_C | CC_A));
11094132431fSAlex Bennée TEST_BCD(aas, 0x12340306, CC_A, (CC_C | CC_A));
11104132431fSAlex Bennée TEST_BCD(aas, 0x1234040a, CC_A, (CC_C | CC_A));
11114132431fSAlex Bennée TEST_BCD(aas, 0x123405fa, CC_A, (CC_C | CC_A));
11124132431fSAlex Bennée TEST_BCD(aas, 0x12340205, 0, (CC_C | CC_A));
11134132431fSAlex Bennée TEST_BCD(aas, 0x12340306, 0, (CC_C | CC_A));
11144132431fSAlex Bennée TEST_BCD(aas, 0x1234040a, 0, (CC_C | CC_A));
11154132431fSAlex Bennée TEST_BCD(aas, 0x123405fa, 0, (CC_C | CC_A));
11164132431fSAlex Bennée
11174132431fSAlex Bennée TEST_BCD(aam, 0x12340547, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));
11184132431fSAlex Bennée TEST_BCD(aad, 0x12340407, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));
11194132431fSAlex Bennée }
11204132431fSAlex Bennée #endif
11214132431fSAlex Bennée
11224132431fSAlex Bennée #define TEST_XCHG(op, size, opconst)\
11234132431fSAlex Bennée {\
11244132431fSAlex Bennée long op0, op1;\
11254132431fSAlex Bennée op0 = i2l(0x12345678);\
11264132431fSAlex Bennée op1 = i2l(0xfbca7654);\
11274132431fSAlex Bennée asm(#op " %" size "0, %" size "1" \
11284132431fSAlex Bennée : "=q" (op0), opconst (op1) \
11294132431fSAlex Bennée : "0" (op0));\
11304132431fSAlex Bennée printf("%-10s A=" FMTLX " B=" FMTLX "\n",\
11314132431fSAlex Bennée #op, op0, op1);\
11324132431fSAlex Bennée }
11334132431fSAlex Bennée
11344132431fSAlex Bennée #define TEST_CMPXCHG(op, size, opconst, eax)\
11354132431fSAlex Bennée {\
11364132431fSAlex Bennée long op0, op1, op2;\
11374132431fSAlex Bennée op0 = i2l(0x12345678);\
11384132431fSAlex Bennée op1 = i2l(0xfbca7654);\
11394132431fSAlex Bennée op2 = i2l(eax);\
11404132431fSAlex Bennée asm(#op " %" size "0, %" size "1" \
11414132431fSAlex Bennée : "=q" (op0), opconst (op1) \
11424132431fSAlex Bennée : "0" (op0), "a" (op2));\
11434132431fSAlex Bennée printf("%-10s EAX=" FMTLX " A=" FMTLX " C=" FMTLX "\n",\
11444132431fSAlex Bennée #op, op2, op0, op1);\
11454132431fSAlex Bennée }
11464132431fSAlex Bennée
test_xchg(void)11474132431fSAlex Bennée void test_xchg(void)
11484132431fSAlex Bennée {
11494132431fSAlex Bennée #if defined(__x86_64__)
11504132431fSAlex Bennée TEST_XCHG(xchgq, "", "+q");
11514132431fSAlex Bennée #endif
11524132431fSAlex Bennée TEST_XCHG(xchgl, "k", "+q");
11534132431fSAlex Bennée TEST_XCHG(xchgw, "w", "+q");
11544132431fSAlex Bennée TEST_XCHG(xchgb, "b", "+q");
11554132431fSAlex Bennée
11564132431fSAlex Bennée #if defined(__x86_64__)
115782c48fb7Sfabrice.desclaux@cea.fr TEST_XCHG(xchgq, "", "+m");
11584132431fSAlex Bennée #endif
11594132431fSAlex Bennée TEST_XCHG(xchgl, "k", "+m");
11604132431fSAlex Bennée TEST_XCHG(xchgw, "w", "+m");
11614132431fSAlex Bennée TEST_XCHG(xchgb, "b", "+m");
11624132431fSAlex Bennée
11634132431fSAlex Bennée #if defined(__x86_64__)
11644132431fSAlex Bennée TEST_XCHG(xaddq, "", "+q");
11654132431fSAlex Bennée #endif
11664132431fSAlex Bennée TEST_XCHG(xaddl, "k", "+q");
11674132431fSAlex Bennée TEST_XCHG(xaddw, "w", "+q");
11684132431fSAlex Bennée TEST_XCHG(xaddb, "b", "+q");
11694132431fSAlex Bennée
11704132431fSAlex Bennée {
11714132431fSAlex Bennée int res;
11724132431fSAlex Bennée res = 0x12345678;
11734132431fSAlex Bennée asm("xaddl %1, %0" : "=r" (res) : "0" (res));
11744132431fSAlex Bennée printf("xaddl same res=%08x\n", res);
11754132431fSAlex Bennée }
11764132431fSAlex Bennée
11774132431fSAlex Bennée #if defined(__x86_64__)
11784132431fSAlex Bennée TEST_XCHG(xaddq, "", "+m");
11794132431fSAlex Bennée #endif
11804132431fSAlex Bennée TEST_XCHG(xaddl, "k", "+m");
11814132431fSAlex Bennée TEST_XCHG(xaddw, "w", "+m");
11824132431fSAlex Bennée TEST_XCHG(xaddb, "b", "+m");
11834132431fSAlex Bennée
11844132431fSAlex Bennée #if defined(__x86_64__)
11854132431fSAlex Bennée TEST_CMPXCHG(cmpxchgq, "", "+q", 0xfbca7654);
11864132431fSAlex Bennée #endif
11874132431fSAlex Bennée TEST_CMPXCHG(cmpxchgl, "k", "+q", 0xfbca7654);
11884132431fSAlex Bennée TEST_CMPXCHG(cmpxchgw, "w", "+q", 0xfbca7654);
11894132431fSAlex Bennée TEST_CMPXCHG(cmpxchgb, "b", "+q", 0xfbca7654);
11904132431fSAlex Bennée
11914132431fSAlex Bennée #if defined(__x86_64__)
11924132431fSAlex Bennée TEST_CMPXCHG(cmpxchgq, "", "+q", 0xfffefdfc);
11934132431fSAlex Bennée #endif
11944132431fSAlex Bennée TEST_CMPXCHG(cmpxchgl, "k", "+q", 0xfffefdfc);
11954132431fSAlex Bennée TEST_CMPXCHG(cmpxchgw, "w", "+q", 0xfffefdfc);
11964132431fSAlex Bennée TEST_CMPXCHG(cmpxchgb, "b", "+q", 0xfffefdfc);
11974132431fSAlex Bennée
11984132431fSAlex Bennée #if defined(__x86_64__)
11994132431fSAlex Bennée TEST_CMPXCHG(cmpxchgq, "", "+m", 0xfbca7654);
12004132431fSAlex Bennée #endif
12014132431fSAlex Bennée TEST_CMPXCHG(cmpxchgl, "k", "+m", 0xfbca7654);
12024132431fSAlex Bennée TEST_CMPXCHG(cmpxchgw, "w", "+m", 0xfbca7654);
12034132431fSAlex Bennée TEST_CMPXCHG(cmpxchgb, "b", "+m", 0xfbca7654);
12044132431fSAlex Bennée
12054132431fSAlex Bennée #if defined(__x86_64__)
12064132431fSAlex Bennée TEST_CMPXCHG(cmpxchgq, "", "+m", 0xfffefdfc);
12074132431fSAlex Bennée #endif
12084132431fSAlex Bennée TEST_CMPXCHG(cmpxchgl, "k", "+m", 0xfffefdfc);
12094132431fSAlex Bennée TEST_CMPXCHG(cmpxchgw, "w", "+m", 0xfffefdfc);
12104132431fSAlex Bennée TEST_CMPXCHG(cmpxchgb, "b", "+m", 0xfffefdfc);
12114132431fSAlex Bennée
12124132431fSAlex Bennée {
12134132431fSAlex Bennée uint64_t op0, op1, op2;
12144132431fSAlex Bennée long eax, edx;
12154132431fSAlex Bennée long i, eflags;
12164132431fSAlex Bennée
12174132431fSAlex Bennée for(i = 0; i < 2; i++) {
12184132431fSAlex Bennée op0 = 0x123456789abcdLL;
12194132431fSAlex Bennée eax = i2l(op0 & 0xffffffff);
12204132431fSAlex Bennée edx = i2l(op0 >> 32);
12214132431fSAlex Bennée if (i == 0)
12224132431fSAlex Bennée op1 = 0xfbca765423456LL;
12234132431fSAlex Bennée else
12244132431fSAlex Bennée op1 = op0;
12254132431fSAlex Bennée op2 = 0x6532432432434LL;
12264132431fSAlex Bennée asm("cmpxchg8b %2\n"
12274132431fSAlex Bennée "pushf\n"
12284132431fSAlex Bennée "pop %3\n"
12294132431fSAlex Bennée : "=a" (eax), "=d" (edx), "=m" (op1), "=g" (eflags)
12304132431fSAlex Bennée : "0" (eax), "1" (edx), "m" (op1), "b" ((int)op2), "c" ((int)(op2 >> 32)));
12314132431fSAlex Bennée printf("cmpxchg8b: eax=" FMTLX " edx=" FMTLX " op1=" FMT64X " CC=%02lx\n",
12324132431fSAlex Bennée eax, edx, op1, eflags & CC_Z);
12334132431fSAlex Bennée }
12344132431fSAlex Bennée }
12354132431fSAlex Bennée }
12364132431fSAlex Bennée
12374132431fSAlex Bennée #ifdef TEST_SEGS
12384132431fSAlex Bennée /**********************************************/
12394132431fSAlex Bennée /* segmentation tests */
12404132431fSAlex Bennée
12414132431fSAlex Bennée #include <sys/syscall.h>
12424132431fSAlex Bennée #include <unistd.h>
12434132431fSAlex Bennée #include <asm/ldt.h>
12444132431fSAlex Bennée #include <linux/version.h>
12454132431fSAlex Bennée
modify_ldt(int func,void * ptr,unsigned long bytecount)12464132431fSAlex Bennée static inline int modify_ldt(int func, void * ptr, unsigned long bytecount)
12474132431fSAlex Bennée {
12484132431fSAlex Bennée return syscall(__NR_modify_ldt, func, ptr, bytecount);
12494132431fSAlex Bennée }
12504132431fSAlex Bennée
12514132431fSAlex Bennée #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66)
12524132431fSAlex Bennée #define modify_ldt_ldt_s user_desc
12534132431fSAlex Bennée #endif
12544132431fSAlex Bennée
12554132431fSAlex Bennée #define MK_SEL(n) (((n) << 3) | 7)
12564132431fSAlex Bennée
12574132431fSAlex Bennée uint8_t seg_data1[4096];
12584132431fSAlex Bennée uint8_t seg_data2[4096];
12594132431fSAlex Bennée
12604132431fSAlex Bennée #define TEST_LR(op, size, seg, mask)\
12614132431fSAlex Bennée {\
12624132431fSAlex Bennée int res, res2;\
12634132431fSAlex Bennée uint16_t mseg = seg;\
12644132431fSAlex Bennée res = 0x12345678;\
12654132431fSAlex Bennée asm (op " %" size "2, %" size "0\n" \
12664132431fSAlex Bennée "movl $0, %1\n"\
12674132431fSAlex Bennée "jnz 1f\n"\
12684132431fSAlex Bennée "movl $1, %1\n"\
12694132431fSAlex Bennée "1:\n"\
12704132431fSAlex Bennée : "=r" (res), "=r" (res2) : "m" (mseg), "0" (res));\
12714132431fSAlex Bennée printf(op ": Z=%d %08x\n", res2, res & ~(mask));\
12724132431fSAlex Bennée }
12734132431fSAlex Bennée
12744132431fSAlex Bennée #define TEST_ARPL(op, size, op1, op2)\
12754132431fSAlex Bennée {\
12764132431fSAlex Bennée long a, b, c; \
12774132431fSAlex Bennée a = (op1); \
12784132431fSAlex Bennée b = (op2); \
12794132431fSAlex Bennée asm volatile(op " %" size "3, %" size "0\n"\
12804132431fSAlex Bennée "movl $0,%1\n"\
12814132431fSAlex Bennée "jnz 1f\n"\
12824132431fSAlex Bennée "movl $1,%1\n"\
12834132431fSAlex Bennée "1:\n"\
12844132431fSAlex Bennée : "=r" (a), "=r" (c) : "0" (a), "r" (b)); \
12854132431fSAlex Bennée printf(op size " A=" FMTLX " B=" FMTLX " R=" FMTLX " z=%ld\n",\
12864132431fSAlex Bennée (long)(op1), (long)(op2), a, c);\
12874132431fSAlex Bennée }
12884132431fSAlex Bennée
12894132431fSAlex Bennée /* NOTE: we use Linux modify_ldt syscall */
test_segs(void)12904132431fSAlex Bennée void test_segs(void)
12914132431fSAlex Bennée {
12924132431fSAlex Bennée struct modify_ldt_ldt_s ldt;
12934132431fSAlex Bennée long long ldt_table[3];
12944132431fSAlex Bennée int res, res2;
12954132431fSAlex Bennée char tmp;
12964132431fSAlex Bennée struct {
12974132431fSAlex Bennée uint32_t offset;
12984132431fSAlex Bennée uint16_t seg;
12994132431fSAlex Bennée } __attribute__((__packed__)) segoff;
13004132431fSAlex Bennée
13014132431fSAlex Bennée ldt.entry_number = 1;
13024132431fSAlex Bennée ldt.base_addr = (unsigned long)&seg_data1;
13034132431fSAlex Bennée ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12;
13044132431fSAlex Bennée ldt.seg_32bit = 1;
13054132431fSAlex Bennée ldt.contents = MODIFY_LDT_CONTENTS_DATA;
13064132431fSAlex Bennée ldt.read_exec_only = 0;
13074132431fSAlex Bennée ldt.limit_in_pages = 1;
13084132431fSAlex Bennée ldt.seg_not_present = 0;
13094132431fSAlex Bennée ldt.useable = 1;
13104132431fSAlex Bennée modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
13114132431fSAlex Bennée
13124132431fSAlex Bennée ldt.entry_number = 2;
13134132431fSAlex Bennée ldt.base_addr = (unsigned long)&seg_data2;
13144132431fSAlex Bennée ldt.limit = (sizeof(seg_data2) + 0xfff) >> 12;
13154132431fSAlex Bennée ldt.seg_32bit = 1;
13164132431fSAlex Bennée ldt.contents = MODIFY_LDT_CONTENTS_DATA;
13174132431fSAlex Bennée ldt.read_exec_only = 0;
13184132431fSAlex Bennée ldt.limit_in_pages = 1;
13194132431fSAlex Bennée ldt.seg_not_present = 0;
13204132431fSAlex Bennée ldt.useable = 1;
13214132431fSAlex Bennée modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
13224132431fSAlex Bennée
13234132431fSAlex Bennée modify_ldt(0, &ldt_table, sizeof(ldt_table)); /* read ldt entries */
13244132431fSAlex Bennée #if 0
13254132431fSAlex Bennée {
13264132431fSAlex Bennée int i;
13274132431fSAlex Bennée for(i=0;i<3;i++)
13284132431fSAlex Bennée printf("%d: %016Lx\n", i, ldt_table[i]);
13294132431fSAlex Bennée }
13304132431fSAlex Bennée #endif
13314132431fSAlex Bennée /* do some tests with fs or gs */
13324132431fSAlex Bennée asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1)));
13334132431fSAlex Bennée
13344132431fSAlex Bennée seg_data1[1] = 0xaa;
13354132431fSAlex Bennée seg_data2[1] = 0x55;
13364132431fSAlex Bennée
13374132431fSAlex Bennée asm volatile ("fs movzbl 0x1, %0" : "=r" (res));
13384132431fSAlex Bennée printf("FS[1] = %02x\n", res);
13394132431fSAlex Bennée
13404132431fSAlex Bennée asm volatile ("pushl %%gs\n"
13414132431fSAlex Bennée "movl %1, %%gs\n"
13424132431fSAlex Bennée "gs movzbl 0x1, %0\n"
13434132431fSAlex Bennée "popl %%gs\n"
13444132431fSAlex Bennée : "=r" (res)
13454132431fSAlex Bennée : "r" (MK_SEL(2)));
13464132431fSAlex Bennée printf("GS[1] = %02x\n", res);
13474132431fSAlex Bennée
13484132431fSAlex Bennée /* tests with ds/ss (implicit segment case) */
13494132431fSAlex Bennée tmp = 0xa5;
13504132431fSAlex Bennée asm volatile ("pushl %%ebp\n\t"
13514132431fSAlex Bennée "pushl %%ds\n\t"
13524132431fSAlex Bennée "movl %2, %%ds\n\t"
13534132431fSAlex Bennée "movl %3, %%ebp\n\t"
13544132431fSAlex Bennée "movzbl 0x1, %0\n\t"
13554132431fSAlex Bennée "movzbl (%%ebp), %1\n\t"
13564132431fSAlex Bennée "popl %%ds\n\t"
13574132431fSAlex Bennée "popl %%ebp\n\t"
13584132431fSAlex Bennée : "=r" (res), "=r" (res2)
13594132431fSAlex Bennée : "r" (MK_SEL(1)), "r" (&tmp));
13604132431fSAlex Bennée printf("DS[1] = %02x\n", res);
13614132431fSAlex Bennée printf("SS[tmp] = %02x\n", res2);
13624132431fSAlex Bennée
13634132431fSAlex Bennée segoff.seg = MK_SEL(2);
13644132431fSAlex Bennée segoff.offset = 0xabcdef12;
13654132431fSAlex Bennée asm volatile("lfs %2, %0\n\t"
13664132431fSAlex Bennée "movl %%fs, %1\n\t"
13674132431fSAlex Bennée : "=r" (res), "=g" (res2)
13684132431fSAlex Bennée : "m" (segoff));
13694132431fSAlex Bennée printf("FS:reg = %04x:%08x\n", res2, res);
13704132431fSAlex Bennée
13714132431fSAlex Bennée TEST_LR("larw", "w", MK_SEL(2), 0x0100);
13724132431fSAlex Bennée TEST_LR("larl", "", MK_SEL(2), 0x0100);
13734132431fSAlex Bennée TEST_LR("lslw", "w", MK_SEL(2), 0);
13744132431fSAlex Bennée TEST_LR("lsll", "", MK_SEL(2), 0);
13754132431fSAlex Bennée
13764132431fSAlex Bennée TEST_LR("larw", "w", 0xfff8, 0);
13774132431fSAlex Bennée TEST_LR("larl", "", 0xfff8, 0);
13784132431fSAlex Bennée TEST_LR("lslw", "w", 0xfff8, 0);
13794132431fSAlex Bennée TEST_LR("lsll", "", 0xfff8, 0);
13804132431fSAlex Bennée
13814132431fSAlex Bennée TEST_ARPL("arpl", "w", 0x12345678 | 3, 0x762123c | 1);
13824132431fSAlex Bennée TEST_ARPL("arpl", "w", 0x12345678 | 1, 0x762123c | 3);
13834132431fSAlex Bennée TEST_ARPL("arpl", "w", 0x12345678 | 1, 0x762123c | 1);
13844132431fSAlex Bennée }
13854132431fSAlex Bennée
13864132431fSAlex Bennée /* 16 bit code test */
13874132431fSAlex Bennée extern char code16_start, code16_end;
13884132431fSAlex Bennée extern char code16_func1;
13894132431fSAlex Bennée extern char code16_func2;
13904132431fSAlex Bennée extern char code16_func3;
13914132431fSAlex Bennée
test_code16(void)13924132431fSAlex Bennée void test_code16(void)
13934132431fSAlex Bennée {
13944132431fSAlex Bennée struct modify_ldt_ldt_s ldt;
13954132431fSAlex Bennée int res, res2;
13964132431fSAlex Bennée
13974132431fSAlex Bennée /* build a code segment */
13984132431fSAlex Bennée ldt.entry_number = 1;
13994132431fSAlex Bennée ldt.base_addr = (unsigned long)&code16_start;
14004132431fSAlex Bennée ldt.limit = &code16_end - &code16_start;
14014132431fSAlex Bennée ldt.seg_32bit = 0;
14024132431fSAlex Bennée ldt.contents = MODIFY_LDT_CONTENTS_CODE;
14034132431fSAlex Bennée ldt.read_exec_only = 0;
14044132431fSAlex Bennée ldt.limit_in_pages = 0;
14054132431fSAlex Bennée ldt.seg_not_present = 0;
14064132431fSAlex Bennée ldt.useable = 1;
14074132431fSAlex Bennée modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
14084132431fSAlex Bennée
14094132431fSAlex Bennée /* call the first function */
14104132431fSAlex Bennée asm volatile ("lcall %1, %2"
14114132431fSAlex Bennée : "=a" (res)
14124132431fSAlex Bennée : "i" (MK_SEL(1)), "i" (&code16_func1): "memory", "cc");
14134132431fSAlex Bennée printf("func1() = 0x%08x\n", res);
14144132431fSAlex Bennée asm volatile ("lcall %2, %3"
14154132431fSAlex Bennée : "=a" (res), "=c" (res2)
14164132431fSAlex Bennée : "i" (MK_SEL(1)), "i" (&code16_func2): "memory", "cc");
14174132431fSAlex Bennée printf("func2() = 0x%08x spdec=%d\n", res, res2);
14184132431fSAlex Bennée asm volatile ("lcall %1, %2"
14194132431fSAlex Bennée : "=a" (res)
14204132431fSAlex Bennée : "i" (MK_SEL(1)), "i" (&code16_func3): "memory", "cc");
14214132431fSAlex Bennée printf("func3() = 0x%08x\n", res);
14224132431fSAlex Bennée }
14234132431fSAlex Bennée #endif
14244132431fSAlex Bennée
14254132431fSAlex Bennée #if defined(__x86_64__)
14264132431fSAlex Bennée asm(".globl func_lret\n"
14274132431fSAlex Bennée "func_lret:\n"
14284132431fSAlex Bennée "movl $0x87654641, %eax\n"
14294132431fSAlex Bennée "lretq\n");
14304132431fSAlex Bennée #else
14314132431fSAlex Bennée asm(".globl func_lret\n"
14324132431fSAlex Bennée "func_lret:\n"
14334132431fSAlex Bennée "movl $0x87654321, %eax\n"
14344132431fSAlex Bennée "lret\n"
14354132431fSAlex Bennée
14364132431fSAlex Bennée ".globl func_iret\n"
14374132431fSAlex Bennée "func_iret:\n"
14384132431fSAlex Bennée "movl $0xabcd4321, %eax\n"
14394132431fSAlex Bennée "iret\n");
14404132431fSAlex Bennée #endif
14414132431fSAlex Bennée
14424132431fSAlex Bennée extern char func_lret;
14434132431fSAlex Bennée extern char func_iret;
14444132431fSAlex Bennée
test_misc(void)14454132431fSAlex Bennée void test_misc(void)
14464132431fSAlex Bennée {
14474132431fSAlex Bennée char table[256];
14484132431fSAlex Bennée long res, i;
14494132431fSAlex Bennée
14504132431fSAlex Bennée for(i=0;i<256;i++) table[i] = 256 - i;
14514132431fSAlex Bennée res = 0x12345678;
14524132431fSAlex Bennée asm ("xlat" : "=a" (res) : "b" (table), "0" (res));
14534132431fSAlex Bennée printf("xlat: EAX=" FMTLX "\n", res);
14544132431fSAlex Bennée
14554132431fSAlex Bennée #if defined(__x86_64__)
14564132431fSAlex Bennée #if 0
14574132431fSAlex Bennée {
14584132431fSAlex Bennée /* XXX: see if Intel Core2 and AMD64 behavior really
14594132431fSAlex Bennée differ. Here we implemented the Intel way which is not
14604132431fSAlex Bennée compatible yet with QEMU. */
14614132431fSAlex Bennée static struct QEMU_PACKED {
14624132431fSAlex Bennée uint64_t offset;
14634132431fSAlex Bennée uint16_t seg;
14644132431fSAlex Bennée } desc;
14654132431fSAlex Bennée long cs_sel;
14664132431fSAlex Bennée
14674132431fSAlex Bennée asm volatile ("mov %%cs, %0" : "=r" (cs_sel));
14684132431fSAlex Bennée
14694132431fSAlex Bennée asm volatile ("push %1\n"
14704132431fSAlex Bennée "call func_lret\n"
14714132431fSAlex Bennée : "=a" (res)
14724132431fSAlex Bennée : "r" (cs_sel) : "memory", "cc");
14734132431fSAlex Bennée printf("func_lret=" FMTLX "\n", res);
14744132431fSAlex Bennée
14754132431fSAlex Bennée desc.offset = (long)&func_lret;
14764132431fSAlex Bennée desc.seg = cs_sel;
14774132431fSAlex Bennée
14784132431fSAlex Bennée asm volatile ("xor %%rax, %%rax\n"
14794132431fSAlex Bennée "rex64 lcall *(%%rcx)\n"
14804132431fSAlex Bennée : "=a" (res)
14814132431fSAlex Bennée : "c" (&desc)
14824132431fSAlex Bennée : "memory", "cc");
14834132431fSAlex Bennée printf("func_lret2=" FMTLX "\n", res);
14844132431fSAlex Bennée
14854132431fSAlex Bennée asm volatile ("push %2\n"
14864132431fSAlex Bennée "mov $ 1f, %%rax\n"
14874132431fSAlex Bennée "push %%rax\n"
14884132431fSAlex Bennée "rex64 ljmp *(%%rcx)\n"
14894132431fSAlex Bennée "1:\n"
14904132431fSAlex Bennée : "=a" (res)
14914132431fSAlex Bennée : "c" (&desc), "b" (cs_sel)
14924132431fSAlex Bennée : "memory", "cc");
14934132431fSAlex Bennée printf("func_lret3=" FMTLX "\n", res);
14944132431fSAlex Bennée }
14954132431fSAlex Bennée #endif
14964132431fSAlex Bennée #else
14974132431fSAlex Bennée asm volatile ("push %%cs ; call %1"
14984132431fSAlex Bennée : "=a" (res)
14994132431fSAlex Bennée : "m" (func_lret): "memory", "cc");
15004132431fSAlex Bennée printf("func_lret=" FMTLX "\n", res);
15014132431fSAlex Bennée
15024132431fSAlex Bennée asm volatile ("pushf ; push %%cs ; call %1"
15034132431fSAlex Bennée : "=a" (res)
15044132431fSAlex Bennée : "m" (func_iret): "memory", "cc");
15054132431fSAlex Bennée printf("func_iret=" FMTLX "\n", res);
15064132431fSAlex Bennée #endif
15074132431fSAlex Bennée
15084132431fSAlex Bennée #if defined(__x86_64__)
15094132431fSAlex Bennée /* specific popl test */
15104132431fSAlex Bennée asm volatile ("push $12345432 ; push $0x9abcdef ; pop (%%rsp) ; pop %0"
15114132431fSAlex Bennée : "=g" (res));
15124132431fSAlex Bennée printf("popl esp=" FMTLX "\n", res);
15134132431fSAlex Bennée #else
15144132431fSAlex Bennée /* specific popl test */
15154132431fSAlex Bennée asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popl (%%esp) ; popl %0"
15164132431fSAlex Bennée : "=g" (res));
15174132431fSAlex Bennée printf("popl esp=" FMTLX "\n", res);
15184132431fSAlex Bennée
15194132431fSAlex Bennée /* specific popw test */
15204132431fSAlex Bennée asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popw (%%esp) ; addl $2, %%esp ; popl %0"
15214132431fSAlex Bennée : "=g" (res));
15224132431fSAlex Bennée printf("popw esp=" FMTLX "\n", res);
15234132431fSAlex Bennée #endif
15244132431fSAlex Bennée }
15254132431fSAlex Bennée
15264132431fSAlex Bennée uint8_t str_buffer[4096];
15274132431fSAlex Bennée
15284132431fSAlex Bennée #define TEST_STRING1(OP, size, DF, REP)\
15294132431fSAlex Bennée {\
15304132431fSAlex Bennée long esi, edi, eax, ecx, eflags;\
15314132431fSAlex Bennée \
15324132431fSAlex Bennée esi = (long)(str_buffer + sizeof(str_buffer) / 2);\
15334132431fSAlex Bennée edi = (long)(str_buffer + sizeof(str_buffer) / 2) + 16;\
15344132431fSAlex Bennée eax = i2l(0x12345678);\
15354132431fSAlex Bennée ecx = 17;\
15364132431fSAlex Bennée \
15374132431fSAlex Bennée asm volatile ("push $0\n\t"\
15384132431fSAlex Bennée "popf\n\t"\
15394132431fSAlex Bennée DF "\n\t"\
15404132431fSAlex Bennée REP #OP size "\n\t"\
15414132431fSAlex Bennée "cld\n\t"\
15424132431fSAlex Bennée "pushf\n\t"\
15434132431fSAlex Bennée "pop %4\n\t"\
15444132431fSAlex Bennée : "=S" (esi), "=D" (edi), "=a" (eax), "=c" (ecx), "=g" (eflags)\
15454132431fSAlex Bennée : "0" (esi), "1" (edi), "2" (eax), "3" (ecx));\
15464132431fSAlex Bennée printf("%-10s ESI=" FMTLX " EDI=" FMTLX " EAX=" FMTLX " ECX=" FMTLX " EFL=%04x\n",\
15474132431fSAlex Bennée REP #OP size, esi, edi, eax, ecx,\
15484132431fSAlex Bennée (int)(eflags & (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)));\
15494132431fSAlex Bennée }
15504132431fSAlex Bennée
15514132431fSAlex Bennée #define TEST_STRING(OP, REP)\
15524132431fSAlex Bennée TEST_STRING1(OP, "b", "", REP);\
15534132431fSAlex Bennée TEST_STRING1(OP, "w", "", REP);\
15544132431fSAlex Bennée TEST_STRING1(OP, "l", "", REP);\
15554132431fSAlex Bennée X86_64_ONLY(TEST_STRING1(OP, "q", "", REP));\
15564132431fSAlex Bennée TEST_STRING1(OP, "b", "std", REP);\
15574132431fSAlex Bennée TEST_STRING1(OP, "w", "std", REP);\
15584132431fSAlex Bennée TEST_STRING1(OP, "l", "std", REP);\
15594132431fSAlex Bennée X86_64_ONLY(TEST_STRING1(OP, "q", "std", REP))
15604132431fSAlex Bennée
test_string(void)15614132431fSAlex Bennée void test_string(void)
15624132431fSAlex Bennée {
15634132431fSAlex Bennée int i;
15644132431fSAlex Bennée for(i = 0;i < sizeof(str_buffer); i++)
15654132431fSAlex Bennée str_buffer[i] = i + 0x56;
15664132431fSAlex Bennée TEST_STRING(stos, "");
15674132431fSAlex Bennée TEST_STRING(stos, "rep ");
15684132431fSAlex Bennée TEST_STRING(lods, ""); /* to verify stos */
15694132431fSAlex Bennée TEST_STRING(lods, "rep ");
15704132431fSAlex Bennée TEST_STRING(movs, "");
15714132431fSAlex Bennée TEST_STRING(movs, "rep ");
15724132431fSAlex Bennée TEST_STRING(lods, ""); /* to verify stos */
15734132431fSAlex Bennée
15744132431fSAlex Bennée /* XXX: better tests */
15754132431fSAlex Bennée TEST_STRING(scas, "");
15764132431fSAlex Bennée TEST_STRING(scas, "repz ");
15774132431fSAlex Bennée TEST_STRING(scas, "repnz ");
15784132431fSAlex Bennée TEST_STRING(cmps, "");
15794132431fSAlex Bennée TEST_STRING(cmps, "repz ");
15804132431fSAlex Bennée TEST_STRING(cmps, "repnz ");
15814132431fSAlex Bennée }
15824132431fSAlex Bennée
15834132431fSAlex Bennée #ifdef TEST_VM86
15844132431fSAlex Bennée /* VM86 test */
15854132431fSAlex Bennée
set_bit(uint8_t * a,unsigned int bit)15864132431fSAlex Bennée static inline void set_bit(uint8_t *a, unsigned int bit)
15874132431fSAlex Bennée {
15884132431fSAlex Bennée a[bit / 8] |= (1 << (bit % 8));
15894132431fSAlex Bennée }
15904132431fSAlex Bennée
seg_to_linear(unsigned int seg,unsigned int reg)15914132431fSAlex Bennée static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
15924132431fSAlex Bennée {
15934132431fSAlex Bennée return (uint8_t *)((seg << 4) + (reg & 0xffff));
15944132431fSAlex Bennée }
15954132431fSAlex Bennée
pushw(struct vm86_regs * r,int val)15964132431fSAlex Bennée static inline void pushw(struct vm86_regs *r, int val)
15974132431fSAlex Bennée {
15984132431fSAlex Bennée r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff);
15994132431fSAlex Bennée *(uint16_t *)seg_to_linear(r->ss, r->esp) = val;
16004132431fSAlex Bennée }
16014132431fSAlex Bennée
vm86(int func,struct vm86plus_struct * v86)16024132431fSAlex Bennée static inline int vm86(int func, struct vm86plus_struct *v86)
16034132431fSAlex Bennée {
16044132431fSAlex Bennée return syscall(__NR_vm86, func, v86);
16054132431fSAlex Bennée }
16064132431fSAlex Bennée
16074132431fSAlex Bennée extern char vm86_code_start;
16084132431fSAlex Bennée extern char vm86_code_end;
16094132431fSAlex Bennée
16104132431fSAlex Bennée #define VM86_CODE_CS 0x100
16114132431fSAlex Bennée #define VM86_CODE_IP 0x100
16124132431fSAlex Bennée
test_vm86(void)16134132431fSAlex Bennée void test_vm86(void)
16144132431fSAlex Bennée {
16154132431fSAlex Bennée struct vm86plus_struct ctx;
16164132431fSAlex Bennée struct vm86_regs *r;
16174132431fSAlex Bennée uint8_t *vm86_mem;
16184132431fSAlex Bennée int seg, ret;
16194132431fSAlex Bennée
16204132431fSAlex Bennée vm86_mem = mmap((void *)0x00000000, 0x110000,
16214132431fSAlex Bennée PROT_WRITE | PROT_READ | PROT_EXEC,
16224132431fSAlex Bennée MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
16234132431fSAlex Bennée if (vm86_mem == MAP_FAILED) {
16244132431fSAlex Bennée printf("ERROR: could not map vm86 memory");
16254132431fSAlex Bennée return;
16264132431fSAlex Bennée }
16274132431fSAlex Bennée memset(&ctx, 0, sizeof(ctx));
16284132431fSAlex Bennée
16294132431fSAlex Bennée /* init basic registers */
16304132431fSAlex Bennée r = &ctx.regs;
16314132431fSAlex Bennée r->eip = VM86_CODE_IP;
16324132431fSAlex Bennée r->esp = 0xfffe;
16334132431fSAlex Bennée seg = VM86_CODE_CS;
16344132431fSAlex Bennée r->cs = seg;
16354132431fSAlex Bennée r->ss = seg;
16364132431fSAlex Bennée r->ds = seg;
16374132431fSAlex Bennée r->es = seg;
16384132431fSAlex Bennée r->fs = seg;
16394132431fSAlex Bennée r->gs = seg;
16404132431fSAlex Bennée r->eflags = VIF_MASK;
16414132431fSAlex Bennée
16424132431fSAlex Bennée /* move code to proper address. We use the same layout as a .com
16434132431fSAlex Bennée dos program. */
16444132431fSAlex Bennée memcpy(vm86_mem + (VM86_CODE_CS << 4) + VM86_CODE_IP,
16454132431fSAlex Bennée &vm86_code_start, &vm86_code_end - &vm86_code_start);
16464132431fSAlex Bennée
16474132431fSAlex Bennée /* mark int 0x21 as being emulated */
16484132431fSAlex Bennée set_bit((uint8_t *)&ctx.int_revectored, 0x21);
16494132431fSAlex Bennée
16504132431fSAlex Bennée for(;;) {
16514132431fSAlex Bennée ret = vm86(VM86_ENTER, &ctx);
16524132431fSAlex Bennée switch(VM86_TYPE(ret)) {
16534132431fSAlex Bennée case VM86_INTx:
16544132431fSAlex Bennée {
16554132431fSAlex Bennée int int_num, ah, v;
16564132431fSAlex Bennée
16574132431fSAlex Bennée int_num = VM86_ARG(ret);
16584132431fSAlex Bennée if (int_num != 0x21)
16594132431fSAlex Bennée goto unknown_int;
16604132431fSAlex Bennée ah = (r->eax >> 8) & 0xff;
16614132431fSAlex Bennée switch(ah) {
16624132431fSAlex Bennée case 0x00: /* exit */
16634132431fSAlex Bennée goto the_end;
16644132431fSAlex Bennée case 0x02: /* write char */
16654132431fSAlex Bennée {
16664132431fSAlex Bennée uint8_t c = r->edx;
16674132431fSAlex Bennée putchar(c);
16684132431fSAlex Bennée }
16694132431fSAlex Bennée break;
16704132431fSAlex Bennée case 0x09: /* write string */
16714132431fSAlex Bennée {
16724132431fSAlex Bennée uint8_t c, *ptr;
16734132431fSAlex Bennée ptr = seg_to_linear(r->ds, r->edx);
16744132431fSAlex Bennée for(;;) {
16754132431fSAlex Bennée c = *ptr++;
16764132431fSAlex Bennée if (c == '$')
16774132431fSAlex Bennée break;
16784132431fSAlex Bennée putchar(c);
16794132431fSAlex Bennée }
16804132431fSAlex Bennée r->eax = (r->eax & ~0xff) | '$';
16814132431fSAlex Bennée }
16824132431fSAlex Bennée break;
16834132431fSAlex Bennée case 0xff: /* extension: write eflags number in edx */
16844132431fSAlex Bennée v = (int)r->edx;
16854132431fSAlex Bennée #ifndef LINUX_VM86_IOPL_FIX
16864132431fSAlex Bennée v &= ~0x3000;
16874132431fSAlex Bennée #endif
16884132431fSAlex Bennée printf("%08x\n", v);
16894132431fSAlex Bennée break;
16904132431fSAlex Bennée default:
16914132431fSAlex Bennée unknown_int:
16924132431fSAlex Bennée printf("unsupported int 0x%02x\n", int_num);
16934132431fSAlex Bennée goto the_end;
16944132431fSAlex Bennée }
16954132431fSAlex Bennée }
16964132431fSAlex Bennée break;
16974132431fSAlex Bennée case VM86_SIGNAL:
16984132431fSAlex Bennée /* a signal came, we just ignore that */
16994132431fSAlex Bennée break;
17004132431fSAlex Bennée case VM86_STI:
17014132431fSAlex Bennée break;
17024132431fSAlex Bennée default:
17034132431fSAlex Bennée printf("ERROR: unhandled vm86 return code (0x%x)\n", ret);
17044132431fSAlex Bennée goto the_end;
17054132431fSAlex Bennée }
17064132431fSAlex Bennée }
17074132431fSAlex Bennée the_end:
17084132431fSAlex Bennée printf("VM86 end\n");
17094132431fSAlex Bennée munmap(vm86_mem, 0x110000);
17104132431fSAlex Bennée }
17114132431fSAlex Bennée #endif
17124132431fSAlex Bennée
17134132431fSAlex Bennée /* exception tests */
17144132431fSAlex Bennée #if defined(__i386__) && !defined(REG_EAX)
17154132431fSAlex Bennée #define REG_EAX EAX
17164132431fSAlex Bennée #define REG_EBX EBX
17174132431fSAlex Bennée #define REG_ECX ECX
17184132431fSAlex Bennée #define REG_EDX EDX
17194132431fSAlex Bennée #define REG_ESI ESI
17204132431fSAlex Bennée #define REG_EDI EDI
17214132431fSAlex Bennée #define REG_EBP EBP
17224132431fSAlex Bennée #define REG_ESP ESP
17234132431fSAlex Bennée #define REG_EIP EIP
17244132431fSAlex Bennée #define REG_EFL EFL
17254132431fSAlex Bennée #define REG_TRAPNO TRAPNO
17264132431fSAlex Bennée #define REG_ERR ERR
17274132431fSAlex Bennée #endif
17284132431fSAlex Bennée
17294132431fSAlex Bennée #if defined(__x86_64__)
17304132431fSAlex Bennée #define REG_EIP REG_RIP
17314132431fSAlex Bennée #endif
17324132431fSAlex Bennée
17334132431fSAlex Bennée jmp_buf jmp_env;
17344132431fSAlex Bennée int v1;
17354132431fSAlex Bennée int tab[2];
17364132431fSAlex Bennée
sig_handler(int sig,siginfo_t * info,void * puc)17374132431fSAlex Bennée void sig_handler(int sig, siginfo_t *info, void *puc)
17384132431fSAlex Bennée {
17394132431fSAlex Bennée ucontext_t *uc = puc;
17404132431fSAlex Bennée
17414132431fSAlex Bennée printf("si_signo=%d si_errno=%d si_code=%d",
17424132431fSAlex Bennée info->si_signo, info->si_errno, info->si_code);
17434132431fSAlex Bennée printf(" si_addr=0x%08lx",
17444132431fSAlex Bennée (unsigned long)info->si_addr);
17454132431fSAlex Bennée printf("\n");
17464132431fSAlex Bennée
17474132431fSAlex Bennée printf("trapno=" FMTLX " err=" FMTLX,
17484132431fSAlex Bennée (long)uc->uc_mcontext.gregs[REG_TRAPNO],
17494132431fSAlex Bennée (long)uc->uc_mcontext.gregs[REG_ERR]);
17504132431fSAlex Bennée printf(" EIP=" FMTLX, (long)uc->uc_mcontext.gregs[REG_EIP]);
17514132431fSAlex Bennée printf("\n");
17524132431fSAlex Bennée longjmp(jmp_env, 1);
17534132431fSAlex Bennée }
17544132431fSAlex Bennée
test_exceptions(void)17554132431fSAlex Bennée void test_exceptions(void)
17564132431fSAlex Bennée {
17574132431fSAlex Bennée struct sigaction act;
17584132431fSAlex Bennée volatile int val;
17594132431fSAlex Bennée
17604132431fSAlex Bennée act.sa_sigaction = sig_handler;
17614132431fSAlex Bennée sigemptyset(&act.sa_mask);
17624132431fSAlex Bennée act.sa_flags = SA_SIGINFO | SA_NODEFER;
17634132431fSAlex Bennée sigaction(SIGFPE, &act, NULL);
17644132431fSAlex Bennée sigaction(SIGILL, &act, NULL);
17654132431fSAlex Bennée sigaction(SIGSEGV, &act, NULL);
17664132431fSAlex Bennée sigaction(SIGBUS, &act, NULL);
17674132431fSAlex Bennée sigaction(SIGTRAP, &act, NULL);
17684132431fSAlex Bennée
17694132431fSAlex Bennée /* test division by zero reporting */
17704132431fSAlex Bennée printf("DIVZ exception:\n");
17714132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
17724132431fSAlex Bennée /* now divide by zero */
17734132431fSAlex Bennée v1 = 0;
17744132431fSAlex Bennée v1 = 2 / v1;
17754132431fSAlex Bennée }
17764132431fSAlex Bennée
17774132431fSAlex Bennée #if !defined(__x86_64__)
17784132431fSAlex Bennée printf("BOUND exception:\n");
17794132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
17804132431fSAlex Bennée /* bound exception */
17814132431fSAlex Bennée tab[0] = 1;
17824132431fSAlex Bennée tab[1] = 10;
17834132431fSAlex Bennée asm volatile ("bound %0, %1" : : "r" (11), "m" (tab[0]));
17844132431fSAlex Bennée }
17854132431fSAlex Bennée #endif
17864132431fSAlex Bennée
17874132431fSAlex Bennée #ifdef TEST_SEGS
17884132431fSAlex Bennée printf("segment exceptions:\n");
17894132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
17904132431fSAlex Bennée /* load an invalid segment */
17914132431fSAlex Bennée asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 1));
17924132431fSAlex Bennée }
17934132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
17944132431fSAlex Bennée /* null data segment is valid */
17954132431fSAlex Bennée asm volatile ("movl %0, %%fs" : : "r" (3));
17964132431fSAlex Bennée /* null stack segment */
17974132431fSAlex Bennée asm volatile ("movl %0, %%ss" : : "r" (3));
17984132431fSAlex Bennée }
17994132431fSAlex Bennée
18004132431fSAlex Bennée {
18014132431fSAlex Bennée struct modify_ldt_ldt_s ldt;
18024132431fSAlex Bennée ldt.entry_number = 1;
18034132431fSAlex Bennée ldt.base_addr = (unsigned long)&seg_data1;
18044132431fSAlex Bennée ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12;
18054132431fSAlex Bennée ldt.seg_32bit = 1;
18064132431fSAlex Bennée ldt.contents = MODIFY_LDT_CONTENTS_DATA;
18074132431fSAlex Bennée ldt.read_exec_only = 0;
18084132431fSAlex Bennée ldt.limit_in_pages = 1;
18094132431fSAlex Bennée ldt.seg_not_present = 1;
18104132431fSAlex Bennée ldt.useable = 1;
18114132431fSAlex Bennée modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
18124132431fSAlex Bennée
18134132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
18144132431fSAlex Bennée /* segment not present */
18154132431fSAlex Bennée asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1)));
18164132431fSAlex Bennée }
18174132431fSAlex Bennée }
18184132431fSAlex Bennée #endif
18194132431fSAlex Bennée
18204132431fSAlex Bennée /* test SEGV reporting */
18214132431fSAlex Bennée printf("PF exception:\n");
18224132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
18234132431fSAlex Bennée val = 1;
18244132431fSAlex Bennée /* we add a nop to test a weird PC retrieval case */
18254132431fSAlex Bennée asm volatile ("nop");
18264132431fSAlex Bennée /* now store in an invalid address */
18274132431fSAlex Bennée *(char *)0x1234 = 1;
18284132431fSAlex Bennée }
18294132431fSAlex Bennée
18304132431fSAlex Bennée /* test SEGV reporting */
18314132431fSAlex Bennée printf("PF exception:\n");
18324132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
18334132431fSAlex Bennée val = 1;
18344132431fSAlex Bennée /* read from an invalid address */
18354132431fSAlex Bennée v1 = *(char *)0x1234;
18364132431fSAlex Bennée }
18374132431fSAlex Bennée
18384132431fSAlex Bennée /* test illegal instruction reporting */
18394132431fSAlex Bennée printf("UD2 exception:\n");
18404132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
18414132431fSAlex Bennée /* now execute an invalid instruction */
18424132431fSAlex Bennée asm volatile("ud2");
18434132431fSAlex Bennée }
18444132431fSAlex Bennée printf("lock nop exception:\n");
18454132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
18464132431fSAlex Bennée /* now execute an invalid instruction */
18474132431fSAlex Bennée asm volatile(".byte 0xf0, 0x90");
18484132431fSAlex Bennée }
18494132431fSAlex Bennée
18504132431fSAlex Bennée printf("INT exception:\n");
18514132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
18524132431fSAlex Bennée asm volatile ("int $0xfd");
18534132431fSAlex Bennée }
18544132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
18554132431fSAlex Bennée asm volatile ("int $0x01");
18564132431fSAlex Bennée }
18574132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
18584132431fSAlex Bennée asm volatile (".byte 0xcd, 0x03");
18594132431fSAlex Bennée }
18604132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
18614132431fSAlex Bennée asm volatile ("int $0x04");
18624132431fSAlex Bennée }
18634132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
18644132431fSAlex Bennée asm volatile ("int $0x05");
18654132431fSAlex Bennée }
18664132431fSAlex Bennée
18674132431fSAlex Bennée printf("INT3 exception:\n");
18684132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
18694132431fSAlex Bennée asm volatile ("int3");
18704132431fSAlex Bennée }
18714132431fSAlex Bennée
18724132431fSAlex Bennée printf("CLI exception:\n");
18734132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
18744132431fSAlex Bennée asm volatile ("cli");
18754132431fSAlex Bennée }
18764132431fSAlex Bennée
18774132431fSAlex Bennée printf("STI exception:\n");
18784132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
18794132431fSAlex Bennée asm volatile ("cli");
18804132431fSAlex Bennée }
18814132431fSAlex Bennée
18824132431fSAlex Bennée #if !defined(__x86_64__)
18834132431fSAlex Bennée printf("INTO exception:\n");
18844132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
18854132431fSAlex Bennée /* overflow exception */
18864132431fSAlex Bennée asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff));
18874132431fSAlex Bennée }
18884132431fSAlex Bennée #endif
18894132431fSAlex Bennée
18904132431fSAlex Bennée printf("OUTB exception:\n");
18914132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
18924132431fSAlex Bennée asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0));
18934132431fSAlex Bennée }
18944132431fSAlex Bennée
18954132431fSAlex Bennée printf("INB exception:\n");
18964132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
18974132431fSAlex Bennée asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321));
18984132431fSAlex Bennée }
18994132431fSAlex Bennée
19004132431fSAlex Bennée printf("REP OUTSB exception:\n");
19014132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
19024132431fSAlex Bennée asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1));
19034132431fSAlex Bennée }
19044132431fSAlex Bennée
19054132431fSAlex Bennée printf("REP INSB exception:\n");
19064132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
19074132431fSAlex Bennée asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1));
19084132431fSAlex Bennée }
19094132431fSAlex Bennée
19104132431fSAlex Bennée printf("HLT exception:\n");
19114132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
19124132431fSAlex Bennée asm volatile ("hlt");
19134132431fSAlex Bennée }
19144132431fSAlex Bennée
19154132431fSAlex Bennée printf("single step exception:\n");
19164132431fSAlex Bennée val = 0;
19174132431fSAlex Bennée if (setjmp(jmp_env) == 0) {
19184132431fSAlex Bennée asm volatile ("pushf\n"
19194132431fSAlex Bennée "orl $0x00100, (%%esp)\n"
19204132431fSAlex Bennée "popf\n"
19214132431fSAlex Bennée "movl $0xabcd, %0\n"
19224132431fSAlex Bennée "movl $0x0, %0\n" : "=m" (val) : : "cc", "memory");
19234132431fSAlex Bennée }
19244132431fSAlex Bennée printf("val=0x%x\n", val);
19254132431fSAlex Bennée }
19264132431fSAlex Bennée
19274132431fSAlex Bennée #if !defined(__x86_64__)
19284132431fSAlex Bennée /* specific precise single step test */
sig_trap_handler(int sig,siginfo_t * info,void * puc)19294132431fSAlex Bennée void sig_trap_handler(int sig, siginfo_t *info, void *puc)
19304132431fSAlex Bennée {
19314132431fSAlex Bennée ucontext_t *uc = puc;
19324132431fSAlex Bennée printf("EIP=" FMTLX "\n", (long)uc->uc_mcontext.gregs[REG_EIP]);
19334132431fSAlex Bennée }
19344132431fSAlex Bennée
19354132431fSAlex Bennée const uint8_t sstep_buf1[4] = { 1, 2, 3, 4};
19364132431fSAlex Bennée uint8_t sstep_buf2[4];
19374132431fSAlex Bennée
test_single_step(void)19384132431fSAlex Bennée void test_single_step(void)
19394132431fSAlex Bennée {
19404132431fSAlex Bennée struct sigaction act;
19414132431fSAlex Bennée volatile int val;
19424132431fSAlex Bennée int i;
19434132431fSAlex Bennée
19444132431fSAlex Bennée val = 0;
19454132431fSAlex Bennée act.sa_sigaction = sig_trap_handler;
19464132431fSAlex Bennée sigemptyset(&act.sa_mask);
19474132431fSAlex Bennée act.sa_flags = SA_SIGINFO;
19484132431fSAlex Bennée sigaction(SIGTRAP, &act, NULL);
19494132431fSAlex Bennée asm volatile ("pushf\n"
19504132431fSAlex Bennée "orl $0x00100, (%%esp)\n"
19514132431fSAlex Bennée "popf\n"
19524132431fSAlex Bennée "movl $0xabcd, %0\n"
19534132431fSAlex Bennée
19544132431fSAlex Bennée /* jmp test */
19554132431fSAlex Bennée "movl $3, %%ecx\n"
19564132431fSAlex Bennée "1:\n"
19574132431fSAlex Bennée "addl $1, %0\n"
19584132431fSAlex Bennée "decl %%ecx\n"
19594132431fSAlex Bennée "jnz 1b\n"
19604132431fSAlex Bennée
19614132431fSAlex Bennée /* movsb: the single step should stop at each movsb iteration */
19624132431fSAlex Bennée "movl $sstep_buf1, %%esi\n"
19634132431fSAlex Bennée "movl $sstep_buf2, %%edi\n"
19644132431fSAlex Bennée "movl $0, %%ecx\n"
19654132431fSAlex Bennée "rep movsb\n"
19664132431fSAlex Bennée "movl $3, %%ecx\n"
19674132431fSAlex Bennée "rep movsb\n"
19684132431fSAlex Bennée "movl $1, %%ecx\n"
19694132431fSAlex Bennée "rep movsb\n"
19704132431fSAlex Bennée
19714132431fSAlex Bennée /* cmpsb: the single step should stop at each cmpsb iteration */
19724132431fSAlex Bennée "movl $sstep_buf1, %%esi\n"
19734132431fSAlex Bennée "movl $sstep_buf2, %%edi\n"
19744132431fSAlex Bennée "movl $0, %%ecx\n"
19754132431fSAlex Bennée "rep cmpsb\n"
19764132431fSAlex Bennée "movl $4, %%ecx\n"
19774132431fSAlex Bennée "rep cmpsb\n"
19784132431fSAlex Bennée
19794132431fSAlex Bennée /* getpid() syscall: single step should skip one
19804132431fSAlex Bennée instruction */
19814132431fSAlex Bennée "movl $20, %%eax\n"
19824132431fSAlex Bennée "int $0x80\n"
19834132431fSAlex Bennée "movl $0, %%eax\n"
19844132431fSAlex Bennée
19854132431fSAlex Bennée /* when modifying SS, trace is not done on the next
19864132431fSAlex Bennée instruction */
19874132431fSAlex Bennée "movl %%ss, %%ecx\n"
19884132431fSAlex Bennée "movl %%ecx, %%ss\n"
19894132431fSAlex Bennée "addl $1, %0\n"
19904132431fSAlex Bennée "movl $1, %%eax\n"
19914132431fSAlex Bennée "movl %%ecx, %%ss\n"
19924132431fSAlex Bennée "jmp 1f\n"
19934132431fSAlex Bennée "addl $1, %0\n"
19944132431fSAlex Bennée "1:\n"
19954132431fSAlex Bennée "movl $1, %%eax\n"
19964132431fSAlex Bennée "pushl %%ecx\n"
19974132431fSAlex Bennée "popl %%ss\n"
19984132431fSAlex Bennée "addl $1, %0\n"
19994132431fSAlex Bennée "movl $1, %%eax\n"
20004132431fSAlex Bennée
20014132431fSAlex Bennée "pushf\n"
20024132431fSAlex Bennée "andl $~0x00100, (%%esp)\n"
20034132431fSAlex Bennée "popf\n"
20044132431fSAlex Bennée : "=m" (val)
20054132431fSAlex Bennée :
20064132431fSAlex Bennée : "cc", "memory", "eax", "ecx", "esi", "edi");
20074132431fSAlex Bennée printf("val=%d\n", val);
20084132431fSAlex Bennée for(i = 0; i < 4; i++)
20094132431fSAlex Bennée printf("sstep_buf2[%d] = %d\n", i, sstep_buf2[i]);
20104132431fSAlex Bennée }
20114132431fSAlex Bennée
20124132431fSAlex Bennée /* self modifying code test */
20134132431fSAlex Bennée uint8_t code[] = {
20144132431fSAlex Bennée 0xb8, 0x1, 0x00, 0x00, 0x00, /* movl $1, %eax */
20154132431fSAlex Bennée 0xc3, /* ret */
20164132431fSAlex Bennée };
20174132431fSAlex Bennée
2018d64655c2SRichard Henderson asm(".section \".data_x\",\"awx\"\n"
20194132431fSAlex Bennée "smc_code2:\n"
20204132431fSAlex Bennée "movl 4(%esp), %eax\n"
20214132431fSAlex Bennée "movl %eax, smc_patch_addr2 + 1\n"
20224132431fSAlex Bennée "nop\n"
20234132431fSAlex Bennée "nop\n"
20244132431fSAlex Bennée "nop\n"
20254132431fSAlex Bennée "nop\n"
20264132431fSAlex Bennée "nop\n"
20274132431fSAlex Bennée "nop\n"
20284132431fSAlex Bennée "nop\n"
20294132431fSAlex Bennée "nop\n"
20304132431fSAlex Bennée "smc_patch_addr2:\n"
20314132431fSAlex Bennée "movl $1, %eax\n"
20324132431fSAlex Bennée "ret\n"
20334132431fSAlex Bennée ".previous\n"
20344132431fSAlex Bennée );
20354132431fSAlex Bennée
20364132431fSAlex Bennée typedef int FuncType(void);
20374132431fSAlex Bennée extern int smc_code2(int);
test_self_modifying_code(void)20384132431fSAlex Bennée void test_self_modifying_code(void)
20394132431fSAlex Bennée {
20404132431fSAlex Bennée int i;
20414132431fSAlex Bennée printf("self modifying code:\n");
20424132431fSAlex Bennée printf("func1 = 0x%x\n", ((FuncType *)code)());
20434132431fSAlex Bennée for(i = 2; i <= 4; i++) {
20444132431fSAlex Bennée code[1] = i;
20454132431fSAlex Bennée printf("func%d = 0x%x\n", i, ((FuncType *)code)());
20464132431fSAlex Bennée }
20474132431fSAlex Bennée
20484132431fSAlex Bennée /* more difficult test : the modified code is just after the
20494132431fSAlex Bennée modifying instruction. It is forbidden in Intel specs, but it
20504132431fSAlex Bennée is used by old DOS programs */
20514132431fSAlex Bennée for(i = 2; i <= 4; i++) {
20524132431fSAlex Bennée printf("smc_code2(%d) = %d\n", i, smc_code2(i));
20534132431fSAlex Bennée }
20544132431fSAlex Bennée }
20554132431fSAlex Bennée #endif
20564132431fSAlex Bennée
20574132431fSAlex Bennée long enter_stack[4096];
20584132431fSAlex Bennée
20594132431fSAlex Bennée #if defined(__x86_64__)
20604132431fSAlex Bennée #define RSP "%%rsp"
20614132431fSAlex Bennée #define RBP "%%rbp"
20624132431fSAlex Bennée #else
20634132431fSAlex Bennée #define RSP "%%esp"
20644132431fSAlex Bennée #define RBP "%%ebp"
20654132431fSAlex Bennée #endif
20664132431fSAlex Bennée
20674132431fSAlex Bennée #if !defined(__x86_64__)
20684132431fSAlex Bennée /* causes an infinite loop, disable it for now. */
20694132431fSAlex Bennée #define TEST_ENTER(size, stack_type, level)
20704132431fSAlex Bennée #else
20714132431fSAlex Bennée #define TEST_ENTER(size, stack_type, level)\
20724132431fSAlex Bennée {\
20734132431fSAlex Bennée long esp_save, esp_val, ebp_val, ebp_save, i;\
20744132431fSAlex Bennée stack_type *ptr, *stack_end, *stack_ptr;\
20754132431fSAlex Bennée memset(enter_stack, 0, sizeof(enter_stack));\
20764132431fSAlex Bennée stack_end = stack_ptr = (stack_type *)(enter_stack + 4096);\
20774132431fSAlex Bennée ebp_val = (long)stack_ptr;\
20784132431fSAlex Bennée for(i=1;i<=32;i++)\
20794132431fSAlex Bennée *--stack_ptr = i;\
20804132431fSAlex Bennée esp_val = (long)stack_ptr;\
20814132431fSAlex Bennée asm("mov " RSP ", %[esp_save]\n"\
20824132431fSAlex Bennée "mov " RBP ", %[ebp_save]\n"\
20834132431fSAlex Bennée "mov %[esp_val], " RSP "\n"\
20844132431fSAlex Bennée "mov %[ebp_val], " RBP "\n"\
20854132431fSAlex Bennée "enter" size " $8, $" #level "\n"\
20864132431fSAlex Bennée "mov " RSP ", %[esp_val]\n"\
20874132431fSAlex Bennée "mov " RBP ", %[ebp_val]\n"\
20884132431fSAlex Bennée "mov %[esp_save], " RSP "\n"\
20894132431fSAlex Bennée "mov %[ebp_save], " RBP "\n"\
20904132431fSAlex Bennée : [esp_save] "=r" (esp_save),\
20914132431fSAlex Bennée [ebp_save] "=r" (ebp_save),\
20924132431fSAlex Bennée [esp_val] "=r" (esp_val),\
20934132431fSAlex Bennée [ebp_val] "=r" (ebp_val)\
20944132431fSAlex Bennée : "[esp_val]" (esp_val),\
20954132431fSAlex Bennée "[ebp_val]" (ebp_val));\
20964132431fSAlex Bennée printf("level=%d:\n", level);\
20974132431fSAlex Bennée printf("esp_val=" FMTLX "\n", esp_val - (long)stack_end);\
20984132431fSAlex Bennée printf("ebp_val=" FMTLX "\n", ebp_val - (long)stack_end);\
20994132431fSAlex Bennée for(ptr = (stack_type *)esp_val; ptr < stack_end; ptr++)\
21004132431fSAlex Bennée printf(FMTLX "\n", (long)ptr[0]);\
21014132431fSAlex Bennée }
21024132431fSAlex Bennée #endif
21034132431fSAlex Bennée
test_enter(void)21044132431fSAlex Bennée static void test_enter(void)
21054132431fSAlex Bennée {
21064132431fSAlex Bennée #if defined(__x86_64__)
21074132431fSAlex Bennée TEST_ENTER("q", uint64_t, 0);
21084132431fSAlex Bennée TEST_ENTER("q", uint64_t, 1);
21094132431fSAlex Bennée TEST_ENTER("q", uint64_t, 2);
21104132431fSAlex Bennée TEST_ENTER("q", uint64_t, 31);
21114132431fSAlex Bennée #else
21124132431fSAlex Bennée TEST_ENTER("l", uint32_t, 0);
21134132431fSAlex Bennée TEST_ENTER("l", uint32_t, 1);
21144132431fSAlex Bennée TEST_ENTER("l", uint32_t, 2);
21154132431fSAlex Bennée TEST_ENTER("l", uint32_t, 31);
21164132431fSAlex Bennée #endif
21174132431fSAlex Bennée
21184132431fSAlex Bennée TEST_ENTER("w", uint16_t, 0);
21194132431fSAlex Bennée TEST_ENTER("w", uint16_t, 1);
21204132431fSAlex Bennée TEST_ENTER("w", uint16_t, 2);
21214132431fSAlex Bennée TEST_ENTER("w", uint16_t, 31);
21224132431fSAlex Bennée }
21234132431fSAlex Bennée
21244132431fSAlex Bennée #define TEST_CONV_RAX(op)\
21254132431fSAlex Bennée {\
21264132431fSAlex Bennée unsigned long a, r;\
21274132431fSAlex Bennée a = i2l(0x8234a6f8);\
21284132431fSAlex Bennée r = a;\
21294132431fSAlex Bennée asm volatile(#op : "=a" (r) : "0" (r));\
21304132431fSAlex Bennée printf("%-10s A=" FMTLX " R=" FMTLX "\n", #op, a, r);\
21314132431fSAlex Bennée }
21324132431fSAlex Bennée
21334132431fSAlex Bennée #define TEST_CONV_RAX_RDX(op)\
21344132431fSAlex Bennée {\
21354132431fSAlex Bennée unsigned long a, d, r, rh; \
21364132431fSAlex Bennée a = i2l(0x8234a6f8);\
21374132431fSAlex Bennée d = i2l(0x8345a1f2);\
21384132431fSAlex Bennée r = a;\
21394132431fSAlex Bennée rh = d;\
21404132431fSAlex Bennée asm volatile(#op : "=a" (r), "=d" (rh) : "0" (r), "1" (rh)); \
21414132431fSAlex Bennée printf("%-10s A=" FMTLX " R=" FMTLX ":" FMTLX "\n", #op, a, r, rh); \
21424132431fSAlex Bennée }
21434132431fSAlex Bennée
test_conv(void)21444132431fSAlex Bennée void test_conv(void)
21454132431fSAlex Bennée {
21464132431fSAlex Bennée TEST_CONV_RAX(cbw);
21474132431fSAlex Bennée TEST_CONV_RAX(cwde);
21484132431fSAlex Bennée #if defined(__x86_64__)
21494132431fSAlex Bennée TEST_CONV_RAX(cdqe);
21504132431fSAlex Bennée #endif
21514132431fSAlex Bennée
21524132431fSAlex Bennée TEST_CONV_RAX_RDX(cwd);
21534132431fSAlex Bennée TEST_CONV_RAX_RDX(cdq);
21544132431fSAlex Bennée #if defined(__x86_64__)
21554132431fSAlex Bennée TEST_CONV_RAX_RDX(cqo);
21564132431fSAlex Bennée #endif
21574132431fSAlex Bennée
21584132431fSAlex Bennée {
21594132431fSAlex Bennée unsigned long a, r;
21604132431fSAlex Bennée a = i2l(0x12345678);
21614132431fSAlex Bennée asm volatile("bswapl %k0" : "=r" (r) : "0" (a));
21624132431fSAlex Bennée printf("%-10s: A=" FMTLX " R=" FMTLX "\n", "bswapl", a, r);
21634132431fSAlex Bennée }
21644132431fSAlex Bennée #if defined(__x86_64__)
21654132431fSAlex Bennée {
21664132431fSAlex Bennée unsigned long a, r;
21674132431fSAlex Bennée a = i2l(0x12345678);
21684132431fSAlex Bennée asm volatile("bswapq %0" : "=r" (r) : "0" (a));
21694132431fSAlex Bennée printf("%-10s: A=" FMTLX " R=" FMTLX "\n", "bswapq", a, r);
21704132431fSAlex Bennée }
21714132431fSAlex Bennée #endif
21724132431fSAlex Bennée }
21734132431fSAlex Bennée
21744132431fSAlex Bennée extern void *__start_initcall;
21754132431fSAlex Bennée extern void *__stop_initcall;
21764132431fSAlex Bennée
21774132431fSAlex Bennée
main(int argc,char ** argv)21784132431fSAlex Bennée int main(int argc, char **argv)
21794132431fSAlex Bennée {
21804132431fSAlex Bennée void **ptr;
21814132431fSAlex Bennée void (*func)(void);
21824132431fSAlex Bennée
21834132431fSAlex Bennée ptr = &__start_initcall;
21844132431fSAlex Bennée while (ptr != &__stop_initcall) {
21854132431fSAlex Bennée func = *ptr++;
21864132431fSAlex Bennée func();
21874132431fSAlex Bennée }
21884132431fSAlex Bennée test_bsx();
2189*ff5b5739SPaolo Bonzini test_xcnt();
21904132431fSAlex Bennée test_mul();
21914132431fSAlex Bennée test_jcc();
21924132431fSAlex Bennée test_loop();
21934132431fSAlex Bennée test_floats();
21944132431fSAlex Bennée #if !defined(__x86_64__)
21954132431fSAlex Bennée test_bcd();
21964132431fSAlex Bennée #endif
21974132431fSAlex Bennée test_xchg();
21984132431fSAlex Bennée test_string();
21994132431fSAlex Bennée test_misc();
22004132431fSAlex Bennée test_lea();
22014132431fSAlex Bennée #ifdef TEST_SEGS
22024132431fSAlex Bennée test_segs();
22034132431fSAlex Bennée test_code16();
22044132431fSAlex Bennée #endif
22054132431fSAlex Bennée #ifdef TEST_VM86
22064132431fSAlex Bennée test_vm86();
22074132431fSAlex Bennée #endif
22084132431fSAlex Bennée #if !defined(__x86_64__)
22094132431fSAlex Bennée test_exceptions();
22104132431fSAlex Bennée test_self_modifying_code();
22114132431fSAlex Bennée test_single_step();
22124132431fSAlex Bennée #endif
22134132431fSAlex Bennée test_enter();
22144132431fSAlex Bennée test_conv();
22154132431fSAlex Bennée return 0;
22164132431fSAlex Bennée }
2217