【自制操作系统01】硬核讲解计算机的启动过程和

通过【自制操作系统01】电脑启动过程的硬核讲解和【自制操作系统02】环境准备和启动区实现的讲解,我们实现了最简单的操作系统之一(只有一条机器指令)。

今天我们要更进一步,逐步完善这个最简单的操作系统。之前最简单的操作系统写在引导区的512字节。这么小的空间以后肯定不会用来写操作系统的代码了,所以它的主要任务就是从硬盘读取更多的数据到内存。在里面,然后跳转到内存中的那个位置开始运行。

我必须复习每节课中提到的四个跳跃:

一跳:按下电源键,CPU会强制PC的寄存器值被初始化到这个位置就是BIOS程序的入口地址。二跳转:入口地址为跳转指令,跳转到该位置,开始执行 3.跳转:执行一些硬件检测工作后,最后一步是将引导区的内容加载(复制)到内存中,并跳到它。四跳转:boot区的代码主要是加载操作系统内核,跳转到加载的地方

事实上,我们可以无限期地跳跃。只要某个环节的任务比较复杂,我们可以分两步走。但是,完全可以停止从第三次跳转开始,将操作系统所需的所有指令和数据从硬盘加载到内存中执行,但这显然是不好的。

一、代码概览

别的不谈了,先把本章的全部代码发过来

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

.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'

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的重点和职责。

那么如何读取硬盘中的数据,就得从磁盘的结构说起。我对硬件不是很了解,所以我只能做一个粗略的想法。硬盘是磁盘的一种硬盘数据怎么导入空硬盘,分为硬盘和软盘。但是它们的逻辑结构是一样的:

光盘()

头(头)

跟踪(跟踪)

扇区 ()

气缸()

图片[1]-【自制操作系统01】硬核讲解计算机的启动过程和-4747i站长资讯

我不想担心它是如何移动的。我只需要弄清楚。一旦确定了磁头、柱面和扇区,就确定了 512 字节的区域。这就够了。这是硬盘的CHS表示,即(柱面)、Head(磁头)、(扇区),只要知道硬盘的CHS个数,就可以确定硬盘的容量。硬盘容量=柱面数×磁头数×扇区数×512B。

如果不考虑这个物理结构,硬盘实际上是由n个512字节的区域组成的。我们可以从 0 开始编号,每 512 字节加一个,这样我们根本不需要考虑任何扇区。 ,这个是我最喜欢的(好像是软件工程师的思维),这个方法叫做LBA 。

LBA = (柱面号 * 磁头数 + 磁头号) * 扇区数 + 扇区编号 - 1

所以如果CPU需要处理硬盘,要么用CHS记法,要么至少告诉硬盘柱面、磁头、扇区号,要么用LBA记法告诉硬盘LBA号,然后给硬盘一个 read Still write 信号。硬盘厂商上千万,CPU厂商也不一样。自然要有硬盘接口标准。该标准称为ATA标准,也可以通常称为IDE硬盘接口技术标准。你可以下载这个标准的总共三卷,但我们用的不多。找到了正宗的中文版论文《IDE接口硬盘读写技术》。这基本上就够了。

三、IDE 硬盘接口技术

CPU和外设通过IO接口进行交互,所以核心就是这个技术标准定义的IO接口是什么硬盘数据怎么导入空硬盘,它们的作用是什么

I/O 地址读取(主机从硬盘读取数据)写入(主机数据写入硬盘)

1F0H

数据寄存器

数据寄存器

1F1H

错误寄存器(只读寄存器)

特征寄存器

1F2H

扇区计数寄存器

扇区计数寄存器

1F3H

扇区号寄存器或 LBA 块地址 0~7

扇区号或LBA块地址0~7

1F4H

轨道号或LBA块地址8~15的低8位

轨道号或LBA块地址8~15的低8位

1F5H

高8位轨道号或LBA块地址16~23

高8位轨道号或LBA块地址16~23

1F6H

驱动器/头或LBA块地址24~27

驱动器/头或LBA块地址24~27

1F7H

命令寄存器或状态寄存器

命令寄存器

所以如果你要写一个读取文件的程序,不难分析整个过程:

在 1F3H ~ 1F6H 写入 1F2H 中要读取的扇区数。这四个端口写入计算出的起始 LBA 地址。在1F7H处,写入读命令的指令号,不断检查1F7H(此时已经成为状态寄存器的意思)如果第四步不忙,开始从1F0H读取数据到内存中的指定位置,直到阅读完成

这五个步骤对应上面的代码

最后别忘了我们的代码还是要加载到boot area的,所以最后两个字节还是boot area 0x55 0xaa

四、运行代码

写完mbr.asm后,我们再写一个.asm,把它的起始地址设置为0x900(因为这是读写磁盘后存储的内存位置,是我们自己定义的),放在第二个扇区盘的(这个也是我们自己设置的,只要和读盘的代码一致即可)

.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'

剩下的本质都在我们的文件里,可以参考上面的代码

执行make brun,可以看到如下效果,说明从磁盘加载代码到内存的过程已经生效。

图片[2]-【自制操作系统01】硬核讲解计算机的启动过程和-4747i站长资讯

五、开源项目和课程规划

如果你对做一个操作系统感兴趣,不妨跟着这一系列的课程来阅读,甚至加入我们(下面的公众号和助手微信)一起开发。

参考书

《操作系统真相还原》这本书真的很棒!强烈推荐

项目开源

项目开源地址:

当你看到这篇文章时,代码可能比文章中写了更多的部分。您可以通过提交记录历史查看历史代码。我会慢慢整理提交历史和项目描述文档,争取为每节课准备一个可执行代码。当然,文章中的代码也是完整的,完全可以使用复制粘贴。

文章来源:https://www.cnblogs.com/flashsun/p/12232630.html

------本页内容已结束,喜欢请分享------

感谢您的来访,获取更多精彩文章请收藏本站。

© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享