本系列学习有前面的汇编学习基础最好,如果没有影响也不大本系列学习主要资源来自《[30天自制操作系统].(川合秀实)》,《自己动手写操作系统》两本书

一、准备工作

bochs
virtualbox,windows虚拟机
nasm

二、操作流程

回顾前文的程序,我们的引导程序已经可以加载软盘的10个柱面的数据到内存的 0x0820 处,引导区本身的512字节由BIOS加载到0x8200处。
这一节让程序从这些数据中找到软盘上的程序,并运行其中的程序。

下面程序的重点是加载文件后,程序所在位置。通过前一节可以知道:

文件名在磁盘的是 0x2600处
文件内容在磁盘的0x4200处
磁盘的内容加载到内存的0x8000处
所以磁盘的0x4200处的内容在 内存的 0x8000+0x4200=0xc200处

  1. 修改程序
 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
68
69
70
71
;%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
  1. 编译,生成镜像 ```sh make img
 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


  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语言了。