当前位置: 首页 > news >正文

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

1 制作真正的IPL

BIOS 在启动时,会自动将引导扇区(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 ; AH=0x02 : 读盘 MOV AL,1 ; 1个扇区 MOV BX,0 MOV DL,0x00 ; A驱动器 INT 0x13 ; 调用磁盘BIOS JC error

JC: 是“jump if carry”的缩写,意思是如果进位标志(carry flag)是1的话,就跳转。

磁盘读、写,扇区校验(verify)​,以及寻道(seek)
AH=0x02;(读盘)
AH=0x03;(写盘)
AH=0x04;(校验)
AH=0x0c;(寻道)
AL=处理对象的扇区数;​(只能同时处理连续的扇区)

CH=柱面号 &0xff;
CL=扇区号(0-5位)|(柱面号&0x300)>>2;
DH=磁头号;
DL=驱动器号;
ES:BX=缓冲地址;(校验及寻道时不使用)

返回值:
FLACS.CF == 0:没有错误,AH == 0
FLAGS.CF == 1:有错误,错误号码存入AH内(与重置(reset)功能一样)
我们这次用的是AH=0x02,是“读盘”的意思。

x86 实模式(1MB 空间)内存布局速查表

地址范围空间大小归属 / 主要用途引导程序能否写入?
0x00000-0x003FF1 KB中断向量表(IVT)
CPU 处理键盘、时钟、磁盘中断时的跳转表。
绝对禁区
覆盖会导致中断机制崩溃,系统立即死机。
0x00400-0x004FF256 BBIOS 数据区(BDA)
存放键盘状态、启动盘号、显存模式等。
绝对禁区
BIOS 依赖它维护硬件状态,乱写会导致外设异常。
0x00500-0x7BFFF~495 KB常规可用内存(用户区)
可自由加载内核、文件系统缓存等。
安全地带
常见加载地址如0x500(DOS 常驻)、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 保护错误)。

📌 记忆口诀

  • 底部(1KB):BIOS/CPU 内部表,打死别碰
  • 中部(640KB - 1KB)你家菜地,随便种(只要你记得种子埋哪了)。
  • 顶部(384KB):硬件厂房(显存、固件),只看不摸
  • 0x7C00(512B)你自己脚下,挪窝之前别踩空。

harib00a:

; hello-os ; TAB=4 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 ; AH=0x02 : 读盘 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, 0xaa

2 试错

这一节就是添加了判断是否读磁盘出错的代码,防止读出错误的数据。

harib00b

; hello-os ; TAB=4 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 ; AH=0x02 : 读入磁盘 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, 0xaa

JNC是另一个条件跳转指令,是“Jump if not carry”的缩写。也就是说进位标志是0的话就跳转。
JAE也是条件跳转,是“Jump if above or equal”的缩写,意思是大于或等于时跳转。

AH=0x00
DL=0x00
INT 0x13
// 这是“系统复位”​。它的功能是复位软盘状态,再读一次。

3 读到18扇区

这一节添加的代码通过一个循环连续读出了18个扇区

; hello-os ; TAB=4 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 ; AH=0x02 : 读入磁盘 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, 0xaa

JBE:这也是个条件跳转指令,是“jump if below or equal”的缩写,意思是小于等于则跳转。

要读下一个扇区,只需给CL加1,给ES加上0x20就行了。CL是扇区号,ES指定读入地址。0x20是十六进制下512除以16的结果。

就结果而言,写成AL=17结果也是完全一样的。但这样的方式在下一次的程序中,就会成为问题,因此为了能够循序渐进,这里特意用循环来一个扇区一个扇区地读盘。

此时已经把磁盘上C0-H0-S2到C0-H0-S18的512×17=8704字节的内容,装载到了内存的0x8200~0xa3ff处。

4 读入10个柱面

C0-H0-S18扇区的下一扇区,是磁盘反面的C0-H1-S1。这次从0xa400读入,按顺序读到C0-H1-S18后,接着读下一个柱面C1-H0-S1。保持这个势头,一直读到C9-H1-S18。

; hello-os ; TAB=4 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 ; AH=0x02 : 读入磁盘 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, 0xaa

JB。这也是条件跳转指令,是“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处的内容就应该位于内存0x8000+0x4200=0xc200号地址。

这样的话,我们就往haribote.nas里加上ORG 0xc200,然后在ipl.nas处理的最后加上JMP 0xc200这个指令。

7 确认操作系统的执行情况

这节就是切换一下画面模式。

设置显卡模式(video mode)
❏ AH=0x00;
❏ AL=模式:​(省略了一些不重要的画面模式)

  • 0x03:16色字符模式,80× 25
  • 0x12:VGA图形模式,640× 480× 4位彩色模式,独特的4面存储模式
  • 0x13:VGA图形模式,320× 200× 8位彩色模式,调色板模式
  • 0x6a:扩展VGA图形模式,800× 600× 4位彩色模式,独特的4面存储模式(有的显卡不支持这个模式)

❏ 返回值:无

8 32位模式前期准备

; haribote-os ; TAB=4 ; 有关BOOT_INFO CYLS EQU 0x0ff0 ; 设定启动区 LEDS EQU 0x0ff1 VMODE EQU 0x0ff2 ; 关于颜色数目的信息。颜色的位数。 SCRNX EQU 0x0ff4 ; 分辨率的X(screen x) SCRNY EQU 0x0ff6 ; 分辨率的Y(screen 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 fin

9 - 10 开始导入C语言

这部分突然添加了很多莫名其妙的代码,有的没看懂,还有makefile里面的一些流程,也没搞清楚,几个obj怎么链接的小白看不太明白,总之跟着代码跑就完了

http://www.jsqmd.com/news/1407487/

相关文章:

  • likeadmin-api 全驱动数字人参数避坑:file_url、ref_file_url 和 mode 怎么传
  • 农村宅基地流转、继承、翻建遇纠纷,专业宅基地律所处理这类案件的核心法律依据 - 好物分享知识传播
  • LLM as Judge与Best of N:构建自优化的AI代码生成流水线
  • 2026年上海GEO代运营服务筛选与对比指南 - 筑云鲸
  • Linux系统安装Docker Compose:二进制与pip方式详解与避坑指南
  • Git Push报错全解析:从权限认证到分支冲突的完整解决方案
  • 从Docker到nerdctl:轻量级容器管理工具实战指南
  • 基于 PlantUML 的软件系统行为建模:图表选型、描述规范与乙方交付要求
  • 构建统一AI网关:多模型API集成、路由与成本管控实战
  • VNP43IA3:VIIRS BRDF/反照率日值全球 500 米数据集(V002)
  • Unity Tile Palette 2D地图编辑:从基础绘制到Rule Tile智能生成
  • bugku easy_hash
  • 大模型无状态架构解析:从原理到实战,构建有记忆的AI应用
  • Vue + Element Plus 实现文本溢出显示省略号及悬浮提示
  • 争取8周岁以上子女抚养权时,专业抚养权律所的核心办案思路是什么 - 好物分享知识传播
  • 大数据专业不考证能找到工作吗
  • 基于大语言模型与向量数据库的智能写作辅助系统搭建指南
  • 邮寄电动车哪个物流便宜又好?2026年托运避坑指南,这样选最省心! - 快递物流资讯
  • 大模型工具调用进阶:MCP协议下的格式、并行与安全实践
  • 六西格玛绿带报考官网 - 众智商学院官方
  • YOLOv8分类任务实战|全网完整复现玻式绝缘子缺失二分类、均衡数据集训练调参、助力电力巡检缺陷识别落地涨点
  • 智能体记忆系统设计:从向量数据库到个性化助手的工程实践
  • 构建端到端智能体审计引擎:从可观测性到持续优化
  • JavaScript安全最佳实践
  • 从Prompt工程到LLM应用开发:快速构建NLP推理系统的实战指南
  • 手把手教你学 Simulink—— 群体无人机协同覆盖路径生成
  • windows 驱动实例分析系列: wintun驱动分析-api篇(三)
  • 【AIGC】创意领域,AI 的短板不是执行力,而是“选择“
  • Windows硬件信息查询批处理脚本:WMIC与PowerShell实战指南
  • 电子商务专业考研还是考证更适合就业