learning_OS——day3
- BIOS:基本输入输出系统,电脑启动时的“第一道程序”,负责初始化硬件,检测系统状态等。
BIOS中断的相关指令:
- INT 10H:控制屏幕输出
- INT 13H:磁盘读写
汇编程序1:加载操作系统的第一道程序——BIOS程序。加载软盘启动区至内存指定区域,并在新的操作系统中输出"Hello, World"
; hello-os
; TAB=4
ORG 0x7c00 ; 指定程序加载到内存地址0x7c00
; 以下是FAT12格式磁盘的引导扇区信息
JMP entry
DB 0x90
DB "HELLOIPL" ; 引导扇区的标识符(8字节)
DW 512 ; 每扇区的字节数(通常为512)
DB 1 ; 每簇的扇区数(通常为1)
DW 1 ; 保留扇区数(通常为1)
DB 2 ; FAT表的数量(通常为2)
DW 224 ; 根目录的条目数(通常为224)
DW 2880 ; 总扇区数(通常为2880,1.44MB软盘)
DB 0xf0 ; 媒体描述符(0xf0表示软盘)
DW 9 ; 每个FAT表占用的扇区数(通常为9)
DW 18 ; 每个磁道的扇区数(通常为18)
DW 2 ; 磁头数(通常为2)
DD 0 ; 隐藏扇区数(通常为0)
DD 2880 ; 总扇区数(32位值,通常为2880)
DB 0,0,0x29 ; 扩展引导标志
DD 0xffffffff ; 卷序列号
DB "HELLO-OS " ; 卷标(11字节)
DB "FAT12 " ; 文件系统类型(8字节)
RESB 18 ; 保留18字节
; 程序入口
entry:
MOV AX,0 ; 初始化寄存器
MOV SS,AX
MOV SP,0x7c00
MOV DS,AX
MOV ES,AX
MOV SI,msg
putloop:
MOV AL,[SI]
ADD SI,1 ; SI加1
CMP AL,0
JE fin
MOV AH,0x0e ; BIOS打印字符功能
MOV BX,15 ; 设置字符颜色
INT 0x10 ; 调用BIOS中断
JMP putloop
fin:
HLT ; 停止CPU
JMP fin ; 无限循环
msg:
DB 0x0a, 0x0a ; 换行两次
DB "hello, world" ; 输出的字符串
DB 0x0a ; 换行
DB 0
RESB 0x7dfe-$ ; 填充到0x7dfe地址
DB 0x55, 0xaa ; 引导扇区结束标志
(以下程序省略了汇编程序1的大部分结构,只保留了重点)
汇编程序2:在汇编程序1的基础上,将软盘的第二个扇区读入内存
entry:
MOV AX,0 ; 初始化寄存器
MOV SS,AX
MOV SP,0x7c00 ; 设置堆栈指针
MOV DS,AX
(新添加部分)
MOV AX,0x0820
MOV ES,AX
MOV CH,0 ; 磁道号0
MOV DH,0 ; 磁头号0
MOV CL,2 ; 扇区号2
MOV AH,0x02 ; AH=0x02:读磁盘
MOV AL,1 ; 读取1个扇区
MOV BX,0
MOV DL,0x00 ; 驱动器号
INT 0x13 ; 调用磁盘BIOS
JC error ; 如果出错,跳转到error
汇编程序3:在汇编程序2的基础上,添加读软盘的试错功能(可能会读取失败)。连续读错5次以上则停止读取并报错。
; 初始化寄存器
entry:
MOV AX,0 ; AX清零
MOV SS,AX ; 设置栈段寄存器为0
MOV SP,0x7c00 ; 设置栈指针为加载地址0x7c00
MOV DS,AX ; 设置数据段寄存器为0
; 加载第二扇区
MOV AX,0x0820 ; 设置第二扇区加载内存的起始地址为0x0820:0000
MOV ES,AX ; ES:BX构成第二扇区载入的内存地址区间
MOV CH,0 ; 柱面号为0
MOV DH,0 ; 磁头号为0
MOV CL,2 ; 扇区号为2
MOV SI,0 ; 重试计数器清零
retry:
MOV AH,0x02 ; AH=0x02:读取磁盘扇区
MOV AL,1 ; 读取1个扇区
MOV BX,0 ; BX清零,偏移地址为0
MOV DL,0x00 ; 驱动器号为0(软盘)
INT 0x13 ; 调用磁盘BIOS中断
JNC fin ; 如果没有错误,跳转到fin
ADD SI,1 ; 重试计数器加1
CMP SI,5 ; 判断是否重试超过5次
JAE error ; 如果重试次数>=5,跳转到error
MOV AH,0x00 ; AH=0x00:复位磁盘系统
MOV DL,0x00 ; 驱动器号为0
INT 0x13 ; 调用磁盘BIOS中断
JMP retry ; 重新尝试读取
汇编程序4:在汇编程序3的基础上,读取完整18个扇区。
执行完毕后,磁盘上的 C0-H0-S2 到 C0-H0-S18(第2~18个扇区)会装载到内存的 0x8200~0xa3ff 处。
retry:(读取当前扇区)
MOV AH,0x02 ; AH=0x02:读取磁盘
MOV AL,1 ; 读取1个扇区
MOV BX,0
MOV DL,0x00 ; 驱动器号
INT 0x13 ; 调用磁盘BIOS
JNC next ; 如果没有错误,跳转到next
ADD SI,1 ; 重试计数+1
CMP SI,5 ; 如果重试次数>=5
JAE error ; 跳转到error
MOV AH,0x00
MOV DL,0x00 ; 驱动器号
INT 0x13 ; 重置驱动器
JMP retry
next:(更换下一个扇区)
MOV AX,ES ; 地址偏移+0x200
ADD AX,0x0020 ; 一个扇区512字节,这里16*ES变化量刚好为512
MOV ES,AX ; 更新ES寄存器
ADD CL,1 ; 扇区号+1
CMP CL,18 ; 如果扇区号<=18
JBE readloop ; 跳转到readloop
汇编程序5:在汇编程序4的基础上,读取完整10个柱面。
读取顺序:先读完18个扇区,再更换磁头读取另一面的18个扇区;两个面均读完后才更新柱面。
执行该程序后,10个柱面的内容已读取到内存地址范围0x08200 ~0x34fff。
retry:(读取当前扇区)
MOV AH,0x02 ; AH=0x02:读取磁盘
MOV AL,1 ; 读取1个扇区
MOV BX,0
MOV DL,0x00 ; 驱动器号
INT 0x13 ; 调用磁盘BIOS
JNC next ; 如果没有错误,跳转到next
ADD SI,1 ; 重试计数器加1
CMP SI,5 ; 如果重试次数>=5
JAE error ; 跳转到error
MOV AH,0x00
MOV DL,0x00 ; 驱动器号
INT 0x13 ; 重置驱动器
JMP retry
next:(更换扇区,磁头与柱面)
MOV AX,ES ; 内存地址加0x200(512字节)
ADD AX,0x0020
MOV ES,AX ; 更新ES
ADD CL,1 ; 扇区号加1
CMP CL,18 ; 如果扇区号<=18
JBE readloop ; 跳转到readloop
MOV CL,1 ; 18个扇区全部读完,扇区号重置为1,并更新磁头
ADD DH,1 ; 磁头号加1
CMP DH,2
JB readloop ; 如果磁头号<2,跳转到readloop
MOV DH,0 ; 2个磁头全部读完,磁头号重置为0,并更新柱面
ADD CH,1 ; 柱面号加1
CMP CH,CYLS ; CYLS = 10
JB readloop ; 如果柱面号<CYLS,跳转到readloop
汇编程序6:BIOS的初始化——画面模式设定(存储在内存中,以备后用)与得到键盘状态
; haribote-os
; TAB=4
; BOOT_INFO的定义
CYLS EQU 0x0ff0 ; 设置启动扇区数
LEDS EQU 0x0ff1 ; LED状态
VMODE EQU 0x0ff2 ; 显示模式,8位颜色
SCRNX EQU 0x0ff4 ; 屏幕分辨率X
SCRNY EQU 0x0ff6 ; 屏幕分辨率Y
VRAM EQU 0x0ff8 ; 图形缓冲区的起始地址
ORG 0xc200 ; 从这个地址开始加载程序
MOV AL,0x13 ; 设置VGA图形模式为320x200x8位颜色
MOV AH,0x00
INT 0x10
MOV BYTE [VMODE],8 ; 设置当前模式为8位颜色
MOV WORD [SCRNX],320 ; 设置屏幕宽度为320
MOV WORD [SCRNY],200 ; 设置屏幕高度为200
MOV DWORD [VRAM],0x000a0000 ; 设置图形缓冲区起始地址为0x000a0000
; 从键盘读取LED状态并保存到内存
MOV AH,0x02
INT 0x16 ; 调用键盘BIOS
MOV [LEDS],AL ; 保存LED状态到内存
fin:
HLT ; 停止CPU
JMP fin ; 无限循环
上述汇编程序中BIOS参与的事情:
- 画面模式的设定
- 磁盘的读写
- 得到键盘状态
由于BIOS是16位机器语言模式的,而现在要逐渐转入32位机器语言模式,二者互不兼容。这也就意味着进入32位系统后就不能再使用BIOS的功能了,故在进入操作系统之前必须要提前做好BIOS要做的事情。

浙公网安备 33010602011771号