day3
helloos e
解释.nas .sys .img,以及他们之间的关系
在操作系统开发中,这些文件类型有特定的作用和关系:
- .nas 文件 (NASK汇编源文件)
- 这是使用NASK汇编器编写的汇编语言源代码文件
- 包含低级硬件操作指令,如你提供的
ipl.nas
就是引导加载程序 - 需要经过汇编器编译生成二进制文件
- .sys 文件 (系统文件)
- 通常是操作系统的核心组件
- 在你的Makefile中由
haribote.nas
编译生成haribote.sys
- 包含操作系统的主要功能代码
- 会被加载到内存中执行
- .img 文件 (磁盘映像文件)
- 完整的磁盘镜像,模拟物理软盘/硬盘
- 在你的项目中由
ipl.bin
和haribote.sys
组合生成 - 包含引导扇区(ipl)和操作系统核心(sys)
- 可直接用于虚拟机或写入物理介质
它们的关系链:
ipl.nas → [编译] → ipl.bin → [组合]
→ haribote.img
haribote.nas → [编译] → haribote.sys → [组合]
在Makefile中体现为:
ipl.bin : ipl.nas Makefile
$(NASK) ipl.nas ipl.bin ipl.lst
haribote.sys : haribote.nas Makefile
$(NASK) haribote.nas haribote.sys haribote.lst
haribote.img : ipl.bin haribote.sys Makefile
$(EDIMG) 指令组合生成img文件
简单说:.nas
是源代码,.sys
是编译后的系统核心,.img
是包含引导程序和系统核心的完整磁盘映像。
代码存储顺序
在引导扇区被BIOS加载到内存0x7C00后,代码和数据在内存中的顺序如下:
- 内存布局顺序:
0x7C00: JMP entry ; 跳转指令(3字节)
0x7C03: DB 0x90 ; 填充字节(1字节)
0x7C04: "HARIBOTE" ; 8字节OEM标识
0x7C0C: 引导扇区参数区 ; 从0x7C0C开始的FAT12 BPB(BIOS Parameter Block)数据结构
...
0x7C??: entry: ; 实际引导代码开始处
...
0x7DFE: 0x55, 0xAA ; 引导扇区结束标志
- 执行流程:
- BIOS加载512字节引导扇区到0x7C00
- 从0x7C00处开始执行,第一条指令就是
JMP entry
- 跳转到
entry:
标签处执行实际引导代码
- 关键点:
- 前3字节必须是跳转指令或NOP+跳转
- 0x7C03-0x7C0B是OEM标识区
- 0x7C0C-0x7C35是标准FAT12 BPB结构
- 引导代码从
entry:
标签开始 - 最后2字节(0x7DFE-0x7DFF)必须是0x55AA
这种布局是FAT12文件系统引导扇区的标准要求,确保BIOS和操作系统都能正确识别。
这个文件
ipl是引导扇区的文件
haribote.nas 是最简单的操作系统
fin:
HLT
JMP fin
以上内容可以总结为:一般向一个空软盘保存文件时,
- 文件名会写在0x002600以后的地方;
- 文件的内容会写在0x004200以后的地方。
我们将操作系统本身的内容写到名为
haribote.sys文件中,再把它保存到磁盘映像里,然后我们从启动区执行这个
haribote.sys就行了。接下来我们就来做这件事
引导区和启动区
在操作系统开发中,引导区和启动区是两个关键概念,它们协同工作来完成系统启动过程:
- 引导区 (Boot Sector)
- 位于磁盘的第一个扇区(512字节)
- 包含BIOS加载的初始引导代码(如你的ipl.nas编译后的内容)
- 必须以0x55 0xAA作为结束标志
- 主要功能是加载并移交控制权给启动区
- 启动区 (Loader)
- 通常位于磁盘的后续扇区
- 包含更复杂的启动逻辑(如你的haribote.sys)
- 负责:
- 设置保护模式
- 加载内核到内存
- 初始化基本硬件
- 最终跳转到内核入口
在你的代码中体现为:
; 引导区代码 (ipl.nas)
ORG 0x7c00 ; BIOS加载引导区到0x7c00
; ... FAT12头信息 ...
entry:
; 初始化寄存器
; 读取启动区(haribote.sys)到内存0x8200
; 如果成功则跳转到0x8200执行
在Makefile中的构建关系:
ipl.bin : ipl.nas # 编译引导区
haribote.sys : haribote.nas # 编译启动区
haribote.img : ipl.bin haribote.sys # 组合成完整镜像
典型启动流程:
- BIOS → 引导区(0x7c00)
- 引导区 → 启动区(0x8200)
- 启动区 → 内核
这种分离设计使得:
- 引导区保持简单可靠(只做最基本加载)
- 启动区可以实现复杂功能
- 方便后续扩展和维护
org伪指令再度解释
ORG
指令在汇编语言中是一个非常重要的伪指令,它的作用是设置程序在内存中的加载地址。具体到你的代码:
ORG 0x7c00 ; 程序加载到内存的地址(BIOS默认加载引导扇区到0x7c00)
关键点解释:
- 0x7c00 是BIOS固定将引导扇区加载到的内存地址
- 所有后续的标号(label)地址计算都会基于这个基地址
- 如果没有ORG指令:
- 汇编器会假设程序从0x0000开始
- 导致生成的实际内存地址错误
例如当你的代码中有:
entry:
MOV AX,0
实际内存地址会是 0x7c00 + (entry的偏移量)
在引导程序开发中必须正确设置ORG,因为:
- BIOS固定加载引导扇区到0x7c00
- 所有跳转指令和内存访问都依赖正确的地址计算
- 错误的ORG值会导致程序无法正确执行
bios解释
BIOS(Basic Input/Output System)是计算机启动时最先运行的固件程序,它负责硬件初始化和操作系统加载。以下是关键解释和常用功能:
BIOS核心作用
- 硬件检测(POST自检)
- 检查CPU、内存、硬盘等关键硬件
- 通过蜂鸣代码报告错误(如"一长两短"表示显卡故障)
- 引导加载
- 读取磁盘第一个扇区(MBR/VBR)到内存0x7C00
- 移交控制权给引导程序(如你的ipl.nas)
- 硬件抽象层
- 提供标准化的硬件访问接口(通过中断调用)
常用BIOS中断(INT指令)
在你的代码中已使用的关键中断:
- 磁盘服务(INT 0x13)
MOV AH,0x02 ; 读扇区功能
MOV AL,1 ; 读取扇区数
MOV DL,0x00 ; 驱动器号(0x00=A:)
INT 0x13 ; 调用磁盘服务
- 视频服务(INT 0x10)
MOV AH,0x0E ; 显示字符功能
MOV AL,'A' ; 要显示的字符
INT 0x10 ; 调用视频服务
- 其他常用中断
- INT 0x16 键盘服务
- AH=0x00 读取键盘输入
- INT 0x19 系统重启
- INT 0x1A 实时时钟服务
现代替代方案
- UEFI(统一可扩展固件接口)
- 更快的启动速度
- 支持GPT分区和>2TB磁盘
- 图形化配置界面
- Coreboot(开源固件)
- 谷歌Chromebook采用
- 启动速度极快(约1秒)
在你的操作系统中,BIOS中断是硬件控制的核心方式,后续开发可能会用到更多中断服务。
显卡模式
设定AH=0x00后,调用显卡BIOS的函数,这样就可以切换显示模式了。我们还可
以在支持网页(AT)BIOS里看看。
设置显卡模式(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面存储模式
(有的显卡不支持这个模式)
返回值:无
[VRAM]里保存的是0xa0000。在电脑的世界里,VRAM指的是显卡内存(video
RAM),也就是用来显示画面的内存。这一块内存当然可以像一般的内存一样存
储数据,但VRAM的功能不仅限于此,它的各个地址都对应着画面上的像素,可以
利用这一机制在画面上绘制出五彩缤纷的图案。
其实VRAM分布在内存分布图上好几个不同的地方。这是因为,不同画面模式的像
素数也不一样。当画面模式为〇×时使用这个VRAM;而画面模式为◇△时可能使
用那个VRAM,像这样,不同画面模式可以使用的内存也不一样。所以我们就预先
把要使用的VRAM地址保存在BOOT_INFO里以备后用。
这次VRAM的值是0xa0000。这个值又是从哪儿得来的呢?还是来看看我们每次都
参考的(AT)BIOS支持网页。在INT 0x10的说明的最后写着,这种画面模式
下“VRAM是0xa0000~0xaffff的64KB”。
另外,我们还把画面的像素数、颜色数,以及从BIOS取得的键盘信息都保存了起
来。保存位置是在内存0x0ff0附近。从内存分布图上看,这一块并没被使用,所以
应该没问题。
关于es和bios
MOV ES,AX 为什么要在这里设置es
在汇编代码中 MOV ES,AX
这条指令的作用是设置 ES (Extra Segment) 段寄存器的值。这里的具体原因和上下文相关:
- 前一条指令
MOV AX,0x0820
将 AX 设置为 0x0820 - 这里将 ES 设置为 0x0820 是为了指定后续磁盘读取操作的目标内存地址
在实模式下,内存访问使用"段:偏移"的寻址方式。这里设置 ES=0x0820 表示:
- 磁盘读取的数据将被加载到内存地址 ES:BX = 0x0820:0x0000
- 计算物理地址 = (ES << 4) + BX = 0x8200 + 0x0000 = 0x8200
选择 0x0820 这个值是因为:
- 引导扇区(0x7c00-0x7dff)已经被使用
- 0x8200 是引导程序之后的一个安全区域
- 这个位置不会覆盖BIOS数据区或其他关键内存区域
后续的磁盘读取操作(INT 0x13)将使用这个ES值作为目标内存段地址。
问题:这个不是附加段寄存器吗,读取不是默认ds吗
在x86实模式下,磁盘读取操作(INT 0x13, AH=0x02)使用的是ES:BX作为目标缓冲区地址,而不是DS段寄存器。这是BIOS磁盘服务的设计规范。
具体原因如下:
- BIOS的INT 0x13/AH=0x02(读磁盘)功能明确规定:
- ES:BX 必须指向接收数据的缓冲区
- 这是BIOS接口的硬性规定,不是由程序员决定的
- 在您的代码中:
MOV AX,0x0820 ; 设置目标内存地址ES:BX=0x0820:0x0000
MOV ES,AX ; ES=0x0820
MOV BX,0 ; BX=0x0000
; ...
INT 0x13 ; 调用BIOS磁盘服务,数据将被读到ES:BX(0x0820:0x0000)
- DS(数据段寄存器)通常用于普通的内存访问指令(如MOV [SI],AL),但BIOS中断服务有自己特定的寄存器使用规则。
- 这样设计的原因可能是:
- BIOS服务需要明确指定目标缓冲区,而不依赖当前DS值
- 保持灵活性,允许读取数据到任意内存位置
- 历史遗留设计,早期x86架构的约定
所以在这个场景下,必须使用ES而不是DS,这是由BIOS接口规范决定的,不是程序员的自主选择。
helloos h
关于.img二进制文件002600处的.sys文件名解释
根据您提供的工程文件和问题,我来解释为什么haribote.img
映像文件中会出现HARIBOTESYS
文件名以及文件内容的位置:
-
文件名来源:
-
文件名
HARIBOTESYS
不是来自ipl10.nas
,而是来自haribote.sys
文件本身 -
在Makefile中,
haribote.sys
是通过以下命令生成的:haribote.sys : haribote.nas Makefile $(NASK) haribote.nas haribote.sys haribote.lst
-
当
haribote.sys
被写入映像文件时,FAT12文件系统会自动为其创建目录项
-
-
文件内容位置(0x004200):
- 文件内容出现在0x004200是因为FAT12文件系统的结构:
- 引导扇区(0x0000-0x01FF)
- FAT表(0x0200-0x13FF)
- 根目录区(0x1400-0x25FF)
- 数据区从0x2600开始
haribote.sys
的内容被放在数据区的第一个可用簇
- 文件内容出现在0x004200是因为FAT12文件系统的结构:
-
为什么在ipl10.nas看不到:
-
ipl10.nas
只是引导程序,负责加载操作系统 -
文件名和文件内容是由构建过程(
make img
)和FAT12文件系统自动处理的 -
在Makefile的
haribote.img
目标中,haribote.sys
被复制到映像文件中:haribote.img : ipl10.bin haribote.sys Makefile $(EDIMG) imgin:..\..\..\tolset\z_tools\fdimg0at.tek \ wbinimg src:ipl10.bin len:512 from:0 to:0 \ copy from:haribote.sys to:@: \ imgout:haribote.img
-
-
二进制编辑器的观察:
- 0x002600附近是根目录区,存储了
HARIBOTESYS
文件名(11字符,空格填充) - 0x004200是文件内容区域,存储了
haribote.sys
的实际内容
- 0x002600附近是根目录区,存储了
总结:文件名和文件内容的位置是由FAT12文件系统结构和构建过程决定的,不是直接在ipl10.nas
中指定的。make img
命令会自动处理这些文件系统元数据的创建和文件内容的放置。
文件名HARIBOTESYS
(11字符)与HARIBOTE
(8字符)的区别源于FAT12文件系统的目录项命名规则。以下是具体原因:
-
FAT12文件系统规范:
- 根目录区的每个文件名条目固定为11字节(8字节主名 + 3字节扩展名)
- 文件名会被自动转换为大写并填充空格
- 如果文件名不足11字节,系统会用空格(0x20)填充
-
在您的工程中:
haribote.sys
编译后的文件名会被FAT12处理为:- 主名:
HARIBOTE
(8字符,自动截断) - 扩展名:
SYS
(3字符) - 组合为
HARIBOTESYS
(无分隔点,共11字符)
- 主名:
-
与ipl10.nas中的
HARIBOTE
区别:-
ipl10.nas中的
HARIBOTE
(12行)是磁盘卷标(8字节),不是文件名 -
卷标和文件名在FAT12中是独立存储的:
DB "HARIBOTE" ; 启动盘名称(8字节) DB "HARIBOTEOS " ; 卷标(11字节)
-
-
自动转换过程:
-
当
edimg
工具处理haribote.sys
时:copy from:haribote.sys to:@: # 自动转换为FAT12目录项
-
工具会:
- 去除文件名中的点(
.
) - 主名补足8字符(不够补空格)
- 扩展名补足3字符
- 全部转为大写
- 去除文件名中的点(
-
因此haribote.sys
→ HARIBOTESYS
是FAT12文件系统的自动命名规范,而ipl10.nas中的HARIBOTE
是独立的磁盘标识信息。
关于启动区地址的处理问题(bios缓冲)
MOV [0x0ff0],CH ; 保存实际读取的柱面数
JMP 0xc200 ; 跳转到加载的程序,这个跳转地址怎么计算出来的
在FAT12文件系统中,0xC200
这个跳转地址是通过以下步骤计算得出的:
-
内存加载位置计算:
- 引导扇区(IPL)被BIOS加载到
0x7C00
- 程序将操作系统内核(
haribote.sys
)读取到内存地址0x8000
开始的位置- 计算方式:
0x0820:0x0000
(ES:BX) - 物理地址 =
0x0820 << 4 + 0x0000 = 0x8200
- 但实际从
0x8000
开始是因为BIOS磁盘读取会使用额外的缓冲区
- 计算方式:
- 引导扇区(IPL)被BIOS加载到
-
内核入口点偏移:
haribote.sys
的汇编代码通常会在开头定义ORG 0xc200
指令- 这个地址是固定的约定值,由开发工具链决定
-
地址组成:
0xC200
=0x8000
(加载基址) +0x4200
(内核偏移)- 其中
0x4200
是haribote.sys
编译时确定的入口点偏移
-
Makefile中的对应关系: 在Makefile中,
edimg
工具会自动处理这个地址映射:haribote.img : ipl10.bin haribote.sys Makefile $(EDIMG) imgin:... \ wbinimg src:ipl10.bin len:512 from:0 to:0 \ copy from:haribote.sys to:@: \ # 自动计算加载地址 imgout:haribote.img
这个地址是开发环境预先约定好的,确保:
- 不会覆盖BIOS数据区(0x0000-0x7FFF)
- 不会覆盖引导程序(0x7C00-0x7DFF)
- 留有足够空间给内核代码和数据
如果需要修改这个地址,需要同时修改:
ipl10.nas
中的跳转指令haribote.nas
中的ORG指令- Makefile中的地址映射参数
问题:但实际从0x8000开始是因为BIOS磁盘读取会使用额外的缓冲区,额外的缓冲区为什么是0x0200
在x86实模式下,BIOS磁盘读取操作(INT 0x13)使用的额外缓冲区大小是0x0200(512字节),这是由以下原因决定的:
-
扇区大小匹配:
- 标准磁盘扇区大小固定为512字节
- BIOS需要确保缓冲区足够存放一个完整扇区
- 0x0200(十六进制) = 512(十进制)
-
内存地址计算:
-
代码中设置
ES=0x0820
,BX=0x0000
-
物理地址计算:
(ES << 4) + BX = 0x8200
-
但实际数据从
0x8000
开始是因为:MOV AX,0x0820 ; ES将被设为0x0820 MOV ES,AX ; 此时ES:BX = 0x0820:0x0000 → 物理地址0x8200
-
这里存在一个常见的误解,实际BIOS可能会使用
0x8000-0x81FF
作为临时缓冲区
-
-
BIOS内部机制:
- 某些BIOS实现会在传输数据时使用额外的临时缓冲区
- 这个缓冲区通常位于
0x8000-0x81FF
(也是512字节) - 最终数据会被复制到请求的目标地址(0x8200)
-
代码中的证据: 在读取循环中,每次成功读取后调整ES值:
next: MOV AX,ES ADD AX,0x0020 ; 每次增加0x200(512)字节 MOV ES,AX
这个增量0x0020左移4位就是0x0200,正好匹配扇区大小
-
内存布局考虑:
0x8000
以上的区域通常不会被系统占用- 这样的设计避免了覆盖BIOS数据区(0x0000-0x7FFF)
- 也避开了引导扇区本身(0x7C00-0x7DFF)
所以0x0200这个值不是随意选择的,而是严格匹配磁盘扇区大小和x86内存分段机制的必然结果。
make.bat程序解释
问题:…\tolset\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9。解释一下这里的%1等的含义
在Windows批处理文件(.bat)中,%1
到%9
是批处理参数占位符,用于接收调用批处理文件时传入的命令行参数。具体解释如下:
-
参数表示:
%1
表示第一个参数%2
表示第二个参数- …
%9
表示第九个参数
-
在您的
make.bat
中的使用:..\..\..\tolset\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
这行代码会将调用
make.bat
时传入的所有参数(最多9个)原样传递给make.exe
-
实际使用示例:
-
当您执行:实际执行的命令是:其中:
make.bat run clean
..\..\..\tolset\z_tools\make.exe run clean
%1
= “run”%2
= “clean”%3
到%9
为空
-
-
与Makefile的关系:
- 这些参数通常对应Makefile中的目标名,如:
img
run
clean
src_only
- 这些参数通常对应Makefile中的目标名,如:
-
特殊参数:
%0
表示批处理文件本身的名字(这里没用)- 超过9个参数需要用
shift
命令处理
这种设计使得make.bat
可以作为一个简单的包装器(wrapper),将所有参数透明地传递给真正的make.exe
工具。
键盘BIOS中断调用
INT 0x16
是x86架构中的键盘BIOS中断调用,用于处理键盘输入。在您的代码中具体使用的是 AH=0x02
功能,以下是详细解释:
haribote.nas
;(从BIOS获取键盘LED状态)
MOV AH,0x02 ; 功能号0x02 - 获取键盘LED状态
INT 0x16 ; 调用键盘BIOS中断
MOV [LEDS],AL ; 将结果(AL)保存到内存LEDS位置(0x0ff1)
功能细节:
- 输入参数:
AH=0x02
:指定要获取键盘LED状态
- 输出参数:
AL
寄存器返回一个字节,包含以下位标志:- Bit 0 (0x01): Scroll Lock状态 (1=ON)
- Bit 1 (0x02): Num Lock状态 (1=ON)
- Bit 2 (0x04): Caps Lock状态 (1=ON)
- 其他位保留(为0)
- 内存保存:
- 结果被存入
0x0ff1
(LEDS常量定义的位置) - 这个值后续可能被操作系统用来同步键盘LED状态
- 结果被存入
- 硬件交互:
- 该中断会直接查询键盘控制器的状态寄存器
- 不需要实际按键操作就能获取当前LED状态
- 典型用途:
- 操作系统启动时初始化键盘状态
- 保存当前键盘LED状态供后续使用
- 实现键盘状态指示灯同步
这个调用是早期PC兼容系统中获取键盘状态的标准方法,在现代系统中可能被更高级的API取代,但在裸机编程中仍然有效。
在 INT 0x16
(键盘BIOS中断) 中,除了 AH=0x02
(获取键盘LED状态) 外,还有其他常用的功能号。以下是主要的键盘BIOS功能及其说明:
1. AH=0x00 - 读取键盘输入
MOV AH,0x00
INT 0x16 ; 返回: AH=扫描码, AL=ASCII码
- 阻塞等待键盘输入
- 返回的扫描码可用于识别特殊键(如F1-F12,方向键等)
2. AH=0x01 - 检查键盘缓冲区
MOV AH,0x01
INT 0x16 ; ZF=0有按键, ZF=1无按键
- 非阻塞检查是否有按键
- 如果有按键,可通过AH=0x00读取
3. AH=0x02 - 获取键盘标志(已在代码中使用)
MOV AH,0x02
INT 0x16 ; AL=标志字节
- 返回Shift/Ctrl/Alt等状态
- 也返回LED状态(Scroll Lock, Num Lock, Caps Lock)
4. AH=0x05 - 写入键盘缓冲区
MOV AH,0x05
MOV CH,扫描码
MOV CL,ASCII码
INT 0x16 ; AL=0成功, AL=1缓冲区满
- 模拟按键输入
- 可用于自动化测试
5. AH=0x10 - 扩展键盘读取(AT键盘)
MOV AH,0x10
INT 0x16 ; AH=扫描码, AL=ASCII码
- 支持102键扩展键盘
- 能识别更多特殊键
在您的操作系统开发中,最可能用到的是 AH=0x00
和 AH=0x01
来实现键盘输入功能。例如:
wait_key:
MOV AH,0x00
INT 0x16 ; 等待按键
CMP AL,0x1B ; 检查是否是ESC键
JE exit
JMP wait_key
这些功能共同构成了PC兼容系统的基本键盘输入体系。
关于BOOT_INFO中的储存地址的确认
CYLS EQU 0x0ff0 ; 引导扇区设置的读取柱面数
LEDS EQU 0x0ff1 ; 键盘LED状态存储位置
VMODE EQU 0x0ff2 ; 显示模式(色彩位数)
SCRNX EQU 0x0ff4 ; 屏幕水平分辨率(X)
SCRNY EQU 0x0ff6 ; 屏幕垂直分辨率(Y)
VRAM EQU 0x0ff8 ;
问题:显存起始地址这些地址是怎么确认的
这些内存地址的确定是基于以下几个关键因素:
-
引导程序约定:
-
在
ipl10.nas
中,引导程序(IPL)将实际读取的柱面数保存在0x0ff0
:MOV [0x0ff0],CH ; 保存柱面数到0x0ff0
-
这个地址选择在
0x7c00-0x7dff
(引导扇区)和0x8000
(内核加载区)之间的空闲区域
-
-
内存安全区域:
-
0x0ff0-0x0fff
是BIOS和引导程序都不会使用的"安全区域" -
典型PC内存布局:
0x00000-0x003FF : BIOS中断向量表 0x00400-0x004FF : BIOS数据区 0x7C00-0x7DFF : 引导扇区加载位置 0xA0000-0xBFFFF : 显存区域
-
-
信息传递需求:
- 这些地址用于引导程序(IPL)向内核传递硬件信息:
0x0ff0
:读取的柱面数0x0ff1
:键盘状态0x0ff2-0x0ff7
:显示参数0x0ff8
:显存地址(固定为0xA0000)
- 这些地址用于引导程序(IPL)向内核传递硬件信息:
-
对齐考虑:
-
地址按数据类型对齐:
CYLS EQU 0x0ff0 ; 单字节(实际使用CH寄存器) LEDS EQU 0x0ff1 ; 单字节 VMODE EQU 0x0ff2 ; 单字节 SCRNX EQU 0x0ff4 ; 字(2字节对齐) SCRNY EQU 0x0ff6 ; 字(2字节对齐) VRAM EQU 0x0ff8 ; 双字(4字节对齐)
-
-
历史兼容性:
- 这些地址是早期PC开发中形成的约定
- 在《30天自制操作系统》等教程中被标准化使用
这种设计确保了:
- 不会覆盖BIOS关键数据
- 内核可以可靠地获取硬件信息
- 各参数有足够空间存储
- 兼容大多数x86实模式环境
书中一部分解释
看一下程序就能明白,设置画面模式之后,还把画面模式的信息保存在了内存里。
这是因为,以后我们可能要支持各种不同的画面模式,这就需要把现在的设置信息
保存起来以备后用。我们暂且将启动时的信息称为BOOT_INFO。INFO是英文
information(信息)的缩写。
■■■■■
[VRAM]里保存的是0xa0000。在电脑的世界里,VRAM指的是显卡内存(video
RAM),也就是用来显示画面的内存。这一块内存当然可以像一般的内存一样存
储数据,但VRAM的功能不仅限于此,它的各个地址都对应着画面上的像素,可以
利用这一机制在画面上绘制出五彩缤纷的图案。
其实VRAM分布在内存分布图上好几个不同的地方。这是因为,不同画面模式的像
素数也不一样。当画面模式为〇×时使用这个VRAM;而画面模式为◇△时可能使
用那个VRAM,像这样,不同画面模式可以使用的内存也不一样。所以我们就预先
把要使用的VRAM地址保存在BOOT_INFO里以备后用。
这次VRAM的值是0xa0000。这个值又是从哪儿得来的呢?还是来看看我们每次都
参考的(AT)BIOS支持网页。在INT 0x10的说明的最后写着,这种画面模式
下“VRAM是0xa0000~0xaffff的64KB”。
另外,我们还把画面的像素数、颜色数,以及从BIOS取得的键盘信息都保存了起
来。保存位置是在内存0x0ff0附近。从内存分布图上看,这一块并没被使用,所以
应该没问题。
harib00i
保护模式和实模式
保护模式和实模式是x86架构CPU的两种主要运行模式,它们在内存访问、特权级别和功能支持等方面有显著差异:
- 实模式(Real Mode)
- 特点:
- 16位模式,兼容最早的8086处理器
- 直接物理内存寻址(1MB地址空间)
- 使用段寄存器:偏移地址的寻址方式(段地址×16+偏移)
- 无内存保护机制,所有代码具有相同特权级
- 应用场景:
- 计算机启动时的初始模式
- 运行传统的DOS程序
- 在操作系统引导阶段使用
- 特点:
- 保护模式(Protected Mode)
- 特点:
- 32位/64位模式(支持更大地址空间)
- 支持虚拟内存和分页机制
- 引入特权级(0-3级)和内存保护
- 使用段选择子和描述符表的复杂内存管理
- 支持多任务和任务隔离
- 优势:
- 可访问4GB物理内存(32位)
- 提供硬件级的内存保护
- 支持现代操作系统功能(如虚拟内存、多任务)
- 特点:
- 关键区别: | 特性 | 实模式 | 保护模式 | |------------|------------------|------------------| | 地址空间 | 1MB | 4GB(32位) | | 寻址方式 | 段:偏移(16+16) | 段选择子+偏移 | | 特权级别 | 无 | 0-3级(Ring0-3) | | 内存保护 | 无 | 有 | | 任务隔离 | 无 | 支持 |
- 模式切换:
- 从实模式切换到保护模式需要:
- 设置GDT(全局描述符表)
- 设置CR0寄存器的保护模式位
- 执行远跳转刷新流水线
- 从实模式切换到保护模式需要:
在您提供的代码中,[INSTRSET "i486p"]
和后续的CR0寄存器操作正是完成了从实模式到保护模式的切换过程。保护模式是现代操作系统运行的基础模式。
关于c-机器语言
首先,使用cc1.exe从bootpack.c生成bootpack.gas。
第二步,使用gas2nask.exe从bootpack.gas生成bootpack.nas。
第三步,使用nask.exe从bootpack.nas生成bootpack.obj。
第四步,使用obi2bim.exe从bootpack.obj生成bootpack.bim。
最后,使用bim2hrb.exe从bootpack.bim生成bootpack.hrb。
英特尔家谱:
8086→80186→286→386→486→Pentium→PentiumPro→PentiumII→PentiumIII→Pentiu