Assembly 实模式BIOS例程和保护模式
我正在做一些操作系统实验。到目前为止,我所有的代码都使用实模式BIOS中断来操作硬盘和软盘。但是,一旦我的代码启用了CPU的保护模式,所有的实模式BIOS中断服务例程将不可用。我怎样才能拆装硬盘和软盘我现在需要做一些硬件驱动程序吗?如何启动?这是操作系统如此难以开发的原因之一吗 我知道硬件都是通过读写某些控制寄存器或数据寄存器来控制的。例如,我知道硬盘的命令块寄存器的范围是0x1F0到0x1F7但我想知道在PC平台上这么多不同硬件的注册地址是否相同?或者我必须在使用它们之前检测到吗?如何检测它们??? 由于我不确定如何在保护模式下R/W软盘或硬盘,我现在必须使用BIOS中断将所有必需的内核文件从软盘加载到内存中。但是如果我的内核文件超过实模式1M空间限制,我该怎么办? 对于任何回应,我深表感谢 更新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例程。也许我记错了。有人没记错吗?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!