10

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

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

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

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

更新

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

4

9 回答 9

5

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

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

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

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

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

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

于 2010-09-02T04:34:33.883 回答
2

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

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

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

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

于 2010-09-02T03:47:51.570 回答
1

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

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

于 2010-09-02T03:37:54.423 回答
1

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

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

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

于 2010-09-17T03:00:31.363 回答
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!
于 2013-01-27T06:18:32.603 回答
0

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

于 2011-11-29T09:52:56.600 回答
0

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

于 2010-09-02T03:33:35.130 回答
0

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

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

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

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

于 2010-09-10T15:07:23.350 回答
-1

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

于 2010-09-02T03:26:48.327 回答