title: os 002 os start
tags: [os]
categories:
- os
date: 2021-05-11 23:19:37
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 |
计算机的启动过程
- 按下开机键,cs:ip被初始化为F000:FFF0,指向BIOS入口地址。
- BIOS被加载进ROM并被映射到1MB内存的顶部(见上表)。
- jmp f000:e05b,执行BIOS的工作。
- BIOS的最后一项工作是校验启动盘中位于0盘0道1扇区的内容,若最后两个字节分别为0x55与0xaa,(即最后一个字的内容为0xaa55(小端字节序)),则认为这是一个MBR程序(主引导记录),则将此512字节加载如内存0x7C00. BIOS跳转,jmp 0:7C00
- 执行MBR。
- MBR,加载boot loader
- boot loader加载os 内核。
- 内核执行
BIOS
- BIOS本身是一个程序。BIOS的工作:检测硬件,做各种初始化工作,建立中断向量表,加载MBR。
- 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)将硬盘数据读出。
;-------------------------------------------------------------------------------
;功能:读取硬盘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