【免费下载链接】Visor-BootManager
A minimal, fast, graphical UEFI boot manager written in C. no external dependencies — just a config file :)
你有没有遇到过磁盘分区表损坏、电脑直接无法启动的绝望场景?Visor 是一个只有约 340 KB 的图形化 UEFI 启动管理器,它内置了 GPT 诊断与备份表修复能力:在开机画面就自动检测分区表健康状态,一旦主表损坏而备份表完好,就能用备份表把主分区表一键重建,让机器重新可引导。这篇文章带你完整看懂这套"自救机制"的原理。
对大多数人来说,分区表是"看不见但离不了"的东西:系统靠它找到每个分区的位置和大小。分区表一坏,哪怕磁盘上的文件一个都没丢,机器也会表现得像"硬盘凭空消失"。Visor 正是针对这种场景,把修复能力直接做进了启动管理器里。
一、分区表损坏为什么能救:GPT 的双表保险机制
要理解 Visor 的修复原理,先要明白 GPT(GUID Partition Table)自带"双备份"设计:
- 主表(Primary):位于磁盘第 1 扇区(LBA 1),紧随其后的 LBA 2 起存放分区条目数组;
- 备份表(Backup):位于磁盘最后一个扇区,它的分区条目数组则存放在紧邻其前的位置;
- 保护性 MBR:LBA 0 处是一个 0xEE 类型的保护扇区,防止老工具误操作 GPT 磁盘;
- CRC32 校验:表头和分区条目数组都带有校验值,任何一位数据被破坏都能被发现。
正常情况下,两块表内容完全一致。因此当主表被坏道、异常掉电或写入事故破坏时,只要磁盘尾部的备份表还完好,主表就理论上可以 100% 恢复——这正是 Visor GPT 修复的核心依据。Visor 对这一机制的完整数据模型定义在 src/include/gpt.h 中。
二、Visor 的三步诊断:它如何"给磁盘做体检"
Visor 的诊断入口是 gpt_diagnose()(src/gpt/gpt_diagnose.c#L231-L364),流程非常克制、可预测:
- 读 MBR(LBA 0):确认存在保护性 MBR 签名;
- 读主表(LBA 1):检查
EFI PART签名、版本号、表头 CRC32、主/备 LBA 交叉引用是否自洽; - 读备份表(磁盘最后一个扇区):同样解析并校验;
- 逐份做三层验证:表头(header)→ 分区条目数组(entries,含条目数量/大小/CRC)→ 分区布局(layout,检查分区越界、互相重叠、GUID 重复、与 GPT 元数据冲突等);
- 两份表逐字段对比,输出统一的损伤分级。
每个字段校验失败都会带一个明确的"病因码",从 GPT_R_INVALID_SIGNATURE(签名非法)到 GPT_R_PARTITION_OVERLAP(分区重叠)共 30 多种,全部列在 src/include/gpt.h#L33-L74 中,方便排障时精准定位。
三、损伤分级:8 种诊断结果与对应的救援策略
诊断完成后,gpt_classify()(src/gpt/gpt_diagnose.c#L74-L145)把磁盘归入 8 种类别之一。Visor 的修复策略极其保守——只有一种情况允许自动修复:
| 诊断分级 | 含义 | 能否自动修复 |
|---|---|---|
HEALTHY | 两份表完好且一致 | 无需处理 |
PRIMARY_CORRUPT_BACKUP_VALID | 主表损坏,备份表完好 | ✅ 自动修复 |
BACKUP_CORRUPT_PRIMARY_VALID | 备份表损坏 | ⚠️ 仅人工处理 |
BOTH_COPIES_CORRUPT | 两份表都损坏 | ⚠️ 仅人工处理 |
COPIES_DIFFER | 两份表内容不一致 | ⚠️ 仅人工处理 |
INVALID_LAYOUT | 分区布局本身非法 | ⚠️ 仅人工处理 |
NOT_GPT | 根本不是 GPT 磁盘 | 不适用 |
UNSAFE_TO_RECOVER | 修复存在安全风险 | 拒绝修复 |
为什么这么保守?因为"两份表不一致"或"布局非法"时,自动写入任何一个版本都可能覆盖掉用户真实的数据边界。与其赌,不如交给人判断——这是刻进 src/gpt/gpt_diagnose.c 的安全底线。
四、修复原理:从备份表重建主表的五道安全关卡
当且仅当磁盘处于"主表损坏、备份表完好"且介质可写时,Visor 才会生成修复计划。gpt_build_primary_plan()(src/gpt/gpt_repair.c#L11-L146)会先过五道关卡:
- 备份表头必须真实位于磁盘最后一个扇区,且其"备份 LBA"字段确实指向 LBA 1;
- 写入目标区域(LBA 1~条目数组末尾)不得与任何已定义分区重叠;
- 目标区域不得侵入"可用 LBA 范围"之外;
- 重新计算备份条目数组的 CRC32,必须与表头记录的校验值完全一致(防止备份表自身是"半损坏"状态);
- 基于备份表头在内存中组装新的主表头:修正当前/备份 LBA、条目区地址,并重新计算表头 CRC。
任何一关不过,修复直接取消,磁盘一个字节都不会被改动。
真正的执行在 gpt_execute_plan()(src/gpt/gpt_repair.c#L244-L321)中,顺序同样经过精心设计:
- 写前再校验:执行前重新读取备份表,确认磁盘指纹(media ID、扇区大小、总扇区数)和 CRC 与诊断时一致,防止"诊断到写入之间磁盘发生了变化";
- 先写条目数组,后写表头,每步之间 flush 缓存,保证表头永远指向一份完整的条目数组;
- 写后全量复检:再跑一遍完整诊断,要求主表、备份表均 VALID 且两份表完全一致,才宣告修复成功;
- 备份表全程只读:修复只重建主表,备份表永远不被写入,保证"救命稻草"始终在场。
五、两条使用路径:图形警告屏与文本恢复控制台
这套能力通过两条路径暴露给用户,均无需进入操作系统:
1. 图形警告屏(开机自动触发)
Visor 每次进入菜单前都会静默扫描所有整盘块设备(src/gui/gui_gptwarn.c#L315)。一旦命中"主表损坏、备份表完好"的磁盘,会先于启动菜单弹出 "Disk corruption detected" 卡片:
Enter:进入确认流程,必须手动键入 YES 才会执行修复(防止误触);D:查看完整诊断细节(MBR 状态、主/备份表逐项校验结果、分区清单);Esc/B:忽略警告照常引导(例如你想先拷贝数据时)。
2. 文本恢复控制台(gpt 命令)
如果图形界面不可用,在菜单按 Esc 进入救援控制台(rescue console),可以直接使用三个子命令(src/gpt/text_gptcmd.c):
gpt # 扫描所有磁盘,列出每块盘的 GPT 诊断分级
gpt <N> # 查看 N 号磁盘(media id)的详细诊断
gpt repair <N> # 从验证过的备份表重建 N 号磁盘的主 GPT
执行修复前同样会先打印完整计划(源备份位置、写入目标、分区数量)并要求键入 YES 确认,失败时会明确给出原因码并提示磁盘未被修改。
六、安全设计:为什么敢让启动管理器自己写磁盘
在 OS 都起不来的时候让引导程序直接写分区表,风险是实打实的。Visor 的对策可以概括为一句话:宁可不修,绝不乱修。
- 只读介质直接拒绝(
GPT_R_READ_ONLY_MEDIA),只读光驱/写保护盘不会进入修复流程; - 诊断与写入之间做磁盘指纹复核,介质被拔插替换会立即中止(
GPT_R_DISK_CHANGED); - 备份表永不写入,写失败路径下明确提示 "The disk was not modified.";
- 成功后必须通过"写后全量复检" 才算完成,复检不通过则报告
GPT_R_POST_WRITE_VERIFY_FAILED,而不是盲目报喜。
这也是 README.md 对比表中把它列为 "Windows immunity"(Windows 免疫)特性的原因:Windows 更新或磁盘异常损坏 GPT 主表后,Visor 可以在开机第一时间把它救回来,同时它的 NVRAM 自修复模块 还会顺手修复被固件重置的启动项,两者构成完整的"引导自救链"。
七、动手验证与延伸阅读
GPT 修复是一个独立的功能模块(feature flag),在功能注册表 features/features.json 中被定义为 gptrepair,构建侧对应 features/features.mk#L148-L152;如果你裁剪了最小化构建,可以检查该功能是否包含在内。
📌 关键源码索引:
- 解析与比对:src/gpt/gpt.c
- 损伤分级与诊断:src/gpt/gpt_diagnose.c
- 修复计划与执行:src/gpt/gpt_repair.c
- 图形警告屏:src/gui/gui_gptwarn.c
- 文本
gpt命令:src/gpt/text_gptcmd.c
💡 一句话总结:GPT 天生有"主表 + 备份表"的双保险,而 Visor 做的事,就是在保险还生效时,用最保守、可验证的方式把主表从备份表里"复印"回来。下次分区表损坏导致无法开机时,Visor 的启动画面很可能就是你这台机器的最后一道防线。
【免费下载链接】Visor-BootManager
A minimal, fast, graphical UEFI boot manager written in C. no external dependencies — just a config file :)
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考







