发生了什么,为什么要折腾

距离上次折腾的那个 UEFI/BIOS 双启动 Linux 已经过去有一段时间了,这个方案在我的U盘上工作得也十分良好,在实验室里摆脱了那个慢到极点,预装了各种杂七杂八东西的 Windows(并不是说 Windows 不好的问题,而是给机房做系统的人实在是....)

直到有一天,我重新给U盘装 openSUSE 想换一个 DE 换换口味,放着安装我出门吃了一顿饭,我回到宿舍惊讶的发现仍然在安装,而且进度才一半不到,瞬间意识到这个U盘的寿命是不是差不多了,写放大已经很严重了。用 CrystalDiskMark 测试速度,发现随机写速度已经是刚买回来的时候的 1/10 了。

刚好前阵子买了块便宜的 SSD 加上硬盘盒来做成移动硬盘做 Windows To Go,SSD + 硬盘盒的方案比起U盘方案性价比着实是高了不少,这下可以试试把 Linux 扔到 SSD 里面一起来折腾。

安装 Windows To Go

遵循优先 Windows 再装 Linux 的原则,先搞定 Windows。为了方便,直接使用 nkc3g4 大佬的 GUI 工具 Windows To Go Assistant。这一步需要清空 SSD 上的东西(因为需要重新建立分区表,重新分区),如果上面有东西请提前备份

I Tell You 获取最新的 Windows 10 镜像,右键 ISO 镜像装载这个镜像,这样在“此电脑”中就可以挂载出来的虚拟光驱了,如果老版本 Windows 没有这个功能的话,只能用第三方虚拟光驱软件或者直接解压 ISO 了。

以下为回忆的简单的说明,为了能顺利进行,建议你先打开 WTGA 看看里面有啥,也可以先读一下

http://bbs.luobotou.org/thread-761-1-1.html

打开 WTGA,选中 SSD 所在的盘符,一定要二次确认,要不然就删干净了哦,接着浏览选中 ISO 镜像中 sources/install.wim

为了最佳的性能,我们选择固定大小的 VHDX 安装方式,勾选 UEFI + MBR固定大小。切换到 VHD 页,建议创建的 VHDX 在 50G 以上,Windows 分区没个 50G 还是挺难生存的hhhhhh

EFI 分区大小其实不需要 350MB,只要有 64MB 以上就行了,甚至可以更小,我没试过了。

磁盘选项卡中勾选 不中转VHD 可以提高 WTG 安装速度。

安装好之后,其实 SSD 会使用 MBR 分区表,有两个主分区,一个 FAT32 的 EFI 分区和一个 NTFS 的数据分区,NTFS 分区中包含系统镜像 VHDX。此时你可以直接重启电脑用 SSD 引导进入这个 WTG 系统进行一些初始化和基本配置。此时已经可以 UEFI 和 MBR 双启动 Windows 了。

为 Linux 重新分区

以下操作为了不老是重启机器都是在 VMware Player 中完成的。

在 GParted 中压缩 NTFS 分区,留出 20G 以上用于 Linux 安装和使用。

这个时候为了安装方便,可以直接分好安装 Linux 的 /, /home, swap 分区。

安装 Linux

建议在 UEFI 引导的虚拟机中操作

新建 VMware Player 虚拟机,操作系统类型选择 Linux 64位,结束向导之后,配置虚拟机,光驱定向到 Linux 安装镜像,添加物理虚拟磁盘指向物理 SSD。通过 tricks,在虚拟机的 vmx 文件中添加

firmware = 'efi'

令 VMware Player 以 UEFI 模式启动。

进入安装向导后,主要注意的有以下几点

  • 挂载 /boot/efisdx1,也就是刚刚 WTGA 分出来的 EFI 分区,无视那些 warning 就好,因为这个 EFI 分区好像不是那么合乎规范....
  • 按照你的分区习惯挂载好 /, /home, swap,不要对 NTFS 分区做任何改动

接着正常安装 Linux 就行了。

配置 Grub2 使其可以支持 BIOS 引导

由于我们使用的是 MBR 分区表,所以不需要像 GPT 下那样建立 bios_grub 分区。直接使用

sudo grub2-install --target=i386-pc --recheck /dev/sdx

即可让 Legacy BIOS 引导进 Grub2。

引导 Windows 的思路

参考以下文章得到基本思路

难点在于从 VHDX 引导,需要 Windows Boot Manager 二次接管引导。

UEFI 下,我们可以直接使用 chainloader 将启动直接交给 Windows Boot Manager 接管就好,EFI 的 Windows Boot Manager 就在 EFI 分区下 的 /EFI/Microsoft/Boot/bootmgfw.efi

BIOS 下我们依赖 MBR 中的引导代码,可是 MBR 中的 Windows Boot Manager 已经被 Grub2 覆盖掉了...这时候我们要使用 memdisk 加载一个包含 MBR Windows Boot Manager 的镜像。

动手实现

Windows 下创建一个 VHD 用来保存 Windows Boot Manager。开启一个管理员权限的 Powershell,输入 diskpart 进入 Windows 分区命令行。

// 64M 的空间感觉比较合适?也不会浪费很多空间啦,现在机器内存都够大的
Create vdisk file=C:\bootmgr.vhd maximum=64 type=fixed 
Select vdisk file=C:\bootmgr.vhd 
Attach vdisk 
Create partition primary 
Active // 这一步是 MBR 硬盘上必须的,激活使其可引导 
Format label=bootmgr quick 
Assign letter=j // 分配到 J 盘

exit 退出 diskpart

bcdboot C:\windows /s J: /l zh-cn

将引导文件写入这个分区。接着将 SSD 中 EFI 分区中 \Boot\BCD 文件复制到 J:\Boot\BCD,覆盖掉原来的 BCD 配置文件。

SSD 的 EFI 分区可能默认不会分配盘符,可以在 Windows 磁盘管理中手动给其分配盘符,并且你需要在资源管理器选项中取消“隐藏保护的系统文件”和“不显示隐藏的文件”才能看到 /Boot/BCD

到此,前期准备完成,将 vhd 文件拷贝到 NTFS 分区备用。

添加 Grub2 Entry

虚拟机中从 SSD 引导进入 Linux。

编辑 /etc/grub.d/40_custom 以便以后每次 grub2_mkconfig 都包含我们的更改。

添加以下 entry 用于 UEFI

menuentry "Windows 10 To Go (UEFI)" {
		insmod part_gpt
		insmod fat
		insmod search_fs_uuid
		insmod chain
		search --fs-uuid --set=root $hints_string $fs_uuid
		chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}

$hints_string$uuid 需要替换,可以通过以下命令获取。

$uuid:

grub-probe --target=fs_uuid /boot/efi/EFI/Microsoft/Boot/bootmgfw.efi

得到类似 1ce5-7f28 的 UUID。

$hints_string:

grub-probe --target=hints_string /boot/efi/EFI/Microsoft/Boot/bootmgfw.efi

得到类似 --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 的参数。

添加以下 entry 用于 Legacy BIOS

menuentry "Windows 10 To Go (Legacy)" {
    set root='hd0,msdos3'
    echo 'Loading memdisk...'
    linux16 /usr/share/syslinux/memdisk raw
    echo 'Loading VHD...'
    initrd16 /boot/bootmgr.vhd
    echo 'Done!'
}

复制 bootmgr.vhd 就是我们之前创建的 vhd 到 /boot/ 下,其中第二行的 set root='hd0,msdos3',你的 /boot 目录挂载在何处就如何修改,例如,我的安装方案,/boot/ 同时挂载在 sda3,那么就是hd0,msdos3

在系统中安装好 syslinux 其中带有 memdisk,找不到的话,可以

find / -name memdisk

找找看在什么地方,替换配置文件中 linux16 中的路径。

然后使用

sudo grub2_mkconfig > grub.cfg

生成 grub.cfg 替换掉原来的 /boot/grub2/grub.cfg,并对其进行

sudo chown root:root grub.cfg
sudo chmod -x grub.cfg

修改其权限。

大功告成

接着就可以重启看看效果了。

UEFI 下就通过 Windows 10 To Go (UEFI) 引导 Windows

BIOS 下就通过 Windows 10 To Go (Legacy) 引导 Windows

两种情况下都通过原有的 Linux Entry 引导 Linux 即可。