赞
踩
本文需要的工具: https://gitee.com/xundh/learn-os
本文源代码: https://gitee.com/xundh/learn-os/tree/master/lesson9
回顾前文的程序,引导程序已经可以加载软盘的10个柱面的数据到段地址 0x0820
处(物理地址 0x8200)。
引导区本身的512字节由BIOS加载到0x7c00
处。
这一节让程序从这些数据中找到软盘上的程序,并运行其中的程序。
对于一个标准的 FAT12 格式的软盘(1.44 MB),根目录的起始位置通常在第 19 个扇区(偏移地址为 0x2600 处)。每个目录项的大小为 32 字节,因此可以通过根目录的起始位置和目录项的大小来计算特定文件名的偏移地址。
在这个情况下,虽然文件名的偏移地址是根目录中的某个位置(通常为 0x2600 处开始),但是这个位置并不代表文件名的实际存储位置,而是文件名在根目录中的偏移地址。文件名本身是根目录中的一部分,它的确保存在根目录中,但是要正确读取文件名,需要使用根目录中相应目录项的偏移地址。
加载文件后,程序所在位置:
0x2600
处;0x4200
处;0x8200
处(不包括启动扇区);0x4200
处的内容在 内存的 0x8200+0x4200=0xc200
处。[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
[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
nasm loader.s -o ../target/os.img
nasm boot.s -o ../target/boot.sys
使用VirtualBox Windows环境,软盘加载 os.img 镜像:
命令:
bochsdbg.exe -q -f bochsrc.bxrc
命令暂停时输入 c 并回车继续运行。
后面的重心终于可以跳到C语言了。
本系列学习主要资源来自《[30天自制操作系统].(川合秀实)》,《自己动手写操作系统》两本书
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。