x86_64引导加载程序设计
基于HIC架构需求,以下是x86_64平台引导加载程序的详细设计方案:
一、总体架构
1.1 多阶段引导流程
UEFI/BIOS → HIC Bootloader (多阶段) → HIC Core-0
│ │
├─ UEFI模式 ├─ BIOS模式
│ (UEFI应用) │ (MBR+引导扇区)
└─ 安全启动 └─ 传统启动
## 三、BIOS引导模式(传统兼容)
### 3.1 多阶段设计
### 3.2 第一阶段(MBR/VBR)
**MBR结构(实模式):**
**执行流程:**
1. BIOS加载MBR到`0x7C00`
2. 切换到保护模式(32位)
3. 从活动分区加载VBR(卷引导记录)
4. VBR加载第二阶段加载器到`0x10000`
### 3.3 第二阶段加载器(32位保护模式)
**主要功能:**
1. **初始化保护模式**
- 设置GDT、IDT
- 启用A20地址线
- 设置临时页表
2. **探测硬件**
- 通过BIOS INT 0x15获取内存映射
- 探测VESA VBE显示模式
- 初始化PS/2键盘控制器
3. **加载内核映像**
- 从文件系统(FAT32/EXT2)读取
- 支持从硬盘、USB、光盘启动
- 实现简单的文件系统驱动
4. **验证内核**
- 计算映像哈希(SHA-256)
- 与内置公钥比较(简化验证)
5. **切换到长模式**
- 设置4级分页
- 进入64位长模式
- 加载64位GDT
6. **传递信息**
- 构建Multiboot2兼容信息结构
- 包含内存映射、命令行、模块信息
7. **跳转到内核**
- 设置栈指针
- 禁用中断
- 跳转到内核入口点
## 四、引导信息结构(Boot Information Structure)
### 4.1 通用结构(UEFI和BIOS通用)
```c
struct hic_boot_info {
uint32_t magic; // 0x48 0x49 0x4B 0x21 ("HIC!")
uint32_t version; // 结构版本
uint64_t flags; // 特性标志位
// 内存信息
struct memory_map *mem_map;
uint64_t mem_map_size;
uint64_t mem_map_desc_size;
// ACPI信息
void *rsdp; // ACPI根系统描述指针
void *xsdp; // ACPI扩展系统描述指针(UEFI)
// 固件信息
union {
struct {
EFI_SYSTEM_TABLE *system_table;
EFI_HANDLE image_handle;
} uefi;
struct {
void *bios_data_area; // BDA指针
uint32_t vbe_info; // VESA信息块
} bios;
} firmware;
// 内核映像信息
void *kernel_base;
uint64_t kernel_size;
uint64_t entry_point;
// 命令行
char cmdline[256];
// 设备树(x86通常为空)
void *device_tree;
uint64_t device_tree_size;
// 模块信息(用于动态模块加载)
struct module_info *modules;
uint64_t module_count;
};
4.2 内存映射描述符
struct memory_map_entry {
uint64_t base_address;
uint64_t length;
uint32_t type; // 1=可用, 2=保留, 3=ACPI, 4=NVS, 5=坏内存
uint32_t attributes;
};
五、内核映像格式
5.1 整体结构
+------------------+
| HIC 文件头 | 120 字节 (0x00-0x77)
+------------------+
| 段表 | 48 字节 × 段数量
+------------------+
| 段数据 | 可变大小
| - 代码段 |
| - 数据段 |
| - 只读数据段 |
| - BSS段(无数据) |
| - 配置段 |
+------------------+
| 配置表 | 可变大小 (可选)
+------------------+
| 签名数据 | 可变大小 (可选)
+------------------+
5.2 文件头结构
偏移量 大小 描述
0x00 8 魔数 "HIC_IMG" (以\0结尾)
0x08 2 架构ID (1=x86_64, 2=ARM64, 3=RISC-V64)
0x0A 2 版本 (主版本 << 8 | 次版本)
0x0C 8 入口点偏移
0x14 8 映像总大小
0x1C 8 段表偏移
0x24 8 段表项数
0x2C 8 配置表偏移
0x34 8 配置表大小
0x3C 8 签名偏移
0x44 8 签名大小
0x4C 64 预留
头部总大小:120字节
C结构体定义:
typedef struct {
char magic[8]; // "HIC_IMG"
uint16_t arch_id; // 架构ID
uint16_t version; // 版本号
uint64_t entry_point; // 入口点偏移
uint64_t image_size; // 映像总大小
uint64_t segment_table_offset; // 段表偏移
uint64_t segment_count; // 段表项数
uint64_t config_table_offset; // 配置表偏移
uint64_t config_table_size; // 配置表大小
uint64_t signature_offset; // 签名偏移
uint64_t signature_size; // 签名大小
uint8_t reserved[64]; // 预留
} hic_image_header_t;
注意: - segment_table_offset 通常为 120(紧跟文件头) - segment_count 段表项数(每个段表项 40 字节) - entry_point 是相对于内核加载基地址的偏移
5.3 段表项
typedef struct {
uint32_t type; // 段类型 (1=代码, 2=数据, 3=只读数据, 4=BSS, 5=配置)
uint32_t flags; // 段标志 (位0=可读, 位1=可写, 位2=可执行)
uint64_t file_offset; // 文件中的偏移
uint64_t memory_offset; // 内存中的偏移
uint64_t file_size; // 文件大小
uint64_t memory_size; // 内存大小
} hic_segment_entry_t;
段表项大小:40字节 (4+4+8×4)
段类型定义:
#define HIC_SEGMENT_TYPE_CODE 1 // 代码段
#define HIC_SEGMENT_TYPE_DATA 2 // 数据段
#define HIC_SEGMENT_TYPE_RODATA 3 // 只读数据段
#define HIC_SEGMENT_TYPE_BSS 4 // BSS段(零初始化)
#define HIC_SEGMENT_TYPE_CONFIG 5 // 配置段
段标志定义:
#define HIC_SEGMENT_FLAG_READABLE (1 << 0) // 可读
#define HIC_SEGMENT_FLAG_WRITABLE (1 << 1) // 可写
#define HIC_SEGMENT_FLAG_EXECUTABLE (1 << 2) // 可执行
5.4 简化格式(内核)
对于简单的内核(如当前实现),可以使用简化格式: - 段表项数:1 - 段表偏移:120 - 段类型:1 (CODE) - 段标志:0x7 (可读+可写+可执行) - 文件偏移:160 (120 + 40) - 内存偏移:0x100000 (内核加载地址) - 文件大小 = 内存大小
示例布局:
偏移 大小 内容
0x00 120 HIC 文件头
0x78 40 段表 (1个段)
0xA0 N 内核代码
六、安全启动实现
6.1 签名验证流程
加载映像 → 计算哈希 → 提取签名 → 验证签名 → 加载内核
│ │ │ │
│ SHA-384 │ RSA-3072验证
│ │
│ PKCS#1 v2.1签名
└───────── 公钥证书链验证 ────────┘
6.2 密钥管理
- 平台密钥(PK):存储在UEFI固件或TPM
- 内核签名密钥(KSK):用于签名内核映像
- 恢复密钥(RK):用于恢复模式
- 开发密钥(DK):仅用于开发构建
七、恢复与调试支持
7.1 恢复模式
- 内核故障检测:通过启动计数器检测连续失败
- 自动回滚:加载备份内核映像
- 恢复控制台:通过串口或网络提供诊断接口
- 网络恢复:通过TFTP/PXE重新下载内核
7.2 调试接口
- 串口输出:COM1 (0x3F8) 或 COM2 (0x2F8)
- 内存日志缓冲区:固定物理地址的循环缓冲区
- QEMU/GDB支持:通过0xE9端口输出和调试器接口
- 错误代码显示:通过VGA文本模式显示错误信息
八、构建系统集成
8.1 构建流程
1. 编译引导加载程序
$ make bootloader ARCH=x86_64 MODE=uefi
2. 生成内核映像
$ make kernel
3. 签名内核映像
$ make sign-kernel KEY=production
4. 创建启动介质
$ make install TARGET=usb DISK=/dev/sdb
8.2 输出文件
- UEFI:
bootx64.efi(引导加载程序) +kernel.hic(内核) - BIOS:
boot.bin(引导扇区) +loader.bin(第二阶段) - ISO映像:
hic-x86_64.iso(用于虚拟机测试)
九、测试与验证
9.1 测试环境
- QEMU/KVM:用于虚拟化测试
- 物理硬件:Intel/AMD服务器和工作站
- CI/CD集成:自动化构建和启动测试
9.2 验证要点
- 启动时间:从UEFI到内核入口的总时间
- 内存占用:引导加载程序的内存使用量
- 兼容性:在不同硬件平台的兼容性
- 安全性:签名验证的可靠性