Virtual Monitor

来自osdev
Zhang3讨论 | 贡献2022年3月24日 (四) 02:38的版本 (创建页面,内容为“Virtual Monitor是在虚拟8086模式中设置和控制任务所需的一段代码。 == 要求 == * 必须启用保护模式 * 必须支持中断服务例程,更具体地说,必须支持GPF(一般保护异常)的工作异常处理程序。 == 相关工作 == 嗯,你主要有两种风格: 要么你可以创建一个独立的任务,它将在你的操作系统中在V86模式下…”)
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)
跳到导航 跳到搜索

Virtual Monitor是在虚拟8086模式中设置和控制任务所需的一段代码。

要求

相关工作

嗯,你主要有两种风格: 要么你可以创建一个独立的任务,它将在你的操作系统中在V86模式下作为其他任务单独运行,或者你可以暂时从当前任务切换到V86模式,执行一个简单的命令,然后回来。

你需要知道的是,有些操作在V86模式下是被禁止的,但是像BIOS或DOS程序这样的遗留代码仍然会发出它们。 因此,你需要挂接GPF处理程序,以便它检测到来自虚拟模式任务的错误操作,并将其推迟到monitor执行。 如何设置虚拟任务?

VM任务的设置与操作系统中任何“普通”进程的设置有一些区别:

  1. 如果使用分页,则需要确保将BIOS、实模式IVT和任何与BIOS相关的数据(例如,0xb8000处的视频RAM)映射到预期的虚拟地址。 这可以简单地通过Identity Paging这个过程的第一兆字节的地址空间来完成,或者你可能希望将这些位置的私有副本提供给不同的VM任务。
  2. 在任务控制块(TCB-Task Control Block)中,当你为初始运行在堆栈映像上设置寄存器时,你必须初始化一些附加标志(请参阅Tim Robinson的教程)。 确保至少有EFLAGS=VM|IF,即0x20202。 ip/cs值必须位于可以通过实模式访问的区域内,并且最好使堆栈与某些0xffff地址对齐。
  3. 你还需要设置一些额外的字段:段寄存器,处理器返回vm86进程时会弹出堆栈。最好你也为vm86任务创建一个堆栈映像结构:比如vm86_context_t。
  4. 如果你想要允许V86代码在没有GPF的情况下访问端口,则需要将TSS扩展8192字节(足够65,536个端口,每个端口一位),将I/O映射字段指向位图的开头,并将所有位设置为零。

第二点注意: 对于从0x100000到0x1fffef (iirc) 的区域,你可以映射任何你想要的页面。 只有第一个mb需要进行身份映射。

任务控制块(Task Control Block)
内核用于记录任务信息的结构: 处理器注册转储,页面目录,运行时间,优先级等。


一般保护故障(GPF-General Protection Faults)的作用

基本上,每当CPU需要Virtual Monitor的干预时,它都会引发GPF异常。一旦检测到异常是由虚拟任务引起的,就调用Monitor的GPF处理程序。

在那里,你需要阅读当前尝试的指令 (注意诸如ES:,REPNE等前缀),并决定如何模仿它...

需要支持的操作码包括:

  • 0x9C(pushf)和 0x9D(popf)
  • 0xCD(int nn)和 0xCF(iret)
  • INx/OUTx (0xE4-0xE7,0x6C-0x6F,0xEC-0xEF),除非你相应地设置了io权限bitmap/iopl
  • 0xFA(cli)和0xFB(sti)

我应该如何继续?

你的Monitor将不得不执行例如伪造中断,检查指令等操作。 一个好的做法是编写两个“核心”函数,这些函数将执行简单的操作,比如在虚拟任务的堆栈上推送一个值,在给定的段读取一个字:偏移量(比如实模式),从虚拟CS:IP获取当前执行的字节,等等。

例如,Chris Giese的Monitor中的此类方法列表包括

  • unsigned peekb(unsigned seg, unsigned off); 它将返回位于seg:off的字节
  • unsigned peekw(unsigned seg, unsigned off); 同上返回word字
  • void pokeb(unsigned seg, unsigned off, unsigned val); 它将向seg:off写入一个字节
  • void pokew(unsigned seg, unsigned off, unsigned val); 同上写入word
  • void v86_push16(uregs_t *regs, unsigned value); 这将调整寄存器映像,在堆栈上推送一个(16位)值。
  • void v86_int(uregs_t *regs, unsigned int_num); 它实际上在vmode中调用INT。

没有IF相关指令的硬件中断

你可以使用两种intel认同的技巧:

  • 初始化时设置IOPL=3。 这不会影响IN/OUT指令,而是允许VM任务自己弄IF标志。 注意irq和软件中断将直接进入IDT (例如,IVT被忽略), 因此,你可能需要在pm IRQ处理程序中编写代码,根据该IVT编辑CS:IP值。
  • 使用 “虚拟模式扩展(Virtual Mode Extensions)”,这将允许你给TSS一个 “中断重定向位图(interrupt redirection bitmap)”,告诉哪个中断应该使用IVT在虚拟模式下处理,哪个中断应该使用IDT在保护模式下处理。 不过,在QEMU上不能使用VME。

另见

外部链接

论坛