【问题标题】:Real mode BIOS routine and Protected Mode实模式 BIOS 例程和保护模式
【发布时间】:2011-04-07 02:53:29
【问题描述】:

我正在做一些操作系统实验。到目前为止,我所有的代码都使用实模式 BIOS 中断来操作硬盘和软盘。但是一旦我的代码启用了 CPU 的保护模式,所有的实模式 BIOS 中断服务程序都将不可用。我怎样才能读/写硬盘和软盘? 我现在需要做一些硬件驱动程序吗?我该如何开始?这是操作系统如此难以开发的原因之一吗?

我知道硬件都是通过读取和写入某些控制或数据寄存器来控制的。例如,我知道硬盘的命令块寄存器范围从 0x1F0 到 0x1F7。 但是我想知道这么多不同硬件的寄存器地址在PC平台上是否相同?还是我必须在使用它们之前检测到这一点?如何检测它们??

由于我不确定如何在保护模式下读/写软盘或硬盘,我现在必须使用 BIOS 中断将所有必要的内核文件从软盘加载到内存中。但是如果我的内核文件超过实模式 1M 空间限制怎么办?

对于任何回复,我深表感谢。

更新

我隐约记得有一种方法可以先切换保护模式,然后再切换回实模式。然后我们可以在保护模式下使用 BIOS 例程。也许我记错了。有人没记错吗?

【问题讨论】:

  • 很多问题,只有一个问题。而且我没有看到任何与 C 或 C++ 作为语言有关的内容。
  • 嗨,詹斯。我用 c/c++ 标记它只是为了引起更多关注。现在我删除它。抱歉标记错误。

标签: assembly operating-system x86 x86-16 protected-mode


【解决方案1】:

V86:是的,但如果设置操作系统:

试试这个(专为长模式设计,但应该可以工作。我还没有测试过这个,我看不出它不能工作的原因。问题不是 nasm,它的 ld。)

LD H8s 16 位 ELF/aout 参考。这是从 GRUB 加载的标准。

我知道 32 位 CS 已关闭,我需要仔细检查它的位置。否则看起来没问题。

这很难找到代码。

-- ;修改为32位??

;this code is placed somewhere after 10000h
;-----we're in LONG MODE-----
  mov          dword [.stckptr], esp   ;first of all save stack
  sgdt         [.gdtv32]               ;save your gdt pointer
  lgdt         [.gdtv16]               ;load a new one
  sidt         [.idt32]                ;save your idt pointer
  lidt         [.idt16]                ;load real mode idt
  ;far jump in long mode is not possible, do a trick
  push         DESC_REAL
  push         @f-10000h               ;this is CS*10h, modify if needed!
  retfd
.stckptr:
  dd           0
  align        16
.gdtv32:
  dw           0
  dd           0
  align        16
.gdtv16:
  dw           .gdtend-.gdt-1
  dd           .gdt,0
  align        16
.gdt:
  dd           0,0                      ;null descriptor
DESC_DATA=8                                 ;descriptor in YOUR GDT (modify)
DESC_LONG=$-.gdt
  dd           00000000h,00209800h      ;32 bit  mode cs -MOD ME
DESC_REAL=$-.gdt
  dd           0000FFFFh,00009801h      ;16 bit real mode cs (modify base if needed!)
.gdtend:
  align        16
.idt32:
  dw           0
  dd           0
  align        16
.idt16:
  dw           3FFh
  dd           0
  USE16

;-----we're in COMPATIBLITY MODE-----
  ;disable paging and protmode at once
@@:   mov          eax, cr0
  and          eax, 7FFFFFFEh   
  mov          cr0, eax

  ;set up real mode segment registers and stack
  mov          esp, realmode_stack_top          ;modify it to your needs!
  xor          ax, ax
  mov          ds, ax
  mov          es, ax
  mov          fs, ax
  mov          gs, ax
  mov          ss, ax
  ;convert long mode rip to real mode cs:ip
  ;jmp CS:(pmode address)-CS*10h

  jmp          1000h:@f-10000h                  ;modify if needed!
;-----we're in REAL MODE-----
@@:   ;***********call some BIOS interrupt here**********
  mov          ax, 3
  int          10h


  ;switch back to long mode
  mov          eax, cr0
  or           eax, 80000001h
  mov          cr0, eax                         ;enable protmode and paging

  ;jmp         DESC_LONG:@f
  db           66h
  db           0EAh
  dd           @f
  dw           DESC_LONG
  USE32
;-----we're in protected MODE-----
@@:   lgdt         [cs:.gdtv32]                    ;restore gdt
  mov          ax, DESC_DATA                   ;read YOUR DATA descriptor to selectors
  mov          ds, ax
  mov          es, ax
  mov          fs, ax
  mov          gs, ax
  mov          ss, ax
  lidt         [.idt32]                        ;restore idt
  mov          rsp, qword [.stckptr]           ;restore stack
  ;must be a non rip-relative jump
  mov          eax, @f
  jmp          eax
@@:

  ;AS WE WERE!

【讨论】:

    【解决方案2】:

    有一组关于保护模式的教程here。 Tut15 和 tut16 在 v86 模式下有效运行 DOS 和 BIOS,所有中断都有效。

    【讨论】:

      【解决方案3】:

      如果您想要从 32 位模式读取硬盘驱动器(或 USB 密钥)的代码,您可以从我的操作系统项目 PwnOS 中找到一些代码。它不支持 DMA 或任何东西,但基本工作。具体来说,trunk/Core/IO/ATA Driver.asm 包含用于读取 ATA 设备的代码,例如硬盘驱动器(没有幻数!:D)

      我决定不编写用于编写设备的代码,因为我不想冒险,但它非常相似。这些规范可以在谷歌第一次搜索“cottontail os dev”时找到(你会想要 ATA/ATAPI-6 文档),但它们有点难以理解。

      如果您对此还有任何疑问,请随时提出。我也有设置为 64 位模式的代码,以及我专门为 OS 开发设计的汇编语言编辑器(搜索 Inventor IDE),因为它具有 16 个内置的汇编和链接位、32 位和 64 位代码在定义的地址和文件偏移量。这样一来,您就可以专注于您感兴趣的部分,而不是一无是处。

      【讨论】:

        【解决方案4】:

        该项目现在是一个旧项目,但犹他州的 OSKit 项目可能仍然在现代机器上运行,因为其他 1990 年代后期的操作系统仍然可以在今天的 PC 上找到 RAM 和磁盘驱动器? — 是与任何特定操作系统分开构建的设备驱动程序堆栈,因此您只需编写 C 代码即可开发自己的内核。

        这有点整洁;你可以编译“你好,世界”。在 C 中针对 OSKit 并获得一个可以启动并打印“Hello, world”的操作系统。然后停了下来。 :-)

        无论如何,如果您真的在做“操作系统实验”,您可能想尝试一下——或者至少使用它的代码作为如何启动和运行某些驱动程序的指南。当然,如果你真的做的不是“操作系统实验”而是更多的是“学习关于 x86 的晦涩事实”,那么它可能会做的比你想要的更多。 :-)

        http://www.cs.utah.edu/flux/oskit/

        【讨论】:

        • 嗨,布兰登。你给了我一个很好的线索!!我去看看那个网站。也许它可以让我从大量不同的设备驱动程序中解脱出来。我的重点是操作系统框架和一些主要部分,例如进程、调度、内存管理、文件格式、文件系统等。至少目前不是设备驱动程序。
        • 希望你发现项目还是可以编译的!我希望它继续得到维护,因为在裸硬件上运行 C 程序的能力是一种很酷的能力,如果你想得到一台旧机器并对其进行编程以非常快地完成一些单一的任务而没有操作系统“挡道”。
        • "这很简洁;你可以用 C 语言针对 OSKit 编译“Hello, world.”,然后得到一个你可以启动的操作系统,它会出现并打印“Hello, world.”然后停止。 :-)”——Linus 的姐姐站在那里,只是说“好”,因为 Linus 无法向她解释成就不是展示的内容,而是他做事的方式。
        【解决方案5】:

        虽然可以在保护模式和实模式之间切换,但几乎可以肯定不是您想要做的。这就是 286 上的操作方式(相当笨拙,因为它并没有刻意支持从保护模式切换回实模式)。但是,从 386 开始,他们添加了 V86 模式,可以在受保护模式下作为任务运行。

        如果您想在保护模式下使用 BIOS,这几乎可以肯定是做事的方式。您基本上可以创建一个 V86 任务,切换到它以使用 BIOS,然后切换回另一个任务以执行保护模式代码。

        如果你想玩这个,你可能想看看DJGPP,它是一个 DOS 扩展器(基本上,像我刚刚描述的一个程序,用于根据需要处理切换到/退出 V86 任务处理磁盘 I/O 等)以及一个相当旧版本的 gcc 的端口,以便您可以编写在其上运行的代码。

        DOS 扩展器的商业市场现在基本上已经死了,因此至少有一个以前的商业 DOS 扩展器 (HX) 现在可以作为开源使用。如果您打算使用它,您可能希望将它与OpenWatcom 编译器一起使用。

        编辑:就您如何读取超过 1 MB 的文件(例如)而言,它很简单但很笨拙:以块的形式读取数据,当您完成读取后,您可以重新映射内存,或者复制内容,把你读到的内容放到你真正想要的地方,然后再读另一个块。

        就硬件而言:很大程度上取决于您是否只是想要在某种程度上可以工作的东西,或者您是否想充分利用现有的硬件。只需使用基本的 IDE 端口,您就可以与几乎所有并非真正古老的硬盘进行通信——但要充分利用硬件还需要更多的工作。 IDE/ATAPI 驱动器使用了大约六种不同的 DMA 模式,每种模式的设置都略有不同。其中相当一部分已经足够老了,您可能并不关心它们,因此您可能只想直接支持几个最新的,而对于其他任何东西都回退到基本(非 DMA)传输。

        【讨论】:

          【解决方案6】:

          您的问题似乎不是如何与硬件通信(设备驱动程序会解决的问题),因为 BIOS 接口对您来说已经足够了。

          相反,您需要知道如何在保护模式环 0(它可以无限制地访问 BIOS 调用和所有其他特权指令)和保护模式环 3 之间进行通信,其中应用程序代码通常存在于此。这是一个系统调用。几乎所有架构都在特权模式下运行中断处理程序,因此软件中断是实现系统调用的一种方式,x86 还提供了为此目的优化的syscall 指令。

          当然,您可以使用平面内存模型运行环 0 中的所有内容,您可以直接访问所有内存。

          Ring 0/ring 3 是 x86 术语,但所有具有 MPU 的系统都支持特权模式的一些概念,它允许通过物理地址访问内存(对于拆分内存 I/O 架构,访问所有 I /O 空间)。

          【讨论】:

          • 我认为 BIOS(这是一个 16 位接口)在 32 位模式下根本无法工作,即使在 ring 0 中也是如此。
          • 很遗憾,您无需拥有产品 即可获得专利。并不是说康柏没有这样做,只是没有必要获得专利。
          【解决方案7】:

          如果您使用旧版 IDE,所有硬件都将以相同的方式进行通信 - 您不必担心编写自定义驱动程序(尽管如果您走得够远,您会发现即使他们都说他们遵循相同的规格,他们都有自己有趣的怪癖)

          http://www.t13.org/ 和 http://www.t10.org 是您可以找到相关规格的地方 - 如果您有勇气,也可以编写一个 SATA 驱动程序 - 您可以在英特尔网站 (http://www.intel.com/technology/serialata/ahci.htm) 上找到 AHCI 规格

          【讨论】:

            【解决方案8】:

            如果您正在编写一个操作系统,它确实需要为它需要使用的任何硬件配备设备驱动程序,包括存储设备。如果您想避免在这么早的阶段需要驱动程序,您可以考虑使用现有的引导加载程序,例如 grub,但最终您还是需要它们。

            【讨论】:

              【解决方案9】:

              ATAPI 设备使用相同的端口。您可以模拟 DPMI 以超过 1MB+64k 的限制,但是,学习保护模式。

              【讨论】:

                猜你喜欢
                • 2012-05-08
                • 2014-12-14
                • 1970-01-01
                • 2020-06-08
                • 1970-01-01
                • 2018-11-30
                • 2014-10-08
                • 2018-08-07
                • 1970-01-01
                相关资源
                最近更新 更多