Virtual 8086 Mode: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
m (Added source highlighting to asm)
(Major edit. The original was incorrect. In order to enter V86, the data segment registers must be pushed onto the stack, otherwise there would be no way to set the before entry. Removed the code sample and abridged the intro.)
Line 3: Line 3:
==Entering V86==
==Entering V86==


The CPU is executing in virtual 86 mode when the VM bit (bit 17) is set in the EFLAGS register. If you want to enter virtual 86 mode you must set this bit to 1.
The CPU is executing in virtual 86 mode when the VM bit (bit 17) is set in the ''EFLAGS'' register. If you want to enter virtual 86 mode you must set this bit to 1.
A way of modifying the EFLAG register is to use the pushf and popf instructions. These instructions respectively push and pop the eflags register on the stack. So you could push the register, modify it on the stack and pop it. But the popf instruction doesn't modify bits 16 and 17 in the eflags register.
A way of modifying the EFLAGS register is to use the ''PUSHF'' and ''POPF'' instructions, but these instructions are for user space and cannot modify supervisor flags. The only way to set the VM flag is to use the iret instruction. This instruction is normally used to return from an interrupt. When ''IRET'' is called with the VM=1 in the stack ''EFLAGS'' (the context being returned to is V86), the interrupt stack frame will contain segments ''ES'', ''DS'', ''FS'', and ''GS'', so that they can be set before entry.
The only way to set the VM flag is to use the iret instruction. This instruction is normally used to return from an interrupt. When executing an iret, the CPU pops eip, cs, eflags, esp, ss from the stack and continues executing at the new eip.


A task gate can also be used to enter V86. This allows setting the segment registers. It is probably not necessary to do it this way unless the OS is using hardware multitasking.
<source lang="asm">
; you should declare this function as :
; extern void enter_v86(uint32_t ss, uint32_t esp, uint32_t cs, uint32_t eip);
enter_v86:
mov ebp, esp ; save stack pointer


[[File:Fig15-3.gif]]
push dword [ebp+4] ; ss
push dword [ebp+8] ; esp
pushfd ; eflags
or dword [esp], (1 << 17) ; set VM flags
push dword [ebp+12] ; cs
push dword [ebp+16] ; eip
iret
</source>


==V86 Problem==
==V86 Problem==

Revision as of 13:06, 6 March 2023

Virtual 8086 mode is a sub-mode of Protected mode. In short, Virtual 8086 mode is whereby the CPU (in protected mode) is running a "Emulated" 16bit Real Mode machine.

Entering V86

The CPU is executing in virtual 86 mode when the VM bit (bit 17) is set in the EFLAGS register. If you want to enter virtual 86 mode you must set this bit to 1. A way of modifying the EFLAGS register is to use the PUSHF and POPF instructions, but these instructions are for user space and cannot modify supervisor flags. The only way to set the VM flag is to use the iret instruction. This instruction is normally used to return from an interrupt. When IRET is called with the VM=1 in the stack EFLAGS (the context being returned to is V86), the interrupt stack frame will contain segments ES, DS, FS, and GS, so that they can be set before entry.

A task gate can also be used to enter V86. This allows setting the segment registers. It is probably not necessary to do it this way unless the OS is using hardware multitasking.

V86 Problem

The most common problem with v86 mode is that you can't enter Protected mode from inside of a v86 task. In other words, if you are running Windows or have emm386 in memory, you can't do a "raw" switch into protected mode (it causes an exception). DOS extenders worked around that problem using either VCPI or DPMI interfaces to switch into pmode (actually, promoting their V86 task as a 'regular' user task). For an OS programmer such interfaces are simply useless as they're part of another OS.

There are a few other more "technical" problems people have when using v86 mode, mostly because v86 has some instructions "emulated" by what's known as a v86-monitor program, as the CPU is in protected mode, some instructions are high up on the security/protection level and running those directly would cause no-end of trouble for the OS.

Detecting v8086

EFLAGS.VM is NEVER pushed onto the stack if the V86 task uses PUSHFD. You should check if CR0.PE=1 and then assume it's V86 if that bit is set.

detect_v86:
   smsw    ax
   and     eax,1           ;CR0.PE bit
   ret

VM mode detection is mainly useful when writing DOS extenders or other programs that could be started either in plain real mode or in virtual mode from a protected mode system. An 'ordinary' bootloader shouldn't worry about this since the BIOS will not set up VM86 to read the bootsector ;)

Usage

VM86 can be very useful if one needs access to BIOS functions while in Protected mode. It is in fact necessary in order to set up video mode, as many modern card/chipsets lack support for the VBE3 protected mode interface, so setting up a VM86 task that will perform the 'set video mode' call is the preferred method.

Kernels below 1MB

It has been suggested that you map your kernel to a 'high' logical address (e.g. 0xC0000000) to avoid VM86 tasks interfering with it. This is especially important with large kernels which leave no room for VM86 code below 1MB, or when larger programs are expected to run within the VM86 box.

If all that is needed is a BIOS interrupt wrapper, then the following should work:

  1. ensure that your 16bits code is on a separate page from any 32 bits code
  2. enable paging
  3. make kernel pages unwritable (and unreadable ?) for DPL3 and allow user-access only to those pages that contains your 16 bits code and pages that contains BIOS code or data.

Using VM86 for disk access

Though theoretically possible, it is probably not a good idea. Most BIOS disk access will include IRQ handlers, DMA transfers (uncontrollable from within your VM monitor), and may stick in VM86 task while the BIOS waits for an interrupt response while a 'good' driver would have let the CPU free for other processes.

Windows 9x suffered from system freezing during disk access. Often due to an INT13-through-VM86 problem.

See Also

Articles

Threads

External Links