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