Revision b333af06 linux-user/vm86.c
b/linux-user/vm86.c | ||
---|---|---|
36 | 36 |
|
37 | 37 |
static inline int is_revectored(int nr, struct target_revectored_struct *bitmap) |
38 | 38 |
{ |
39 |
return (tswap32(bitmap->__map[nr >> 5]) >> (nr & 0x1f)) & 1;
|
|
39 |
return (((uint8_t *)bitmap)[nr >> 3] >> (nr & 7)) & 1;
|
|
40 | 40 |
} |
41 | 41 |
|
42 | 42 |
static inline void vm_putw(uint8_t *segptr, unsigned int reg16, unsigned int val) |
... | ... | |
194 | 194 |
uint8_t *ssp; |
195 | 195 |
unsigned int sp; |
196 | 196 |
|
197 |
#if 1 |
|
198 |
if (intno == 0xe6 && (env->regs[R_EAX] & 0xffff) == 0x00c0) |
|
199 |
loglevel = 1; |
|
200 |
#endif |
|
201 |
|
|
202 | 197 |
if (env->segs[R_CS] == TARGET_BIOSSEG) |
203 | 198 |
goto cannot_handle; |
204 |
if (is_revectored(intno, &ts->target_v86->int_revectored))
|
|
199 |
if (is_revectored(intno, &ts->vm86plus.int_revectored))
|
|
205 | 200 |
goto cannot_handle; |
206 | 201 |
if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff, |
207 |
&ts->target_v86->int21_revectored))
|
|
202 |
&ts->vm86plus.int21_revectored))
|
|
208 | 203 |
goto cannot_handle; |
209 | 204 |
int_ptr = (uint32_t *)(intno << 2); |
210 | 205 |
segoffs = tswap32(*int_ptr); |
... | ... | |
244 | 239 |
} |
245 | 240 |
} |
246 | 241 |
|
247 |
#define CHECK_IF_IN_TRAP(disp) \
|
|
248 |
if ((tswap32(ts->target_v86->vm86plus.flags) & TARGET_vm86dbg_active) && \
|
|
249 |
(tswap32(ts->target_v86->vm86plus.flags) & TARGET_vm86dbg_TFpendig)) \
|
|
250 |
vm_putw(ssp,sp + disp,vm_getw(ssp,sp + disp) | TF_MASK)
|
|
242 |
#define CHECK_IF_IN_TRAP() \ |
|
243 |
if ((ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) && \
|
|
244 |
(ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_TFpendig)) \
|
|
245 |
newflags |= TF_MASK
|
|
251 | 246 |
|
252 | 247 |
#define VM86_FAULT_RETURN \ |
253 |
if ((tswap32(ts->target_v86->vm86plus.flags) & TARGET_force_return_for_pic) && \
|
|
248 |
if ((ts->vm86plus.vm86plus.flags & TARGET_force_return_for_pic) && \
|
|
254 | 249 |
(ts->v86flags & (IF_MASK | VIF_MASK))) \ |
255 | 250 |
return_to_32bit(env, TARGET_VM86_PICRETURN); \ |
256 | 251 |
return |
... | ... | |
259 | 254 |
{ |
260 | 255 |
TaskState *ts = env->opaque; |
261 | 256 |
uint8_t *csp, *pc, *ssp; |
262 |
unsigned int ip, sp; |
|
257 |
unsigned int ip, sp, newflags, newip, newcs, opcode, intno; |
|
258 |
int data32, pref_done; |
|
263 | 259 |
|
264 | 260 |
csp = (uint8_t *)(env->segs[R_CS] << 4); |
265 | 261 |
ip = env->eip & 0xffff; |
... | ... | |
273 | 269 |
env->segs[R_CS], env->eip, pc[0], pc[1]); |
274 | 270 |
#endif |
275 | 271 |
|
272 |
data32 = 0; |
|
273 |
pref_done = 0; |
|
274 |
do { |
|
275 |
opcode = csp[ip]; |
|
276 |
ADD16(ip, 1); |
|
277 |
switch (opcode) { |
|
278 |
case 0x66: /* 32-bit data */ data32=1; break; |
|
279 |
case 0x67: /* 32-bit address */ break; |
|
280 |
case 0x2e: /* CS */ break; |
|
281 |
case 0x3e: /* DS */ break; |
|
282 |
case 0x26: /* ES */ break; |
|
283 |
case 0x36: /* SS */ break; |
|
284 |
case 0x65: /* GS */ break; |
|
285 |
case 0x64: /* FS */ break; |
|
286 |
case 0xf2: /* repnz */ break; |
|
287 |
case 0xf3: /* rep */ break; |
|
288 |
default: pref_done = 1; |
|
289 |
} |
|
290 |
} while (!pref_done); |
|
291 |
|
|
276 | 292 |
/* VM86 mode */ |
277 |
switch(pc[0]) { |
|
278 |
case 0x66: |
|
279 |
switch(pc[1]) { |
|
280 |
case 0x9c: /* pushfd */ |
|
281 |
ADD16(env->eip, 2); |
|
282 |
ADD16(env->regs[R_ESP], -4); |
|
293 |
switch(opcode) { |
|
294 |
case 0x9c: /* pushf */ |
|
295 |
ADD16(env->eip, 2); |
|
296 |
if (data32) { |
|
283 | 297 |
vm_putl(ssp, sp - 4, get_vflags(env)); |
284 |
VM86_FAULT_RETURN; |
|
298 |
ADD16(env->regs[R_ESP], -4); |
|
299 |
} else { |
|
300 |
vm_putw(ssp, sp - 2, get_vflags(env)); |
|
301 |
ADD16(env->regs[R_ESP], -2); |
|
302 |
} |
|
303 |
env->eip = ip; |
|
304 |
VM86_FAULT_RETURN; |
|
285 | 305 |
|
286 |
case 0x9d: /* popfd */ |
|
287 |
ADD16(env->eip, 2); |
|
306 |
case 0x9d: /* popf */ |
|
307 |
if (data32) { |
|
308 |
newflags = vm_getl(ssp, sp); |
|
288 | 309 |
ADD16(env->regs[R_ESP], 4); |
289 |
CHECK_IF_IN_TRAP(0); |
|
290 |
if (set_vflags_long(vm_getl(ssp, sp), env)) |
|
310 |
} else { |
|
311 |
newflags = vm_getw(ssp, sp); |
|
312 |
ADD16(env->regs[R_ESP], 2); |
|
313 |
} |
|
314 |
env->eip = ip; |
|
315 |
CHECK_IF_IN_TRAP(); |
|
316 |
if (data32) { |
|
317 |
if (set_vflags_long(newflags, env)) |
|
291 | 318 |
return; |
292 |
VM86_FAULT_RETURN; |
|
293 |
|
|
294 |
case 0xcf: /* iretd */ |
|
295 |
ADD16(env->regs[R_ESP], 12); |
|
296 |
env->eip = vm_getl(ssp, sp) & 0xffff; |
|
297 |
cpu_x86_load_seg(env, R_CS, vm_getl(ssp, sp + 4) & 0xffff); |
|
298 |
CHECK_IF_IN_TRAP(8); |
|
299 |
if (set_vflags_long(vm_getl(ssp, sp + 8), env)) |
|
319 |
} else { |
|
320 |
if (set_vflags_short(newflags, env)) |
|
300 | 321 |
return; |
301 |
VM86_FAULT_RETURN; |
|
302 |
|
|
303 |
default: |
|
304 |
goto vm86_gpf; |
|
305 | 322 |
} |
306 |
break; |
|
307 |
case 0x9c: /* pushf */ |
|
308 |
ADD16(env->eip, 1); |
|
309 |
ADD16(env->regs[R_ESP], -2); |
|
310 |
vm_putw(ssp, sp - 2, get_vflags(env)); |
|
311 |
VM86_FAULT_RETURN; |
|
312 |
|
|
313 |
case 0x9d: /* popf */ |
|
314 |
ADD16(env->eip, 1); |
|
315 |
ADD16(env->regs[R_ESP], 2); |
|
316 |
CHECK_IF_IN_TRAP(0); |
|
317 |
if (set_vflags_short(vm_getw(ssp, sp), env)) |
|
318 |
return; |
|
319 | 323 |
VM86_FAULT_RETURN; |
320 | 324 |
|
321 | 325 |
case 0xcd: /* int */ |
322 |
ADD16(env->eip, 2); |
|
323 |
do_int(env, pc[1]); |
|
326 |
intno = csp[ip]; |
|
327 |
ADD16(ip, 1); |
|
328 |
env->eip = ip; |
|
329 |
if (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) { |
|
330 |
if ( (ts->vm86plus.vm86plus.vm86dbg_intxxtab[intno >> 3] >> |
|
331 |
(intno &7)) & 1) { |
|
332 |
return_to_32bit(env, TARGET_VM86_INTx + (intno << 8)); |
|
333 |
return; |
|
334 |
} |
|
335 |
} |
|
336 |
do_int(env, intno); |
|
324 | 337 |
break; |
325 | 338 |
|
326 | 339 |
case 0xcf: /* iret */ |
327 |
ADD16(env->regs[R_ESP], 6); |
|
328 |
env->eip = vm_getw(ssp, sp); |
|
329 |
cpu_x86_load_seg(env, R_CS, vm_getw(ssp, sp + 2)); |
|
330 |
CHECK_IF_IN_TRAP(4); |
|
331 |
if (set_vflags_short(vm_getw(ssp, sp + 4), env)) |
|
332 |
return; |
|
340 |
if (data32) { |
|
341 |
newip = vm_getl(ssp, sp) & 0xffff; |
|
342 |
newcs = vm_getl(ssp, sp + 4) & 0xffff; |
|
343 |
newflags = vm_getl(ssp, sp + 8); |
|
344 |
ADD16(env->regs[R_ESP], 12); |
|
345 |
} else { |
|
346 |
newip = vm_getw(ssp, sp); |
|
347 |
newcs = vm_getw(ssp, sp + 2); |
|
348 |
newflags = vm_getw(ssp, sp + 4); |
|
349 |
ADD16(env->regs[R_ESP], 6); |
|
350 |
} |
|
351 |
env->eip = newip; |
|
352 |
cpu_x86_load_seg(env, R_CS, newcs); |
|
353 |
CHECK_IF_IN_TRAP(); |
|
354 |
if (data32) { |
|
355 |
if (set_vflags_long(newflags, env)) |
|
356 |
return; |
|
357 |
} else { |
|
358 |
if (set_vflags_short(newflags, env)) |
|
359 |
return; |
|
360 |
} |
|
333 | 361 |
VM86_FAULT_RETURN; |
334 |
|
|
362 |
|
|
335 | 363 |
case 0xfa: /* cli */ |
336 |
ADD16(env->eip, 1);
|
|
364 |
env->eip = ip;
|
|
337 | 365 |
clear_IF(env); |
338 | 366 |
VM86_FAULT_RETURN; |
339 | 367 |
|
340 | 368 |
case 0xfb: /* sti */ |
341 |
ADD16(env->eip, 1);
|
|
369 |
env->eip = ip;
|
|
342 | 370 |
if (set_IF(env)) |
343 | 371 |
return; |
344 | 372 |
VM86_FAULT_RETURN; |
345 | 373 |
|
346 | 374 |
default: |
347 |
vm86_gpf: |
|
348 | 375 |
/* real VM86 GPF exception */ |
349 | 376 |
return_to_32bit(env, TARGET_VM86_UNKNOWN); |
350 | 377 |
break; |
... | ... | |
398 | 425 |
ts->v86flags = tswap32(target_v86->regs.eflags); |
399 | 426 |
env->eflags = (env->eflags & ~SAFE_MASK) | |
400 | 427 |
(tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK; |
401 |
ts->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK; |
|
428 |
|
|
429 |
ts->vm86plus.cpu_type = tswapl(target_v86->cpu_type); |
|
430 |
switch (ts->vm86plus.cpu_type) { |
|
431 |
case TARGET_CPU_286: |
|
432 |
ts->v86mask = 0; |
|
433 |
break; |
|
434 |
case TARGET_CPU_386: |
|
435 |
ts->v86mask = NT_MASK | IOPL_MASK; |
|
436 |
break; |
|
437 |
case TARGET_CPU_486: |
|
438 |
ts->v86mask = AC_MASK | NT_MASK | IOPL_MASK; |
|
439 |
break; |
|
440 |
default: |
|
441 |
ts->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK; |
|
442 |
break; |
|
443 |
} |
|
402 | 444 |
|
403 | 445 |
env->regs[R_EBX] = tswap32(target_v86->regs.ebx); |
404 | 446 |
env->regs[R_ECX] = tswap32(target_v86->regs.ecx); |
... | ... | |
416 | 458 |
cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs)); |
417 | 459 |
ret = tswap32(target_v86->regs.eax); /* eax will be restored at |
418 | 460 |
the end of the syscall */ |
461 |
memcpy(&ts->vm86plus.int_revectored, |
|
462 |
&target_v86->int_revectored, 32); |
|
463 |
memcpy(&ts->vm86plus.int21_revectored, |
|
464 |
&target_v86->int21_revectored, 32); |
|
465 |
ts->vm86plus.vm86plus.flags = tswapl(target_v86->vm86plus.flags); |
|
466 |
memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab, |
|
467 |
target_v86->vm86plus.vm86dbg_intxxtab, 32); |
|
468 |
|
|
419 | 469 |
#ifdef DEBUG_VM86 |
420 | 470 |
fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n", env->segs[R_CS], env->eip); |
421 | 471 |
#endif |
Also available in: Unified diff