Commit 3a27ad0b57f5ac1dc5aaf1805d8caa4be2deb2dd

Authored by bellard
1 parent 2b413144

added vm86, exceptions and self modifying regression tests


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@174 c046a42c-6fe2-441c-8c8c-71466251a162
tests/test-i386-vm86.S 0 → 100644
  1 + .code16
  2 + .globl vm86_code_start
  3 + .globl vm86_code_end
  4 +
  5 +#define GET_OFFSET(x) ((x) - vm86_code_start + 0x100)
  6 +
  7 +vm86_code_start:
  8 + movw $GET_OFFSET(hello_world), %dx
  9 + movb $0x09, %ah
  10 + int $0x21
  11 +
  12 + /* prepare int 0x90 vector */
  13 + xorw %ax, %ax
  14 + movw %ax, %es
  15 + es movw $GET_OFFSET(int90_test), 0x90 * 4
  16 + es movw %cs, 0x90 * 4 + 2
  17 +
  18 + /* launch int 0x90 */
  19 +
  20 + int $0x90
  21 +
  22 + /* test IF support */
  23 + movw $GET_OFFSET(IF_msg), %dx
  24 + movb $0x09, %ah
  25 + int $0x21
  26 +
  27 + pushf
  28 + popw %dx
  29 + movb $0xff, %ah
  30 + int $0x21
  31 +
  32 + cli
  33 + pushf
  34 + popw %dx
  35 + movb $0xff, %ah
  36 + int $0x21
  37 +
  38 + sti
  39 + pushfl
  40 + popl %edx
  41 + movb $0xff, %ah
  42 + int $0x21
  43 +
  44 +#if 0
  45 + movw $GET_OFFSET(IF_msg1), %dx
  46 + movb $0x09, %ah
  47 + int $0x21
  48 +
  49 + pushf
  50 + movw %sp, %bx
  51 + andw $~0x200, (%bx)
  52 + popf
  53 +#else
  54 + cli
  55 +#endif
  56 +
  57 + pushf
  58 + popw %dx
  59 + movb $0xff, %ah
  60 + int $0x21
  61 +
  62 + pushfl
  63 + movw %sp, %bx
  64 + orw $0x200, (%bx)
  65 + popfl
  66 +
  67 + pushfl
  68 + popl %edx
  69 + movb $0xff, %ah
  70 + int $0x21
  71 +
  72 + movb $0x00, %ah
  73 + int $0x21
  74 +
  75 +int90_test:
  76 + pushf
  77 + pop %dx
  78 + movb $0xff, %ah
  79 + int $0x21
  80 +
  81 + movw %sp, %bx
  82 + movw 4(%bx), %dx
  83 + movb $0xff, %ah
  84 + int $0x21
  85 +
  86 + movw $GET_OFFSET(int90_msg), %dx
  87 + movb $0x09, %ah
  88 + int $0x21
  89 + iret
  90 +
  91 +int90_msg:
  92 + .string "INT90 started\n$"
  93 +
  94 +hello_world:
  95 + .string "Hello VM86 world\n$"
  96 +
  97 +IF_msg:
  98 + .string "VM86 IF test\n$"
  99 +
  100 +IF_msg1:
  101 + .string "If you see a diff here, your Linux kernel is buggy, please update to 2.4.20 kernel\n$"
  102 +
  103 +vm86_code_end:
  104 +
0 105 \ No newline at end of file
... ...
tests/test-i386.c
  1 +#define _GNU_SOURCE
1 2 #include <stdlib.h>
2 3 #include <stdio.h>
3 4 #include <inttypes.h>
4 5 #include <math.h>
  6 +#include <signal.h>
  7 +#include <setjmp.h>
  8 +#include <sys/ucontext.h>
  9 +#include <sys/mman.h>
  10 +#include <asm/vm86.h>
5 11  
6 12 #define TEST_CMOV 0
7 13  
... ... @@ -913,6 +919,316 @@ void test_string(void)
913 919 TEST_STRING(cmps, "repnz ");
914 920 }
915 921  
  922 +/* VM86 test */
  923 +
  924 +static inline void set_bit(uint8_t *a, unsigned int bit)
  925 +{
  926 + a[bit / 8] |= (1 << (bit % 8));
  927 +}
  928 +
  929 +static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
  930 +{
  931 + return (uint8_t *)((seg << 4) + (reg & 0xffff));
  932 +}
  933 +
  934 +static inline void pushw(struct vm86_regs *r, int val)
  935 +{
  936 + r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff);
  937 + *(uint16_t *)seg_to_linear(r->ss, r->esp) = val;
  938 +}
  939 +
  940 +#undef __syscall_return
  941 +#define __syscall_return(type, res) \
  942 +do { \
  943 + return (type) (res); \
  944 +} while (0)
  945 +
  946 +_syscall2(int, vm86, int, func, struct vm86plus_struct *, v86)
  947 +
  948 +extern char vm86_code_start;
  949 +extern char vm86_code_end;
  950 +
  951 +#define VM86_CODE_CS 0x100
  952 +#define VM86_CODE_IP 0x100
  953 +
  954 +void test_vm86(void)
  955 +{
  956 + struct vm86plus_struct ctx;
  957 + struct vm86_regs *r;
  958 + uint8_t *vm86_mem;
  959 + int seg, ret;
  960 +
  961 + vm86_mem = mmap((void *)0x00000000, 0x110000,
  962 + PROT_WRITE | PROT_READ | PROT_EXEC,
  963 + MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
  964 + if (vm86_mem == MAP_FAILED) {
  965 + printf("ERROR: could not map vm86 memory");
  966 + return;
  967 + }
  968 + memset(&ctx, 0, sizeof(ctx));
  969 +
  970 + /* init basic registers */
  971 + r = &ctx.regs;
  972 + r->eip = VM86_CODE_IP;
  973 + r->esp = 0xfffe;
  974 + seg = VM86_CODE_CS;
  975 + r->cs = seg;
  976 + r->ss = seg;
  977 + r->ds = seg;
  978 + r->es = seg;
  979 + r->fs = seg;
  980 + r->gs = seg;
  981 + r->eflags = VIF_MASK;
  982 +
  983 + /* move code to proper address. We use the same layout as a .com
  984 + dos program. */
  985 + memcpy(vm86_mem + (VM86_CODE_CS << 4) + VM86_CODE_IP,
  986 + &vm86_code_start, &vm86_code_end - &vm86_code_start);
  987 +
  988 + /* mark int 0x21 as being emulated */
  989 + set_bit((uint8_t *)&ctx.int_revectored, 0x21);
  990 +
  991 + for(;;) {
  992 + ret = vm86(VM86_ENTER, &ctx);
  993 + switch(VM86_TYPE(ret)) {
  994 + case VM86_INTx:
  995 + {
  996 + int int_num, ah;
  997 +
  998 + int_num = VM86_ARG(ret);
  999 + if (int_num != 0x21)
  1000 + goto unknown_int;
  1001 + ah = (r->eax >> 8) & 0xff;
  1002 + switch(ah) {
  1003 + case 0x00: /* exit */
  1004 + goto the_end;
  1005 + case 0x02: /* write char */
  1006 + {
  1007 + uint8_t c = r->edx;
  1008 + putchar(c);
  1009 + }
  1010 + break;
  1011 + case 0x09: /* write string */
  1012 + {
  1013 + uint8_t c, *ptr;
  1014 + ptr = seg_to_linear(r->ds, r->edx);
  1015 + for(;;) {
  1016 + c = *ptr++;
  1017 + if (c == '$')
  1018 + break;
  1019 + putchar(c);
  1020 + }
  1021 + r->eax = (r->eax & ~0xff) | '$';
  1022 + }
  1023 + break;
  1024 + case 0xff: /* extension: write hex number in edx */
  1025 + printf("%08x\n", (int)r->edx);
  1026 + break;
  1027 + default:
  1028 + unknown_int:
  1029 + printf("unsupported int 0x%02x\n", int_num);
  1030 + goto the_end;
  1031 + }
  1032 + }
  1033 + break;
  1034 + case VM86_SIGNAL:
  1035 + /* a signal came, we just ignore that */
  1036 + break;
  1037 + case VM86_STI:
  1038 + break;
  1039 + default:
  1040 + printf("ERROR: unhandled vm86 return code (0x%x)\n", ret);
  1041 + goto the_end;
  1042 + }
  1043 + }
  1044 + the_end:
  1045 + printf("VM86 end\n");
  1046 + munmap(vm86_mem, 0x110000);
  1047 +}
  1048 +
  1049 +/* exception tests */
  1050 +#ifndef REG_EAX
  1051 +#define REG_EAX EAX
  1052 +#define REG_EBX EBX
  1053 +#define REG_ECX ECX
  1054 +#define REG_EDX EDX
  1055 +#define REG_ESI ESI
  1056 +#define REG_EDI EDI
  1057 +#define REG_EBP EBP
  1058 +#define REG_ESP ESP
  1059 +#define REG_EIP EIP
  1060 +#define REG_EFL EFL
  1061 +#define REG_TRAPNO TRAPNO
  1062 +#define REG_ERR ERR
  1063 +#endif
  1064 +
  1065 +jmp_buf jmp_env;
  1066 +int dump_eip;
  1067 +int dump_si_addr;
  1068 +int v1;
  1069 +int tab[2];
  1070 +
  1071 +void sig_handler(int sig, siginfo_t *info, void *puc)
  1072 +{
  1073 + struct ucontext *uc = puc;
  1074 +
  1075 + printf("si_signo=%d si_errno=%d si_code=%d",
  1076 + info->si_signo, info->si_errno, info->si_code);
  1077 + if (dump_si_addr) {
  1078 + printf(" si_addr=0x%08lx",
  1079 + (unsigned long)info->si_addr);
  1080 + }
  1081 + printf("\n");
  1082 +
  1083 + printf("trapno=0x%02x err=0x%08x",
  1084 + uc->uc_mcontext.gregs[REG_TRAPNO],
  1085 + uc->uc_mcontext.gregs[REG_ERR]);
  1086 + if (dump_eip)
  1087 + printf(" EIP=0x%08x", uc->uc_mcontext.gregs[REG_EIP]);
  1088 + printf("\n");
  1089 + longjmp(jmp_env, 1);
  1090 +}
  1091 +
  1092 +void test_exceptions(void)
  1093 +{
  1094 + struct sigaction act;
  1095 + volatile int val;
  1096 +
  1097 + act.sa_sigaction = sig_handler;
  1098 + sigemptyset(&act.sa_mask);
  1099 + act.sa_flags = SA_SIGINFO;
  1100 + sigaction(SIGFPE, &act, NULL);
  1101 + sigaction(SIGILL, &act, NULL);
  1102 + sigaction(SIGSEGV, &act, NULL);
  1103 + sigaction(SIGTRAP, &act, NULL);
  1104 +
  1105 + /* test division by zero reporting */
  1106 + dump_eip = 0;
  1107 + dump_si_addr = 0;
  1108 + printf("DIVZ exception (currently imprecise):\n");
  1109 + if (setjmp(jmp_env) == 0) {
  1110 + /* now divide by zero */
  1111 + v1 = 0;
  1112 + v1 = 2 / v1;
  1113 + }
  1114 +
  1115 + dump_si_addr = 1;
  1116 + printf("BOUND exception (currently imprecise):\n");
  1117 + if (setjmp(jmp_env) == 0) {
  1118 + /* bound exception */
  1119 + tab[0] = 1;
  1120 + tab[1] = 10;
  1121 + asm volatile ("bound %0, %1" : : "r" (11), "m" (tab));
  1122 + }
  1123 +
  1124 + /* test SEGV reporting */
  1125 + printf("PF exception (currently imprecise):\n");
  1126 + if (setjmp(jmp_env) == 0) {
  1127 + /* now store in an invalid address */
  1128 + *(char *)0x1234 = 1;
  1129 + }
  1130 +
  1131 + /* test SEGV reporting */
  1132 + printf("PF exception (currently imprecise):\n");
  1133 + if (setjmp(jmp_env) == 0) {
  1134 + /* read from an invalid address */
  1135 + v1 = *(char *)0x1234;
  1136 + }
  1137 +
  1138 + printf("segment GPF exception (currently imprecise):\n");
  1139 + if (setjmp(jmp_env) == 0) {
  1140 + /* load an invalid segment */
  1141 + asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 0));
  1142 + }
  1143 +
  1144 + dump_eip = 1;
  1145 + /* test illegal instruction reporting */
  1146 + printf("UD2 exception:\n");
  1147 + if (setjmp(jmp_env) == 0) {
  1148 + /* now execute an invalid instruction */
  1149 + asm volatile("ud2");
  1150 + }
  1151 +
  1152 + printf("INT exception:\n");
  1153 + if (setjmp(jmp_env) == 0) {
  1154 + asm volatile ("int $0xfd");
  1155 + }
  1156 +
  1157 + printf("INT3 exception:\n");
  1158 + if (setjmp(jmp_env) == 0) {
  1159 + asm volatile ("int3");
  1160 + }
  1161 +
  1162 + printf("CLI exception:\n");
  1163 + if (setjmp(jmp_env) == 0) {
  1164 + asm volatile ("cli");
  1165 + }
  1166 +
  1167 + printf("STI exception:\n");
  1168 + if (setjmp(jmp_env) == 0) {
  1169 + asm volatile ("cli");
  1170 + }
  1171 +
  1172 + printf("INTO exception:\n");
  1173 + if (setjmp(jmp_env) == 0) {
  1174 + /* overflow exception */
  1175 + asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff));
  1176 + }
  1177 +
  1178 + printf("OUTB exception:\n");
  1179 + if (setjmp(jmp_env) == 0) {
  1180 + asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0));
  1181 + }
  1182 +
  1183 + printf("INB exception:\n");
  1184 + if (setjmp(jmp_env) == 0) {
  1185 + asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321));
  1186 + }
  1187 +
  1188 + printf("REP OUTSB exception:\n");
  1189 + if (setjmp(jmp_env) == 0) {
  1190 + asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1));
  1191 + }
  1192 +
  1193 + printf("REP INSB exception:\n");
  1194 + if (setjmp(jmp_env) == 0) {
  1195 + asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1));
  1196 + }
  1197 +
  1198 + printf("HLT exception:\n");
  1199 + if (setjmp(jmp_env) == 0) {
  1200 + asm volatile ("hlt");
  1201 + }
  1202 +
  1203 + printf("single step exception:\n");
  1204 + val = 0;
  1205 + if (setjmp(jmp_env) == 0) {
  1206 + asm volatile ("pushf\n"
  1207 + "orl $0x00100, (%%esp)\n"
  1208 + "popf\n"
  1209 + "movl $0xabcd, %0\n"
  1210 + "movl $0x0, %0\n" : "=m" (val) : : "cc", "memory");
  1211 + }
  1212 + printf("val=0x%x\n", val);
  1213 +}
  1214 +
  1215 +/* self modifying code test */
  1216 +uint8_t code[] = {
  1217 + 0xb8, 0x1, 0x00, 0x00, 0x00, /* movl $1, %eax */
  1218 + 0xc3, /* ret */
  1219 +};
  1220 +
  1221 +void test_self_modifying_code(void)
  1222 +{
  1223 + int (*func)(void);
  1224 +
  1225 + func = (void *)code;
  1226 + printf("self modifying code:\n");
  1227 + printf("func1 = 0x%x\n", func());
  1228 + code[1] = 0x2;
  1229 + printf("func1 = 0x%x\n", func());
  1230 +}
  1231 +
916 1232 static void *call_end __init_call = NULL;
917 1233  
918 1234 int main(int argc, char **argv)
... ... @@ -936,5 +1252,8 @@ int main(int argc, char **argv)
936 1252 test_lea();
937 1253 test_segs();
938 1254 test_code16();
  1255 + test_vm86();
  1256 + test_exceptions();
  1257 + test_self_modifying_code();
939 1258 return 0;
940 1259 }
... ...