# os **Repository Path**: gsool/os ## Basic Information - **Project Name**: os - **Description**: 从零开始写一个操作系统 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-07 - **Last Updated**: 2026-07-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 从零开始写一个操作系统 — Turbo C 界面演示 > 一个运行在 x86 实模式下的 Turbo C 2.01 风格界面演示程序,从引导扇区开始,完全用 NASM 汇编编写,展示两阶段引导和 VGA 文本模式界面绘制技术。 --- ## 1. 项目简介 本项目实现了一个可以在计算机启动时直接运行的 Turbo C 2.01 风格界面演示程序。按下电源键后,经过 BIOS 引导 → 加载第二阶段代码 → 绘制完整界面,无需任何操作系统。 ### 1.1 项目目标 - 理解计算机从按下电源键到执行自定义代码的完整流程 - 掌握 BIOS 中断调用(视频、磁盘) - 理解 MBR 引导扇区结构和二级引导原理 - 学习 NASM 汇编语言和 16 位实模式编程 - 实践 VGA 文本模式界面绘制和 CP437 边框字符 ### 1.2 项目文件结构 ``` os/ ├── boot.asm # 引导加载器(512 字节,MBR) ├── boot.bin # 编译后的引导扇区 ├── sprite_720x400.asm # 第二阶段代码(1024 字节,界面绘制) ├── sprite.bin # 编译后的第二阶段代码 ├── sprite.img # 最终可启动镜像(boot.bin + sprite.bin) ├── build.bat # 编译脚本 ├── run.bat # 编译 + QEMU 运行 ├── flash-boot.c # 磁盘烧录工具(支持多扇区写入) ├── flash-boot.exe # 编译后的烧录工具 ├── nasm.exe # NASM 汇编器 └── Turbo C 2.01.png # 参考界面图片 ``` --- ## 2. 预备知识 ### 2.1 x86 实模式 - 计算机刚开机时处于 **16 位实模式**(Real Mode) - 只能访问 1MB 内存(地址线 20 位) - 使用 16 位寄存器:`AX`, `BX`, `CX`, `DX`, `SI`, `DI`, `BP`, `SP` ### 2.2 BIOS 中断 BIOS 提供了基本的硬件操作接口,通过 `int` 指令调用: | 中断号 | 用途 | 本项目中的使用 | |--------|------|---------------| | `int 0x10` | 视频服务 | 设置文本模式、移动光标 | | `int 0x13` | 磁盘服务 | 加载第二阶段代码到内存 | ### 2.3 MBR 引导扇区 - **大小**:正好 512 字节 - **签名**:最后两个字节必须是 `0x55` `0xAA` - **加载地址**:BIOS 会把它加载到内存地址 `0x7C00` ### 2.4 VGA 文本模式 - **分辨率**:80×25 字符 - **显存地址**:`0xB8000` - **每个字符**:2 字节(低字节=字符码,高字节=属性) - **属性字节**:低 4 位前景色,高 4 位背景色 ### 2.5 CP437 边框字符 使用扩展 ASCII 字符集绘制界面边框: | 字符码 | 显示 | 用途 | |--------|------|------| | `0xCD` | ═ | 标题栏横线 | | `0xD5` | ╒ | 标题栏左上角 | | `0xB8` | ╕ | 标题栏右上角 | | `0xB3` | ┃ | 竖线 | | `0xC4` | ─ | 横线(消息行) | | `0xC3` | ├ | T型连接(消息行左边框) | | `0xB4` | ┤ | T型连接(消息行右边框) | | `0xC0` | └ | 左下角(消息区) | | `0xD9` | ┘ | 右下角(消息区) | --- ## 3. 启动流程 ``` 按下电源键 ↓ BIOS 自检(POST),初始化硬件 ↓ 读取磁盘第一个扇区(boot.bin,512 字节)→ 内存 0x7C00 ↓ boot.asm(引导加载器)用 int 0x13 加载扇区 2-3 → 内存 0x7E00 ↓ 设置 80×25 文本模式(int 0x10) ↓ 跳转到 0x7E00 执行第二阶段代码 ↓ sprite_720x400.asm:绘制完整界面 ├── fill_screen:填充背景色 ├── draw_menu_text:绘制菜单栏 ├── draw_title_bar:绘制标题栏 ├── draw_status_text:绘制状态栏 ├── draw_editor_borders:绘制编辑区边框(含消息区) └── draw_function_keys:绘制功能键提示 ↓ 显示 Turbo C 风格界面,暂停 ``` --- ## 4. boot.asm — 引导加载器 `boot.asm` 是 BIOS 加载的第一个程序,运行在 `0x7C00`,职责是加载第二阶段代码并跳转执行。 ```asm [org 0x7C00] [bits 16] xor ax, ax ; 设置段寄存器 mov ds, ax mov es, ax mov ss, ax mov sp, 0x7C00 mov [drive], dl ; 用 int 0x13 从磁盘读取扇区 2-3 到内存 0x7E00 mov ah, 0x02 ; AH=0x02: 磁盘读取 mov al, 2 ; 读 2 个扇区 mov ch, 0 ; 柱面 0 mov cl, 2 ; 从扇区 2 开始 mov dh, 0 ; 磁头 0 mov dl, [drive] mov bx, 0x7E00 int 0x13 jnc .ok ; 读取失败:显示 "Error" ... .ok: mov ax, 0x0003 ; 设置 80×25 文本模式 int 0x10 jmp 0x7E00 ; 跳转到第二阶段代码 ``` --- ## 5. sprite_720x400.asm — 第二阶段代码 第二阶段代码(1024 字节)包含所有界面绘制函数: | 函数 | 功能 | |------|------| | `fill_screen` | 填充背景色(行0和行24灰色,其余蓝色) | | `draw_menu_text` | 绘制菜单栏(8个菜单项,快捷键红字) | | `draw_title_bar` | 绘制标题栏(边框+Edit文字) | | `draw_status_text` | 绘制状态栏(Line 1 Col 1...) | | `draw_editor_borders` | 绘制编辑区边框(竖线+底线+消息区) | | `draw_function_keys` | 绘制功能键提示(F1-F10) | ### 界面布局 | 行号 | 区域 | 背景色 | 内容 | |------|------|--------|------| | 0 | 菜单栏 | 灰色 | File、Edit、Run、Compile、Project、Options、Debug、Break/watch | | 1 | 标题栏 | 蓝色 | 边框+Edit标题 | | 2 | 状态栏 | 蓝色 | Line、Col、Insert、Indent、Tab、Fill、Unindent、文件名 | | 3-20 | 编辑区 | 蓝色 | 代码编辑区域,带左右竖边框 | | 21 | 底部边框行 | 蓝色 | 水平边框线,中间显示"Message" | | 22 | 分隔行 | 蓝色 | 只有左右竖边框 | | 23 | 消息行 | 蓝色 | 水平边框线 | | 24 | 功能键提示 | 灰色 | F1-Help、F5-Zoom、F6-Switch 等 | --- ## 6. 颜色方案 | 属性字节 | 前景色 | 背景色 | 用途 | |----------|--------|--------|------| | `0x70` | 黑色 | 灰色 | 菜单栏、功能键行背景 | | `0x74` | 红色 | 灰色 | 功能键数字高亮 | | `0x17` | 白色 | 蓝色 | 编辑区、标题栏、状态栏背景和边框 | | `0x1F` | 白色 | 蓝色(高亮) | 标题栏"Edit"文字 | --- ## 7. 编译与运行 ### 7.1 快速开始(推荐) 双击 `run.bat` 或在命令行执行: ```cmd run.bat ``` 它会自动编译并启动 QEMU 虚拟机运行演示。 ### 7.2 手动编译 ```cmd build.bat ``` 执行以下步骤: ```bash nasm boot.asm -f bin -o boot.bin # 编译引导加载器(512字节) nasm sprite_720x400.asm -f bin -o sprite.bin # 编译第二阶段代码(1024字节) ``` ### 7.3 生成可启动镜像 ```cmd copy /b boot.bin + sprite.bin sprite.img ``` `/b` 表示二进制拼接,将 boot.bin(512 字节)和 sprite.bin(1024 字节)拼接成 sprite.img(1536 字节)。 ### 7.4 QEMU 运行 ```bash qemu-system-i386 -drive file=sprite.img,format=raw,if=floppy ``` `if=floppy` 模拟软盘,BIOS 会从软盘的第一个扇区引导。 ### 7.5 写入真实磁盘 > ⚠️ **警告:此操作会覆盖目标磁盘的前 N 个扇区,可能导致数据丢失!** ```cmd :: 以管理员身份运行 flash-boot.exe sprite.img 1 # 写入磁盘 1 ``` 工具会列出所有磁盘供选择,自动备份原有扇区,确认后写入。 --- ## 8. flash-boot.c — 磁盘烧录工具 将镜像文件(如 `sprite.img`)写入物理磁盘起始位置,支持多扇区写入。 ### 8.1 功能 - 列出系统所有物理磁盘(型号、大小) - 自动验证镜像的引导签名(`0x55AA`) - 写入前自动备份原扇区到文件 - 支持命令行参数和交互式两种模式 ### 8.2 写入流程 ``` 读取镜像文件 → 扇区对齐 → 验证签名 → 用户确认 → 备份原扇区 → 写入磁盘 ``` ### 8.3 编译 ```bash gcc flash-boot.c -o flash-boot.exe ``` 需要 Windows API(`CreateFileA`、`DeviceIoControl` 等),仅支持 Windows 平台。 --- ## 9. 常见问题 **Q: 为什么要用 NASM 而不是 GCC?** 引导扇区和第二阶段代码都必须是**纯二进制**格式,没有 ELF/PE 等格式头。C 编译器产出的目标文件无法直接作为引导代码。 **Q: 为什么用软盘格式而不是硬盘?** `if=floppy` 让 QEMU 将镜像视为软盘,BIOS 会从软盘引导。使用 `if=ide` 也可以模拟硬盘,但需要确保镜像的第一个扇区是有效的 MBR。 **Q: 第二阶段代码为什么是 1024 字节?** 因为所有界面绘制函数(fill_screen、draw_menu_text、draw_title_bar、draw_status_text、draw_editor_borders、draw_function_keys)和数据字符串(菜单、标题、状态栏、功能键文本)需要超过 512 字节,所以占用 2 个扇区。 **Q: 为什么 boot.asm 中 `int 0x13` 的 `al=2`?** `al` 指定读取的扇区数。第二阶段代码是 1024 字节(2 个扇区),所以需要读取 2 个扇区。 --- ## 10. 学习路线 本项目涵盖的知识点可以延伸到操作系统开发的多个方向: 1. **已完成** — 引导扇区、二级加载、BIOS 中断、文本模式显示、界面绘制 2. **下一步** — 进入 32 位保护模式(设置 GDT、打开 A20 地址线) 3. **内核开发** — 用 C 语言编写内核主体,汇编作为入口 4. **内存管理** — 实现分页和内存分配器 5. **文件系统** — 实现 FAT12/ext2 等简单文件系统 6. **图形模式** — 从文本模式切换到 VGA 图形模式 --- > 从一个 512 字节的引导扇区到完整的 Turbo C 风格界面——这就是底层编程的魅力。