用复制粘贴的方式迁移系统(第二次)

我之前写过一篇博客,标题是《移用复制粘贴的方式迁系统》,其中说到了如何把一份安装好的 Windows 10,以近乎文件复制粘贴的方式迁移到新的硬盘的新的分区,而且,新的硬盘上原本已经具有 Ubuntu 操作系统,还要使 Grub 能够正常将 Windows 10 引导起来。

日前,又遇到了类似的场景。Dell E7280 上是我的 Ubuntu 环境,大小 512GB;ThinkPad X230T 上是我的 Windows 10 工作环境,大小 500GB。由于后者厚重,携带起来要远比前者沉重,因而就计划把两个系统同时置于前者之内。首先要做的显然是搞一块大硬盘咯。作为一个资深二手垃圾佬,在闲鱼上守到一块 Intel 的 760p,2TB 包邮价谈到 1650 元,写入量其实不算小,考虑到这块盘的体质,也就认了。买回来以后发现了一个悲剧性的事实:机器里只有一个 NVMe 的接口,无法通过对刻的方式来迁移 Ubuntu。此问题直到 NVMe 外置硬盘盒到手后才解决:512GB 的数据,dd 耗时 20 分钟,感觉挺快。换用新盘后系统一切正常。既然 Ubuntu 已经就绪,那接下来就该 Windows 10 了。

按照前文提及的历史经验文中的步骤,用 PE 系统引导,首先又创建了一个分区,其大小不小于 Windows 10 系统所在分区,然后将 Windows 10 所在磁盘用易驱线接入,用克隆分区的方式,把 Windows 系统分区复制到了新建分区上(470GB 的数据,耗时 30 分钟)。此工作完毕后,又把 Windows 10 的引导分区上的文件复制到了新建分区上(这一操作事实上是把 Windows 10 的两个分区合并了)。将 PE 环境的 U 盘取下,Windows 10 的源盘取下,重启至 Ubuntu 下。如果按照之前的推测,此时执行 update-grub 命令的话,它会自动检测到新分区上的 Windows 10,并将其列入到 Grub 的开机菜单列表内。然而,Grub 完全无视新的 Windows 10 的存在,没有做出任何相应的所期望的改变。剧本从此开始走偏。

原因很好找,老夫瞬间就明白过来了:这个 Ubuntu,在 E7280 上安装时,是以 UEFI 的模式安装成功的,而那份新近闯入的 Windows 10 在源盘上是 BIOS 方式引导的。知道了原因,其实问题也不难解决,至少当时就是这么想的。

第一件事,就是要为 UEFI 引导项做准备。ESP 分区在引导成功的 Ubuntu 系统中被加载到 /boot/efi 目录。从 Windows 10 所在分区的 Windows\Boot\EFI 目录下,把 bootmgfw.efiboormgr.efi 两个文件复制到 /boot/efi/EFI/Microsoft 目录下,其中的 Microsoft 目录应该需要现创建。在这儿又执行过一次 update-grub,仍然没有效果。所以后续的所有操作,都是为了开机时设备固件可以识别到 Windows 10,而不再针对于 Grub。

到 E7280 的固件(也许你更喜欢历史延续而来的俗称 BIOS?尽管严格意义上已经不是 BIOS 了)中,增加新的 UEFI 引导项,名称设为“Windows 10”,要加载的文件指向 ESP 对应分区的 /EFI/Microsoft/bootmgfw.efi,保存后在重新启动时就可以通过按 F12 键来选择 Windows 10 了。选择之后,如果不出意料,会出现缺少 /EFI/Microsoft/Boot/BCD 文件的提示。虽然,Windows 10 还没有启动成功,但也不要气馁,毕竟 UEFI 引导项已经工作,BCD 文件正是 Windows 的引导配置核心数据所在。道路虽然曲折,前途依旧光明。

如果你上面执行的步骤和我一样,那么就应该知道去哪儿搞到一份 BCD 文件:Windows 10 分区下的 \Boot 目录(当然,在源盘里的时候,是在引导分区中的)下。将 BCD 文件复制到 EFI 分区的 /EFI/Microsoft/Boot 目录下。此时再尝试引导 Windows 10,则错误信息就不再是无法找到 BCD 文件,而是告诉你某些应该连接着的设备没找到。这也就意味着,BCD 已经被解析,只不过其中存放的磁盘信息是作用于源盘的。那接下来我们就要修改它以适应新环境。

插曲。修改 BCD 文件的最佳方式,是一个叫 EasyBCD 的工具。我兴冲冲在 PE 环境下执行它的时候,出现了眼熟的 0x...135 错误,那是没有找到 .net framework 时候的错误码。于是,百般不情愿地,需要操练 bcdedit.exe 了。

bcdedit.exe 之前曾经在某些特殊的时候,照着网上的教程执行过几次,未求甚解,这次属于被逼上梁山。中间体会探索的过程不再细表,此处概略说一下它的数据存储组织结构。逻辑层面,共有三层:存储(store)、项(item)、值(value)。存储最终通常是以文件的形式出现。项,是一组值的集合。启动项,会是一个项,但并不是每一项都是一个启动项。项和值的组织,是通过物理层面的注册表文件内的 key 和 value 的组织来实现的,但并非一一对应。以后有空再具体描述此处的细节。

回归到引导问题的解决。在 PE 中打开命令提示符,切换到 EFI 分区下 BCD 文件所在目录,执行 bcdedit.exe /store BCD /enum,此命令会以其自己认为适当的过滤条件显示若干项的信息。端详“Windows 启动加载器”那一项的各个值,你会发现,deviceosdevice 的内容会被显示为 unknown。执行相应的命令来修改它:bcdedit.exe /store BCD /set {default} device partition=\Device\HarddiskVolume3,执行后(注意需要是管理员身份)会有成功提示,然后把其中的 device 改作 osdevice 再来一次。如果想查看执行结果,可以再次如前 enum。之所以执行的命令中,把系统所在分区设置为 HarddiskVolume3,这个完全是需要根据实际情况来的,在我眼下的硬盘上,第一个分区是 EPS 分区,第二个分区是 Ubuntu 系统,第三个分区才是 Windows 10,诸君如要照猫画虎,务必仔细打量自家情况,万万不可胶柱鼓瑟。指定的时候,可以写作 partition=D: 这样的形式,但是,由于此时位于 PE 环境下,为了避免与届时真正引导时的盘符分配方案产生偏差,还是硬数比较靠谱。不过,enum 的输出里,会自动显示出在当前环境下该分区映射的盘符,不必介意,以为是自己设置时写错了。

经过这个修改,自信就爆棚了。尝试重启,果然不再说有设备未连接。事实上,它不但没说设备未连接,而是什么都没说,在之前报错的那一步,直接黑屏,然后自动重启。这就尴尬了。我开始是把所有看起来有分区信息这个值的项(如内存检测项、启动管理器项、休眠/睡眠后的唤醒恢复项等等),全改了一遍,不好使;又把所有无关的项(如:DOS 分区,未克隆,删除对应项;Recovery 分区,未克隆,删除对应项)全删除掉,不好使。技穷有若黔驴。

最后,为了方便,把 BCD 文件用注册表管理器加载到 HKLM 下查看,看到 winload.exe 的时候心念一动,特意到 Windows 分区下去求证,发现存在一个 winload.efi 的文件。返回头来怯怯地把值里的 exe 字样换成了 efi。重启,吼吼哈嘿,熟悉的散点绕圈开机引导动画出现了!

喜不自胜。在系统迁移的道路上,又多路过了一块里程碑。以此文供同好者参考。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注