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
|