公司动态

OSASK学习第3天 进入32位模式并导入C语言

📅 2026/8/16 23:12:30
OSASK学习第3天 进入32位模式并导入C语言
1 制作真正的IPLBIOS 在启动时会自动将引导扇区512字节读取到内存的 0x7c00 地址处然后跳转到 0x7c00 开始执行。将软盘上的第二个扇区512字节加载到内存的 0x8200 地址处为下一步执行更大的程序做准备。MOV AX,0x0820 MOV ES, AX MOV CH,0 ; 柱面0 MOV DH,0 ; 磁头0 MOV CL,2 ; 扇区2 MOV AH,0x02 ; AH0x02 : 读盘 MOV AL,1 ; 1个扇区 MOV BX,0 MOV DL,0x00 ; A驱动器 INT 0x13 ; 调用磁盘BIOS JC errorJC: 是“jump if carry”的缩写意思是如果进位标志carry flag是1的话就跳转。❏磁盘读、写扇区校验verify​以及寻道seekAH0x02;读盘AH0x03;写盘AH0x04;校验AH0x0c;寻道AL处理对象的扇区数​只能同时处理连续的扇区CH柱面号 0xffCL扇区号0-5位|柱面号0x3002DH磁头号DL驱动器号ES:BX缓冲地址(校验及寻道时不使用)返回值FLACS.CF 0没有错误AH 0FLAGS.CF 1有错误错误号码存入AH内与重置reset功能一样我们这次用的是AH0x02是“读盘”的意思。x86 实模式1MB 空间内存布局速查表地址范围空间大小归属 / 主要用途引导程序能否写入0x00000-0x003FF1 KB中断向量表IVTCPU 处理键盘、时钟、磁盘中断时的跳转表。❌绝对禁区覆盖会导致中断机制崩溃系统立即死机。0x00400-0x004FF256 BBIOS 数据区BDA存放键盘状态、启动盘号、显存模式等。❌绝对禁区BIOS 依赖它维护硬件状态乱写会导致外设异常。0x00500-0x7BFFF~495 KB常规可用内存用户区可自由加载内核、文件系统缓存等。✅安全地带常见加载地址如0x500DOS 常驻、0x8000等。0x7C00-0x7DFF512 B引导扇区运行区你当前这 512 字节代码正驻留在此。⚠️极度危险这就是你自己覆盖等于“开枪自杀”程序立即跑飞。0x7E00-0x9FBFF~150 KB常规可用内存用户区引导扇区之后的预留加载区。✅最推荐地带你的0x8200就落在这里完美避开了栈向下增长和当前代码。0x9FC00-0x9FFFF1 KBEBDA扩展 BIOS 数据区通常由 BIOS 用作高级电源管理ACPI等。⚠️建议回避虽然物理可写但可能覆盖 BIOS 运行时变量导致关机异常。0xA0000-0xBFFFF128 KBVGA 显存映射区显卡帧缓冲文本模式0xB8000图形模式0xA0000。❌硬件冲突写入会直接改变屏幕显示花屏或乱码无法存储程序代码。0xC0000-0xFFFFF256 KBBIOS 固件 / 扩展 ROM主板 BIOS、显卡 BIOS、硬盘控制器固件。❌物理只读或映射写入无效或直接触发硬件异常#GP 保护错误。 记忆口诀底部1KBBIOS/CPU 内部表打死别碰。中部640KB - 1KB你家菜地随便种只要你记得种子埋哪了。顶部384KB硬件厂房显存、固件只看不摸。0x7C00512B你自己脚下挪窝之前别踩空。harib00a; hello-os ; TAB4 ORG 0x7c00 ; 指明程序装载地址 ; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code JMP entry DB 0x90 DB HELLOIPL ; 启动扇区名称8字节 DW 512 ; 每个扇区sector大小必须512字节 DB 1 ; 簇cluster大小必须为1个扇区 DW 1 ; FAT起始位置一般为第一个扇区 DB 2 ; FAT个数必须为2 DW 224 ; 根目录大小一般为224项 DW 2880 ; 该磁盘大小必须为2880扇区1440*1024/512 DB 0xf0 ; 磁盘类型必须为0xf0 DW 9 ; FAT的长度必??9扇区 DW 18 ; 一个磁道track有几个扇区必须为18 DW 2 ; 磁头数必??2 DD 0 ; 不使用分区必须是0 DD 2880 ; 重写一次磁盘大小 DB 0,0,0x29 ; 意义不明固定 DD 0xffffffff ; 可能是卷标号码 DB HELLO-OS ; 磁盘的名称必须为11字?不足填空格 DB FAT12 ; 磁盘格式名称必??8字?不足填空格 RESB 18 ; 先空出18字节 ; 程序主体 entry: MOV AX,0 ; 初始化寄存器 MOV SS,AX MOV SP,0x7c00 MOV DS,AX MOV ES,AX ; 读磁盘 MOV AX,0x0820 MOV ES, AX MOV CH,0 ; 柱面0 MOV DH,0 ; 磁头0 MOV CL,2 ; 扇区2 MOV AH,0x02 ; AH0x02 : 读盘 MOV AL,1 ; 1个扇区 MOV BX,0 MOV DL,0x00 ; A驱动器 INT 0x13 ; 调用磁盘BIOS JC error JMP fin error: MOV SI,msg putloop: MOV AL,[SI] ADD SI,1 ; 给SI加1 CMP AL,0 JE fin MOV AH,0x0e ; 显示一个文字 MOV BX,15 ; 指定字符颜色 INT 0x10 ; 调用显卡BIOS JMP putloop fin: HLT ; 让CPU停止等待指令 JMP fin ; 无限循环 msg: DB 0x0a, 0x0a ; 换行两次 DB load error DB 0X07 DB 0x0a ; 换行 DB 0 RESB 0x7dfe-$ ; 填写0x00直到0x001fe DB 0x55, 0xaa2 试错这一节就是添加了判断是否读磁盘出错的代码防止读出错误的数据。harib00b; hello-os ; TAB4 ORG 0x7c00 ; 指明程序装载地址 ; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code JMP entry DB 0x90 DB HELLOIPL ; 启动扇区名称8字节 DW 512 ; 每个扇区sector大小必须512字节 DB 1 ; 簇cluster大小必须为1个扇区 DW 1 ; FAT起始位置一般为第一个扇区 DB 2 ; FAT个数必须为2 DW 224 ; 根目录大小一般为224项 DW 2880 ; 该磁盘大小必须为2880扇区1440*1024/512 DB 0xf0 ; 磁盘类型必须为0xf0 DW 9 ; FAT的长度必??9扇区 DW 18 ; 一个磁道track有几个扇区必须为18 DW 2 ; 磁头数必??2 DD 0 ; 不使用分区必须是0 DD 2880 ; 重写一次磁盘大小 DB 0,0,0x29 ; 意义不明固定 DD 0xffffffff ; 可能是卷标号码 DB HELLO-OS ; 磁盘的名称必须为11字?不足填空格 DB FAT12 ; 磁盘格式名称必??8字?不足填空格 RESB 18 ; 先空出18字节 ; 程序主体 entry: MOV AX,0 ; 初始化寄存器 MOV SS,AX MOV SP,0x7c00 MOV DS,AX MOV ES,AX ;读磁盘 MOV AX,0x0820 MOV ES, AX MOV CH,0 ; 柱面0 MOV DH, 0 ; 磁头0 MOV CL, 2 ; 扇区2 MOV SI,0 ; 记录失败次数的寄存器 retry: MOV AH,0x02 ; AH0x02 : 读入磁盘 MOV AL,1 ; 1个扇区 MOV BX,0 MOV DL,0x00 ; A驱动器 INT 0x13 ; 调用磁盘BIOS JNC fin ; 没出错的话跳转到fin ADD SI,1 ; 往SI加1 CMP SI,5 ; 比较SI与5 JAE error ; SI 5时跳转到error MOV AH,0x00 MOV DL,0x00 ; A驱动器 INT 0x13 ; 重置驱动器 JMP retry error: MOV SI,msg putloop: MOV AL,[SI] ADD SI,1 ; 给SI加1 CMP AL,0 JE fin MOV AH,0x0e ; 显示一个文字 MOV BX,15 ; 指定字符颜色 INT 0x10 ; 调用显卡BIOS JMP putloop fin: HLT ; 让CPU停止等待指令 JMP fin ; 无限循环 msg: DB 0x0a, 0x0a ; 换行两次 DB load error DB 0X07 DB 0x0a ; 换行 DB 0 RESB 0x7dfe-$ ; 填写0x00直到0x001fe DB 0x55, 0xaaJNC是另一个条件跳转指令是“Jump if not carry”的缩写。也就是说进位标志是0的话就跳转。JAE也是条件跳转是“Jump if above or equal”的缩写意思是大于或等于时跳转。AH0x00DL0x00INT 0x13// 这是“系统复位”​。它的功能是复位软盘状态再读一次。3 读到18扇区这一节添加的代码通过一个循环连续读出了18个扇区; hello-os ; TAB4 ORG 0x7c00 ; 指明程序装载地址 ; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code JMP entry DB 0x90 DB HELLOIPL ; 启动扇区名称8字节 DW 512 ; 每个扇区sector大小必须512字节 DB 1 ; 簇cluster大小必须为1个扇区 DW 1 ; FAT起始位置一般为第一个扇区 DB 2 ; FAT个数必须为2 DW 224 ; 根目录大小一般为224项 DW 2880 ; 该磁盘大小必须为2880扇区1440*1024/512 DB 0xf0 ; 磁盘类型必须为0xf0 DW 9 ; FAT的长度必??9扇区 DW 18 ; 一个磁道track有几个扇区必须为18 DW 2 ; 磁头数必??2 DD 0 ; 不使用分区必须是0 DD 2880 ; 重写一次磁盘大小 DB 0,0,0x29 ; 意义不明固定 DD 0xffffffff ; 可能是卷标号码 DB HELLO-OS ; 磁盘的名称必须为11字?不足填空格 DB FAT12 ; 磁盘格式名称必??8字?不足填空格 RESB 18 ; 先空出18字节 ; 程序主体 entry: MOV AX,0 ; 初始化寄存器 MOV SS,AX MOV SP,0x7c00 MOV DS,AX MOV ES,AX ;读磁盘 MOV AX,0x0820 MOV ES, AX MOV CH,0 ; 柱面0 MOV DH, 0 ; 磁头0 MOV CL, 2 ; 扇区2 readloop: MOV SI,0 ; 记录失败次数的寄存器 retry: MOV AH,0x02 ; AH0x02 : 读入磁盘 MOV AL,1 ; 1个扇区 MOV BX,0 MOV DL,0x00 ; A驱动器 INT 0x13 ; 调用磁盘BIOS JNC next ; 没出错的话跳转到fin ADD SI,1 ; 往SI加1 CMP SI,5 ; 比较SI与5 JAE error ; SI 5时跳转到error MOV AH,0x00 MOV DL,0x00 ; A驱动器 INT 0x13 ; 重置驱动器 JMP retry next: MOV AX,ES ;把内存地址后移0x0200 ADD AX,0X0020 ; MOV ES,AX ;因为没有ADD ES,0X0020指令座椅这里稍微绕个弯 ADD CL,1 ;往CL里加1 CMP CL,18 ;比较CL和18 JBE readloop ;如果 CL 18 跳转至readloop读下一个扇区 fin: HLT ; 让CPU停止等待指令 JMP fin ; 无限循环 error: MOV SI,msg putloop: MOV AL,[SI] ADD SI,1 ; 给SI加1 CMP AL,0 JE fin MOV AH,0x0e ; 显示一个文字 MOV BX,15 ; 指定字符颜色 INT 0x10 ; 调用显卡BIOS JMP putloop msg: DB 0x0a, 0x0a ; 换行两次 DB load error DB 0X07 DB 0x0a ; 换行 DB 0 RESB 0x7dfe-$ ; 填写0x00直到0x001fe DB 0x55, 0xaaJBE这也是个条件跳转指令是“jump if below or equal”的缩写意思是小于等于则跳转。要读下一个扇区只需给CL加1给ES加上0x20就行了。CL是扇区号ES指定读入地址。0x20是十六进制下512除以16的结果。就结果而言写成AL17结果也是完全一样的。但这样的方式在下一次的程序中就会成为问题因此为了能够循序渐进这里特意用循环来一个扇区一个扇区地读盘。此时已经把磁盘上C0-H0-S2到C0-H0-S18的512×178704字节的内容装载到了内存的0x82000xa3ff处。4 读入10个柱面C0-H0-S18扇区的下一扇区是磁盘反面的C0-H1-S1。这次从0xa400读入按顺序读到C0-H1-S18后接着读下一个柱面C1-H0-S1。保持这个势头一直读到C9-H1-S18。; hello-os ; TAB4 ORG 0x7c00 ; 指明程序装载地址 CYLS EQU 10 ; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code JMP entry DB 0x90 DB HELLOIPL ; 启动扇区名称8字节 DW 512 ; 每个扇区sector大小必须512字节 DB 1 ; 簇cluster大小必须为1个扇区 DW 1 ; FAT起始位置一般为第一个扇区 DB 2 ; FAT个数必须为2 DW 224 ; 根目录大小一般为224项 DW 2880 ; 该磁盘大小必须为2880扇区1440*1024/512 DB 0xf0 ; 磁盘类型必须为0xf0 DW 9 ; FAT的长度必??9扇区 DW 18 ; 一个磁道track有几个扇区必须为18 DW 2 ; 磁头数必??2 DD 0 ; 不使用分区必须是0 DD 2880 ; 重写一次磁盘大小 DB 0,0,0x29 ; 意义不明固定 DD 0xffffffff ; 可能是卷标号码 DB HELLO-OS ; 磁盘的名称必须为11字?不足填空格 DB FAT12 ; 磁盘格式名称必??8字?不足填空格 RESB 18 ; 先空出18字节 ; 程序主体 entry: MOV AX,0 ; 初始化寄存器 MOV SS,AX MOV SP,0x7c00 MOV DS,AX MOV ES,AX ;读磁盘 MOV AX,0x0820 MOV ES, AX MOV CH,0 ; 柱面0 MOV DH,0 ; 磁头0 MOV CL,2 ; 扇区2 readloop: MOV SI,0 ; 记录失败次数的寄存器 retry: MOV AH,0x02 ; AH0x02 : 读入磁盘 MOV AL,1 ; 1个扇区 MOV BX,0 MOV DL,0x00 ; A驱动器 INT 0x13 ; 调用磁盘BIOS JNC next ; 没出错时跳转到next ADD SI,1 ; SI加1 CMP SI,5 ; 比较SI与5 JAE error ; SI 5时跳转到error MOV AH,0x00 MOV DL,0x00 ; A驱动器 INT 0x13 ; 重置驱动器 JMP retry next: MOV AX, ES ; 把内存地址后移0x200 ADD AX,0x0020 MOV ES, AX ; 因为没有ADD ES,0x020指令所以这里稍微绕个弯 ADD CL,1 ; CL加1 CMP CL,18 ; 比较CL与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 fin: HLT ; 让CPU停止等待指令 JMP fin ; 无限循环 error: MOV SI,msg putloop: MOV AL,[SI] ADD SI,1 ; 给SI加1 CMP AL,0 JE fin MOV AH,0x0e ; 显示一个文字 MOV BX,15 ; 指定字符颜色 INT 0x10 ; 调用显卡BIOS JMP putloop msg: DB 0x0a, 0x0a ; 换行两次 DB load error DB 0X07 DB 0x0a ; 换行 DB 0 RESB 0x7dfe-$ ; 填写0x00直到0x001fe DB 0x55, 0xaaJB。这也是条件跳转指令是“jump if below”的缩写。翻译过来就是​“如果小于的话就跳转。​”EQU。这相当于C语言的#define命令用来声明常数。​“CYLS EQU 10”意思是“CYLS 10”​。EQU是“equal”的缩写。只将它定义成常数是因为以后我们可能修改这个数字。现在我们先随意定义成10个柱面以后再对它进行调整CYLS代表cylinders​。5 着手开发操作系统一般向一个空软盘保存文件时 (1) 文件名会写在0x002600以后的地方(2) 文件的内容会写在0x004200以后的地方。6 从启动区执行操作系统那么要怎样才能执行磁盘映像上位于0x004200号地址的程序呢现在的程序是从启动区开始把磁盘上的内容装载到内存0x8000号地址所以磁盘0x4200处的内容就应该位于内存0x80000x42000xc200号地址。这样的话我们就往haribote.nas里加上ORG 0xc200然后在ipl.nas处理的最后加上JMP 0xc200这个指令。7 确认操作系统的执行情况这节就是切换一下画面模式。设置显卡模式video mode❏ AH0x00❏ AL模式​省略了一些不重要的画面模式0x03:16色字符模式80× 250x12:VGA图形模式640× 480× 4位彩色模式独特的4面存储模式0x13:VGA图形模式320× 200× 8位彩色模式调色板模式0x6a扩展VGA图形模式800× 600× 4位彩色模式独特的4面存储模式有的显卡不支持这个模式❏ 返回值无8 32位模式前期准备; haribote-os ; TAB4 ; 有关BOOT_INFO CYLS EQU 0x0ff0 ; 设定启动区 LEDS EQU 0x0ff1 VMODE EQU 0x0ff2 ; 关于颜色数目的信息。颜色的位数。 SCRNX EQU 0x0ff4 ; 分辨率的Xscreen x SCRNY EQU 0x0ff6 ; 分辨率的Yscreen y VRAM EQU 0x0ff8 ; 图像缓冲区的开始地址 ORG 0xc200 ; 这个程序将要被装载到内存的什么地方呢 MOV AL,0x13 ; VGA显卡320x200x8位彩色 MOV AH,0x00 INT 0x10 MOV BYTE [VMODE],8 ; 记录画面模式 MOV WORD [SCRNX],320 MOV WORD [SCRNY],200 MOV DWORD [VRAM],0x000a0000 ;用BIOS取得键盘上各种LED指示灯的状态 MOV AH,0x02 INT 0x16 ; keyboard BIOS MOV [LEDS], AL fin: HLT JMP fin9 - 10 开始导入C语言这部分突然添加了很多莫名其妙的代码有的没看懂还有makefile里面的一些流程也没搞清楚几个obj怎么链接的小白看不太明白总之跟着代码跑就完了