本系列学习有前面的汇编学习基础最好,如果没有影响也不大本系列学习主要资源来自《[30天自制操作系统].(川合秀实)》,《自己动手写操作系统》两本书
一、准备工作
bochs
virtualbox,windows虚拟机
nasm
二、操作流程
回顾前文的程序,我们的引导程序已经可以加载软盘的10个柱面的数据到内存的 0x0820 处,引导区本身的512字节由BIOS加载到0x8200处。
这一节让程序从这些数据中找到软盘上的程序,并运行其中的程序。
下面程序的重点是加载文件后,程序所在位置。通过前一节可以知道:
文件名在磁盘的是 0x2600处
文件内容在磁盘的0x4200处
磁盘的内容加载到内存的0x8000处
所以磁盘的0x4200处的内容在 内存的 0x8000+0x4200=0xc200处
- 修改程序
;%define _BOOT_DEBUG_ ; 做Boot Sector时把这行注释掉
; 启用这行就用nasm Boot.asm -o Boot.com生成.com文件用于调试
%ifdef _BOOT_DEBUG_
org 0100h%
else
org 07c00h
%endif
CYLS EQU 10 ; 一共读取10个柱面, 共 10柱面*2面*18扇区*512字节 = 184320 byte = 180K; 把软盘按Fat12格式填充
start:
JMP init ; 跳转指令
DB 0x90 ; 空 DB,DD用来写单字节
DB "NotOneOS" ; 厂商名,8字节,DB用来写双字节
DW 512 ; 每个扇区大小512字节,DW用来写4字节
DB 1 ; 每个簇的扇区数
DW 1 ; Boot占的扇区
DB 2 ; 有2个FAT表
DW 224 ; 根目录大小224
DW 2880 ; 磁盘扇区总数 2880
DB 0xf0 ; 介质描述符,磁盘种类必须为0xf0
DW 9 ; 每个FAT扇区数
DW 18 ; 每个磁道18个扇区
DW 2 ; 2个磁头
DD 0 ; 隐藏扇区数
DD 2880 ; 同上,磁盘大小
DB 0, 0, 0x29 ; 0x29 扩展引用标记
DD 0xffffffff ; 无意义,固定这么写
DB "NotOneOS " ; 磁盘名(卷标),11字节
DB "FAT12 " ; 磁盘格式名,8字节
RESB 18 ; 空18个字节,填充0x00
init:
MOV AX,0
MOV SS,AX
MOV SP,0x7c00 ; 堆栈空间,从0x7c00向前
MOV DS,AX; 读取磁盘
MOV AX,0x0820 ; 把磁盘数据加载到内存0x0820处。 0x8000~0x81ff的512字节给启动区用的,所以从0x8200开始
MOV ES,AX ; 注意 ES:BX 是指向的地址,后面还需要对BX赋值0
; 初始化磁盘接口
MOV CH,0 ; 柱面 0
MOV DH,0 ; 磁头 0
MOV CL,2 ; 扇区 2
readloop:
MOV SI,0 ; 记录失败次数
retry:
MOV AH,0x02 ; 0x02 读磁盘
MOV AL,1 ; 读1个扇区
MOV BX,0
MOV DL,0x00 ; A驱动器
INT 0x13 ; BIOS 读磁盘功能
JNC next ; 成功跳转
ADD SI,1 ; 失败加一次
CMP SI,5 ; 到5次就跳到error
JAE error
MOV AH,0x00 ; 复位磁盘功能
MOV DL,0x00 ; A 驱动器
INT 0x13 ; 重置磁盘驱动器
JMP retry ; 重试
next:
MOV AX,ES ; 内存地址向后移动0x0020
ADD AX,0x0020
MOV ES,AX ; 通过AX给ES加0x0020
ADD CL,1 ; 扇区+1
CMP CL,18 ; 有没有到18个扇区
JBE readloop ; CL<=18,就跳到 readloop
MOV CL,1
ADD DH,1
CMP DH,2
JB readloop ; 如果 DH < 2 ,则跳到readloop
MOV DH,0
ADD CH,1
CMP CH,CYLS
JB readloop ; 如果CH
- 编译,生成镜像 ```sh make img
3. 在Win7虚拟机中打开A盘,装载镜像
![](/images/2022/01/image-1641370071804.png)
把NotOneOs.sys拷到A盘:
![](/images/2022/01/image-1641370088368.png)
再移除虚拟盘:
![](/images/2022/01/image-1641370097503.png)
# 三、启动镜像
这时候boot.img里包含了启动的NotOneOs.sys程序,使用bochs加载运行:
这里进入调试状态,以确定是否运行了NotOneOs.sys程序make debug b 0x7c00cs
![](/images/2022/01/image-1641370141921.png)
通过反汇编,可以找到我们的重点代码位置:
u 0x7c00 0x7cff
![](/images/2022/01/image-1641370157004.png)
在0x7cca处设置断点:
b 0x7cca
![](/images/2022/01/image-1641370175337.png)
查看现在寄存器的值:
rdx的值里看到 DH确实为1,再次单步运行,程序跳转到了0xc200:
![](/images/2022/01/image-1641370189404.png)
而0xc200处正是NotOneOs.sys的程序:
![](/images/2022/01/image-1641370267219.png)
![](/images/2022/01/image-1641370274633.png)
后面的重心终于可以跳到C语言了。