从零手写X86操作系统:实模式到保护模式实战
📅 2026/7/17 21:57:24
👁️ 次浏览
1. 项目概述为什么要手写X86操作系统2008年我在大学计算机实验室第一次见到GRUB引导界面时就被操作系统启动过程的神秘感深深吸引。当时教授说理解操作系统最好的方式就是自己写一个。如今十五年过去我依然记得在QEMU模拟器上看到自己编写的Hello OS成功启动时的激动心情。这个项目将带您从零构建一个能通过U盘启动的X86操作系统内核。不同于市面上大多数教程只停留在理论层面我们将完整实现以下核心功能实模式到保护模式的切换含GDT构建物理内存管理简易版页表实现键盘中断处理PS/2控制器编程VGA文本模式输出直接操作显存简易文件系统FAT16格式支持注意本教程需要读者具备C语言基础和基本的计算机组成原理知识特别是对寄存器、内存地址等概念的理解。完全零基础者建议先学习《深入理解计算机系统》CSAPP前四章。2. 开发环境搭建2.1 工具链选型经过对比测试我推荐以下开发工具组合编译器GCC交叉编译工具链target: i686-elf模拟器QEMU版本≥5.0调试器GDB with QEMU远程调试磁盘工具ddLinux或 RufusWindows# Ubuntu环境安装示例 sudo apt install qemu-system-x86 gcc-i686-elf nasm mtools2.2 项目目录结构建议采用模块化代码组织方式os-project/ ├── boot/ # 引导程序 │ ├── boot.asm # BIOS引导扇区 │ └── loader.asm # 二级加载器 ├── kernel/ # 内核代码 │ ├── main.c # 内核入口 │ └── include/ # 头文件 ├── scripts/ # 构建脚本 └── diskimg/ # 生成的磁盘镜像3. BIOS引导实现3.1 引导扇区开发BIOS会将磁盘第一个扇区512字节加载到内存0x7C00处执行。这段代码必须以0xAA55结束Magic Number使用16位实模式汇编禁用中断cli设置栈指针sp0x7C00; boot.asm [bits 16] [org 0x7C00] start: cli mov ax, 0 mov ds, ax mov es, ax mov ss, ax mov sp, 0x7C00 sti ; 加载第二段加载器 mov bx, 0x7E00 mov ah, 0x02 mov al, 4 ; 读取4个扇区 mov ch, 0 ; 柱面0 mov cl, 2 ; 从第2扇区开始 mov dh, 0 ; 磁头0 int 0x13 jmp 0:0x7E00 ; 跳转到loader times 510-($-$$) db 0 dw 0xAA55经验现代BIOS默认从USB设备模拟的FDD模式启动因此磁盘CHS参数需要特别处理。建议先用QEMU测试再烧录U盘。3.2 二级加载器设计由于引导扇区空间有限我们需要二级加载器完成检测内存布局通过BIOS中断0x15启用A20地址线解决8086兼容性问题加载GDT并进入保护模式将内核从磁盘加载到1MB以上内存// loader.c关键片段 void enable_a20() { // 通过键盘控制器启用A20 while (inb(0x64) 0x2); outb(0x64, 0xD1); while (inb(0x64) 0x2); outb(0x60, 0xDF); }4. 内核核心功能实现4.1 保护模式初始化进入32位保护模式需要构建全局描述符表GDT加载GDTR寄存器设置CR0寄存器PE位struct gdt_entry { uint16_t limit_low; uint16_t base_low; uint8_t base_middle; uint8_t access; uint8_t granularity; uint8_t base_high; } __attribute__((packed)); void load_gdt() { struct gdt_ptr gp; gp.limit sizeof(gdt) - 1; gp.base (uint32_t)gdt; asm volatile(lgdt %0 : : m(gp)); }4.2 内存管理简易物理内存管理器实现思路通过GRUB或自行检测内存大小维护空闲页帧位图实现kmalloc/kfree接口#define PAGE_SIZE 4096 struct page_frame { uint32_t addr; uint8_t used; }; void* kmalloc(size_t size) { uint32_t pages (size PAGE_SIZE - 1) / PAGE_SIZE; // 在位图中查找连续空闲页... }4.3 中断处理X86中断控制器编程步骤配置8259A PIC或APIC设置IDT中断描述符表实现中断服务例程ISRvoid isr_handler(struct regs *r) { if (r-int_no 33) { // 键盘中断 uint8_t scancode inb(0x60); handle_keypress(scancode); } outb(0x20, 0x20); // EOI }5. U盘启动适配5.1 镜像生成与烧录制作可启动镜像的完整流程创建空白磁盘镜像dd if/dev/zero格式化为FAT16mkfs.fat安装GRUB或直接写入引导扇区拷贝内核文件# 生成镜像示例 dd if/dev/zero ofos.img bs1M count32 sudo losetup /dev/loop0 os.img sudo mkfs.fat -F16 /dev/loop0 sudo mount /dev/loop0 /mnt sudo cp kernel.bin /mnt sudo umount /mnt sudo losetup -d /dev/loop05.2 主流BIOS兼容性处理不同厂商BIOS的特殊处理Dell/联想可能需要关闭Secure Boot华硕注意USB Legacy Support设置虚拟机确保选择正确的BIOS类型避坑指南如果U盘无法被识别为启动设备尝试以下步骤使用USB 2.0接口非蓝色在BIOS中将USB模式设为Full Initialization换用Ventoy等新型启动工具6. 调试技巧与常见问题6.1 QEMU调试方法启动调试会话qemu-system-i386 -s -S -drive formatraw,fileos.img # 另开终端 gdb -ex target remote localhost:1234常用调试命令info registers查看寄存器状态x/10i $eip反汇编当前指令break *0x7C00在引导扇区设断点6.2 典型问题排查三重错误Triple Fault检查GDT/IDT设置是否正确确认栈指针未越界屏幕无输出验证VGA显存地址0xB8000检查CR0 PG位是否过早启用键盘中断不触发确认PIC初始化序列检查键盘控制器状态端口0x647. 进阶开发建议完成基础内核后可以考虑添加ELF加载器支持用户程序实现分页内存管理MMU增加系统调用接口int 0x80移植Newlib标准库我在实际开发中发现最耗时的不是功能实现而是各种硬件兼容性问题。建议购买一个便宜的旧笔记本如ThinkPad X220作为专用测试机比虚拟机调试效率高很多。
先按场景给答案
2026年新媒体人提取抖音视频文案,不需要复杂的录屏转音频操作,目前有3款免费工具可以满足不同场景需求。我作为长期测试AI效率工具的博主,亲测了市面主流工具后按场景匹配给出推荐,不是绝对排名,职场新…
📅 2026/7/17 21:57:24
1. 项目概述:为什么我们需要一个跨平台的自动化测试框架?如果你在多个平台上维护过软件产品,无论是桌面端的Windows、macOS、Linux,还是移动端的Android、iOS,甚至是游戏模拟器,你一定会对“测试”这件事感…
📅 2026/7/17 21:56:24
1. 项目概述:为什么Wireshark过滤DNS是网络分析的必修课 刚接触Wireshark的新手,面对海量的数据包,最常问的问题就是:“我怎么只看我想看的?” 这感觉就像在嘈杂的菜市场里,只想听清隔壁摊位在聊什么。而DN…
📅 2026/7/17 21:56:24
一、前言:AI 应用安全的"五条红线"做 AI Agent 应用,有五条安全红线绝不能碰:Key 不落盘:API Key 只在进程内存,永不写入文件/数据库/preferences/rawfile/日志。Key 不入 State:AgentState 持久…
📅 2026/7/17 22:46:55
一、前言:多模态的"三个难题"假设你让 Agent 接收用户拍的烘焙成品照片,分析烘焙效果。你查了智谱 API 文档,发现它支持 image_url。你写了:const message new AgentMessage(MessageRole.user, [ContentPart.image(bas…
📅 2026/7/17 22:46:55
AO3镜像站:打破阅读壁垒的7步完整解决方案 【免费下载链接】AO3-Mirror-Site 项目地址: https://gitcode.com/gh_mirrors/ao/AO3-Mirror-Site
还在为无法访问Archive of Our Own(AO3)而烦恼吗?这个全球最大的同人创作平台…
📅 2026/7/17 22:46:55
你有没有遇到过这样的场景:在无人机飞控系统开发中,需要给多个外设(如电调、GPS模块、传感器等)进行固件升级,传统的做法是逐个连接、烧录,既耗时又容易出错。特别是在现场调试时,一个固件版本不…
📅 2026/7/17 22:46:55
ngx_output_chain_filter_pt 分析为什么在有了 ngx_http_output_body_filter_pt 的情况下
还需要 ngx_output_chain_filter_pt?1. 问题引入:copy_filter 中的两行神秘代码
如果你阅读过 ngx_http_copy_filter 的源码(src/http/ngx_http_copy_…
📅 2026/7/17 22:46:55
今天必须得跟大伙聊聊 echarts 地图 geo 这个老生常谈但又让人头秃的话题。说实话,刚接触的时候我觉得挺简单,不就是画个图嘛,结果真上手了才发现,坑多得能把你埋了。特别是那个 geo 组件,跟 series 里的 map 虽然长得像,但底层逻辑完全两码事。很多新手朋友,包括我之前…
📅 2026/7/17 22:45:49
1. 为什么选择用DeepSeek V4替换Codex的底座模型去年我在开发一个智能代码补全工具时,发现Codex的默认底座模型在复杂业务逻辑场景下表现不尽如人意。经过多次测试对比,DeepSeek V4在以下几个关键指标上展现出明显优势:代码补全准确率&#x…
📅 2026/7/17 0:00:32
1. VS Code 高效配置基础作为一款轻量级但功能强大的代码编辑器,VS Code 的默认配置已经能满足基本需求,但通过合理调整设置可以大幅提升编码效率。我使用 VS Code 已经有五年多时间,期间尝试过各种配置方案,总结出这套适合大多数…
📅 2026/7/17 0:00:32
在异常检测领域,很多优秀算法最初都是以研究代码的形式发布的。它们能够在固定测试集上复现实验结果,却不一定能被普通用户直接拿来测试自己的图片。尤其是最近很多算法仅提供在固定测试集的测试环境,而gradio的demo演示也不会提供。
对工程应用和在自己的图片上进行测试来…
📅 2026/7/17 0:00:32
豆包openclaw最近圈子里都在聊豆包openclaw,我也没忍住,掏腰包入手了一套。说实话,刚拿到手的时候,心里是打鼓的。毕竟市面上类似的智能硬件太多了,有的吹得天花乱坠,用起来却是一堆bug。为了不让大家的钱打水漂,我连续用了半个月。从开箱到日常高频使用,甚至故意测试它…
📅 2026/7/17 2:37:27
SQLyog 13.3.1 社区版在Windows 10/11上的完整安装与连接指南 对于刚接触MySQL数据库管理的开发者和学生来说,选择一个直观易用的图形化管理工具至关重要。SQLyog作为一款轻量级但功能强大的MySQL GUI工具,能够显著提升数据库操作的效率和体验。本文将详…
📅 2026/7/16 21:45:29
SPEC CPU 2006 跨平台基准测试深度实战:ARM/X86/MIPS 架构配置优化与结果分析方法论在当今多元化的计算架构时代,如何客观评估不同处理器平台的真实性能成为系统工程师和性能优化专家的核心挑战。SPEC CPU 2006 作为业界公认的计算密集型基准测试套件&am…
📅 2026/7/17 15:13:18
目录
第一步:选对模板,省心一半
第二步:打开扫码点餐功能
开启功能按钮
桌台管理与桌码生成
第三步:个性化设计,打造品牌感
调整点餐页面
设置点餐规则 你还在让顾客站着排队点餐吗?2025年ÿ…
📅 2026/7/17 6:11:34
在业务中快速构建一个能理解私有文档、准确回答专业问题的智能助手,是很多开发团队面临的共同挑战。传统方案往往需要从零开始搭建复杂的 RAG(检索增强生成)系统,涉及文档解析、向量化、检索、大模型调用等多个环节,整…
📅 2026/7/17 15:13:18
FAE放射组学分析工具:医学影像特征探索的完整解决方案 【免费下载链接】FAE FeAture Explorer 项目地址: https://gitcode.com/gh_mirrors/fae/FAE
你是否曾经面对海量医学影像数据感到无从下手?想要从CT、MRI等影像中提取有价值的定量特征&#…
📅 2026/7/17 2:40:57