Assembly 实模式BIOS例程和保护模式

Assembly 实模式BIOS例程和保护模式,assembly,operating-system,x86,x86-16,protected-mode,Assembly,Operating System,X86,X86 16,Protected Mode,我正在做一些操作系统实验。到目前为止,我所有的代码都使用实模式BIOS中断来操作硬盘和软盘。但是,一旦我的代码启用了CPU的保护模式,所有的实模式BIOS中断服务例程将不可用。我怎样才能拆装硬盘和软盘我现在需要做一些硬件驱动程序吗?如何启动?这是操作系统如此难以开发的原因之一吗 我知道硬件都是通过读写某些控制寄存器或数据寄存器来控制的。例如,我知道硬盘的命令块寄存器的范围是0x1F0到0x1F7但我想知道在PC平台上这么多不同硬件的注册地址是否相同?或者我必须在使用它们之前检测到吗?如何检测它们

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

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

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

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

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

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

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

< P>如果使用传统IDE,所有的硬件都会以相同的方式进行通信——你不必担心编写自定义驱动程序。(如果你走得够远,你会发现,尽管他们都说他们遵循相同的规范,但他们都有自己的有趣怪癖)


在这里你可以找到相关的规范——如果你觉得勇敢,你也可以编写SATA驱动程序——你可以在英特尔网站上找到AHCI规范()

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

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

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

环0/环3是x86术语,但所有带有MPU的系统都支持某种特权模式的概念,允许通过物理地址访问内存(对于拆分内存I/O体系结构,访问所有I/O空间).

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

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

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

DOS扩展器的商业市场现在基本上已经死了,所以至少有一个以前的商业DOS扩展器()现在可以作为开源软件使用。如果你想玩这个,你可能会想在编译器中使用它

编辑:至于如何读取超过1MB的文件(例如),这很简单但很笨拙:分块读取数据,当您完成一次读取时,您要么重新映射内存,要么复制内容,以将所读取的内容获取到您真正想要的位置,然后再读取另一个块


就硬件而言:这在很大程度上取决于你是想要某种程度上可以工作的东西,还是你想充分利用现有的硬件。只需使用基本的IDE端口,你就可以与几乎所有不太古老的硬盘进行对话,但充分利用硬件是相当困难的IDE/ATAPI驱动器使用了大约六种不同的DMA模式,每种模式的设置都略有不同。其中有相当一部分已经足够旧了,您可能不关心它们,因此您可能只想直接支持两种最新的模式,而对于其他模式,请使用基本(非DMA)模式传输。

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


它有点简洁;你可以在C语言中针对OSKit编译“Hello,world.”,然后得到一个操作系统,你可以启动它并打印“Hello,world.”,然后停止。:-)

;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!