<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>http://wiki.foofun.cn//index.php?action=history&amp;feed=atom&amp;title=Virtual_Monitor</id>
	<title>Virtual Monitor - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.foofun.cn//index.php?action=history&amp;feed=atom&amp;title=Virtual_Monitor"/>
	<link rel="alternate" type="text/html" href="http://wiki.foofun.cn//index.php?title=Virtual_Monitor&amp;action=history"/>
	<updated>2026-05-15T02:25:39Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.37.1</generator>
	<entry>
		<id>http://wiki.foofun.cn//index.php?title=Virtual_Monitor&amp;diff=1009&amp;oldid=prev</id>
		<title>Zhang3：创建页面，内容为“Virtual Monitor是在虚拟8086模式中设置和控制任务所需的一段代码。 == 要求 == * 必须启用保护模式 * 必须支持中断服务例程，更具体地说，必须支持GPF（一般保护异常）的工作异常处理程序。  == 相关工作 == 嗯，你主要有两种风格: 要么你可以创建一个独立的任务，它将在你的操作系统中在V86模式下…”</title>
		<link rel="alternate" type="text/html" href="http://wiki.foofun.cn//index.php?title=Virtual_Monitor&amp;diff=1009&amp;oldid=prev"/>
		<updated>2022-03-24T02:38:24Z</updated>

		<summary type="html">&lt;p&gt;创建页面，内容为“Virtual Monitor是在&lt;a href=&quot;/index.php?title=Virtual_8086_Mode&quot; title=&quot;Virtual 8086 Mode&quot;&gt;虚拟8086模式&lt;/a&gt;中设置和控制任务所需的一段代码。 == 要求 == * 必须启用&lt;a href=&quot;/index.php?title=Protected_mode&quot; class=&quot;mw-redirect&quot; title=&quot;Protected mode&quot;&gt;保护模式&lt;/a&gt; * 必须支持&lt;a href=&quot;/index.php?title=Interrupt_Service_Routines&quot; title=&quot;Interrupt Service Routines&quot;&gt;中断服务例程&lt;/a&gt;，更具体地说，必须支持GPF（一般保护异常）的工作异常处理程序。  == 相关工作 == 嗯，你主要有两种风格: 要么你可以创建一个独立的任务，它将在你的操作系统中在V86模式下…”&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Virtual Monitor是在[[Virtual 8086 Mode|虚拟8086模式]]中设置和控制任务所需的一段代码。&lt;br /&gt;
== 要求 ==&lt;br /&gt;
* 必须启用[[Protected mode|保护模式]]&lt;br /&gt;
* 必须支持[[Interrupt Service Routines|中断服务例程]]，更具体地说，必须支持GPF（一般保护异常）的工作异常处理程序。&lt;br /&gt;
&lt;br /&gt;
== 相关工作 ==&lt;br /&gt;
嗯，你主要有两种风格: 要么你可以创建一个独立的任务，它将在你的操作系统中在V86模式下作为其他任务单独运行，或者你可以暂时从当前任务切换到V86模式，执行一个简单的命令，然后回来。&lt;br /&gt;
&lt;br /&gt;
你需要知道的是，有些操作在V86模式下是被禁止的，但是像BIOS或DOS程序这样的遗留代码仍然会发出它们。 因此，你需要挂接GPF处理程序，以便它检测到来自虚拟模式任务的错误操作，并将其推迟到monitor执行。&lt;br /&gt;
如何设置虚拟任务？&lt;br /&gt;
&lt;br /&gt;
VM任务的设置与操作系统中任何“普通”进程的设置有一些区别：&lt;br /&gt;
&lt;br /&gt;
# 如果使用分页，则需要确保将[[BIOS]]、实模式[[IVT]]和任何与BIOS相关的数据(例如，0xb8000处的视频RAM)映射到预期的虚拟地址。 这可以简单地通过[[Identity Paging]]这个过程的第一兆字节的地址空间来完成，或者你可能希望将这些位置的私有副本提供给不同的VM任务。&lt;br /&gt;
# 在任务控制块（TCB-Task Control Block）中，当你为初始运行在堆栈映像上设置寄存器时，你必须初始化一些附加标志（请参阅Tim Robinson的教程）。 确保至少有EFLAGS=VM|IF，即0x20202。 ip/cs值必须位于可以通过实模式访问的区域内，并且最好使堆栈与某些0xffff地址对齐。&lt;br /&gt;
# 你还需要设置一些额外的字段：段寄存器，处理器返回vm86进程时会弹出堆栈。最好你也为vm86任务创建一个堆栈映像结构：比如vm86_context_t。&lt;br /&gt;
# 如果你想要允许V86代码在没有GPF的情况下访问端口，则需要将TSS扩展8192字节(足够65,536个端口，每个端口一位)，将I/O映射字段指向位图的开头，并将所有位设置为零。&lt;br /&gt;
&lt;br /&gt;
第二点注意: 对于从0x100000到0x1fffef (iirc) 的区域，你可以映射任何你想要的页面。 只有第一个mb需要进行身份映射。&lt;br /&gt;
&lt;br /&gt;
; 任务控制块（Task Control Block）&lt;br /&gt;
: 内核用于记录任务信息的结构: 处理器注册转储，页面目录，运行时间，优先级等。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 一般保护故障（GPF-General Protection Faults）的作用 ==&lt;br /&gt;
基本上，每当CPU需要Virtual Monitor的干预时，它都会引发GPF异常。一旦检测到异常是由虚拟任务引起的，就调用Monitor的GPF处理程序。&lt;br /&gt;
&lt;br /&gt;
在那里，你需要阅读当前尝试的指令 (注意诸如ES:，REPNE等前缀)，并决定如何模仿它...&lt;br /&gt;
&lt;br /&gt;
需要支持的操作码包括：&lt;br /&gt;
&lt;br /&gt;
* 0x9C（pushf）和 0x9D（popf）&lt;br /&gt;
* 0xCD(int nn)和 0xCF(iret)&lt;br /&gt;
* INx/OUTx (0xE4-0xE7，0x6C-0x6F，0xEC-0xEF)，除非你相应地设置了io权限bitmap/iopl&lt;br /&gt;
* 0xFA（cli）和0xFB（sti）&lt;br /&gt;
&lt;br /&gt;
==我应该如何继续？==&lt;br /&gt;
&lt;br /&gt;
你的Monitor将不得不执行例如伪造中断，检查指令等操作。 一个好的做法是编写两个“核心”函数，这些函数将执行简单的操作，比如在虚拟任务的堆栈上推送一个值，在给定的段读取一个字：偏移量（比如[[Real Mode|实模式]]），从虚拟CS:IP获取当前执行的字节，等等。&lt;br /&gt;
&lt;br /&gt;
例如，Chris Giese的Monitor中的此类方法列表包括&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;unsigned peekb(unsigned seg, unsigned off);&amp;lt;/tt&amp;gt; 它将返回位于seg:off的字节&lt;br /&gt;
* &amp;lt;tt&amp;gt;unsigned peekw(unsigned seg, unsigned off);&amp;lt;/tt&amp;gt; 同上返回word字&lt;br /&gt;
* &amp;lt;tt&amp;gt;void pokeb(unsigned seg, unsigned off, unsigned val);&amp;lt;/tt&amp;gt; 它将向seg：off写入一个字节&lt;br /&gt;
* &amp;lt;tt&amp;gt;void pokew(unsigned seg, unsigned off, unsigned val);&amp;lt;/tt&amp;gt; 同上写入word&lt;br /&gt;
* &amp;lt;tt&amp;gt;void v86_push16(uregs_t *regs, unsigned value);&amp;lt;/tt&amp;gt; 这将调整寄存器映像，在堆栈上推送一个（16位）值。&lt;br /&gt;
* &amp;lt;tt&amp;gt;void v86_int(uregs_t *regs, unsigned int_num);&amp;lt;/tt&amp;gt; 它实际上在vmode中调用INT。&lt;br /&gt;
&lt;br /&gt;
== 没有IF相关指令的硬件中断 ==&lt;br /&gt;
&lt;br /&gt;
你可以使用两种intel认同的技巧：&lt;br /&gt;
&lt;br /&gt;
* 初始化时设置IOPL=3。 这不会影响IN/OUT指令，而是允许VM任务自己弄IF标志。 注意irq和软件中断将直接进入IDT (例如，IVT被忽略)， 因此，你可能需要在pm IRQ处理程序中编写代码，根据该IVT编辑CS:IP值。&lt;br /&gt;
* 使用 “虚拟模式扩展（Virtual Mode Extensions）”，这将允许你给TSS一个 “中断重定向位图（interrupt redirection bitmap）”，告诉哪个中断应该使用IVT在虚拟模式下处理，哪个中断应该使用IDT在保护模式下处理。 不过，在QEMU上不能使用VME。&lt;br /&gt;
&lt;br /&gt;
==另见==&lt;br /&gt;
===外部链接===&lt;br /&gt;
* http://alexfru.chat.ru/epm.html#v86monitor&lt;br /&gt;
* http://osdev.berlios.de/v86.html - TimRobinson's vm86-tutorial (dead link, available on archive.org at https://web.archive.org/web/20090719085533/http://osdev.berlios.de/v86.html)&lt;br /&gt;
* http://my.execpc.com/~geezer/osd/pmode/v86mm.zip - Chris Giese's YAV86MM&lt;br /&gt;
* http://oslib.cvs.sourceforge.net/viewvc/oslib/oslib/xlib/vm86.c?view=markup - OSLib's basic vm86 code (pages-tuning required)&lt;br /&gt;
&lt;br /&gt;
=== 论坛 ===&lt;br /&gt;
* [[Topic:9943|Problem with v86 mode and INT n instruction]]&lt;br /&gt;
* [[Topic:10287|Issues while implementing VM86 support]]&lt;br /&gt;
&lt;br /&gt;
[[Category:X86 CPU]]&lt;/div&gt;</summary>
		<author><name>Zhang3</name></author>
	</entry>
</feed>