Virtual 8086 Mode

来自osdev
跳到导航 跳到搜索

虚拟8086模式是保护模式的子模式。 简而言之,虚拟8086模式是在保护模式下运行的CPU“模拟(Emulated)”得到的16位实模式机器。

进入V86

当在EFLAGS寄存器中设置VM位(位17)为1时,CPU在虚拟86模式下执行。 如果要进入虚拟86模式,则必须将此位设置为1。 修改EFLAG寄存器的一种方法是使用pushf和popf指令。 这些指令分别推送和弹出堆栈上的eflags寄存器。 所以你可以向栈推入寄存器,在堆栈上修改它,然后弹出它。 但是popf指令不会修改eblags寄存器中的位16和17。 设置VM标志的唯一方法是使用iret指令。 此指令通常用于从中断返回。 执行iret时,CPU会从堆栈中弹出eip,cs,eflags,esp,ss,并在新的eip上继续执行。

; 您应该将此函数声明为:
; extern void enter_v86(uint32_t ss, uint32_t esp, uint32_t cs, uint32_t eip);
enter_v86:
   mov ebp, esp               ; 保存堆栈指针

   push dword  [ebp+4]        ; ss
   push dword  [ebp+8]        ; esp
   pushfd                     ; eflags
   or dword [esp], (1 << 17)  ; 设置VM标志
   push dword [ebp+12]        ; cs
   push dword  [ebp+16]       ; eip
   iret

V86问题

v86模式最常见的问题是无法从v86任务内部进入保护模式。 换句话说,如果您正在运行Windows或内存中有emm386,则不能将“原始(raw)”切换到保护模式(这会导致异常)。 DOS extenders使用VCPI或DPMI接口切换到pmode来解决这个问题 (实际上,将其V86任务提升为 “常规” 用户任务)。 对于操作系统程序员来说,这样的接口毫无用处,因为它们是DOS操作系统的一部分。

人们在使用v86模式时还有一些其他的“技术”问题,主要是因为v86有一些指令是由v86监控程序(v86-monitor program)“模拟”产生的,因为CPU处于保护模式,有些指令在安全/保护级别上很高,直接运行这些指令会给操作系统带来无穷无尽的麻烦。

检测V8086

EFLAGS.在V86任务中使用PUSHFD,VM永远不会被推到栈上。 您需要首先检查CR0。PE=1,如果该位被设置1,才假定它是V86。(译者注:CR0的PE位是保护模式启用位)

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

VM模式检测主要用于编写DOS extenders或其他程序,这些程序可以从受保护模式系统以纯实模式或虚拟模式启动。 “普通的”bootloader不应该担心这一点,因为BIOS不会设置VM86来读取引导扇区。  ;)

用法

如果需要在保护模式下访问BIOS功能,VM86非常有用。 实际上,例如设置视频模式(video mode)时是必要的,因为许多现代的视频卡卡/芯片组缺乏对VBE3保护模式接口的支持, 因此,设置一个VM86任务来执行“设置视频模式”调用是首选方法。

1MB以下的内核

建议将内核映射到“高”逻辑地址(例如0xC0000000),以避免VM86任务干扰它。 对于1MB以下没有空间容纳VM86代码的大型内核,或者当更大的程序预计将在VM86机器中运行时,这一点尤其重要。

如果进入VM86模式,所需要的只是BIOS中断包装器,则应执行以下操作:

  1. 确保16位代码与任何32位代码位于单独的页面上
  2. 启用分页
  3. 使DPL3的内核页面不可写 (也不可读?),并仅允许用户访问包含16位代码的页面和包含BIOS代码或数据的页面。

使用VM86访问磁盘

虽然理论上是可能的,但这可能不是一个好主意。大多数BIOS磁盘访问将包括IRQ处理程序、DMA传输(无法从VM monitor中进行控制)、 并且可能会在BIOS等待中断响应时停留在VM86任务中,而 “好的” 驱动程序应使CPU可以用于其他进程。

Windows 9x在访问磁盘时遭遇系统冻结。 通常是由于INT13-through-VM86问题导致的。

另见

文章

论坛主题

外部链接

de:Virtual_8086_Mode