当前位置:   article > 正文

操作系统学习9 引导程序加载和运行系统文件_如何在引导执行文件

如何在引导执行文件

在这里插入图片描述

一、准备工作

本文需要的工具: https://gitee.com/xundh/learn-os
本文源代码: https://gitee.com/xundh/learn-os/tree/master/lesson9

  • bochs
  • virtualbox,win7虚拟机(制作win7虚拟过程可自行参考网上文章,使用它是为了读写软盘镜像)
  • nasm

二、说明

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

1. 根目录说明

对于一个标准的 FAT12 格式的软盘(1.44 MB),根目录的起始位置通常在第 19 个扇区(偏移地址为 0x2600 处)。每个目录项的大小为 32 字节,因此可以通过根目录的起始位置和目录项的大小来计算特定文件名的偏移地址。

在这个情况下,虽然文件名的偏移地址是根目录中的某个位置(通常为 0x2600 处开始),但是这个位置并不代表文件名的实际存储位置,而是文件名在根目录中的偏移地址。文件名本身是根目录中的一部分,它的确保存在根目录中,但是要正确读取文件名,需要使用根目录中相应目录项的偏移地址。

加载文件后,程序所在位置:

  • 文件名在磁盘的是 0x2600 处;
  • 文件内容在磁盘的 0x4200 处;
  • 磁盘的内容加载到内存的 0x8200 处(不包括启动扇区);
  • 所以磁盘的 0x4200 处的内容在 内存的 0x8200+0x4200=0xc200处。

三、程序代码

(1)引导文件 loader.s

[BITS 16]
global _start

;%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
                           ; 加载到内存 0x8200 ~ 0x34fff

; 把软盘按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:0000处。 0x8000~0x81ff的512字节给BIOS加载引导区用的,所以这里从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<CYLS , 则跳到readloop

; 读取磁盘后,跳转到系统文件NotOneOs.sys执行接下来的程序   
   MOV      [0x0ff0] , CH  ; 在0x0ff0处保存 CYLS的值,给后面的程序备用
   MOV      DH, 1          ; 加载磁盘成功置个标记
   MOV      SI , loading_msg  ; 显示正在加载
   JMP      print

; 打印错误信息
error:                  
   MOV      DH, 0          ; 加载失败置个标记
   MOV      SI , error_msg

; 使用前给SI赋值字符串地址
print:
   MOV      AL, [SI]
   ADD      SI, 1
   CMP      AL, 0          ; 字符串有没有读完,到0结束
   JE       end            ; 跳到结束程序
   MOV      AH, 0x0e       ; 显示一个字符
   MOV      BX, 15         ; 指定颜色
   INT      0x10           ; 调用BIOS功能显示字符
   JMP      print

end:
   CMP      DH, 1          ; 比较前面记录的加载成功标识
   JMP    0xc200           ; 跳转到磁盘上的系统程序,就是0x8000+0x4200=0xc200

loading_msg:
   DB "Loading NotOneOS..."; 想要开机后在屏幕上显示的字符串
   DB 0

error_msg:    
   DB "Error"              ; 失败
   DB 0

times  510-($-$$) db 0     ; 填充剩下的空间,使生成的二进制代码恰好为512字节 $$表示一个section的开始处汇编后地址
DW  0xaa55                 ; 结束标志

; 启动扇区以外部分输出

		DB		0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
		RESB	4600
		DB		0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
		RESB	1469432
  • 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
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135

(2)操作系统入口文件 boot.asm

[BITS 16]
ORG     0xc200
entry:
   ; 清屏
   MOV AX, 03h
   INT 10h

   ; 显示正在加载
   MOV      SI , msg  

print:
   MOV      AL, [SI]
   ADD      SI, 1
   CMP      AL, 0          ; 字符串有没有读完,到0结束
   JE       end            ; 跳到结束程序
   MOV      AH, 0x0e       ; 显示一个字符
   MOV      BX, 15         ; 指定颜色
   INT      0x10           ; 调用BIOS功能显示字符
   JMP      print

end:
   HLT
   jmp      end              ; 无限循环停止程序

msg:
		DB		0x0a, 0x0a		; 换行两次
		DB		"Loading boot.sys..."
		DB		0x0a			; 换行
		DB		0

  • 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

四、运行方式

1. 编译

nasm loader.s -o ../target/os.img
nasm boot.s -o ../target/boot.sys
  • 1
  • 2

2. 虚拟机加载 os.img

使用VirtualBox Windows环境,软盘加载 os.img 镜像:
在这里插入图片描述

3. 拷贝启动文件到软盘上

在这里插入图片描述

4. 弹出软盘

在这里插入图片描述

5. 使用 Bochs 调试方式虚拟机

命令:

bochsdbg.exe -q -f bochsrc.bxrc
  • 1

命令暂停时输入 c 并回车继续运行。

6. 执行效果

在这里插入图片描述

后面的重心终于可以跳到C语言了。

本系列学习主要资源来自《[30天自制操作系统].(川合秀实)》,《自己动手写操作系统》两本书

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/346591
推荐阅读
  

闽ICP备14008679号