2023年1月

给巨硬一点小小的FA♂国震撼

起因是发现UUP dump上竟然可以打包aarch64的镜像包,于是准备捞一份10和一份11下来做纪念。结果捞下来以后就想着,下都下好了,不跑起来用用真是怠慢了它们。转念一想,VMware、VirtualBox、Hyper-V这种虚拟机都是同架构下做虚拟化的,性能好是好,但是不支持跨指令集,只好借助开源而万能的QEMU了。

在QEMU上运行Windows ARM版本与实体机器上的流程基本一致:加载固件、启动安装盘、补驱动和安装使用。相比于实体机按个开机键就能够自动加载BIOS,在QEMU中需要手动指定二进制文件作为BIOS。由于ARM处于百花齐放的状态,不能保证像x86一样有统一的Legacy启动模式,因而往往采取新兴而统一的UEFI来引导系统。

一 系统固件准备

系统固件可以认为是一段可以执行的机器码,与硬件环境有强相关性,负责初始化各类硬件设备,以及告诉操作系统如何使用这些设备。我们一般能接触到的UEFI固件通常是TianoCore的EDK,这是一个由Intel主导的社区实现的开源版本,因而不少人选择基于这个EFI固件魔改代码来支持不同平台,今天的主角QEMU正是其中的目标平台之一。Linaro作为ARM产业链中的中性组织,提供了ARM平台下编译好的参考二进制固件(https://releases.linaro.org/components/kernel/uefi-linaro/)。

但是在经过尝试发现,用linaro提供的固件引导Windows无法正常启动,因而在后续流程中,本文只得改用别人魔改的固件。虽说不要轻易采用来路不明的二进制程序,但在眼下并不良好的环境(指代码和文档稀缺),加之学习为主的目的,只得暂且捏着鼻子先用着了。

别人提供的二进制固件可以在GitHub上下载:https://github.com/raspiduino/waq/releases ,里面的vm.7z中解压出来的QEMU_EFI.imgQEMU_VARS.img两个文件就是所需要的UEFI固件。

二 虚拟机配置与启动

QEMU是个定制化程度较高的虚拟机软件,因而默认配置提供的是一个光秃秃的机器,可以认为是只有处理器和内存,完全满足不了运行Windows的需求——显示器、鼠标键盘等交互设备全部需要自己添加。

在这一步需要准备的东西有三个:

QEMU的虚拟机设备需要通过命令行配置,这里给一个我的模板:

qemu-system-aarch64 ^
-M virt,virtualization=true ^
-accel tcg,thread=multi ^
-cpu cortex-a57 ^
-device VGA ^
-smp 4 ^
-m 4G ^
-drive if=pflash,file=QEMU_EFI.img,format=raw ^
-drive if=pflash,file=QEMU_VARS.img,format=raw ^
-device qemu-xhci ^
-device usb-kbd ^
-device usb-mouse ^
-device intel-hda ^
-device hda-duplex ^
-nic user,model=e1000 ^
-boot d ^
-device usb-storage,drive=install -drive if=none,id=install,format=raw,media=cdrom,readonly=on,file=<Windows镜像> ^
-device usb-storage,drive=drivers -drive if=none,id=drivers,format=raw,media=cdrom,readonly=on,file=<virtio驱动镜像> ^
%*

该模板从上到下依次配置了机器类型、硬件加速模式、处理器型号及数量、内存、显示设备、系统固件、外围硬件,以及系统盘和驱动盘。需要注意的是,机器类型最好开虚拟化参数(即virtualization=true),否则可能启动黑屏;系统安装盘和驱动盘要走USB设备而不能是virtio设备,否则会缺驱动,导致读不到数据,无法安装系统;最后的%*表示允许从命令行继续添加参数,比如加个系统盘,或者其他QEMU设置。在接下来的文字中,我会将这段命令行保存为run_win10.bat并直接使用。

如果仅仅是尝试是否能够正常启动的话,此时直接双击运行run_win10.bat就可以启动虚拟机做测试了。

三 安装系统

如果打算尝试体验,则需要创建并挂载一个虚拟硬盘,用于安装系统。

使用qemu-img工具创建虚拟磁盘:

qemu-img create -f raw system_10.img 20G

此时会在当前目录下创建一个大小为20G的img文件,但在ext或者NTFS这类支持文件空洞的文件系统上,实际占用空间为0,文件的实际大小会随着向内写入数据逐步扩大,直至充满声明的文件大小。

如果文件大小为0的话,表示虚拟硬盘创建并未成功,在虚拟机里显示的磁盘大小为0,此时可以通过qemu-img resize命令来补救:

qemu-img resize -f raw system_10.img 20G

此时应该正常显示文件大小为20G,而实际占用空间为0。经测试,安装系统并完成OOBE后空间占用大约在10G左右。

此时可以通过如下命令,启动一个可以安装系统的虚拟机:

run_win10.bat -drive if=virtio,format=raw,file=system_10.img

如上面所提到,这条命令在之前的基础配置上额外添加了刚创建的system_10.img作为系统盘,并启动虚拟机。该系统盘的硬件类型为virtio-blk,性能相对较好,但需要手动安装驱动。

启动虚拟机后,会发现在选择安装盘步骤找不到任何硬盘,此时则需要在左下角加载驱动程序,运气好的话系统会自动搜索光驱,并提供可供安装的驱动;否则则需要手动浏览文件夹,选取viostor\w10\ARM64目录,安装程序才能找到合适的驱动程序;Windows 11同理。

接下来就是常规的安装流程了,与x86电脑上的流程并无大异。不过在OOBE阶段,可能会出现OOBEKEYBOARDOOBELOCAL等错误信息,能跳过的直接跳过就行,如果不能跳过且一直重试失败的话,则可以用组合键Shift+F10调出cmd窗口,输入shutdown -r -t 0软重启后重新开始配置。

四 使用系统

刚进入系统的时候,巨硬会后台起一个索引程序,我给了四核的处理器直接拉满,网上说有办法停下来,有需要的可以自行搜索,在此不作赘述。

不过要吐槽的是右键菜单,在桌面右键想看看系统信息都能给我卡半天= =一开始以为是索引吃CPU导致卡顿,结果后来一看他COM用的竟然还是x86的,相当于x86经过QEMU转成arm64之后,巨硬又给转回x86指令了。。大哥啊这都系统基本组件了,重新写份原生的有那么难么。。。

另一个问题是显示分辨率问题,默认是800*600,看的那叫一个难受。系统里是不能调节的,我在网上找了半天,说是QEMU配个标准VGA设备能支持到1080p,然而倒腾了半天都没用= = 最后才发现系统的UEFI固件里有设置选项,可以调成1080p。

最后一个问题是网络,这个暂时就没研究了,大伙也说网络问题不少,之后有精力再来折腾吧。

有些人就是喜欢折腾

最近又心血来潮,打算把两年前的坑填上,整了两天,算是把部署OpenStack的坑踩得差不多了。部署方法和之前一样,还是采用的kolla-ansible,主要是neutron_external_interface的文档还是写的比较模糊,加上OpenVirtualSwitch一起,折腾了不少时间。

总结起来,这次折腾的主要结论是,能用,但没必要。由于OpenStack本来就是工业级的设计,开发者原本就是基于企业环境控制网络和外网分离的假设做的实现,因而把两个网络合并势必会受到操作系统等外部组件的设计阻碍,这次的坑基本上都是来自这方面。

首先一开始是打算虚拟一个接口给外网,然后用系统做流量转发给物理网口,但是因为技艺不精,一直失败,只好作罢。后来看到OpenStack的开发文档中提到,由于开发者电脑不一定像工业级服务器一样有两个网口,因而还是允许使用单网口机器部署的。只不过由于ovs要独占外网网口,对外网的访问要从原本的物理网口转移到虚拟网口,导致网络配置丢失,因而必须要使用非远程的方法进行配置(BMC除外)。

大致配置流程如下(假设网卡为eth0):

  1. 按照正常流程配置OpenStack安装,并将network_interfaceneutron_external_interface都设置为eth0
    安装到一半的时候,由于kolla-ansible配置了ovs,导致原有网络配置失效,无法访问外网,表现为某些docker pull失败,说无法连接到quay.io。
  2. 此时可以发现eth0被连接到了ovs-system,但是用ovs-vsctl查看,发现eth0又被分配给了br-ex。用nmcli手动进行网络地址的配置:
    nmcli connection modify br-ex connection.autoconnect yes
    nmcli connection modify br-ex ipv4.addresses xxx.xxx.xxx.xxx
    nmcli connection modify br-ex ipv4.gateway xxx.xxx.xxx.xxx
    nmcli connection modify br-ex ipv4.method manual
    nmcli connection modify br-ex ipv4.dns xxx.xxx.xxx.xxx

    其中xxx.xxx.xxx.xxx设置为网卡正常访问外网时的配置即可。需要注意这几条命令的顺序最好不要修改,因为nmcli会做参数检查,如果没设置好某些参数是设置不了另一些的。

  3. 执行nmcli device set br-ex managed yes,将br-ex的网络配置交给nmcli执行,此时可以用ping检查网络是否配置完成;
  4. 修改kolla-ansibleglobals.yml,将network_interface配置为br-ex,因为此时eth0已经无法正常用于访问网络;
  5. 重新执行kolla-ansibledeploy指令,等待部署完成即可。

由于nmtui似乎没法快捷方便地管理ovs的网卡配置,因而每次重启后需要手动将br-ex设置为managed模式,才能由NetworkManager进行配置,即手动执行第三步。

接下来如果有新坑的话,就是在Linux上配个子网,然后让OpenStack用本地虚拟子网作为外网了