需求

一块外置 NVMe 硬盘(雷电/PCIe)里装着 Boot Camp 的 Windows 11:EFI、一个 10GB 的 WinInstall、一个 1TB 的 BOOTCAMP(NTFS)。我想在 macOS 里用 VMware Fusion 把它直接跑起来,并且不是复制一份,而是让原生重启进入的 Windows 和虚拟机里的是同一个系统,软件和数据天然一致。

环境:Intel Mac Pro、macOS 26(Tahoe)、VMware Fusion 26.0.1。Boot Camp 本身只存在于 Intel Mac,Apple Silicon 不适用。

官方向导为什么不行

Fusion 的”迁移 Boot Camp 分区”只面向内置盘,这块外置盘它走不通。手动用 Fusion 自带的工具创建磁盘映射,同样失败:

1
2
vmware-rawdiskCreator create /dev/disk2 fullDevice bootcamp sata
# Unable to create the source raw disk: Resource deadlock avoided (720905)

lsof 查不到任何进程占用磁盘,vmware-rawdiskCreator print 却能正确列出三个分区,说明磁盘本身没问题。这个报错信息很有迷惑性,字面意思是”死锁”,实际和死锁无关。

绕过创建工具:手写 raw disk 描述文件

raw disk 的 vmdk 本质上是一个文本描述文件,指向整块物理盘。总扇区数用 diskutil info 查(这块盘是 2000409264 个 512 字节扇区):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Disk DescriptorFile
version=1
CID=fffffffe
parentCID=ffffffff
createType="fullDevice"

# Extent description
RW 2000409264 FLAT "/dev/disk2" 0

ddb.virtualHWVersion = "21"
ddb.adapterType = "sata"
ddb.geometry.cylinders = "124519"
ddb.geometry.heads = "255"
ddb.geometry.sectors = "63"

虚拟机配置(vmx)的关键点是 UEFI 启动,因为 Boot Camp 的启动项在盘上的 EFI 分区里;同时关闭安全启动,磁盘接 SATA:

1
2
3
4
5
6
firmware = "efi"
uefi.secureBoot.enabled = "FALSE"
guestOS = "windows9-64"
sata0.present = "TRUE"
sata0:0.present = "TRUE"
sata0:0.fileName = "/path/to/bootcamp.vmdk"

系统是 Windows 11 的话,guestOS 改成 windows11-64。

真正的拦路虎:特权助手没有”完全磁盘访问”

第一次开机失败,提示”Cannot open the disk … Module ‘Disk’ power on failed”。这时去看虚拟机目录里的 vmware.log,比弹窗有用得多:

1
2
3
AppleXPC: Connecting to privileged service com.vmware.DiskHelper...
FILE:open error on /dev/disk2: Operation not permitted
DISKLIB-FLAT : "/dev/disk2" : failed to open (Operation not permitted)

描述文件已经被正确解析,是 Fusion 的特权助手 com.vmware.DiskHelper 去打开物理磁盘时被 macOS 的隐私保护(TCC)拒绝了。解决办法是在 系统设置 → 隐私与安全性 → 完全磁盘访问权限 里,同时加上:

  • /Applications/VMware Fusion.app
  • /Library/PrivilegedHelperTools/com.vmware.DiskHelper

添加助手时在文件选择框里按 Cmd+Shift+G 粘贴路径。授权后 Cmd+Q 彻底退出 Fusion 再打开,然后启动虚拟机,就能正常打开磁盘并进入 Windows 了。

这个结论里有一点我没有验证:授权之后我没有再去试 rawdiskCreator,所以它当初报错是不是同一个原因,只是推测。

几个必须注意的坑

1. 磁盘编号会变。 这块盘之前叫 disk0,后来叫 disk2,原来 disk0 的位置换成了装着 macOS 数据的 2TB 盘。vmdk 里写死的是 /dev/diskN,编号一漂移,Windows 就可能对别的盘读写。这是整个方案里最危险的地方。

2. macOS 会把磁盘自动重新挂载。 启动虚拟机前必须先卸载整盘,而且要紧挨着启动动作:

1
diskutil unmountDisk /dev/disk2

3. 关闭 Windows 的快速启动,并且不要挂起虚拟机。 快速启动会让 NTFS 处于半休眠状态,在原生和虚拟机之间切换时可能出现脏卷甚至丢数据。在 Windows 的管理员终端里执行 powercfg /h off,虚拟机只用”关机”,不要用”挂起”。

4. 虚拟机里一旦运行,就不要同时在 macOS 里挂载这块盘。

5. 软盘警告可以忽略。 日志里有 Could not connect to floppy "/dev/fd/0",虚拟机会让软驱以未连接状态启动。在 vmx 里加一行就不再提示:

1
floppy0.present = "FALSE"

用脚本消除”编号漂移”的风险

我写了一个启动脚本,不再直接在 Fusion 里点开机,而是每次这样做:

  1. 按卷名 BOOTCAMP 找到分区,取它所在的整盘,必须恰好找到一块。
  2. 校验这是外置盘,并且总扇区数等于预期值。任何一项不符就直接退出。
  3. 如果磁盘编号变了,用 sed 改写 vmdk 里的 RW ... FLAT "/dev/diskN" 0 那一行。
  4. 卸载整盘后立刻用 vmrun -T fusion start xxx.vmx gui 启动。

脚本还提供 --check 参数,只检查并显示将使用的磁盘,不改文件也不启动,建议第一次先跑这个。如果以后换了更大的盘或重新分区,扇区数会变,脚本会拒绝启动,需要手动更新里面的预期扇区数。

附:同一个问题,两套模型加工具的差异

这个问题我先后交给了两套组合:

  • GLM 5.3 Flash + ZCode:用了一周多(11 月 2 日到 9 日),最后留下一份很详细的排查记录。
  • Claude Code(Sonnet 5.5):接手后,从第一次动手到虚拟机真正跑起来,是一次会话内完成的。

先说明几个会让对比失真的因素,免得结论被夸大:这只是一个案例,不是评测;Flash 本来就是偏小、偏快的档位,和 Sonnet 5.5 不是同一个量级;Claude 接手时,前一阶段已经铺好了一部分路(比如 Fusion 的完全磁盘访问授权)。

即便如此,差别是真实存在的,主要在这几处:

1. 日志证据 vs 推理升级。 GLM 的记录里,每次失败都被解释成更深一层的”系统限制”:先怀疑完全磁盘访问没生效,后来发现生效了,再转向”读可以写不行”,最后下了结论:macOS 26 从系统层面禁止用户级进程写物理磁盘,Fusion 的 Boot Camp 机制架构性失效,并建议改成克隆整盘,或者用 root 无头虚拟机加 VNC。克隆方案违背了我”同一个系统”的核心需求,无头方案体验很差。而今天的结果证明这个结论是错的:用户级的 Fusion 就能直接读写这块盘。Claude 的做法是读 vmware.log,抓到关键的一行:被拒的是特权助手 com.vmware.DiskHelper,不是 Fusion 主程序。授权对象换了,问题就消失了。我不确定 GLM 当时的环境和这次到底差在哪(它的日志里还提到”无 DiskHelper 代理回退”,这次却连上了),但它没有把注意力放到助手进程上。

2. 会不会修正自己。 GLM 在中途承认过一次”FDA 未生效”是误判,这一点值得肯定。但之后依然是同一种模式:把一次失败的现象推广成不可能的结论,并且没有设计一个能反驳这个结论的实验。Claude 这边我也有走弯路:最初把”死锁”理解成磁盘被占用,查了 lsof,还让我白白多输了几次 sudo 密码,rawdiskCreator 到最后也没有修好。区别在于每一次失败都换成了更具体的日志证据,没有往上一层抽象。

3. 对需求的忠实度。 我的需求是”原生和虚拟机共用同一个系统”。GLM 在发现遇到阻力后,把”克隆”列为推荐方案,需求其实被悄悄降级了。Claude 一直围绕 raw disk 直通做,没有降级。

4. 读到别人的记录后的表现。 我把 GLM 的记录交给 Claude 以后,它没有照单全收,而是发现了两件事:结论和今天的事实冲突;以及记录里磁盘叫 disk0、今天却是 disk2,原来的位置换成了另一块盘。它先核对了旧虚拟机是否还在,确认没有误指向数据盘,再提出用脚本消除编号漂移的风险。

5. 工具层面的差别。 Claude Code 能同时读写本机文件、读虚拟机日志、直接开终端标签、打开系统设置页面,整个排查可以在一次会话里闭环。但有两类事它不能替我做,一类是输入 sudo 密码,一类是修改系统的隐私授权,这两步一直是我自己点的。这一点我觉得是合理的边界,不是缺陷。

总结一句:在需要读日志、定位到具体进程、并且敢于推翻前面结论的任务上,两者的差距在这个案例里非常明显。但这个结论的适用范围就是”这个案例”,换一类任务,比如快速改一行代码,差距可能没有这么大。