[patch] vm86: Handle multiply prefixes

Stas Sergeev (stssppnn@yahoo.com)
Sun, 28 Jul 2002 20:13:38 +0400


This is a multi-part message in MIME format.
--------------040401070707020306080609
Content-Type: text/plain; charset=KOI8-R; format=flowed
Content-Transfer-Encoding: 7bit

Hello.

Problem:
Currently v86 monitor doesn't
handle multiply prefixes.
For example, pushfd can be coded
as 66 9c which is handled correctly,
but also as 67 66 9c
(winnt.exe does this) which is not
handled.

The attached patch is intended to
fix the problem. With it applied,
dosemu can run winnt.exe (Windows NT
Setup), otherwise it crashes.
The patch is against the latest
2.4.19-pre-ac kernels.

--------------040401070707020306080609
Content-Type: text/plain;
name="vm86_pref.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="vm86_pref.diff"

--- 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;

--------------040401070707020306080609--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/