Info written by Hans
<lermen@fgan.de>
to describe the virtual flags used by DOSEmu
DOS sees only IF, but IF will never really set in the CPU flagregister,
because this would block Linux. So Linus maintains a virtual IF (VIF),
which he sets and resets accordingly to CLI, STI, POPFx, IRETx.
Because the DOS programm cannot look directly into the flagregister
(exception the low 8 bits, but the IF is in bit 9), it does not
realize, that the IF isn't set. To see it, it has to perform
PUSHF and look at the stack.
Well, but PUSHF or INTxx is intercepted by vm86 and then Linus looks
at his virtual IF to set the IF on the stack.
Also, if IRETx or POPFx happen, Linus is getting the IF from the
stack, sets VIF accordingly, but leaves the real IF untouched.
Now, how is this realized? This is a bit more complicated.
We have 3 places were the eflag register is stored in memory:
vm86s.regs.eflags
in user space, seen by dosemu
current->tss.v86flags
virtual flags, macro VEFLAGS
current->tss.vm86_info->regs.eflags
the real flags, CPU reg. VM86
The last one is a kernel space copy of vm86_struct.regs.eflags.
Also there are some masks to define, which bits of the flag
should be passed to DOS and which should be taken from DOS:
current->tss.v86mask
CPU model dependent bits
SAFE_MASK (0xDD5)
used the way to DOS
RETURN_MASK (0xDFF)
used the way from DOS
When sys_vm86 is entered, it first makes a copy of the whole
vm86_struct vm86s (containing regs.eflags) and saves a pointer to it
to current->tss.vm86_info. It merges the flags from 32-bit user
space (NOTE: IF is always set) over SAFE_MASK and current->tss.v86mask
into current->tss.v86mask. From this point on, all changes to
VIF, VIP (virtual interrupt pending) are only done in VEFLAGS.
To handle the flag setting there are macros within vm86.c,
which do the following:
set_IF, clear_IF
only modifies VEFLAGS;
clear_TF
sets a bit in the real flags;
set_vflags(x)
set flags x over SAFE_MASK to real flags
(IF is not touched)
x=get_vflags
returns real flags over RETURN_MASK and translates
VIF of VEFLAGS to IF in x;
When it's time to return from vm86() to user space, the real flags
are merged together with VIF and VIP from VEFLAGS and put into
the userspace vm86s.regs.eflags. This is done by save_v86_state()
and this does not translate the VIF to IF, it should be as it
was on entry of sys_vm86: set to 1.
Now what are we doing with eflags in dosemu ?
Well, this I don't really know. I saw IF used (told it Larry), I saw
VIF tested an set, I saw TF cleared, and NT flag e.t.c.
But I know what Linus thinks that we should do:
Always interpret and set VIF, and let IF untouched, it will nevertheless
set to 1 at entry of sys_vm86.
How I think we should proceed? Well this I did describe in my last mail.
,,,, and this from a follow-up mail:
NOTE VIF and VIP in DOS-CPU-flagsregister are inherited from 32-bit,
so actually they are both ZERO.
On return to 32-bit, only VIF will appear in vm86s.regs.eflags !
VIP will be ZERO, again: VIP will be used only once !!!!
[ ,,, ]
I have to add, that VIP will be cleared, because it is not in any
of the masks of vm86.