Bug Fixing: CPU exception handling routine

Jiuming Luo (jiuming_luo@yahoo.com)
Fri, 7 May 1999 09:51:56 -0700 (PDT)


System information

The CPU type is Pentium II 300MHz. The total hardware
memory size is 64M bytes. The dosemu.conf lines are
normal(unchanged), except the following variables:

$_rawkeyboard = (1)
$_cpu = "80586"
$_xms = (32768)
$_ems = (0)
$_console = (1)
$_graphics = (1)
$_vmemsize = (4096)
$_chipset = "trident"
$_hdimage = "/dev/hda1 /dev/hdc1"

The /dev/hda1 is a DOS partition and contains Windows 98.
Linux kernel version is 2.2.7. DOSEmu version is 0.99.11.

Bug Description

Now, run DOSEmu, press F8 key to access Win98 startup menu.

Then choose "Safe mode command prompt only".

At the dos prompt, type DEBUG and press Enter. Then type the

letter "A" and press Enter to Assemble something. And then

enter the following lines:

cli
cli
cli
nop
nop
nop

Press an additional Enter to leave the "A" command.

Now type the letter "T" ( single step Trace command ) and

press Enter. O! O! O! Oh! FOUR instructions passed ( other

than ONE instruction )---- the IP register (the program

counter) points to the 5th instruction "NOP".

Similarly, you can try to trace the following:

pushf
pushf
pushf
popf
pushf
cli
sti
popf
pushf
nop

Set IP to point to the first "pushf", then enter "T" command.

You will find that all instructions are executed, and the SP

(stack pointer) and the stack contain the right values. That is

dangerous, especially when the last instruction is not "nop" !

Note that in real mode DOS or even in Win98's DOS Box, there is

no such problem.

##################################################################

Fixing

It seems that this bug is related to Linux kernel. I have re-written

the kernel function 'handle_vm86_faults()' and rebuilt the kernel.

No conflicts encountered so far.

The only change is the addition of DOS debugger trap support.

Note that inside the new function, the 'ip' variable is used as a temp

variable.

'diff -u ' differences between the old ( ver. 2.2.7 ) and the new:

--- linux-2.2.7/arch/i386/kernel/vm86.c Wed Dec 2 03:28:24 1998
+++ linux-n.e.w/arch/i386/kernel/vm86.c Fri May 7 03:44:40 1999
@@ -460,11 +460,14 @@

#define CHECK_IF_IN_TRAP \
if (VMPI.vm86dbg_active && VMPI.vm86dbg_TFpendig) \
- pushw(ssp,sp,popw(ssp,sp) | TF_MASK);
+ pushw(ssp,sp,popw(ssp,sp) | TF_MASK); \
+ ip = regs->eflags & TF_MASK
+
#define VM86_FAULT_RETURN \
if (VMPI.force_return_for_pic && (VEFLAGS & IF_MASK)) \
return_to_32bit(regs, VM86_PICRETURN); \
- return;
+ if (ip) return_to_32bit(regs, VM86_TRAP + (1 << 8)); \
+ return

csp = (unsigned char *) (regs->cs << 4);
ssp = (unsigned char *) (regs->ss << 4);
@@ -481,6 +484,7 @@
case 0x9c:
SP(regs) -= 4;
IP(regs) += 2;
+ ip = regs->eflags & TF_MASK;
pushl(ssp, sp, get_vflags(regs));
VM86_FAULT_RETURN;

@@ -488,7 +492,7 @@
case 0x9d:
SP(regs) += 4;
IP(regs) += 2;
- CHECK_IF_IN_TRAP
+ CHECK_IF_IN_TRAP;
set_vflags_long(popl(ssp, sp), regs);
VM86_FAULT_RETURN;

@@ -497,9 +501,24 @@
SP(regs) += 12;
IP(regs) = (unsigned short)popl(ssp, sp);
regs->cs = (unsigned short)popl(ssp, sp);
- CHECK_IF_IN_TRAP
+ CHECK_IF_IN_TRAP;
set_vflags_long(popl(ssp, sp), regs);
VM86_FAULT_RETURN;
+
+ /* cli, sti ---- only for test purpose */
+ /*---------------------------------------
+ case 0xfa:
+ IP(regs) += 2;
+ ip = regs->eflags & TF_MASK;
+ clear_IF(regs);
+ VM86_FAULT_RETURN;
+ case 0xfb:
+ IP(regs) += 2;
+ ip = regs->eflags & TF_MASK;
+ set_IF(regs);
+ VM86_FAULT_RETURN;
+ ---------------------------------------*/
+
/* need this to avoid a fallthrough */
default:
return_to_32bit(regs, VM86_UNKNOWN);
@@ -509,6 +528,7 @@
case 0x9c:
SP(regs) -= 2;
IP(regs)++;
+ ip = regs->eflags & TF_MASK;
pushw(ssp, sp, get_vflags(regs));
VM86_FAULT_RETURN;

@@ -516,7 +536,7 @@
case 0x9d:
SP(regs) += 2;
IP(regs)++;
- CHECK_IF_IN_TRAP
+ CHECK_IF_IN_TRAP;
set_vflags_short(popw(ssp, sp), regs);
VM86_FAULT_RETURN;

@@ -537,13 +557,14 @@
SP(regs) += 6;
IP(regs) = popw(ssp, sp);
regs->cs = popw(ssp, sp);
- CHECK_IF_IN_TRAP
+ CHECK_IF_IN_TRAP;
set_vflags_short(popw(ssp, sp), regs);
VM86_FAULT_RETURN;

/* cli */
case 0xfa:
IP(regs)++;
+ ip = regs->eflags & TF_MASK;
clear_IF(regs);
VM86_FAULT_RETURN;

@@ -556,12 +577,15 @@
*/
case 0xfb:
IP(regs)++;
+ ip = regs->eflags & TF_MASK;
set_IF(regs);
VM86_FAULT_RETURN;

default:
return_to_32bit(regs, VM86_UNKNOWN);
}
+#undef CHECK_IF_IN_TRAP
+#undef VM86_FAULT_RETURN
}

/* ---------------- vm86 special IRQ passing stuff -----------------
*/

##################################################################

Description of another case

Also under DOSEMU, try to run "td.exe" and "td32.exe" (two
utilities of Borland C++ 5.02). Both will crash with the following
information:

ERROR: unexpected CPU exception 0x06 errorcode: 0x00000000 while in
vm86 (DOS)
Program=sigsegv.c, Line=250

_________________________________________________________
Do You Yahoo!?
Get your free @yahoo.com address at http://mail.yahoo.com

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