Reputation: 340
I've read through section 20 of volume 3 of the Intel Software Developer's Manual, which explains the workings of virtual-8086 mode, including the use of the VIF and VIP flags. However, I'm still confused about some things.
The VIF flag is used as a surrogate for the IF flag, so that an 8086 emulator (which is presumably some user-space program) can receive maskable hardware interrupts even if the real-mode program it's emulating doesn't want to.
The VIP is used as a space to mark when an interrupt is received. According to the manual, if the processor receives a maskable interrupt, but the program being emulated doesn't want to receive them (so the VIF flag would be cleared), the emulator should set the VIP flag, wait until the emulated program sets the IF flag, and then handle the interrupt.
Why do we wait to handle the interrupt instead of handling it immediately? Are interrupts on a real-mode 8086 deferred rather than ignored?
Additional question—the processor generates a #GP when the VIP is set and the program enables interrupts (through STI etc.) But a #GP could be generated while the VIP flag is set in multiple ways—e.g. through an invalid memory access. The manual doesn't make any mention of checking what the cause of the #GP was, so should the program process the pending interrupts regardless of whether the IF was being set?
Edit: Okay, so I see part of my confusion—it's the kernel which needs to keep the IF set. In that case I should rather ask for #2—why do we wait to handle the interrupt instead of ignoring it entirely?
Upvotes: 1
Views: 801
Reputation: 331
I'm having fun on writing a DPMI server for DOS and I've done some homework.
1.Modern OSes don't allow any 'normal' (lower-privileged, aka Ring3) application to disable interrupts, for multitasking & performance reason. But a DOS program usually does that, because DOS is single tasked, and allow programs to operate on the interrupt flag (IF) directly. So OSes like win3.x/9x use 'virtual interrupts' to allow a (virtual 8086 or protected mode such as DOS4GW) DOS program operate on the virtual IF, while the real IF is always ON
. the virtual IF can be implemented in pure software, kept in kernel for each DOS program, when STI/CLI triggers #GP and the kernel set the virtual IF for the program. VIF/VIP is just a hardware level boost (from Pentium+) that avoids #GP on STI/CLI, but set VIF on the fly and gives better performance.
2.A DOS application may have handler installed for a interrupt, it only disable IF temporarily, so it's obvious that OSes won't, and never shouldn't ignore any interrupts that they're aware of. When a DOS application requests interrupt disabled, what really happens is the kernel doesn't wait for the interrupts(for performance reason), but handles it internally & immediately (by drivers), and check the virtual IF for the DOS program, if it disables interrupts, the kernel doesn't send the interrupt to the program immediately, but delayed, until the VIF for the program is on, and send it in the #GP exception.
3.Intel 64 and IA-32 Architectures Software Developers' manual, Vol.3, chapter 20, 20-4 "protected mode virtual interrupts":
If the protected-mode virtual interrupt extension is enabled, CPL = 3,
and the processor finds that both the VIF and VIP flags are set at the beginning of
an instruction, a general-protection exception is generated.
Note the phrase at the beginning of an instruction
, which means at this point, the instruction is not executed yet, and this #GP happens before any other protection violation #GPs thus can be distinguished.
Upvotes: 1
Reputation: 410
As question 1 is already answered, lets deal a bit with 2 and 3.
Are interrupts on a real-mode 8086 deferred rather than ignored?
It is important to note that the execution mode (real or protected) doesn't have much to do with it. CLI indeed ignores the interrupt, it doesn't defer anything. But the interrupt handling is very complex, and, in most configurations, the interrupting device and/or the interrupt controller will make sure the INT pin of the CPU remains active until you did STI and serviced the interrupt. So, with a great over-simplification, you can say that CLI defers the interrupt. But you won't find such statement in the CPU manual, because it is done with the external logic, and depends on many configurable things.
But a #GP could be generated while the VIP flag is set in multiple ways—e.g. through an invalid memory access.
In v86 mode there are quite a lot of GPF sources, for example port IO instructions, when IOPL is less than 3. The only reliable way of distinguishing them is to look up the faulted opcode, and simulate it. Its not possible to, for example, set VIF and raise GPF only after that, as the exception should leave no observable effects of the faulted instruction, allowing the software to cleanly simulate it.
Upvotes: 2
Reputation: 12455
The reason for this is covered in section 20.3.2: "Existing 8086 programs commonly set and clear the IF flag in the EFLAGS register to enable and disable maskable hardware interrupts." When running such an application in virtual-8086 mode under a modern OS, the OS is not going to allow the 8086 program to disable interrupts in the system. Thus the IF flag needs to remain under control of the OS, and it must be virtualized on behalf of the virtual-8086 program. Use of the VIF and VIP flags "eliminat[es] the need for all IF related operations (such as PUSHF, POPF, CLI, and STI instructions) to trap to the virtual-8086 monitor."
The interrupt cannot be delivered to the virtual-8086 mode program if it has executed CLI to clear IF (which has the effect of clearing VIF).
That's a good question. It seems to me that the processor should set VIF before generating #GP; then the GP handler in the virtual-8086 monitor can easily see that VIP and VIF are both set. This is the described behavior for when VIF is set by a POPF or IRET; I don't know why STI behaves differently.
Upvotes: 4