记录一次失败的系统抢救/折腾经历

时间:2024-04-01 19:43:03

一、事故起因

大概描述下事故起因:
win10/ubuntu16.04双系统,分别安装在两块256Gb大小的NVME SSD上,以UEFI模式Grub2引导。某天我心血来潮,想要验证核显与独显是否能一起工作,多次在系统启动过程中强制下电(作死行为。。。),终于在一次强制下电后,win10无法启动了,而且连安全模式都无法进入,一直卡在蓝屏界面。
蓝屏界面提示如下:

你的设备/电脑需要修复

记录一次失败的系统抢救/折腾经历作为一名技术型宅男,当然不甘心重装系统,况且还有很多数据不能丢失,于是开始了对win10的抢救之路。

二、WIN10抢救记录

既然能进入BIOS,说明硬件没出问题,然后“又提示文件丢失“,因此我猜测很可能是ssd开启了写入缓存,在强制下电的过程中数据来不及刷入硬盘,导致一些系统启动文件受损。

当然一般好一些的ssd都会内置电容蓄电,在断电时为I/O争取最后的时间,只不过这是最后一道防线,不能保证100%不会出问题,虽然我用的是将近1000块的浦科特m8peg,在多次强制下电后还是中招了。。。

在此也提醒看到这篇文章的朋友:数据无价,请保持良好的电脑使用习惯,千万不要像我一样作死,最重要的一点是——要关闭写入缓存!
废话不多说了,既然问题已经发生了,那就开始修复吧!

修复NTFS磁盘

进入PE系统,发现系统盘居然无法访问了,然后用DiskGenu工具查看,磁盘显示“未格式化”,如下图:
记录一次失败的系统抢救/折腾经历
可能有些人看到这步就要格式化硬盘了,但我推测:强制下电最多导致部分文件受损,数据不可能全部消失,磁盘用工具修复下应该就可以访问了。

一开始我使用GRUB2下的ntfs-3g工具尝试修复,发现并没有什么卵用。NTFS是Windows家的私有格式,并不开源,还是用WIN10自带的磁盘修复工具吧,由于原系统已经彻底崩溃(磁盘都无法访问),只能借助于WIN10系统安装U盘,步骤如下:

  • 插入WIN10系统安装U盘,在BIOS中设其为启动项
  • 进入安装界面,跳过安装步骤
  • 选择疑难解答->高级工具->磁盘修复

等修复结束,再进入PE系统,发现系统盘已经可以访问了,数据也都还在,抢救成功了一小步~

重建WIN10 EFI引导

然而我还是高兴地太早了,虽然系统盘可以访问了,但还是无法启动WIN10,这次还是卡在蓝屏界面,提示如下:

“自动修复”无法你的电脑
日志文件:D:\WINDOWS\System32\Logfiles\Srt\SrtTrail.txt

找到log文件并打开,错误提示如下:

启动关键文件 d:\boot\resources\custom\bootres.dll 损坏

已经很明显了,启动文件损坏。
头疼医头、脚疼医脚,找到问题了就该对症下药,重建EFI引导吧!

重建EFI引导其实就是将系统盘Windows\Boot\EFI目录下的文件复制至ESP分区中,当然,我们实际应用的时候不用这么原始地复制一个一个文件,WIN10已经替我们集成了一个命令(PE下执行),如下:

bcdboot c:\windows /s o: /f uefi /l zh-cn

具体参数要根据实际情况修改,其中:

  • "c:\windows"为系统盘目录
  • "/s o:"指定EFI系统分区
  • "/f uefi"指定UEFI启动方式
  • "/l zh-cn"指定UEFI图形界面语言为简体中文

修复受损系统文件

重建EFI引导后,仍然无法启动,错误提示也和上述一致。

实际上到这一步我已经放弃了,不得已含泪重装了系统,但是后来根据提示信息在Google搜索,居然找到了Windows官方的QA界面,问题和我99%相似,并且Windows开发者提供了解决方案[^1],因此记录下来,链接为:
Microsoft 支持 - bootres.dll损坏

简单描述下微软官方人员的回答,大意为:

该提示信息意味着系统的.dll文件出现问题,需要重新注册

这就解释了即使我重建EFI引导还是无法启动的原因——系统盘中的EFI相关源文件已经损坏,因此重建的EFI引导也是有问题的。

修复系统文件需要执行以下命令:

cmd /c for %i in (%windir%\system32\*.dll) do regsvr32.exe /s %i
cmd /c for %i in (%windir%\system32\*.ocx) do regsvr32.exe /s %i

若问题依旧需要执行以下命令:

sfc /SCANNOW

后记:
当用Google搜到这个QA界面的时候,我想如果我当时执行这些步骤,应该就大功告成了,也用不着重装系统,不得不感慨:百度误我!

使用MediaCreationTool制作WIN10启动U盘

在失败的系统抢救之后,不得已只能重装系统。
其实我已经有win10 17.03的启动U盘了,但一想到大量的更新就脑壳疼,干脆用最新的镜像制作安装盘,但是惊讶的发现18.09的镜像竟然无法用UltraISO写入U盘,上网一查方知18.09镜像中有单个大小超过4Gb的文件,受FAT32格式限制无法写入。
不知微软为什么要如此设计,总之是无法用UltraISO制作启动U盘了。
天无绝人之路,微软总算提供了官方工具MediaCreationTool制作启动U盘,下载链接:
Download MediaCreationTool
记录一次失败的系统抢救/折腾经历
使用很简单,值得一提的是该工具提供的是一条龙服务——会帮你下载最新的镜像然后直接写入U盘,但是却没有选择本地镜像的入口(意味着我之前下载的18.09镜像做了无用功)。
不错,这很“微软”,就像自动更新一样,根本不给用户选择的余地。

三、Ubuntu抢救记录

重建Ubuntu EFI系统分区及EFI引导

在win10崩溃的时候,我想切到ubuntu,发现ubuntu居然也无法启动,提示:

Could't get size: 0x800000000000000e
MODSIGN: Couldn't get UEFI db list

其实这个问题以前也出现过,原因是win10某些更新会更改EFI系统分区的文件,导致ubuntu的引导文件被破坏。

这种情况只有重建efi引导了,但这也是治标不治本,指不定哪次win10更新又会搞破坏。
有鉴于win10经常更新并祸及EFI系统分区,我决定刮骨疗伤,为ubuntu单独再建立一个EFI系统分区,让两者井水不犯河水。

先介绍下之前ubuntu与win10分区结构吧,两块ssd分别安装了两个系统,但是共享一个EFI系统分区,Window Boot Mangager与GRUB2“共居一室”,如下图:
记录一次失败的系统抢救/折腾经历
这种分区的弊端在前文已经介绍过了(win10更新破坏ubuntu引导),因此我想做一些调整,如下图:
记录一次失败的系统抢救/折腾经历
看似简单,其实也要费一番功夫,具体步骤如下:

1. 通过LiveCD(Ubuntu启动U盘)进入系统

2. 新建EFI系统分区
使用GPart工具在硬盘上划分一个100Mb大小的分区,分区Label设置为“Boot,esp”。

3. chroot切换根目录(LiveCD->待修复的Ubuntu)

  • 将待修复的Ubuntu系统的根分区挂载至/mnt/ubuntu
# mount /dev/nvme1n1p2 /mnt/ubuntu
  • 将新建的EFI系统分区挂载至/mount/ubuntu/boot/efi
# mount /dev/nvme1n1p1 /mount/ubuntu/boot/efi
  • 将LiveCD的虚拟文件系统devfs、procfs、sysfs挂载至待修复的Ubuntu对应目录下,否则使用chroot后无法访问一些硬件资源
# mount -o bind /dev /mnt/ubuntu/dev
# mount -o bind /proc /mnt/ubuntu/proc
# mount -o bind /sys /mnt/ubuntu/sys
  • 使用chroot切换根目录
# chroot /mnt/ubuntu

4. 安装EFI引导

# grub-install --target=x86_64-efi --efi-directory=/boot/efi

5. 修改fstab文件
使用blkid命令获取新建EFI系统分区的UUID,然后修改/etc/fstab文件,替换之前EFI系统分区的UUID。

经过一系列动作,Ubuntu顺利启动~

GRUB2命令行引导WIN10

GRUB2是可以引导WIN10的,相反Windows Boot Manager却不能引导Ubuntu,但是在我安装GRUB2时,不知为何没有自动添加WIN10入口,不过这不打紧,可以先试试GRUB2命令行引导WIN10。

准确地说,GRUB2无法直接引导WIN10,只能通过Windows Boot Manager间接引导,这几者的加载关系如下:
BIOS->GRUB2->Windows Boot Manager->WIN10

理顺了这个关系,就清楚接下来要干的事情了,以下为GRUB2命令行引导WIN10所需要执行的命令:

insmod part_gpt
insmod fat
$ set root=(hd0, gpt1)
$ chainloader /efi/Microsoft/Boot/bootmgfw.efi
  • insmod part_gpt &insmod fat
    GRUB2为了减少自身体积,启动时一些模块是默认不安装的,启动WIN10需要支持GPT与FAT32格式,这里我们手动安装这两个模块。
  • set root=(hd0, gpt1)
    该命令效果和shell下的chroot一样,可以更改当前运行系统的根目录,需要注意的是(hd0,gpt1)并不是WIN10的系统盘所在分区,而是WIN10的EFI分区,这点在前文已经解释了(GRUB2无法直接引导WIN10)。
  • chainloader /efi/Microsoft/Boot/bootmgfw.efi
    顾名思义,该命令是一个链式装载启动工具,通过引导Windows Boot Manager间接引导WIN10

GRUB2添加WIN10启动项

GRUB2命令行成功引导WIN10,那就意味着可以更进一步——在GRUB2中添加WIN10启动项了。有想过手动在GRUB2配置文件中添加WIN10的menuentry,却总觉得不太完美(鄙人强烈的强迫症在作祟)。
有没有让GRUB2侦测WIN10自动生成配置文件的方法呢?答案是Yes。
通过GRUB2官方文档了解到如果在第一次安装时os-probe没有侦测到WIN10,有两种方法可以补救:

  • 挂载WIN10的EFI系统分区,然后执行update-grub
  • 先执行lsblk获取硬盘信息,然后执行update-grub

我用的是第二种方法,果然在update-grub时侦测到了WIN10,然后自动生成了相关的启动配置。查看/etc/grub.conf文件,自动生成的WIN10配置如下:

### BEGIN /etc/grub.d/30_os-prober ###
menuentry 'Windows Boot Manager (on /dev/nvme0n1p2)' --class windows --class os $menuentry_id_option 'osprober-efi-181C-9F4B' {
	insmod part_gpt
	insmod fat
	if [ x$feature_platform_search_hint = xy ]; then
	  search --no-floppy --fs-uuid --set=root  181C-9F4B
	else
	  search --no-floppy --fs-uuid --set=root 181C-9F4B
	fi
	chainloader /efi/Microsoft/Boot/bootmgfw.efi
}

update-grub 与 grub-mkconfig
grub-mkconfig会读取/etc/default/grub文件内容,然后通过os-prober扫描所有分区侦测OS,最终生成相关配置并写入/boot/efi/grub.conf,而update-grub则是一个脚本文件,调用的是grub-mkconfig。

四、小结

生命的意义在于折腾,如果不折腾,那么跟咸鱼有什么区别呢?虽然折腾到最后还是重装了系统,但从中也获得了许多知识,满足感爆棚,因此写下本文,一为记录折腾过程防止自己问题重犯、二为碰到相同问题的朋友们解惑。


参考:

  1. Microsoft 支持 - bootres.dll损坏
  2. GRUB (简体中文) - ArchWiki
  3. the GNU GRUB manual