将自制简易OS从QEMU移植到物理机启动需做哪些修改?
实模式显存地址适配与自动获取方案
1. 0xb8000在真实笔记本上是否可用?
0xb8000是VGA文本模式的标准显存物理起始地址,在绝大多数支持传统BIOS的x86笔记本上都能正常工作——只要你的引导加载程序是从实模式启动(自制引导程序基本都是这个路径),直接写入该地址在大部分机器上都能显示内容。
唯一需要注意的例外:如果笔记本使用UEFI引导且关闭了CSM(兼容支持模块),实模式下可能无法直接访问VGA显存,但这类场景下你自制的引导程序大概率无法启动,所以0xb8000对你的当前场景基本通用。
2. 自动获取显存地址的方法
如果要追求更强的硬件兼容性(比如适配特殊显示卡,或后续进入保护模式/长模式),可以通过以下两种方式实现:
方式一:实模式下调用BIOS中断
在引导加载程序中调用BIOS中断int 0x10的相关子功能,获取显存信息后传递给内核:
- 子功能
0x0F:获取当前视频模式,返回的es寄存器会指向显存段地址(文本模式下通常是0xb800,结合偏移0即可得到0xb8000物理地址) - 子功能
0x12:获取显示适配器扩展信息,可直接得到显存起始地址和大小
示例汇编代码(在引导程序中执行,结果存入内存固定位置供内核读取):
mov ah, 0x0F int 0x10 ; 返回值说明: ; al = 当前视频模式编号 ; bh = 当前显示页号 ; es 寄存器 = 显存段地址(文本模式下为0xb800)
方式二:保护模式下使用VBE扩展
如果内核后续要进入保护模式,推荐使用VESA BIOS Extensions(VBE)获取线性帧缓冲(LFB)地址:
- 调用
int 0x10子功能0x4F00获取VBE控制器信息 - 调用
0x4F01获取支持的显示模式列表 - 调用
0x4F02设置目标模式,从返回的结构体中提取线性显存地址
这种方式能适配更多现代显示硬件,且支持更高分辨率的图形模式。
3. 现有内核代码的小优化
你的C代码存在局部变量覆盖全局变量的问题,且执行完main后会跑飞,建议修改为:
extern "C" void main() { char* addr = (char*)0xb8000; for (int i = 0x00; i < 0xff; i += 0x11) { *addr++ = 'A'; *addr++ = i; } while(1); // 阻止执行完后跑飞 }
内容的提问来源于stack exchange,提问作者Blue Herring
相关产品推荐
相关产品推荐

