--- linux/arch/i386/kernel/vm86.c Sat Jun 15 19:46:46 2002 +++ linux/arch/i386/kernel/vm86.c Fri Jul 26 14:25:35 2002 @@ -502,8 +508,9 @@ void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code) { - unsigned char *csp, *ssp; + unsigned char *csp, *ssp, opcode; unsigned short ip, sp; + int data32, pref_done; #define CHECK_IF_IN_TRAP \ if (VMPI.vm86dbg_active && VMPI.vm86dbg_TFpendig) \ @@ -518,70 +525,63 @@ sp = SP(regs); ip = IP(regs); - switch (popb(csp, ip, simulate_sigsegv)) { + data32 = 0; + pref_done = 0; + do { + switch (opcode = popb(csp, ip, simulate_sigsegv)) { + case 0x66: /* 32-bit data */ data32=1; break; + case 0x67: /* 32-bit address */ break; + case 0x2e: /* CS */ break; + case 0x3e: /* DS */ break; + case 0x26: /* ES */ break; + case 0x36: /* SS */ break; + case 0x65: /* GS */ break; + case 0x64: /* FS */ break; + case 0xf2: /* repnz */ break; + case 0xf3: /* rep */ break; + default: pref_done = 1; + } + } while (!pref_done); - /* operand size override */ - case 0x66: - switch (popb(csp, ip, simulate_sigsegv)) { + switch (opcode) { - /* pushfd */ - case 0x9c: + /* pushf */ + case 0x9c: + if (data32) { pushl(ssp, sp, get_vflags(regs), simulate_sigsegv); SP(regs) -= 4; - IP(regs) += 2; - VM86_FAULT_RETURN; - - /* popfd */ - case 0x9d: - { - unsigned long newflags=popl(ssp, sp, simulate_sigsegv); - SP(regs) += 4; - IP(regs) += 2; - CHECK_IF_IN_TRAP; - set_vflags_long(newflags, regs); - VM86_FAULT_RETURN; - } - - /* iretd */ - case 0xcf: - { - unsigned long newip=popl(ssp, sp, simulate_sigsegv); - unsigned long newcs=popl(ssp, sp, simulate_sigsegv); - unsigned long newflags=popl(ssp, sp, simulate_sigsegv); - SP(regs) += 12; - IP(regs) = (unsigned short)newip; - regs->cs = (unsigned short)newcs; - CHECK_IF_IN_TRAP; - set_vflags_long(newflags, regs); - VM86_FAULT_RETURN; - } - /* need this to avoid a fallthrough */ - default: - return_to_32bit(regs, VM86_UNKNOWN); + } else { + pushw(ssp, sp, get_vflags(regs), simulate_sigsegv); + SP(regs) -= 2; } - - /* pushf */ - case 0x9c: - pushw(ssp, sp, get_vflags(regs), simulate_sigsegv); - SP(regs) -= 2; - IP(regs)++; + IP(regs) = ip; VM86_FAULT_RETURN; /* popf */ case 0x9d: { - unsigned short newflags=popw(ssp, sp, simulate_sigsegv); - SP(regs) += 2; - IP(regs)++; + unsigned long newflags; + if (data32) { + newflags=popl(ssp, sp, simulate_sigsegv); + SP(regs) += 4; + } else { + newflags = popw(ssp, sp, simulate_sigsegv); + SP(regs) += 2; + } + IP(regs) = ip; CHECK_IF_IN_TRAP; - set_vflags_short(newflags, regs); + if (data32) { + set_vflags_long(newflags, regs); + } else { + set_vflags_short(newflags, regs); + } VM86_FAULT_RETURN; } /* int xx */ case 0xcd: { int intno=popb(csp, ip, simulate_sigsegv); - IP(regs) += 2; + IP(regs) = ip; if (VMPI.vm86dbg_active) { if ( (1 << (intno &7)) & VMPI.vm86dbg_intxxtab[intno >> 3] ) return_to_32bit(regs, VM86_INTx + (intno << 8)); @@ -593,20 +593,34 @@ /* iret */ case 0xcf: { - unsigned short newip=popw(ssp, sp, simulate_sigsegv); - unsigned short newcs=popw(ssp, sp, simulate_sigsegv); - unsigned short newflags=popw(ssp, sp, simulate_sigsegv); - SP(regs) += 6; + unsigned long newip; + unsigned long newcs; + unsigned long newflags; + if (data32) { + newip=popl(ssp, sp, simulate_sigsegv); + newcs=popl(ssp, sp, simulate_sigsegv); + newflags=popl(ssp, sp, simulate_sigsegv); + SP(regs) += 12; + } else { + newip = popw(ssp, sp, simulate_sigsegv); + newcs = popw(ssp, sp, simulate_sigsegv); + newflags = popw(ssp, sp, simulate_sigsegv); + SP(regs) += 6; + } IP(regs) = newip; regs->cs = newcs; CHECK_IF_IN_TRAP; - set_vflags_short(newflags, regs); + if (data32) { + set_vflags_long(newflags, regs); + } else { + set_vflags_short(newflags, regs); + } VM86_FAULT_RETURN; } /* cli */ case 0xfa: - IP(regs)++; + IP(regs) = ip; clear_IF(regs); VM86_FAULT_RETURN; @@ -618,7 +632,7 @@ * Probably needs some horsing around with the TF flag. Aiee.. */ case 0xfb: - IP(regs)++; + IP(regs) = ip; set_IF(regs); VM86_FAULT_RETURN;