在 Windows 中运行硬盘上的 Linux 系统:用 VirtualBox 加载硬盘上的 Linux 作为虚拟机运行

前情
我当前电脑里面有两块硬盘,一块里装着 Windows 系统,另一块里的部分空间里装了一个 Ubuntu 18.04 LTS。另外,我还有一个装了 Arch Linux 的移动硬盘。在 Windows 里还有一个 Ubuntu WSL。其中 Windows 和 Arch Linux 是我平时会用的系统,Ubuntu 18.04 LTS 只是懒得删掉,Ubuntu WSL 当 Windows 里的终端用,cmder 之类的启动速度不够快,某种程度上还不如装个 WSL 有意思。

昨天突然想用 Github 搞个 Hugo 博客,又不想在 Windows 或 Ubuntu WSL 里面安装 hugo,想装在 Arch Linux 里又想在不退出 WWindows 的情况下在 Arch Linux 中安装并运行 hugo —— 因为当时 Windows 里还有一些没干完的事,不想重启到 Arch Linux 搞完后再重启到 Windows 把这些程序、网页再打开一遍。而且当时已经搜到了一些用 Github 搞 Hugo 博客的教程,前几天没找到在相同及不同系统中不同浏览器间同步 OneTab 的方法,没什么方便的办法简单地把当前打开的一些关于 Hugo 的网页在 Arch Linux 中打开。就决定找个办法在 Windows 中运行我移动硬盘中的 Arch Linux。

要在一个系统中运行另一个系统,首先想到的就是虚拟机。一般虚拟机都是新建一个系统在当前系统中运行,但是我搜了一下,还是找到了利用 VirtualBox 运行硬盘的上的系统的办法。

此文中介绍的方法非原创,主要步骤来自 lifehackerHow to Dual Boot and Virtualize the Same Partition on Your Computer 一文,但部分细节是我按我实际实现过程中遇到的故障做的补充。关于此问题,互联网上还有一些相似的解决方案,有些我试过但没有成功,有些我没试过。

开始之前

请确认已安装 VirtualBox 软件,这是在 Windows 中唯一需要的软件。在 Linux 中你可能需要安装某些组件。VirtualBox 的 下载地址

虽然我们使用的是虚拟机软件,但是此次我们要用虚拟机软件 VirtualBox 运行硬盘上“真实存在”的系统,所以若是出错,可能会影响目标硬盘上的文件。在开始之前,各位最好确认自己做好了文件的备份,能够承担因操作失误而造成的硬盘数据损坏等风险。

实际上下列步骤出错的可能性很小。只要没有看错硬盘的编号,且能确认 VirtualBox 中运行的 Linux 相关的硬盘或分区是 Windows 无法访问的,应该就没什么特别的注意事项了。

本文中涉及的步骤、问题及其解决方案等都只是我个人单次实践经验的分享,各位实操前请注意不同机器之间的差别。

如果可能,不妨阅读 VirtualBox 官方文档 中与此相关的一节 9.8.1. Using a Raw Host Hard Disk From a Guest

系统及软件版本情况
主系统:Windows 10 64bit 1809 17763.437
VirtualBox 运行的系统:Arch Linux(安装在移动硬盘中)
VirtualBox 版本:6.0.4

在 Windows 中虚拟化硬盘上的 Linux

首先,你需要确认你想虚拟化整个硬盘,还是只想虚拟化硬盘中的部分分区。Windows 不能访问会被虚拟化的分区,否则会出现数据冲突的问题。严重的话可能会让你损失硬盘上的所有数据。这是 VirtualBox 官方文档中的警告:

Warning
Raw hard disk access is for expert users only. Incorrect use or use of an outdated configuration can lead to total loss of data on the physical disk. Most importantly, do not attempt to boot the partition with the currently running host operating system in a guest. This will lead to severe data corruption.

所以,如果你想保留 Windows 对装有 Linux 的硬盘中部分分区的访问能力,需仅虚拟化部分分区。本文主要涉及虚拟化整个硬盘的步骤。

获取目标硬盘的编号

你需要确认目标硬盘的编号,有两种简单的途径:

一种是在电脑的 “磁盘管理” 中查看目标硬盘的编号。右键单击任务栏中的 Windows 徽标,即可找到磁盘管理;在键盘上同时按下 win+R键来唤出运行,输入diskmgmt.msc再按回车键亦可打开磁盘管理。确认目标磁盘在磁盘管理中是 “磁盘?” 。若目标磁盘在 Windows 系统中是 “磁盘2” ,则在接下来的步骤中要用到的目标磁盘的编号是:\\.\PHYSICALDRIVE2(若是 “磁盘3” ,则编号是:\\.\PHYSICALDRIVE3)。

另一种是以管理员身份在命令行中查看。 要以管理员身份运行命令行软件,可以右键单击 Windows 徽标,选择 “Windows PowerShell (管理员)(A)” ,或在开始菜单的软件列表的 “Windows 系统” 中找到 “命令提示符” ,右键单击,选择 “更多” - “以管理员身份运行” 。打开命令行软件后,输入以下命令并回车(在 PowerShell 和命令提示符中,右键单击即可粘贴,而不是 Ctrl+v):

wmic diskdrive list brief /format:list

找到目标硬盘的编号,例如 \\.\PHYSICALDRIVE2,选中并复制(使用 Ctrl+Shift+c,而不是 Ctrl+c),记在某处。

在 Windows 中创建 *.vmdk 文件

首先,我们需要生成一个 *.vmdk 文件。这是磁盘镜像文件的一种, VirtualBox 会将虚拟化的系统对硬盘的读写重定向至磁盘镜像文件。关于 VirtualBox 中的磁盘镜像文件,可以访问 5.2. Disk Image Files (VDI, VMDK, VHD, HDD) 一节了解更多。

Disk image files reside on the host system and are seen by the guest systems as hard disks of a certain geometry. When a guest OS reads from or writes to a hard disk, Oracle VM VirtualBox redirects the request to the image file.

我们将生成的 *.vmdk 文件代表一块物理硬盘,所以其中不包含实际数据,其文件大小不到 1KB。我们将在新建虚拟机时,在 “选择已有的虚拟硬盘文件(U)” 时使用此文件。完成之后,我们可以在所建的虚拟机的 “设置” - “储存” - “控制器:SATA” 中看到它。

我们需要在 VirtualBox 的安装目录下运行生成 *.vmdk 文件的命令。要在命令行中转至 VirtualBox 的安装目录,可以使用如下命令:

cd C:\Program Files\Oracle\VirtualBox

其中,C:\Program Files\Oracle\VirtualBox 是 VirtualBox 的默认安装目录,此目录下包含 VirtualBox.exe 文件。如果你在安装 VirtualBox 时更改了安装目录,请在此命令中使用你安装的目录地址。你也可以在 Windows 资源管理器中打开 VirtualBox 的安装目录,按住 shift 键的同时在文件夹空白处右键单击,选择“在此处打开 Powershell 窗口(S)”。

在命令行中转至 VirtualBox 的安装目录后,使用如下命令生成 *.vmdk 文件文件(由于生成磁盘镜像文件需要对目标磁盘的读写权限,所以此命令要以管理员身份运行):

VBoxManage internalcommands createrawvmdk -filename \path\to\file.vmdk -rawdisk \\.\PhysicalDrive2

其中,/path/to/file.vmdk 为生成的 *.vmdk 文件的输出地址及文件名,你可以任意指定地址和文件名(例如 C:\linuxSSD.vmdk),之后你可以把它重命名或移动到其他目录中。\\.\PhysicalDrive2 为你在上一步中获取的硬盘编号,将其替换为你目标硬盘的编号,如果它不是 “磁盘2” 的话。

正常情况下,命令行中会出现一行消息提示 *.vmdk 文件创建成功。在你选定的输出文件夹中就能找到 *.vmdk 文件。

顺便一提,如果你想在 Linux 上虚拟化运行其他系统的话,硬盘编号就是形如 /dev/sda 了。除了硬盘编号的形式不同之外,在 Linux 中生成 *.vmdk 文件所需的命令和在 Windows 上的基本没什么不同。

在某些帖子或博文中,在 VirtualBox 中新建虚拟机时,在 “虚拟硬盘” 一步中,选择 “选择已有的虚拟硬盘文件(U)” 并选择刚才生成的 *.vmdk 文件即可,其他步骤与新建普通虚拟机相同。完成新建后,启动此虚拟机即可启动硬盘上的 Linux 系统。不过我尝试后失败了,无法启动硬盘中的 Linux 系统。各位也可以在这一步就做个尝试,即使失败了,后续步骤也能在此时新建的虚拟机的基础上继续进行,并无其他影响。

在 Linux 中创建 *.iso 文件

如过你无法仅凭 *.vmdk 文件在 VirtualBox 中成功运行 Linux,你需要由 Linux 的 GRUB 的部分文件来创建一个 *.iso 文件,再添加到由 *.vmdk 文件建成的虚拟机的 “设置” - “储存” - “控制器:IDE” 中,来引导硬盘中的 Linux 系统在 VirtualBox 中启动。

此步骤不会更改 Linux 使用的 GRUB 设置。所以正常情况下不会出问题,运行命令时可能会因为缺少某个组件等问题而报错,按报错去搜索解决方案即可。

现在,你需要重启电脑到 Linux 系统中。进入 Linux 系统后,在某处,例如用户的 home 目录,按如下命令新建文件夹:

mkdir -p ./iso/boot/grub/

上面的命令,会在当前目录中新建 iso 文件夹,再在 iso 文件夹中新建 boot 文件夹,再在 boot 文件夹中新建 grub 文件夹。

然后,将 GRUB 的部分文件复制到刚才新建的 grub 文件夹中:

cp /usr/lib/grub/i386-pc/* /home/YourUserName/iso/boot/grub

上面这条命令是将 /usr/lib/grub/i386-pc/ 文件夹中所有的文件都复制到你刚才新建的 grub 文件夹中。如果你将 iso 文件夹建于你的用户的主目录中,记得将 “YourUserName” 改为你用户的用户名。如果你把 iso 文件夹建在了其他地方,就得把 /home/YourUserName 更改为你新建 iso 文件夹的目录。

然后再运行:

cp /boot/grub/grub.cfg /home/yourusername/Desktop/iso/boot/grub

此命令将 /boot/grub/ 中的 grub.cfg 文件复制到了你新建的 grub 文件夹中。

复制完后,编辑 grub.cfg 文件。此文件中不仅包含引导启动 Linux 系统的内容,还包含引导启动生成此文件时电脑中其他系统的内容。虚拟化运行时,你只虚拟化了包含装有 Linux 系统的硬盘,所以在虚拟机中无法启动在其他盘的系统,为了避免造成错误,我们需要将不必要的内容删去。如果你在生成 grub.cfg 文件时,电脑中除了当前的 Linux 外仅有 Windows 系统,那么只需删除从 menuentry 'Windows Boot Manager' 或类似的内容开始,到与之对应的 }为止,这两者之间的所有内容。如果当时你电脑的其他硬盘上还有其他系统,例如 Ubuntu,那么所有从 menuentry 'Ubuntu' 或类似的内容到对应的 } 之间的内容也需要删除,可能有多个这样的内容。如果在目标硬盘(也就是你想虚拟化的 Linux 所在的硬盘)上有另一个 Linux 系统,而你也想在 Windows 上运行的虚拟机中运行这个 Linux 系统,那么你需要保留和这个系统有关的内容。

可以运行如下命令来编辑 grub.cfg 文件:

sudo vim /home/YourUserName/iso/boot/grub/grub.cfg

如果你更偏好使用 nano 等其他编辑器,请替换命令中的 “vim” 。别忘了替换命令中的 “YourUserName” 。

用你喜欢的编辑器打开 grub.cfg 文件后,按上面所说的删除那些内容。完成后,保存修改并退出。

最后,使用如下命令来生成 *.iso 文件。此命令生成的 *.iso 文件会被输出于当前命令运行的目录。(我不知道有没有什么影响,不过最好不要在 iso 文件夹之内。你不妨在用户的主目录运行这个命令。)

grub-mkrescue -o boot.iso /home/YourUserName/iso/

此命令会利用 iso 文件夹中的内容,生成一个 boot.iso 文件输出到当前文件夹中。当然,你也可以使用其他的文件名。记得更改命令中的 “YourUserName” 。

如果出现 “xorriso: not found” 的报错,就得安装 “xorriso” 。你也可能遇到其他的报错,请自行通过搜索引擎解决。我使用此命令时也遇到了问题,是通过安装 “mtools” 解决的。

成功生成 *.iso 文件后,将其保存到云盘,或 Windows 系统能访问的本地目录中。例如,你可以挂载 Windows 所在的硬盘,把 *.iso 文件保存到 *.vmdk 文件所在的文件夹。稍后我们需要重启到 Windows 系统,并用到此文件。

如果你 Linux 的启动模式是 “graphical.target” ,开机后默认进入图形界面的话,稍后在 VirtualBox 中可能无法正常载入图形界面。如果你需要在虚拟机中运行的 Linux 中使用图形界面,请在遇到问题后自行搜索对应的解决方案,似乎通过修改某些配置可以解决图形界面无法正常使用的问题。如果你无需在虚拟机中运行的 Linux 中使用图形界面,可以更改 Linux 的启动模式,让 Linux 启动后默认不启动图形化界面,直接以命令行界面操作。

使用如下命令来更改 Linux 的默认启动方式:

systemctl set-default multi-user.target

此命令将默认的启动方式由图形界面模式更改为命令行模式。

如果你需要更改回默认以图形界面模式启动,可以将命令中的 multi-user.target 替换为 graphical.target,即:

systemctl set-default graphical.target

你还可以使用如下命令来切换当前运行的模式:

systemctl isolate multi-user.target

此命令仅在使用时将当前的模式更改为命令行模式,不影响下次开机后的情况。

请注意,此命令同时影响通过 VirtualBox 启动 Linux 系统和正常启动的 Linux 系统。如果你希望正常启动 Linux 系统时默认进入图形界面,请自己查找添加新的启动项的途径,或其他方法来达成此目的。或者,你也可以为切换当前模式为图形模式的命令取一个简短的别名(alias)。

你可以访问 Archlinux 关于 “systemd” 的 Wiki 的页面中 “Targets” 小节 来了解更多相关命令。或自行查阅更多相关资料。

在 WIndows 中利用 VirtualBox 创建虚拟机

现在几乎大功告成了。你所需要做得就是重启到 Windows 系统中,以管理员身份运行 VirtualBox。如果你没有在生成 *.vmdk 文件后立即用它新建了虚拟机,现在来新建吧。点击 “新建” ,除了在 “虚拟硬盘” 这一步中得选择 “选择已有的虚拟硬盘文件(U)” 一项并使用刚才生成的 *.vmdk 文件这一点之外,和普通的新建虚拟机并无区别,按你自己的情况和需求自行调节其他设置项。

完成新建虚拟机后,选中新建的虚拟机,点击 “设置” ,再点击 “储存” ,点击 “控制器:IDE” 一行右端的从左到右第一个图标,及右下角有加号的圆盘状那个。点击 “选择磁盘” 并选择刚才生成的 *.iso 文件。

完成添加后,请点击 “控制器:IDE” 和 “控制器:SATA” ,确认这两处的 “使用主机输入输出(I/O)缓存” 一项都已启用。否则可能会在启动 Linux 时出现问题。当然,你也可以再出现相关报错后再来此处启用此选项。

点击 “OK” 确认对设置的修改。

现在,我们应该就能正常在 VirtualBox 中启动硬盘上的 Linux 了。点击 “启动” 来试一试吧。

注意:请勿在虚拟化运行的 Linux 的尝试挂载或访问 Windows 能够访问的硬盘或分区,可能会造成严重的数据损坏。虚拟化运行的 Linux 和正常运行的 Linux 一样,在虚拟化运行的 Linux 中做出的更改就是在正常启动的 Linux 中对其做出相同的更改。

其他相关资料

如开头所说,本文的步骤来自 lifehackerHow to Dual Boot and Virtualize the Same Partition on Your Computer 一文,原文中还涉及因使用私有的显卡驱动而造成的问题的解决方案,以及在 Mac 中虚拟化运行 Windows 和在其他情况下中虚拟化运行 Windows 或 OS X 的部分信息。

除了这篇文章之外,还有一些可能有用的参考资料,虽然它们的办法和此文的有或大或小的差别。一篇是 askubuntuHow to boot from a USB drive in VirtualBox? 问题下的讨论,另一篇是 水景一页 博客更新于 2014.10.25 的 在 Windows 中通过 VirtualBox 启动物理硬盘上的 Linux 操作系统 一文。这些中可能有一些我没有提及的注意事项。