Commit bc8a22cc307ebd9a2577c8fffcb90000724f72f3
1 parent
f631ef9b
better vm86 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@69 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
7 changed files
with
239 additions
and
89 deletions
Changelog
| 1 | +version 0.1.4: | ||
| 2 | + | ||
| 3 | + - more accurate VM86 emulation (can launch small DOS 16 bit | ||
| 4 | + executables in wine). | ||
| 5 | + - fixed push/pop fs/gs | ||
| 6 | + - added iret instruction. | ||
| 7 | + | ||
| 8 | +version 0.1.3: | ||
| 9 | + | ||
| 10 | + - S390 support (Ulrich Weigand) | ||
| 11 | + - glibc 2.3.x compile fix (Ulrich Weigand) | ||
| 12 | + - socketcall endian fix (Ulrich Weigand) | ||
| 13 | + - struct sockaddr endian fix (Ulrich Weigand) | ||
| 14 | + - sendmsg/recvmsg endian fix (Ulrich Weigand) | ||
| 15 | + - execve endian fix (Ulrich Weigand) | ||
| 16 | + - fdset endian fix (Ulrich Weigand) | ||
| 17 | + - partial setsockopt syscall support (Ulrich Weigand) | ||
| 18 | + - more accurate pushf/popf emulation | ||
| 19 | + - first partial vm86() syscall support (can be used with runcom example). | ||
| 20 | + - added bound, cmpxchg8b, cpuid instructions | ||
| 21 | + - added 16 bit addressing support/override for string operations | ||
| 22 | + - poll() fix | ||
| 23 | + | ||
| 24 | +version 0.1.2: | ||
| 25 | + | ||
| 26 | + - compile fixes | ||
| 27 | + - xlat instruction | ||
| 28 | + - xchg instruction memory lock | ||
| 29 | + - added simple vm86 example (not working with QEMU yet). The 54 byte | ||
| 30 | + DOS executable 'pi_10.com' program was released by Bertram | ||
| 31 | + Felgenhauer (more information at http://www.boo.net/~jasonp/pipage.html). | ||
| 32 | + | ||
| 1 | version 0.1.1: | 33 | version 0.1.1: |
| 2 | 34 | ||
| 3 | - glibc 2.2 compilation fixes | 35 | - glibc 2.2 compilation fixes |
| 4 | - added -s and -L options | 36 | - added -s and -L options |
| 5 | - binary distribution of x86 glibc and wine | 37 | - binary distribution of x86 glibc and wine |
| 38 | + - big endian fixes in ELF loader and getdents. | ||
| 6 | 39 | ||
| 7 | version 0.1: | 40 | version 0.1: |
| 8 | 41 |
TODO
| 1 | +- fix thread locks | ||
| 2 | +- fix thread stack liberation | ||
| 3 | +- fix x86 stack allocation | ||
| 1 | - optimize translated cache chaining (DLL PLT-like system) | 4 | - optimize translated cache chaining (DLL PLT-like system) |
| 2 | - more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit | 5 | - more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit |
| 3 | issues, fix 16 bit uid issues) | 6 | issues, fix 16 bit uid issues) |
| 4 | - finish signal handing (fp87 state, more siginfo conversions) | 7 | - finish signal handing (fp87 state, more siginfo conversions) |
| 5 | - verify thread support (clone() and various locks) | 8 | - verify thread support (clone() and various locks) |
| 6 | -- vm86 syscall support | ||
| 7 | - overrides/16bit for string ops | 9 | - overrides/16bit for string ops |
| 8 | - make it self runnable (use same trick as ld.so : include its own relocator and libc) | 10 | - make it self runnable (use same trick as ld.so : include its own relocator and libc) |
| 9 | -- improved 16 bit support | ||
| 10 | - fix FPU exceptions (in particular: gen_op_fpush not before mem load) | 11 | - fix FPU exceptions (in particular: gen_op_fpush not before mem load) |
cpu-i386.h
| @@ -68,24 +68,24 @@ | @@ -68,24 +68,24 @@ | ||
| 68 | #define VIP_MASK 0x00100000 | 68 | #define VIP_MASK 0x00100000 |
| 69 | #define ID_MASK 0x00200000 | 69 | #define ID_MASK 0x00200000 |
| 70 | 70 | ||
| 71 | -#define EXCP00_DIVZ 1 | ||
| 72 | -#define EXCP01_SSTP 2 | ||
| 73 | -#define EXCP02_NMI 3 | ||
| 74 | -#define EXCP03_INT3 4 | ||
| 75 | -#define EXCP04_INTO 5 | ||
| 76 | -#define EXCP05_BOUND 6 | ||
| 77 | -#define EXCP06_ILLOP 7 | ||
| 78 | -#define EXCP07_PREX 8 | ||
| 79 | -#define EXCP08_DBLE 9 | ||
| 80 | -#define EXCP09_XERR 10 | ||
| 81 | -#define EXCP0A_TSS 11 | ||
| 82 | -#define EXCP0B_NOSEG 12 | ||
| 83 | -#define EXCP0C_STACK 13 | ||
| 84 | -#define EXCP0D_GPF 14 | ||
| 85 | -#define EXCP0E_PAGE 15 | ||
| 86 | -#define EXCP10_COPR 17 | ||
| 87 | -#define EXCP11_ALGN 18 | ||
| 88 | -#define EXCP12_MCHK 19 | 71 | +#define EXCP00_DIVZ 0 |
| 72 | +#define EXCP01_SSTP 1 | ||
| 73 | +#define EXCP02_NMI 2 | ||
| 74 | +#define EXCP03_INT3 3 | ||
| 75 | +#define EXCP04_INTO 4 | ||
| 76 | +#define EXCP05_BOUND 5 | ||
| 77 | +#define EXCP06_ILLOP 6 | ||
| 78 | +#define EXCP07_PREX 7 | ||
| 79 | +#define EXCP08_DBLE 8 | ||
| 80 | +#define EXCP09_XERR 9 | ||
| 81 | +#define EXCP0A_TSS 10 | ||
| 82 | +#define EXCP0B_NOSEG 11 | ||
| 83 | +#define EXCP0C_STACK 12 | ||
| 84 | +#define EXCP0D_GPF 13 | ||
| 85 | +#define EXCP0E_PAGE 14 | ||
| 86 | +#define EXCP10_COPR 16 | ||
| 87 | +#define EXCP11_ALGN 17 | ||
| 88 | +#define EXCP12_MCHK 18 | ||
| 89 | 89 | ||
| 90 | #define EXCP_INTERRUPT 256 /* async interruption */ | 90 | #define EXCP_INTERRUPT 256 /* async interruption */ |
| 91 | 91 |
linux-user/main.c
| @@ -106,77 +106,172 @@ uint64_t gdt_table[6]; | @@ -106,77 +106,172 @@ uint64_t gdt_table[6]; | ||
| 106 | 106 | ||
| 107 | //#define DEBUG_VM86 | 107 | //#define DEBUG_VM86 |
| 108 | 108 | ||
| 109 | +static inline int is_revectored(int nr, struct target_revectored_struct *bitmap) | ||
| 110 | +{ | ||
| 111 | + return (tswap32(bitmap->__map[nr >> 5]) >> (nr & 0x1f)) & 1; | ||
| 112 | +} | ||
| 113 | + | ||
| 114 | +static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg) | ||
| 115 | +{ | ||
| 116 | + return (uint8_t *)((seg << 4) + (reg & 0xffff)); | ||
| 117 | +} | ||
| 118 | + | ||
| 119 | +static inline void pushw(CPUX86State *env, int val) | ||
| 120 | +{ | ||
| 121 | + env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | | ||
| 122 | + ((env->regs[R_ESP] - 2) & 0xffff); | ||
| 123 | + *(uint16_t *)seg_to_linear(env->segs[R_SS], env->regs[R_ESP]) = val; | ||
| 124 | +} | ||
| 125 | + | ||
| 126 | +static inline unsigned int get_vflags(CPUX86State *env) | ||
| 127 | +{ | ||
| 128 | + unsigned int eflags; | ||
| 129 | + eflags = env->eflags & ~(VM_MASK | RF_MASK | IF_MASK); | ||
| 130 | + if (eflags & VIF_MASK) | ||
| 131 | + eflags |= IF_MASK; | ||
| 132 | + return eflags; | ||
| 133 | +} | ||
| 134 | + | ||
| 135 | +void save_v86_state(CPUX86State *env) | ||
| 136 | +{ | ||
| 137 | + TaskState *ts = env->opaque; | ||
| 138 | +#ifdef DEBUG_VM86 | ||
| 139 | + printf("save_v86_state\n"); | ||
| 140 | +#endif | ||
| 141 | + | ||
| 142 | + /* put the VM86 registers in the userspace register structure */ | ||
| 143 | + ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]); | ||
| 144 | + ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]); | ||
| 145 | + ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]); | ||
| 146 | + ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]); | ||
| 147 | + ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]); | ||
| 148 | + ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]); | ||
| 149 | + ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]); | ||
| 150 | + ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]); | ||
| 151 | + ts->target_v86->regs.eip = tswap32(env->eip); | ||
| 152 | + ts->target_v86->regs.cs = tswap16(env->segs[R_CS]); | ||
| 153 | + ts->target_v86->regs.ss = tswap16(env->segs[R_SS]); | ||
| 154 | + ts->target_v86->regs.ds = tswap16(env->segs[R_DS]); | ||
| 155 | + ts->target_v86->regs.es = tswap16(env->segs[R_ES]); | ||
| 156 | + ts->target_v86->regs.fs = tswap16(env->segs[R_FS]); | ||
| 157 | + ts->target_v86->regs.gs = tswap16(env->segs[R_GS]); | ||
| 158 | + ts->target_v86->regs.eflags = tswap32(env->eflags); | ||
| 159 | + | ||
| 160 | + /* restore 32 bit registers */ | ||
| 161 | + env->regs[R_EAX] = ts->vm86_saved_regs.eax; | ||
| 162 | + env->regs[R_EBX] = ts->vm86_saved_regs.ebx; | ||
| 163 | + env->regs[R_ECX] = ts->vm86_saved_regs.ecx; | ||
| 164 | + env->regs[R_EDX] = ts->vm86_saved_regs.edx; | ||
| 165 | + env->regs[R_ESI] = ts->vm86_saved_regs.esi; | ||
| 166 | + env->regs[R_EDI] = ts->vm86_saved_regs.edi; | ||
| 167 | + env->regs[R_EBP] = ts->vm86_saved_regs.ebp; | ||
| 168 | + env->regs[R_ESP] = ts->vm86_saved_regs.esp; | ||
| 169 | + env->eflags = ts->vm86_saved_regs.eflags; | ||
| 170 | + env->eip = ts->vm86_saved_regs.eip; | ||
| 171 | + | ||
| 172 | + cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs); | ||
| 173 | + cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss); | ||
| 174 | + cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds); | ||
| 175 | + cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es); | ||
| 176 | + cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs); | ||
| 177 | + cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs); | ||
| 178 | +} | ||
| 179 | + | ||
| 180 | +/* return from vm86 mode to 32 bit. The vm86() syscall will return | ||
| 181 | + 'retval' */ | ||
| 182 | +static inline void return_to_32bit(CPUX86State *env, int retval) | ||
| 183 | +{ | ||
| 184 | +#ifdef DEBUG_VM86 | ||
| 185 | + printf("return_to_32bit: ret=0x%x\n", retval); | ||
| 186 | +#endif | ||
| 187 | + save_v86_state(env); | ||
| 188 | + env->regs[R_EAX] = retval; | ||
| 189 | +} | ||
| 190 | + | ||
| 191 | +/* handle VM86 interrupt (NOTE: the CPU core currently does not | ||
| 192 | + support TSS interrupt revectoring, so this code is always executed) */ | ||
| 193 | +static void do_int(CPUX86State *env, int intno) | ||
| 194 | +{ | ||
| 195 | + TaskState *ts = env->opaque; | ||
| 196 | + uint32_t *int_ptr, segoffs; | ||
| 197 | + | ||
| 198 | + if (env->segs[R_CS] == TARGET_BIOSSEG) | ||
| 199 | + goto cannot_handle; /* XXX: I am not sure this is really useful */ | ||
| 200 | + if (is_revectored(intno, &ts->target_v86->int_revectored)) | ||
| 201 | + goto cannot_handle; | ||
| 202 | + if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff, | ||
| 203 | + &ts->target_v86->int21_revectored)) | ||
| 204 | + goto cannot_handle; | ||
| 205 | + int_ptr = (uint32_t *)(intno << 2); | ||
| 206 | + segoffs = tswap32(*int_ptr); | ||
| 207 | + if ((segoffs >> 16) == TARGET_BIOSSEG) | ||
| 208 | + goto cannot_handle; | ||
| 209 | +#ifdef DEBUG_VM86 | ||
| 210 | + printf("VM86: emulating int 0x%x. CS:IP=%04x:%04x\n", | ||
| 211 | + intno, segoffs >> 16, segoffs & 0xffff); | ||
| 212 | +#endif | ||
| 213 | + /* save old state */ | ||
| 214 | + pushw(env, get_vflags(env)); | ||
| 215 | + pushw(env, env->segs[R_CS]); | ||
| 216 | + pushw(env, env->eip); | ||
| 217 | + /* goto interrupt handler */ | ||
| 218 | + env->eip = segoffs & 0xffff; | ||
| 219 | + cpu_x86_load_seg(env, R_CS, segoffs >> 16); | ||
| 220 | + env->eflags &= ~(VIF_MASK | TF_MASK); | ||
| 221 | + return; | ||
| 222 | + cannot_handle: | ||
| 223 | +#ifdef DEBUG_VM86 | ||
| 224 | + printf("VM86: return to 32 bits int 0x%x\n", intno); | ||
| 225 | +#endif | ||
| 226 | + return_to_32bit(env, TARGET_VM86_INTx | (intno << 8)); | ||
| 227 | +} | ||
| 228 | + | ||
| 109 | void cpu_loop(struct CPUX86State *env) | 229 | void cpu_loop(struct CPUX86State *env) |
| 110 | { | 230 | { |
| 111 | - int err; | 231 | + int trapnr; |
| 112 | uint8_t *pc; | 232 | uint8_t *pc; |
| 113 | target_siginfo_t info; | 233 | target_siginfo_t info; |
| 114 | 234 | ||
| 115 | for(;;) { | 235 | for(;;) { |
| 116 | - err = cpu_x86_exec(env); | 236 | + trapnr = cpu_x86_exec(env); |
| 117 | pc = env->seg_cache[R_CS].base + env->eip; | 237 | pc = env->seg_cache[R_CS].base + env->eip; |
| 118 | - switch(err) { | 238 | + switch(trapnr) { |
| 119 | case EXCP0D_GPF: | 239 | case EXCP0D_GPF: |
| 120 | if (env->eflags & VM_MASK) { | 240 | if (env->eflags & VM_MASK) { |
| 121 | - TaskState *ts; | ||
| 122 | - int ret; | ||
| 123 | #ifdef DEBUG_VM86 | 241 | #ifdef DEBUG_VM86 |
| 124 | - printf("VM86 exception %04x:%08x %02x\n", | ||
| 125 | - env->segs[R_CS], env->eip, pc[0]); | 242 | + printf("VM86 exception %04x:%08x %02x %02x\n", |
| 243 | + env->segs[R_CS], env->eip, pc[0], pc[1]); | ||
| 126 | #endif | 244 | #endif |
| 127 | /* VM86 mode */ | 245 | /* VM86 mode */ |
| 128 | - ts = env->opaque; | ||
| 129 | - | ||
| 130 | - /* XXX: add all cases */ | ||
| 131 | switch(pc[0]) { | 246 | switch(pc[0]) { |
| 132 | case 0xcd: /* int */ | 247 | case 0xcd: /* int */ |
| 133 | env->eip += 2; | 248 | env->eip += 2; |
| 134 | - ret = TARGET_VM86_INTx | (pc[1] << 8); | 249 | + do_int(env, pc[1]); |
| 250 | + break; | ||
| 251 | + case 0x66: | ||
| 252 | + switch(pc[1]) { | ||
| 253 | + case 0xfb: /* sti */ | ||
| 254 | + case 0x9d: /* popf */ | ||
| 255 | + case 0xcf: /* iret */ | ||
| 256 | + env->eip += 2; | ||
| 257 | + return_to_32bit(env, TARGET_VM86_STI); | ||
| 258 | + break; | ||
| 259 | + default: | ||
| 260 | + goto vm86_gpf; | ||
| 261 | + } | ||
| 262 | + break; | ||
| 263 | + case 0xfb: /* sti */ | ||
| 264 | + case 0x9d: /* popf */ | ||
| 265 | + case 0xcf: /* iret */ | ||
| 266 | + env->eip++; | ||
| 267 | + return_to_32bit(env, TARGET_VM86_STI); | ||
| 135 | break; | 268 | break; |
| 136 | default: | 269 | default: |
| 270 | + vm86_gpf: | ||
| 137 | /* real VM86 GPF exception */ | 271 | /* real VM86 GPF exception */ |
| 138 | - ret = TARGET_VM86_UNKNOWN; | 272 | + return_to_32bit(env, TARGET_VM86_UNKNOWN); |
| 139 | break; | 273 | break; |
| 140 | } | 274 | } |
| 141 | -#ifdef DEBUG_VM86 | ||
| 142 | - printf("ret=0x%x\n", ret); | ||
| 143 | -#endif | ||
| 144 | - /* put the VM86 registers in the userspace register structure */ | ||
| 145 | - ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]); | ||
| 146 | - ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]); | ||
| 147 | - ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]); | ||
| 148 | - ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]); | ||
| 149 | - ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]); | ||
| 150 | - ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]); | ||
| 151 | - ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]); | ||
| 152 | - ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]); | ||
| 153 | - ts->target_v86->regs.eip = tswap32(env->eip); | ||
| 154 | - ts->target_v86->regs.cs = tswap16(env->segs[R_CS]); | ||
| 155 | - ts->target_v86->regs.ss = tswap16(env->segs[R_SS]); | ||
| 156 | - ts->target_v86->regs.ds = tswap16(env->segs[R_DS]); | ||
| 157 | - ts->target_v86->regs.es = tswap16(env->segs[R_ES]); | ||
| 158 | - ts->target_v86->regs.fs = tswap16(env->segs[R_FS]); | ||
| 159 | - ts->target_v86->regs.gs = tswap16(env->segs[R_GS]); | ||
| 160 | - | ||
| 161 | - /* restore 32 bit registers */ | ||
| 162 | - env->regs[R_EBX] = ts->vm86_saved_regs.ebx; | ||
| 163 | - env->regs[R_ECX] = ts->vm86_saved_regs.ecx; | ||
| 164 | - env->regs[R_EDX] = ts->vm86_saved_regs.edx; | ||
| 165 | - env->regs[R_ESI] = ts->vm86_saved_regs.esi; | ||
| 166 | - env->regs[R_EDI] = ts->vm86_saved_regs.edi; | ||
| 167 | - env->regs[R_EBP] = ts->vm86_saved_regs.ebp; | ||
| 168 | - env->regs[R_ESP] = ts->vm86_saved_regs.esp; | ||
| 169 | - env->eflags = ts->vm86_saved_regs.eflags; | ||
| 170 | - env->eip = ts->vm86_saved_regs.eip; | ||
| 171 | - | ||
| 172 | - cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs); | ||
| 173 | - cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss); | ||
| 174 | - cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds); | ||
| 175 | - cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es); | ||
| 176 | - cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs); | ||
| 177 | - cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs); | ||
| 178 | - | ||
| 179 | - env->regs[R_EAX] = ret; | ||
| 180 | } else { | 275 | } else { |
| 181 | if (pc[0] == 0xcd && pc[1] == 0x80) { | 276 | if (pc[0] == 0xcd && pc[1] == 0x80) { |
| 182 | /* syscall */ | 277 | /* syscall */ |
| @@ -200,20 +295,28 @@ void cpu_loop(struct CPUX86State *env) | @@ -200,20 +295,28 @@ void cpu_loop(struct CPUX86State *env) | ||
| 200 | } | 295 | } |
| 201 | break; | 296 | break; |
| 202 | case EXCP00_DIVZ: | 297 | case EXCP00_DIVZ: |
| 203 | - /* division by zero */ | ||
| 204 | - info.si_signo = SIGFPE; | ||
| 205 | - info.si_errno = 0; | ||
| 206 | - info.si_code = TARGET_FPE_INTDIV; | ||
| 207 | - info._sifields._sigfault._addr = env->eip; | ||
| 208 | - queue_signal(info.si_signo, &info); | 298 | + if (env->eflags & VM_MASK) { |
| 299 | + do_int(env, trapnr); | ||
| 300 | + } else { | ||
| 301 | + /* division by zero */ | ||
| 302 | + info.si_signo = SIGFPE; | ||
| 303 | + info.si_errno = 0; | ||
| 304 | + info.si_code = TARGET_FPE_INTDIV; | ||
| 305 | + info._sifields._sigfault._addr = env->eip; | ||
| 306 | + queue_signal(info.si_signo, &info); | ||
| 307 | + } | ||
| 209 | break; | 308 | break; |
| 210 | case EXCP04_INTO: | 309 | case EXCP04_INTO: |
| 211 | case EXCP05_BOUND: | 310 | case EXCP05_BOUND: |
| 212 | - info.si_signo = SIGSEGV; | ||
| 213 | - info.si_errno = 0; | ||
| 214 | - info.si_code = 0; | ||
| 215 | - info._sifields._sigfault._addr = 0; | ||
| 216 | - queue_signal(info.si_signo, &info); | 311 | + if (env->eflags & VM_MASK) { |
| 312 | + do_int(env, trapnr); | ||
| 313 | + } else { | ||
| 314 | + info.si_signo = SIGSEGV; | ||
| 315 | + info.si_errno = 0; | ||
| 316 | + info.si_code = 0; | ||
| 317 | + info._sifields._sigfault._addr = 0; | ||
| 318 | + queue_signal(info.si_signo, &info); | ||
| 319 | + } | ||
| 217 | break; | 320 | break; |
| 218 | case EXCP06_ILLOP: | 321 | case EXCP06_ILLOP: |
| 219 | info.si_signo = SIGILL; | 322 | info.si_signo = SIGILL; |
| @@ -226,8 +329,8 @@ void cpu_loop(struct CPUX86State *env) | @@ -226,8 +329,8 @@ void cpu_loop(struct CPUX86State *env) | ||
| 226 | /* just indicate that signals should be handled asap */ | 329 | /* just indicate that signals should be handled asap */ |
| 227 | break; | 330 | break; |
| 228 | default: | 331 | default: |
| 229 | - fprintf(stderr, "0x%08lx: Unknown exception CPU %d, aborting\n", | ||
| 230 | - (long)pc, err); | 332 | + fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", |
| 333 | + (long)pc, trapnr); | ||
| 231 | abort(); | 334 | abort(); |
| 232 | } | 335 | } |
| 233 | process_pending_signals(env); | 336 | process_pending_signals(env); |
linux-user/qemu.h
| @@ -74,5 +74,6 @@ void cpu_loop(CPUX86State *env); | @@ -74,5 +74,6 @@ void cpu_loop(CPUX86State *env); | ||
| 74 | void process_pending_signals(void *cpu_env); | 74 | void process_pending_signals(void *cpu_env); |
| 75 | void signal_init(void); | 75 | void signal_init(void); |
| 76 | int queue_signal(int sig, target_siginfo_t *info); | 76 | int queue_signal(int sig, target_siginfo_t *info); |
| 77 | +void save_v86_state(CPUX86State *env); | ||
| 77 | 78 | ||
| 78 | #endif | 79 | #endif |
linux-user/signal.c
| @@ -198,7 +198,7 @@ void __attribute((noreturn)) force_sig(int sig) | @@ -198,7 +198,7 @@ void __attribute((noreturn)) force_sig(int sig) | ||
| 198 | { | 198 | { |
| 199 | int host_sig; | 199 | int host_sig; |
| 200 | host_sig = target_to_host_signal(sig); | 200 | host_sig = target_to_host_signal(sig); |
| 201 | - fprintf(stderr, "gemu: uncaught target signal %d (%s) - exiting\n", | 201 | + fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", |
| 202 | sig, strsignal(host_sig)); | 202 | sig, strsignal(host_sig)); |
| 203 | #if 1 | 203 | #if 1 |
| 204 | _exit(-host_sig); | 204 | _exit(-host_sig); |
| @@ -223,7 +223,7 @@ int queue_signal(int sig, target_siginfo_t *info) | @@ -223,7 +223,7 @@ int queue_signal(int sig, target_siginfo_t *info) | ||
| 223 | target_ulong handler; | 223 | target_ulong handler; |
| 224 | 224 | ||
| 225 | #if defined(DEBUG_SIGNAL) | 225 | #if defined(DEBUG_SIGNAL) |
| 226 | - fprintf(stderr, "queue_sigal: sig=%d\n", | 226 | + fprintf(stderr, "queue_signal: sig=%d\n", |
| 227 | sig); | 227 | sig); |
| 228 | #endif | 228 | #endif |
| 229 | k = &sigact_table[sig - 1]; | 229 | k = &sigact_table[sig - 1]; |
| @@ -317,7 +317,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info, | @@ -317,7 +317,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info, | ||
| 317 | if (sig < 1 || sig > TARGET_NSIG) | 317 | if (sig < 1 || sig > TARGET_NSIG) |
| 318 | return; | 318 | return; |
| 319 | #if defined(DEBUG_SIGNAL) | 319 | #if defined(DEBUG_SIGNAL) |
| 320 | - fprintf(stderr, "gemu: got signal %d\n", sig); | 320 | + fprintf(stderr, "qemu: got signal %d\n", sig); |
| 321 | dump_regs(puc); | 321 | dump_regs(puc); |
| 322 | #endif | 322 | #endif |
| 323 | host_to_target_siginfo_noswap(&tinfo, info); | 323 | host_to_target_siginfo_noswap(&tinfo, info); |
| @@ -538,7 +538,6 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, | @@ -538,7 +538,6 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, | ||
| 538 | /* non-iBCS2 extensions.. */ | 538 | /* non-iBCS2 extensions.. */ |
| 539 | err |= __put_user(mask, &sc->oldmask); | 539 | err |= __put_user(mask, &sc->oldmask); |
| 540 | err |= __put_user(/*current->thread.cr2*/ 0, &sc->cr2); | 540 | err |= __put_user(/*current->thread.cr2*/ 0, &sc->cr2); |
| 541 | - | ||
| 542 | return err; | 541 | return err; |
| 543 | } | 542 | } |
| 544 | 543 | ||
| @@ -859,7 +858,7 @@ void process_pending_signals(void *cpu_env) | @@ -859,7 +858,7 @@ void process_pending_signals(void *cpu_env) | ||
| 859 | 858 | ||
| 860 | handle_signal: | 859 | handle_signal: |
| 861 | #ifdef DEBUG_SIGNAL | 860 | #ifdef DEBUG_SIGNAL |
| 862 | - fprintf(stderr, "gemu: process signal %d\n", sig); | 861 | + fprintf(stderr, "qemu: process signal %d\n", sig); |
| 863 | #endif | 862 | #endif |
| 864 | /* dequeue signal */ | 863 | /* dequeue signal */ |
| 865 | q = k->first; | 864 | q = k->first; |
| @@ -893,6 +892,14 @@ void process_pending_signals(void *cpu_env) | @@ -893,6 +892,14 @@ void process_pending_signals(void *cpu_env) | ||
| 893 | end of the signal execution (see do_sigreturn) */ | 892 | end of the signal execution (see do_sigreturn) */ |
| 894 | host_to_target_sigset(&target_old_set, &old_set); | 893 | host_to_target_sigset(&target_old_set, &old_set); |
| 895 | 894 | ||
| 895 | + /* if the CPU is in VM86 mode, we restore the 32 bit values */ | ||
| 896 | +#ifdef TARGET_I386 | ||
| 897 | + { | ||
| 898 | + CPUX86State *env = cpu_env; | ||
| 899 | + if (env->eflags & VM_MASK) | ||
| 900 | + save_v86_state(env); | ||
| 901 | + } | ||
| 902 | +#endif | ||
| 896 | /* prepare the stack frame of the virtual CPU */ | 903 | /* prepare the stack frame of the virtual CPU */ |
| 897 | if (k->sa.sa_flags & TARGET_SA_SIGINFO) | 904 | if (k->sa.sa_flags & TARGET_SA_SIGINFO) |
| 898 | setup_rt_frame(sig, k, &q->info, &target_old_set, cpu_env); | 905 | setup_rt_frame(sig, k, &q->info, &target_old_set, cpu_env); |
syscall-i386.h
| @@ -755,6 +755,11 @@ struct target_modify_ldt_ldt_s { | @@ -755,6 +755,11 @@ struct target_modify_ldt_ldt_s { | ||
| 755 | unsigned int flags; | 755 | unsigned int flags; |
| 756 | }; | 756 | }; |
| 757 | 757 | ||
| 758 | + | ||
| 759 | +/* vm86 defines */ | ||
| 760 | + | ||
| 761 | +#define TARGET_BIOSSEG 0x0f000 | ||
| 762 | + | ||
| 758 | #define TARGET_VM86_SIGNAL 0 /* return due to signal */ | 763 | #define TARGET_VM86_SIGNAL 0 /* return due to signal */ |
| 759 | #define TARGET_VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */ | 764 | #define TARGET_VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */ |
| 760 | #define TARGET_VM86_INTx 2 /* int3/int x instruction (ARG = x) */ | 765 | #define TARGET_VM86_INTx 2 /* int3/int x instruction (ARG = x) */ |