1 /* 2 * vm86 linux syscall support 3 * 4 * Copyright (c) 2003 Fabrice Bellard 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 */ 20 #include <stdlib.h> 21 #include <stdio.h> 22 #include <stdarg.h> 23 #include <string.h> 24 #include <errno.h> 25 #include <unistd.h> 26 27 #include "qemu.h" 28 29 //#define DEBUG_VM86 30 31 #define set_flags(X,new,mask) \ 32 ((X) = ((X) & ~(mask)) | ((new) & (mask))) 33 34 #define SAFE_MASK (0xDD5) 35 #define RETURN_MASK (0xDFF) 36 37 static inline int is_revectored(int nr, struct target_revectored_struct *bitmap) 38 { 39 return (((uint8_t *)bitmap)[nr >> 3] >> (nr & 7)) & 1; 40 } 41 42 static inline void vm_putw(uint8_t *segptr, unsigned int reg16, unsigned int val) 43 { 44 stw(segptr + (reg16 & 0xffff), val); 45 } 46 47 static inline void vm_putl(uint8_t *segptr, unsigned int reg16, unsigned int val) 48 { 49 stl(segptr + (reg16 & 0xffff), val); 50 } 51 52 static inline unsigned int vm_getw(uint8_t *segptr, unsigned int reg16) 53 { 54 return lduw(segptr + (reg16 & 0xffff)); 55 } 56 57 static inline unsigned int vm_getl(uint8_t *segptr, unsigned int reg16) 58 { 59 return ldl(segptr + (reg16 & 0xffff)); 60 } 61 62 void save_v86_state(CPUX86State *env) 63 { 64 TaskState *ts = env->opaque; 65 struct target_vm86plus_struct * target_v86; 66 67 lock_user_struct(target_v86, ts->target_v86, 0); 68 /* put the VM86 registers in the userspace register structure */ 69 target_v86->regs.eax = tswap32(env->regs[R_EAX]); 70 target_v86->regs.ebx = tswap32(env->regs[R_EBX]); 71 target_v86->regs.ecx = tswap32(env->regs[R_ECX]); 72 target_v86->regs.edx = tswap32(env->regs[R_EDX]); 73 target_v86->regs.esi = tswap32(env->regs[R_ESI]); 74 target_v86->regs.edi = tswap32(env->regs[R_EDI]); 75 target_v86->regs.ebp = tswap32(env->regs[R_EBP]); 76 target_v86->regs.esp = tswap32(env->regs[R_ESP]); 77 target_v86->regs.eip = tswap32(env->eip); 78 target_v86->regs.cs = tswap16(env->segs[R_CS].selector); 79 target_v86->regs.ss = tswap16(env->segs[R_SS].selector); 80 target_v86->regs.ds = tswap16(env->segs[R_DS].selector); 81 target_v86->regs.es = tswap16(env->segs[R_ES].selector); 82 target_v86->regs.fs = tswap16(env->segs[R_FS].selector); 83 target_v86->regs.gs = tswap16(env->segs[R_GS].selector); 84 set_flags(env->eflags, ts->v86flags, VIF_MASK | ts->v86mask); 85 target_v86->regs.eflags = tswap32(env->eflags); 86 unlock_user_struct(target_v86, ts->target_v86, 1); 87 #ifdef DEBUG_VM86 88 fprintf(logfile, "save_v86_state: eflags=%08x cs:ip=%04x:%04x\n", 89 env->eflags, env->segs[R_CS].selector, env->eip); 90 #endif 91 92 /* restore 32 bit registers */ 93 env->regs[R_EAX] = ts->vm86_saved_regs.eax; 94 env->regs[R_EBX] = ts->vm86_saved_regs.ebx; 95 env->regs[R_ECX] = ts->vm86_saved_regs.ecx; 96 env->regs[R_EDX] = ts->vm86_saved_regs.edx; 97 env->regs[R_ESI] = ts->vm86_saved_regs.esi; 98 env->regs[R_EDI] = ts->vm86_saved_regs.edi; 99 env->regs[R_EBP] = ts->vm86_saved_regs.ebp; 100 env->regs[R_ESP] = ts->vm86_saved_regs.esp; 101 env->eflags = ts->vm86_saved_regs.eflags; 102 env->eip = ts->vm86_saved_regs.eip; 103 104 cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs); 105 cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss); 106 cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds); 107 cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es); 108 cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs); 109 cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs); 110 } 111 112 /* return from vm86 mode to 32 bit. The vm86() syscall will return 113 'retval' */ 114 static inline void return_to_32bit(CPUX86State *env, int retval) 115 { 116 #ifdef DEBUG_VM86 117 fprintf(logfile, "return_to_32bit: ret=0x%x\n", retval); 118 #endif 119 save_v86_state(env); 120 env->regs[R_EAX] = retval; 121 } 122 123 static inline int set_IF(CPUX86State *env) 124 { 125 TaskState *ts = env->opaque; 126 127 ts->v86flags |= VIF_MASK; 128 if (ts->v86flags & VIP_MASK) { 129 return_to_32bit(env, TARGET_VM86_STI); 130 return 1; 131 } 132 return 0; 133 } 134 135 static inline void clear_IF(CPUX86State *env) 136 { 137 TaskState *ts = env->opaque; 138 139 ts->v86flags &= ~VIF_MASK; 140 } 141 142 static inline void clear_TF(CPUX86State *env) 143 { 144 env->eflags &= ~TF_MASK; 145 } 146 147 static inline void clear_AC(CPUX86State *env) 148 { 149 env->eflags &= ~AC_MASK; 150 } 151 152 static inline int set_vflags_long(unsigned long eflags, CPUX86State *env) 153 { 154 TaskState *ts = env->opaque; 155 156 set_flags(ts->v86flags, eflags, ts->v86mask); 157 set_flags(env->eflags, eflags, SAFE_MASK); 158 if (eflags & IF_MASK) 159 return set_IF(env); 160 else 161 clear_IF(env); 162 return 0; 163 } 164 165 static inline int set_vflags_short(unsigned short flags, CPUX86State *env) 166 { 167 TaskState *ts = env->opaque; 168 169 set_flags(ts->v86flags, flags, ts->v86mask & 0xffff); 170 set_flags(env->eflags, flags, SAFE_MASK); 171 if (flags & IF_MASK) 172 return set_IF(env); 173 else 174 clear_IF(env); 175 return 0; 176 } 177 178 static inline unsigned int get_vflags(CPUX86State *env) 179 { 180 TaskState *ts = env->opaque; 181 unsigned int flags; 182 183 flags = env->eflags & RETURN_MASK; 184 if (ts->v86flags & VIF_MASK) 185 flags |= IF_MASK; 186 flags |= IOPL_MASK; 187 return flags | (ts->v86flags & ts->v86mask); 188 } 189 190 #define ADD16(reg, val) reg = (reg & ~0xffff) | ((reg + (val)) & 0xffff) 191 192 /* handle VM86 interrupt (NOTE: the CPU core currently does not 193 support TSS interrupt revectoring, so this code is always executed) */ 194 static void do_int(CPUX86State *env, int intno) 195 { 196 TaskState *ts = env->opaque; 197 uint32_t *int_ptr, segoffs; 198 uint8_t *ssp; 199 unsigned int sp; 200 201 if (env->segs[R_CS].selector == TARGET_BIOSSEG) 202 goto cannot_handle; 203 if (is_revectored(intno, &ts->vm86plus.int_revectored)) 204 goto cannot_handle; 205 if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff, 206 &ts->vm86plus.int21_revectored)) 207 goto cannot_handle; 208 int_ptr = (uint32_t *)(intno << 2); 209 segoffs = tswap32(*int_ptr); 210 if ((segoffs >> 16) == TARGET_BIOSSEG) 211 goto cannot_handle; 212 #if defined(DEBUG_VM86) 213 fprintf(logfile, "VM86: emulating int 0x%x. CS:IP=%04x:%04x\n", 214 intno, segoffs >> 16, segoffs & 0xffff); 215 #endif 216 /* save old state */ 217 ssp = (uint8_t *)(env->segs[R_SS].selector << 4); 218 sp = env->regs[R_ESP] & 0xffff; 219 vm_putw(ssp, sp - 2, get_vflags(env)); 220 vm_putw(ssp, sp - 4, env->segs[R_CS].selector); 221 vm_putw(ssp, sp - 6, env->eip); 222 ADD16(env->regs[R_ESP], -6); 223 /* goto interrupt handler */ 224 env->eip = segoffs & 0xffff; 225 cpu_x86_load_seg(env, R_CS, segoffs >> 16); 226 clear_TF(env); 227 clear_IF(env); 228 clear_AC(env); 229 return; 230 cannot_handle: 231 #if defined(DEBUG_VM86) 232 fprintf(logfile, "VM86: return to 32 bits int 0x%x\n", intno); 233 #endif 234 return_to_32bit(env, TARGET_VM86_INTx | (intno << 8)); 235 } 236 237 void handle_vm86_trap(CPUX86State *env, int trapno) 238 { 239 if (trapno == 1 || trapno == 3) { 240 return_to_32bit(env, TARGET_VM86_TRAP + (trapno << 8)); 241 } else { 242 do_int(env, trapno); 243 } 244 } 245 246 #define CHECK_IF_IN_TRAP() \ 247 if ((ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) && \ 248 (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_TFpendig)) \ 249 newflags |= TF_MASK 250 251 #define VM86_FAULT_RETURN \ 252 if ((ts->vm86plus.vm86plus.flags & TARGET_force_return_for_pic) && \ 253 (ts->v86flags & (IF_MASK | VIF_MASK))) \ 254 return_to_32bit(env, TARGET_VM86_PICRETURN); \ 255 return 256 257 void handle_vm86_fault(CPUX86State *env) 258 { 259 TaskState *ts = env->opaque; 260 uint8_t *csp, *pc, *ssp; 261 unsigned int ip, sp, newflags, newip, newcs, opcode, intno; 262 int data32, pref_done; 263 264 csp = (uint8_t *)(env->segs[R_CS].selector << 4); 265 ip = env->eip & 0xffff; 266 pc = csp + ip; 267 268 ssp = (uint8_t *)(env->segs[R_SS].selector << 4); 269 sp = env->regs[R_ESP] & 0xffff; 270 271 #if defined(DEBUG_VM86) 272 fprintf(logfile, "VM86 exception %04x:%08x %02x %02x\n", 273 env->segs[R_CS].selector, env->eip, pc[0], pc[1]); 274 #endif 275 276 data32 = 0; 277 pref_done = 0; 278 do { 279 opcode = csp[ip]; 280 ADD16(ip, 1); 281 switch (opcode) { 282 case 0x66: /* 32-bit data */ data32=1; break; 283 case 0x67: /* 32-bit address */ break; 284 case 0x2e: /* CS */ break; 285 case 0x3e: /* DS */ break; 286 case 0x26: /* ES */ break; 287 case 0x36: /* SS */ break; 288 case 0x65: /* GS */ break; 289 case 0x64: /* FS */ break; 290 case 0xf2: /* repnz */ break; 291 case 0xf3: /* rep */ break; 292 default: pref_done = 1; 293 } 294 } while (!pref_done); 295 296 /* VM86 mode */ 297 switch(opcode) { 298 case 0x9c: /* pushf */ 299 if (data32) { 300 vm_putl(ssp, sp - 4, get_vflags(env)); 301 ADD16(env->regs[R_ESP], -4); 302 } else { 303 vm_putw(ssp, sp - 2, get_vflags(env)); 304 ADD16(env->regs[R_ESP], -2); 305 } 306 env->eip = ip; 307 VM86_FAULT_RETURN; 308 309 case 0x9d: /* popf */ 310 if (data32) { 311 newflags = vm_getl(ssp, sp); 312 ADD16(env->regs[R_ESP], 4); 313 } else { 314 newflags = vm_getw(ssp, sp); 315 ADD16(env->regs[R_ESP], 2); 316 } 317 env->eip = ip; 318 CHECK_IF_IN_TRAP(); 319 if (data32) { 320 if (set_vflags_long(newflags, env)) 321 return; 322 } else { 323 if (set_vflags_short(newflags, env)) 324 return; 325 } 326 VM86_FAULT_RETURN; 327 328 case 0xcd: /* int */ 329 intno = csp[ip]; 330 ADD16(ip, 1); 331 env->eip = ip; 332 if (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) { 333 if ( (ts->vm86plus.vm86plus.vm86dbg_intxxtab[intno >> 3] >> 334 (intno &7)) & 1) { 335 return_to_32bit(env, TARGET_VM86_INTx + (intno << 8)); 336 return; 337 } 338 } 339 do_int(env, intno); 340 break; 341 342 case 0xcf: /* iret */ 343 if (data32) { 344 newip = vm_getl(ssp, sp) & 0xffff; 345 newcs = vm_getl(ssp, sp + 4) & 0xffff; 346 newflags = vm_getl(ssp, sp + 8); 347 ADD16(env->regs[R_ESP], 12); 348 } else { 349 newip = vm_getw(ssp, sp); 350 newcs = vm_getw(ssp, sp + 2); 351 newflags = vm_getw(ssp, sp + 4); 352 ADD16(env->regs[R_ESP], 6); 353 } 354 env->eip = newip; 355 cpu_x86_load_seg(env, R_CS, newcs); 356 CHECK_IF_IN_TRAP(); 357 if (data32) { 358 if (set_vflags_long(newflags, env)) 359 return; 360 } else { 361 if (set_vflags_short(newflags, env)) 362 return; 363 } 364 VM86_FAULT_RETURN; 365 366 case 0xfa: /* cli */ 367 env->eip = ip; 368 clear_IF(env); 369 VM86_FAULT_RETURN; 370 371 case 0xfb: /* sti */ 372 env->eip = ip; 373 if (set_IF(env)) 374 return; 375 VM86_FAULT_RETURN; 376 377 default: 378 /* real VM86 GPF exception */ 379 return_to_32bit(env, TARGET_VM86_UNKNOWN); 380 break; 381 } 382 } 383 384 int do_vm86(CPUX86State *env, long subfunction, target_ulong vm86_addr) 385 { 386 TaskState *ts = env->opaque; 387 struct target_vm86plus_struct * target_v86; 388 int ret; 389 390 switch (subfunction) { 391 case TARGET_VM86_REQUEST_IRQ: 392 case TARGET_VM86_FREE_IRQ: 393 case TARGET_VM86_GET_IRQ_BITS: 394 case TARGET_VM86_GET_AND_RESET_IRQ: 395 gemu_log("qemu: unsupported vm86 subfunction (%ld)\n", subfunction); 396 ret = -EINVAL; 397 goto out; 398 case TARGET_VM86_PLUS_INSTALL_CHECK: 399 /* NOTE: on old vm86 stuff this will return the error 400 from verify_area(), because the subfunction is 401 interpreted as (invalid) address to vm86_struct. 402 So the installation check works. 403 */ 404 ret = 0; 405 goto out; 406 } 407 408 /* save current CPU regs */ 409 ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */ 410 ts->vm86_saved_regs.ebx = env->regs[R_EBX]; 411 ts->vm86_saved_regs.ecx = env->regs[R_ECX]; 412 ts->vm86_saved_regs.edx = env->regs[R_EDX]; 413 ts->vm86_saved_regs.esi = env->regs[R_ESI]; 414 ts->vm86_saved_regs.edi = env->regs[R_EDI]; 415 ts->vm86_saved_regs.ebp = env->regs[R_EBP]; 416 ts->vm86_saved_regs.esp = env->regs[R_ESP]; 417 ts->vm86_saved_regs.eflags = env->eflags; 418 ts->vm86_saved_regs.eip = env->eip; 419 ts->vm86_saved_regs.cs = env->segs[R_CS].selector; 420 ts->vm86_saved_regs.ss = env->segs[R_SS].selector; 421 ts->vm86_saved_regs.ds = env->segs[R_DS].selector; 422 ts->vm86_saved_regs.es = env->segs[R_ES].selector; 423 ts->vm86_saved_regs.fs = env->segs[R_FS].selector; 424 ts->vm86_saved_regs.gs = env->segs[R_GS].selector; 425 426 ts->target_v86 = vm86_addr; 427 lock_user_struct(target_v86, vm86_addr, 1); 428 /* build vm86 CPU state */ 429 ts->v86flags = tswap32(target_v86->regs.eflags); 430 env->eflags = (env->eflags & ~SAFE_MASK) | 431 (tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK; 432 433 ts->vm86plus.cpu_type = tswapl(target_v86->cpu_type); 434 switch (ts->vm86plus.cpu_type) { 435 case TARGET_CPU_286: 436 ts->v86mask = 0; 437 break; 438 case TARGET_CPU_386: 439 ts->v86mask = NT_MASK | IOPL_MASK; 440 break; 441 case TARGET_CPU_486: 442 ts->v86mask = AC_MASK | NT_MASK | IOPL_MASK; 443 break; 444 default: 445 ts->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK; 446 break; 447 } 448 449 env->regs[R_EBX] = tswap32(target_v86->regs.ebx); 450 env->regs[R_ECX] = tswap32(target_v86->regs.ecx); 451 env->regs[R_EDX] = tswap32(target_v86->regs.edx); 452 env->regs[R_ESI] = tswap32(target_v86->regs.esi); 453 env->regs[R_EDI] = tswap32(target_v86->regs.edi); 454 env->regs[R_EBP] = tswap32(target_v86->regs.ebp); 455 env->regs[R_ESP] = tswap32(target_v86->regs.esp); 456 env->eip = tswap32(target_v86->regs.eip); 457 cpu_x86_load_seg(env, R_CS, tswap16(target_v86->regs.cs)); 458 cpu_x86_load_seg(env, R_SS, tswap16(target_v86->regs.ss)); 459 cpu_x86_load_seg(env, R_DS, tswap16(target_v86->regs.ds)); 460 cpu_x86_load_seg(env, R_ES, tswap16(target_v86->regs.es)); 461 cpu_x86_load_seg(env, R_FS, tswap16(target_v86->regs.fs)); 462 cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs)); 463 ret = tswap32(target_v86->regs.eax); /* eax will be restored at 464 the end of the syscall */ 465 memcpy(&ts->vm86plus.int_revectored, 466 &target_v86->int_revectored, 32); 467 memcpy(&ts->vm86plus.int21_revectored, 468 &target_v86->int21_revectored, 32); 469 ts->vm86plus.vm86plus.flags = tswapl(target_v86->vm86plus.flags); 470 memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab, 471 target_v86->vm86plus.vm86dbg_intxxtab, 32); 472 unlock_user_struct(target_v86, vm86_addr, 0); 473 474 #ifdef DEBUG_VM86 475 fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n", 476 env->segs[R_CS].selector, env->eip); 477 #endif 478 /* now the virtual CPU is ready for vm86 execution ! */ 479 out: 480 return ret; 481 } 482 483