public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [patch] vm86: Handle multiply prefixes
@ 2002-07-28 16:13 Stas Sergeev
  0 siblings, 0 replies; only message in thread
From: Stas Sergeev @ 2002-07-28 16:13 UTC (permalink / raw)
  To: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 399 bytes --]

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.

[-- Attachment #2: vm86_pref.diff --]
[-- Type: text/plain, Size: 4410 bytes --]

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

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2002-07-28 16:41 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-07-28 16:13 [patch] vm86: Handle multiply prefixes Stas Sergeev

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox