第 0 天:准备阶段
下载工具和原版镜像
二进制编辑器
BZ 是一个修改二进制文件的工具。工具可到网上下载,或者使用工具包中 BZ。
取消只读选框,可对文件进行修改。
工具目录 tolset
- nask 编译器
把 nas 文件(作者的汇编源码)转为二进制的,用来把 nas 文件编译成二进制 img 文件。可能用翻译更贴切,不过说成编译也没有什么毛病。
路径:/tolset/z_tools/nask.exe
- imgtol.com
将 img 文件刻录到软盘的工具。
用法:imgtol.com w a: helloos.img
路径:/tolset/z_tools/imgtol.com
- make.exe
读取并执行 Makefile 的 GNU 系列工具,能读取指定目录下的 Makefile 脚本。其参数与 Makefile 有关。
路径:/tolset/z_tools/make.exe
制作运行 img 操作
- 将 nas 源码文件编译成 img 文件
1 | nask.exe helloos.nas helloos.img |
- 将 img 写入软盘 A
1 | imgtol.com w a: helloos.img |
需要重启系统,从软盘进入 img 系统
- 使用 qemu 启动 img 系统
1 | make.exe -C ../z_tools/qemu |
第 1 天:汇编入门
NASM 简介
NASM 全称 The Netwide Assembler,是一款基于 80x86 和 x86-64 平台的汇编语言编译程序,其设计初衷是为了实现编译器程序跨平台和模块化的特性。NASM支持大量的文件格式,包括 Linux,*BSD,a.out,ELF,COFF,Mach−O,Microsoft 16−bit OBJ,Win32 以及Win64,同时也支持简单的二进制文件生成。NASM 是众多汇编器中,免费且比较好用的汇编编译器。
知识学习
- DB(Define Byte):定义一串字节数据(8位)
例如:
1 |
|
编译器默认会将数据认为是 10 进制,所以需要使用 0x 来表示这个数据是 16 进制的。
- DW(伪指令):定义一串字型数据(16 位)
例如:
1 | ; 定义 10 个字,即 20 个字节 |
- DD(伪指令):定义一串双字型数据(32 位)
例如:
1 | ; 定义 10 个双字,即 40 个字节 |
- RESB(Reserve Byte): “RESB”, “RESW”, “RESD”, “RESQ” and “REST” 被设计用在模块的 BSS 段中:它们声明未初始化的内存空间。每一个带有单个操作数,用来表明字节数,字数,或双字数或其它的需要保留单位。这些指令在初始化空间中默认填充0。
1 | ; 初始化 18 个字节的空间,并填充0。 |
- $:用法表示当前的指令在哪个位置。
1 | ; 我当前的指令在 $ 位置,或者说现在已经使用了 $ 个字节。这个指令意思是:填充 "0x1fe-$" 个值位 "0x00" 的字节。 |
上面的这些指令都是伪指令。伪指令是只有编译器能执行的指令,编译器会将伪指令编译成数据。
专业术语
- 启动区(boot sector)
软盘的第一个扇区称为启动区,因为计算机读写软盘的时候是以 512 字节为一个单位进行读写的,所以软盘中的 512 字节称为一个扇区。
计算机在读写软盘的时候,会先读取第一个扇区,如果第一个扇区的最后两个字节不是 0x55 AA,计算机就会认为这张盘上没有所需的启动程序,就会报一个不能启动的错误。因此第一个扇区也被称为启动区。
- IPL(initial program loader)
IPL 启动程序加载器。启动区的 512 字节,肯定是放不下一个正常的操作系统,所以就有了 IPL 这个程序(放到启动区中)来加载操作系统。因此有时启动区也称为 IPL。
第 2 天:汇编语言学习 与 makefile 入门
知识点
- 8 位寄存器
- AL:累加寄存器低位
- CL:计数寄存器低位
- DL:数据寄存器低位
- BL:基地址寄存器低位
- AH:累加寄存器高位
- CH:计数寄存器高位
- DH:数据寄存器高位
- BH:基地址寄存器高位
- 16 位寄存器
- AX:累加寄存器
- CX:计数寄存器
- DX:数据寄存器
- BX:基地址寄存器
- SP:栈指针寄存器
- BP:基地址指针寄存器
- SI:源变地址寄存器
- DI:目的变地址寄存器
AX、CX、DX、BX 可拆分成 8 位寄存器:AH、AL、BH、BL、CH、CL、DH、DL 。这里的 X 表示扩展(extend)的意思,因为之前是 8 位寄存器,现在扩展到了 16 位寄存器。。
- 32 位寄存器
- EAX:累加寄存器
- ECX:计数寄存器
- EDX:数据寄存器
- EBX:基地址寄存器
- ESP:栈指针寄存器
- EBP:基地址指针寄存器
- ESI:源变地址寄存器
- EDI:目的变地址寄存器
- 段寄存器
- ES:附加段寄存器
- CS:代码段寄存器
- SS:栈段寄存器
- DS:数据段寄存器
- FS:没有名称
- GS:没有名称
- 内存地址
一个程序被加载到内存后,CPU 必须要从内存中读取处理一条一条的指令,程序才得以运行。内存中的指令存放在内存地址中,只有当你告诉 CPU 我要执行哪个内存地址的指令时,CPU 才会正确执行这条指令。内存地址用[常量]
来表示。
指令
- ORG(origin) 指令:修改段内偏移地址。
工作原理:org 指令本身不能决定程序将要加载的内存的什么位置,它只是告诉编译器,程序在编译好后需要加载到 xxx 地址,所以在编译时帮我调整好数据访问时的地址。
地址调整方法:指定地址+旧的偏移地址
1 |
|
- JMP 指令:无条件跳转指令
工作原理:jmp 跳转指令根据跳转的距离分为:段内短转移、段内近转移、段间转移。段内转移都是通过当前 IP(偏移地址)的转移位移来进行跳转的。比如,当前 IP=5 ,要跳转的 IP=8,指令跳转的时候就是 jmp 5+3=jmp 8。这里的 3 表示 IP 向后移动 3 个偏移地址。
段内跳转方法:当前IP + 位移
1 |
|
- MOV 指令:传送指令
工作原理:将一个寄存器或者内存单元中的值,传送到另一个寄存器或内存单元中。
1 | ; 将值 0,传送到 ax 寄存器中。原来 ax 寄存器中的值会被覆盖 |
- ADD 指令:加法指令
工作原理:将两个数值相加
1 | ; si=si+1 |
- CMP 指令:比较指令
1 | ; 将 al 中的值和 0 进行比较 |
- JE 指令:有条件跳转指令,根据比较结果进行指令跳转。如果比较结果相等,则跳转到制定地址;如果跳转指令不相等,则不跳转,继续执行下一条指令。
1 |
|
INT 指令:软件中断指令。int 指令调用的是操作系统提供的子程序或者其他特殊的程序
HLT 指令:使程序停止运行,CPU 处于待机状态,当外部发生变化,比如按键盘、鼠标等,CPU 就会醒过来,继续执行程序。
Makefile 入门
Makefile语法:
1 | 规则名称 : 执行这个规则所需要的文件(以空格符隔开) |
make 语法:
make -r 规则名
优点:
使用灵活方便:当规则执行,找不到需要的文件时。程序会自动需找并执行所需文件的规则。Makefile 可集成多个规则,并按要求执行。
第 3 天:进入 32 位模式并导入 C 语言
制作真正的 IPL
INT 0x13 中断指向的是磁盘服务程序。
用途:将指定扇区的代码加载到内存指定位置
参数表:
值 | 功能 |
---|---|
00H | 磁盘系统复位 |
01H | 读取磁盘系统状态 |
02H | 读扇区 |
03H | 写扇区 |
04H | 检验扇区 |
05H | 格式化磁道 |
06H | 格式化坏磁道 |
07H | 格式化驱动器 |
08H | 读取驱动器参数 |
09H | 初始化硬盘参数 |
0AH | 读长扇区 |
0BH | 写长扇区 |
0CH | 查寻 |
0DH | 硬盘系统复位 |
0EH | 读扇区缓冲区 |
0FH | 写扇区缓冲区 |
10H | 读取驱动器状态 |
11H | 校准驱动器 |
12H | 控制器 RAM 诊断 |
13H | 控制器驱动诊断 |
14H | 控制器内部诊断 |
15H | 读取磁盘类型 |
16H | 读取磁盘变化状态 |
17H | 设置磁盘类型 |
18H | 设置格式化媒体类型 |
19H | 磁头保护 |
1AH | 格式化 ESDI 驱动器 |
功能02H
入口参数:AH=02H
- AL=扇区数
- CH=柱面
- CL=扇区
- DH=磁头
- DL=驱动器,00H~7FH:软盘;80H~0FFH:硬盘
- ES:BX=缓冲区地址
出口参数:CF=0 操作成功,AH=00H,AL=传输扇区数,否则,AH=状态码。
上面的图片具体描述了一个软盘的结构图:柱面(环状),一个软盘有 0~79(共 80)个柱面;每个柱面会被分成 1~18(共 18)个扇区;一个软盘有 0~1(共 2)个磁头用来读取数据。
JC 指令
JC(jump if carry),意思是如果 CF(carry flag)是 1 的话就跳转。CF 是标志寄存器,通常用来做条件跳转或数据比较。
从上面部分程序中可以看到:程序先读取扇区,如果成功了 CF=0。如果失败了 CF=1,程序会跳到 error 部分继续执行,最后程序跳到 msg 部分继续执行,最后输出 load error 的信息。
简单来说就是:读扇区失败了,屏幕就会输出 load error 的信息。
新增内容解释
1 |
|
试错
软盘很不可靠,有时会发生不能读取数据的状况,所以要多读取几次,这里尝试读取 5 次,如果还是报错,就会跳转到 error 部分提示错误信息。
1 |
|
JNC 是 “Jump if not carry” 的缩写。也就是说进位标志是 0 的话就跳转。因为当读取磁盘报错时中断会将 cf 置为 1。
reference
- 本文标题:30天制作操作系统
- 本文作者:9unk
- 创建时间:2020-09-06 09:44:11
- 本文链接:https://9unkk.github.io/2020/09/06/30-tian-zhi-zuo-cao-zuo-xi-tong/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!