os 002 os start

实模式下的1M内存布局

起始 结束 大小 用途
FFFF0 FFFFF 16B BIOS入口地址,此16字节的指令是jmp f000:e05b
F0000 FFFEF 64KB-16B BIOS的范围是F0000~FFFFF共640KB
C8000 EFFFF 160KB 映射硬件适配器的ROM或者内存映射式IO
C0000 C7FFF 32KB 显示适配器BIOS
B8000 BFFFF 32KB 用于文本模式的显示适配器
B0000 B7FFF 32KB 用于黑白显示适配器
A0000 AFFFF 64KB 用于彩色显示适配器
9FC00 9FFFF 1KB 扩展BIOS数据区
7E00 9FBFF 608KB 可用区域
7C00 7DFF 512B MBR被加载到此处,共512字节
500 7BFF 30KB 可用区域
400 4FF 256B BIOS数据区
0 3FF 1KB 中断向量表IVT

计算机的启动过程

  1. 按下开机键,cs:ip被初始化为F000:FFF0,指向BIOS入口地址。
  2. BIOS被加载进ROM并被映射到1MB内存的顶部(见上表)。
  3. jmp f000:e05b,执行BIOS的工作。
  4. BIOS的最后一项工作是校验启动盘中位于0盘0道1扇区的内容,若最后两个字节分别为0x55与0xaa,(即最后一个字的内容为0xaa55(小端字节序)),则认为这是一个MBR程序(主引导记录),则将此512字节加载如内存0x7C00. BIOS跳转,jmp 0:7C00
  5. 执行MBR。
  6. MBR,加载boot loader
  7. boot loader加载os 内核。
  8. 内核执行

BIOS

  1. BIOS本身是一个程序。BIOS的工作:检测硬件,做各种初始化工作,建立中断向量表,加载MBR。
  2. BIOS中断只能用于实模式,在保护模式下不可以使用。

硬盘操作

硬盘控制器主要端口寄存器
IO端口 端口用途
primary通道 secondary通道
指令寄存器
0x1F0 0x170 data data
0x1F1 0x171 data features
0x1F2 0x172 扇区数量 扇区数量
0x1F3 0x173 LBA LOW LBA LOW
0x1F4 0x174 LBA MID LBA MID
0x1F5 0x175 LBA HIGH LBA HIGH
0x1F6 0x176 device device
0x1F7 0x177 status command
控制寄存器
0x3F6 0x376 alternate status device control

Sector count 寄存器用来指定待读取或待写入的扇区数。硬盘每完成一个扇区,就会将此寄存器的值
减 1,所以如果中间失败了,此寄存器中的值便是尚未完成的扇区。这是 8 位寄存器,最大值为 255,若
指定为 0,则表示要操作 256 个扇区。

在读硬盘时,端口 0x1F7 或 0x177 的寄存器名称是 Status,它是 8 位宽度的寄存器,用来给出硬盘的
状态信息。第 0 位是 ERR 位,如果此位为 1,表示命令出错了,具体原因可见 error 寄存器。第 3 位是 data
request 位,如果此位为 1,表示硬盘已经把数据准备好了,主机现在可以把数据读出来。第 6 位是 DRDY,
表示硬盘就绪,此位是在对硬盘诊断时用的,表示硬盘检测正常,可以继续执行一些命令。第 7 位是 BSY
位,表示硬盘是否繁忙,如果为 1 表示硬盘正忙着,此寄存器中的其他位都无效。另外的 4 位暂不关注。

在写硬盘时,端口 0x1F7 或 0x177 的寄存器名称是 command,和上面说过的 error 和 feature 寄存器情况
一样,只是用途变了,所以换了个名字表示新的用途,它和 status 寄存器是同一个。此寄存器用来存储让硬
盘执行的命令,只要把命令写进此寄存器,硬盘就开始工作了。主要使用了三个命令。
(1)identify:0xEC,即硬盘识别。
(2)read sector:0x20,即读扇区。
(3)write sector:0x30,即写扇区。

硬盘读取步骤

(1)先选择通道,往该通道的 sector count 寄存器中写入待操作的扇区数。
(2)往该通道上的三个 LBA 寄存器写入扇区起始地址的低 24 位。
(3)往 device 寄存器中写入 LBA 地址的 24~27 位,并置第 6 位为 1,使其为 LBA 模式,设置第4位,选择操作的硬盘(master 硬盘或 slave 硬盘)。
(4)往该通道上的 command 寄存器写入操作命令。
(5)读取该通道上的 status 寄存器,判断硬盘工作是否完成。
(6)如果以上步骤是读硬盘,进入下一个步骤。否则,完工。
(7)将硬盘数据读出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
;-------------------------------------------------------------------------------
;功能:读取硬盘n个扇区
rd_disk_m_16:
;-------------------------------------------------------------------------------
; eax=LBA扇区号
; ebx=将数据写入的内存地址
; ecx=读入的扇区数
mov esi,eax ;备份eax
mov di,cx ;备份cx
;读写硬盘:
;第1步:设置要读取的扇区数
mov dx,0x1f2
mov al,cl
out dx,al ;读取的扇区数

mov eax,esi ;恢复ax

;第2步:将LBA地址存入0x1f3 ~ 0x1f6

;LBA地址7~0位写入端口0x1f3
mov dx,0x1f3
out dx,al

;LBA地址15~8位写入端口0x1f4
mov cl,8
shr eax,cl
mov dx,0x1f4
out dx,al

;LBA地址23~16位写入端口0x1f5
shr eax,cl
mov dx,0x1f5
out dx,al

shr eax,cl
and al,0x0f ;lba第24~27位
or al,0xe0 ; 设置7~4位为1110,表示lba模式
mov dx,0x1f6
out dx,al

;第3步:向0x1f7端口写入读命令,0x20
mov dx,0x1f7
mov al,0x20
out dx,al

;第4步:检测硬盘状态
.not_ready:
;同一端口,写时表示写入命令字,读时表示读入硬盘状态
nop
in al,dx
and al,0x88 ;第4位为1表示硬盘控制器已准备好数据传输,第7位为1表示硬盘忙
cmp al,0x08
jnz .not_ready ;若未准备好,继续等。

;第5步:从0x1f0端口读数据
mov ax, di
mov dx, 256
mul dx
mov cx, ax ; di为要读取的扇区数,一个扇区有512字节,每次读入一个字,
; 共需di*512/2次,所以di*256
mov dx, 0x1f0
.go_on_read:
in ax,dx
mov [bx],ax
add bx,2
loop .go_on_read
ret