
通过[自制操作系统01]计算机启动过程的核心解释和[自制操作系统02]环境准备和引导区域的实现,我们实现了最简单的操作系统(仅一条机器指令).
今天,我们必须更进一步,逐步改进这个最简单的操作系统. 之前最简单的操作系统写在引导区的512字节中. 这么小的空间将来肯定不会用于编写操作系统的代码,因此它的主要任务是将更多数据从硬盘读取到内存内部,然后跳转到内存位置以开始运行.
我必须回顾每节课中提到的四个跳跃:
一次跳转: 按下电源按钮,CPU将强制将PC寄存器的值初始化为0xffff0,该位置是BIOS程序的入口地址. 两次跳转: 入口地址是跳转指令,跳转到0xfe05b的位置,开始执行三个跳转: 在执行了一些硬件检查之后,最后一步是将引导区域的内容加载(复制)到内存0x7c00,并跳转到它. 四级跳转: 引导区中的代码主要用于加载操作系统内核并跳转到加载点
事实上,我们可以无限跳. 只要某个链接的任务很复杂,我们就可以分两步走. 但是也完全有可能停止从第三次跳转中跳出,并将操作系统所需的所有指令和数据从硬盘加载到内存中并执行,但这显然不好.
1. 代码概述
我们别说什么,首先发送一份本章完整代码的副本
mbr.asm
;----BIOS把启动区加载到内存的该位置,所以需设置地址偏移量
section mbr vstart=0x7c00
;----设置堆栈地址
mov sp,0x7c00
;----卷屏中断,目的是清屏
mov ax,0x0600
mov bx,0x0700
mov cx,0
mov dx,0x184f
int 0x10
;----直接往显存中写数据
mov ax,0xb800
mov gs,ax
mov byte [gs:0x00],'m'
mov byte [gs:0x02],'b'
mov byte [gs:0x04],'r'
;----读取硬盘(第2扇区)并加载到内存(0x900)
mov eax,0x02 ;起始扇区lba地址,LBA=(柱面号*磁头数+磁头号)*扇区数+扇区编号-1
mov bx,0x900 ;写入的内存地址,之后用
mov cx,4 ;待读入的扇区数
call read_disk
jmp 0x900
;----读硬盘方法,eax为lba扇区号,bx为待写入内存地址,cx为读入的扇区数
read_disk:
mov esi,eax ;备份
mov di,cx ;备份
;第一步,设置要读取的扇区数
mov dx,0x1f2
mov al,cl
out dx,al
mov eax,esi ;恢复
;第二步,设置LBA地址
mov cl,8
;0-7位写入0x1f3
mov dx,0x1f3
out dx,al
;8-15位写入0x1f4
mov dx,0x1f4
shr eax,cl
out dx,al
;16-23位写入0x1f5
mov dx,0x1f5
shr eax,cl
out dx,al
;24-27位写入0x1f6
mov dx,0x1f6
shr eax,cl
and al,0x0f ;lba的24-27位
or al,0xe0 ;另外4位为1110,表示lba模式
out dx,al
;第三步,写入读命令
mov dx,0x1f7
mov al,0x20
out dx,al
;第四步,检测硬盘状态
.not_ready:
nop
in al,dx
and al,0x88 ;第4位为1表示准备好,第7位为1表示忙
cmp al,0x08
jnz .not_ready
;第五步,读数据
mov ax,di
mov dx,256
mul dx
mov cx,ax
mov dx,0x1f0
.go_on_read:
in ax,dx
mov [bx],ax
add bx,2
loop .go_on_read
ret
;----512字节的最后两字节是启动区标识
times 510-($-$$) db 0
db 0x55,0xaa
loader.asm
section loader vstart=0x900
mov byte [gs:0xa0],'l'
mov byte [gs:0xa2],'o'
mov byte [gs:0xa4],'a'
mov byte [gs:0xa6],'d'
mov byte [gs:0xa8],'e'
mov byte [gs:0xaa],'r'
Makefile
mbr.bin: mbr.asm
nasm -I include/ -o out/mbr.bin mbr.asm -l out/mbr.lst
loader.bin: loader.asm
nasm -I include/ -o out/loader.bin loader.asm -l out/loader.lst
os.raw: mbr.bin loader.bin
../bochs/bin/bximage -hd -mode="flat" -size=60 -q target/os.raw
dd if=out/mbr.bin of=target/os.raw bs=512 count=1
dd if=out/loader.bin of=target/os.raw bs=512 count=4 seek=2
brun:
make install
make only-bochs-run
only-bochs-run:
../bochs/bin/bochs -f ../bochs/bochsrc.disk -q
install:
make clean
make -r os.raw
clean:
rm -rf target/*
rm -rf out/*
第二,磁盘

如果您粗读代码,至少可以在mbr.asm中知道该代码. 前半部分是在屏幕上输出mbr字符串. 在上一课中,以直观的方式编写了此文档,以使操作系统降至最低. 代码,可选. 后半部分只是读取硬盘数据的多个扇区,将其加载到内存中的某个位置,然后跳转到该位置. 这是mbr的关键和责任.
然后如何读取硬盘中的数据,它从磁盘的结构开始. 我对硬件不是很了解,所以我只能提出一个大致的想法. 硬盘是一种磁盘,分为硬盘和软盘. 但是它们的逻辑结构是相同的:
拼盘
头(头)
曲目(曲目)
部门
汽缸(汽缸)

我不想担心它如何移动. 我只需要弄清楚. 确定磁头,圆柱体和扇区后,将确定512字节的区域. 够了这是硬盘的CHS表示法,即圆柱(圆柱),磁头(磁头),扇区(扇区),只要知道硬盘的CHS数量,就可以确定硬盘的容量,硬盘的容量=柱面数×磁头数×扇区数×512B.
如果您不考虑这种物理结构,则硬盘实际上由n个多个512字节区域组成. 我们可以从0开始编号,然后每512字节加一个,因此我们完全不需要考虑任何扇区. 圆柱体,这是我的最爱(似乎是软件工程师的想法),这种方法称为LBA表示法.
LBA = (柱面号 * 磁头数 + 磁头号) * 扇区数 + 扇区编号 - 1
因此,如果CPU需要处理硬盘,则它必须使用CHS表示法,至少要告诉硬盘柱面号,磁头和扇区号,或使用LBA表示法来告诉硬盘LBA号,然后给硬盘一个读取的Still write信号. 硬盘制造商有数千万,而CPU制造商也不同. 自然,必须有一个硬盘接口标准. 该标准称为ATA标准,也可以通常称为IDE硬盘接口技术标准. 该标准总共可以下载三卷AT_Attachment_with_Packet_Interface的内容,但是我们使用的并不多. 我找到了一篇相当真实的中文版论文“ IDE接口硬盘读写技术”. 这基本上是足够的.
三,IDE硬盘接口技术
CPU和设备通过IO接口进行交互,所以核心是该技术标准定义的IO接口是什么,它们的功能是什么

I / O地址读取(主机从硬盘读取数据)写入(主机数据写入硬盘)
1F0H
数据寄存器
数据寄存器
1F1H
错误寄存器(只读寄存器)
特征寄存器
1F2H
扇区计数寄存器
扇区计数寄存器
1F3H
扇区号寄存器或LBA块地址0〜7
扇区号或LBA块地址0〜7
1F4H

轨道号或LBA块地址的低8位8〜15
轨道号或LBA块地址的低8位8〜15
1F5H
轨道号或LBA块地址16〜23的高8位
轨道号或LBA块地址16〜23的高8位
1F6H
驱动器/磁头或LBA块地址24〜27
驱动器/磁头或LBA块地址24〜27
1F7H
命令寄存器或状态寄存器
命令寄存器
因此,如果您想编写一个程序来读取文件,则不难分析整个过程:
在1F3H〜1F6H处写入要在1F2H中读取的扇区数. 这四个端口写入计算出的起始LBA地址. 在1F7H处,写入读取命令的指令号并连续检查1F7H(此时已变为状态寄存器的含义). 如果第四步不忙,它将开始从1F0H读取数据到存储器中的指定位置,直到阅读完毕
这五个步骤与上面的代码相对应

最后,不要忘了我们的代码仍加载到引导区中,因此最后两个字节仍必须是引导区标识符0x55 0xaa
四,运行代码
写入mbr.asm之后,我们将写入另一个loader.asm,将其起始地址设置为0x900(因为这是读写磁盘后存储的内存位置,这是我们自己的定义),并将其放入在磁盘的第二个扇区中(也可以由我们自己设置,只要它与读取磁盘的代码一致)
loader.asm
section loader vstart=0x900
mov byte [gs:0xa0],'l'
mov byte [gs:0xa2],'o'
mov byte [gs:0xa4],'a'
mov byte [gs:0xa6],'d'
mov byte [gs:0xa8],'e'
mov byte [gs:0xaa],'r'
剩下的实质在于我们的Makefile,您可以参考上面的代码
执行make brun,您会看到以下效果,这意味着将加载程序代码从磁盘加载到内存的过程已经生效.

5. 开源项目和课程计划
如果您有兴趣制作一个自制的操作系统,则不妨按照这一系列课程进行观看,甚至可以加入我们(下面的官方帐户和微信助手)一起开发.
参考书
这本书“恢复操作系统真相”真是太棒了!强烈推荐
项目开源
项目开源地址:
当您看到本文时,代码可能编写了比文章更多的部分. 您可以通过提交记录历史记录查看历史代码. 我将慢慢整理提交历史和项目描述文档,并努力为每节课准备一个可执行代码. 当然,本文中的代码也很完整,并且完全可以使用复制和粘贴.
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/dianqi/article-306067-1.html
看看岛礁建设中还存在什么不足之处
拉森舰可不是什么老旧军舰