Re: Using Linux+dosemu to install Windows

Stas Sergeev
2002-07-27T21:10:13Z

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

Hello.

Patrick J. LoPresti wrote:
>> The only good thing here is that the amount of progs that works on
>> 486 but not on 386 is very minor...
> But how annoying when you run into one :-).
I really don't think it is a major
advantage to have an ability to
pass the first stage of NT install... :)

OKey, I have found the bug.
According to this:
http://support.intel.com/design/intarch/techinfo/Pentium/instrefi.htm#89126
AC is cleared by an INT instruction
executed in real mode. As this flag
resides in the higher word of eflags,
it is not saved on stack so it gets
lost.
Two attached patches implements that
functionality. Then you can safely
remove the "BUG" stuff I think.
I have failed to find any docs on
how the hardware interrupts affects
the AC flag but I guess they don't,
otherwise it can be used only when
IF is not set.
ID flag is not affected so I guess
it gets cleared together with AC by
mistake.

> Couldn't you just tell people to use $_cpu=(80386) as a workaround?
> That would have the side-effect of protecting the AC bit, wouldn't it?
Yes, it would. And not, it is not a
side-effect, this is the main and
almost only difference with 80486
in dosemu.

>> Furthermore somehow it happens that if the signal was received while
>> AC is set, dosemu itself executes with AC set and crashs somewhere
>> in glibc functions due to exception 0x11.
> Is that not a bug in the emulator design? I mean, shouldn't *all* of
> the emulator's state be isolated from the emulated machine's?
Right, this is a main design problem
of dosemu which is that the DPMI code
is executed in the same address space
with dosemu. vm86 is separated however.
So DPMI code can do everything and if
dosemu have root privs, it can be easily
exploited by DPMI code.

> Would you accept such a patch?
It is not me who accepting patches
here, this is what the project
coordinators/maintainers does.
Visit
dosemu.sourceforge.net
and
www.sf.net/projects/dosemu
to find out who is responsible.

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

--- src/include/cpu.h Wed Jun 26 21:58:32 2002
+++ src/include/cpu.h Sat Jul 27 23:12:23 2002
@@ -198,6 +198,10 @@
#define set_TF() (_EFLAGS |= TF)
#define clear_TF() (_EFLAGS &= ~TF)
#define isset_TF() ((_EFLAGS & TF) != 0)
+ /* alignment flag */
+#define set_AC() (_EFLAGS |= AC)
+#define clear_AC() (_EFLAGS &= ~AC)
+#define isset_AC() ((_EFLAGS & AC) != 0)
/* Virtual Interrupt Pending flag */
#define set_VIP() (_EFLAGS |= VIP)
#define clear_VIP() (_EFLAGS &= ~VIP)
--- src/emu-i386/do_vm86.c Fri Jul 26 21:16:46 2002
+++ src/emu-i386/do_vm86.c Sun Jul 28 00:06:46 2002
@@ -506,6 +506,14 @@
pic_iret();
break;
case VM86_INTx:
+ /*
+ * AC flag gets cleared by the INT instruction and is not restored
+ * by IRET because it resides in the higher word of eflags and
+ * hence not saved in the stack.
+ * However we can't clear it in real_run_int() et al because
+ * it is not cleared by hardware interrupts (???)
+ */
+ clear_AC();
#ifdef USE_MHPDBG
mhp_debug(DBG_INTx + (VM86_ARG(retval) << 8), 0, 0);
#endif
--- src/dosext/dpmi/dpmi.c Sun Jun 23 23:42:23 2002
+++ src/dosext/dpmi/dpmi.c Sun Jul 28 00:07:35 2002
@@ -2240,6 +2227,14 @@
pic_iret();
break;
case VM86_INTx:
+ /*
+ * AC flag gets cleared by the INT instruction and is not restored
+ * by IRET because it resides in the higher word of eflags and
+ * hence not saved in the stack.
+ * However we can't clear it in real_run_int() et al because
+ * it is not cleared by hardware interrupts (???)
+ */
+ clear_AC();
#ifdef X86_EMULATOR
D_printf("DPMI: Return from vm86() for interrupt\n");
#endif

[-- Attachment #3: vm86_ac.diff --]
[-- Type: text/plain, Size: 550 bytes --]

--- linux/arch/i386/kernel/vm86.c Sat Jul 27 13:12:38 2002
+++ linux/arch/i386/kernel/vm86.c Sat Jul 27 23:56:27 2002
@@ -317,6 +317,11 @@
regs->eflags &= ~TF_MASK;
}

+static inline void clear_AC(struct kernel_vm86_regs * regs)
+{
+ regs->eflags &= ~AC_MASK;
+}
+
/* It is correct to call set_IF(regs) from the set_vflags_*
* functions. However someone forgot to call clear_IF(regs)
* in the opposite case.
@@ -471,6 +476,7 @@
IP(regs) = segoffs & 0xffff;
clear_TF(regs);
clear_IF(regs);
+ clear_AC(regs);
return;