Jarvis's Blog

白帽子、全栈、IoT安全专家、嵌入式系统专家

Windows Dev Kit 2023(WDK2023) 安装Linux (Ubuntu 23.04)操作系统(附镜像)

背景

笔者最近对高通平台的Windows on ARM方案感兴趣,因为之前玩过ARM服务器都是ACPI结构的,可以自由安装操作系统,这次想看看ARM版的windows平台有什么特别之处。由于笔者想买的时候官网已经没货了,所以最后闲鱼二手捡了个垃圾,成色一般,不过就开发来说的话,便宜就行,外观还是其次的。

划痕比较多,可以看到成色非常一般,预装了windows 11 ARM版。

WDK2023的配置如下:

CPU:高通骁龙Snapdragon 8cx gen 3 处理器,8个核心,包含4个Cortex X1超大核和4个Cortex A78大核。

内存: 32G LPDDR4X

硬盘: 512GB NVME SSD

机器出厂已经预装windows,大致使用了一下,由于微软在ARM版windows中也开发了类似ARM版Mac中的Rosetta的系统功能,自动对x86指令集进行翻译,基本可以做到无缝运行x86的windows应用,日常办公也无问题,接下来开始整活。

给WDK2023安装Ubuntu 23.04尝试

为什么会选择把windows的ARM机器安装成Linux呢,主要还是好奇,想看看这台机器的ACPI固件是否强大到可以支持所有操作系统,如果可以那就厉害了。不过经过一番尝试,测试了启动Ubuntu/Debian/Armbian这些操作系统的usb installer镜像,均无法成功启动,一直卡在Boot a command list界面,经过一番搜索,发现很多人都碰到了这个问题,原因似乎在于高通的ACPI固件对操作系统支持不完全,目前仅能支持启动windows 11 ARM版,在安装Linux操作系统这个问题上,大家都碰到了一些困难。

不过好在Thinkpad X13s这台联想笔记本,使用的是相同的平台,之前Armbian已经支持安装在这台笔记本上,因此有一些参考价值,从Armbian的X13s镜像的grub配置中可以了解到,如果要在高通8cx平台上运行Linux,目前只能以设备树方式启动。

也就是说,类似的如果要在Windows dev kit 2023上启动,应该也应该使用这个方式,不过可惜的是,Thinkpas X13s的Armbian镜像,并不能直接在Windows Dev kit 2023上启动,内核启动到一半就直接黑屏卡死了,google搜索了一圈,发现目前网上并不能下载到直接就能启动的镜像,因此,笔者参考了一些资料,最终成功制作出了可以在windows dev kit 2023上启动的Ubuntu 23.04镜像。

主要参考的步骤:

https://github.com/chenguokai/chenguokai/blob/master/tutorial-dev-kit-linux.md

以及为WDK2023适配过的内核源码:

https://github.com/merckhung/linux_ms_dev_kit

为什么选择23.04镜像?因为Ubuntu 23.04镜像的内核版本为6.3,和WDK2023适配使用的内核源码版本一致,为了避免问题,使用了内核源码版本相同的发行版。

接下来记录一下制作过程。

制作WDK2023可用的Ubuntu 23.04镜像

获取并编译内核源码

先clone编译好内核源码,备用。

git clone --depth=1 https://github.com/merckhung/linux_ms_dev_kit -b ms-dev-kit-2023-v6.3.0

如果你和我一样在x86_64机器上编译的话,还需要安装交叉编译工具链(以ubuntu 22.04为例):

sudo apt install -y gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu

然后编译内核:

cd linux_ms_dev_kit 
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- mrproper
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- devkit_defconfig
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig #选上General Setup->Initfamfs source file(s)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j8

由于Ubuntu系统需要Initramfs支持,所以在第三步menuconfig的时候要增加选中在General Setup->Initfamfs source file(s)这一项。(默认config没有选)

编译完成之后先不安装,等准备好文件系统以后再安装内核。

制作可启动的Ubuntu文件系统镜像

由于之前参考的文章使用的是在wdk2023上的windows中使用WSL将文件系统直接写到本机磁盘的,由于我不打算在WDK2023上操作,我打算直接在本机Ubuntu上制作镜像后刻入U盘使用U盘启动。接下来的过程就和原文不同了,过程如下:

创建空的磁盘镜像

新建镜像文件,如果只需要CLI界面,4G就够,如果需要安装桌面环境则需要8G:

dd if=/dev/zero of=bootdisk.img bs=1M count=8192

使用cgdisk对新建的boot镜像进行分区(注意因为wdk使用的是uefi固件,只能从GPT磁盘启动,因此这里要用cgdisk创建GPT分区表):

cgdisk bootdisk.img

分区大家可以参考我的,就是1个256MB的EFI分区,剩下的全部分配给/根分区,如下图

然后使用kpartx工具挂载镜像:

sudo kpartx -a -s -v bootdisk.img

成功的话此时会输出挂载以后每个分区的loop设备:

add map loop22p1 (253:0): 0 524288 linear 7:22 2048
add map loop22p2 (253:1): 0 16250847 linear 7:22 526336

以上输出的loopxxx的设备名称具体不同机器可能有所不同,接下来给每个分区创建文件系统并挂载:

sudo mkfs.vfat /dev/mapper/loop22p1   #efi分区格式化为vfat
sudo mkfs.ext4 /dev/mapper/loop22p2   #根分区格式化为ext4
sudo mount /dev/mapper/loop22p2 /mnt  #挂载根分区

接下来的步骤就和参考文章中的一样了,使用debootstrap将ubuntu文件系统安装到/mnt:

sudo apt install -y debootstrap #如果没安装的话安装一下debootstrap工具
sudo debootstrap --arch arm64 lunar /mnt http://ports.ubuntu.com/ubuntu-ports  #安装Ubuntu根文件系统

接下来经过漫长的等待安装完成即可。

安装内核和设备树

文件系统准备完毕,接下来就可以安装内核了,进入之前编译内核的文件夹:

cd linux_ms_dev_kit/
sudo make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_PATH=/mnt/boot install  #安装内核镜像
sudo make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=/mnt modules_install   #安装内核模块
sudo cp arch/arm64/boot/dts/qcom/sc8280xp-microsoft-dev-kit-2023.dtb /mnt/boot #安装设备树

添加一些必要的软件包

默认的根文件系统安装的只是系统运行必要的包,属于最小安装,为了方便后续使用和调试,我们最好继续安装一些必要的软件包,那么如何在已经安装完的根文件系统中继续安装呢?可以使用systemd-nspawn工具创建一个虚拟root环境,这个工具会帮助处理网络和其他设备的绑定,比chroot要方便,不过笔者是在x86-64的Ubuntu上安装arm64版本的Ubuntu,因此需要先安装qemu-user-static才能运行arm64的程序:

sudo apt install -y  qemu-user-static
sudo mkdir /mnt/boot/efi   #创建efi目录
sudo mount /dev/mapper/loop22p1 /mnt/boot/efi  #挂载efi分区
sudo systemd-nspawn  --quiet   --notify-ready=yes  --register=yes  --bind-ro="/etc/resolv.conf"    --machine="lunar"  --directory="/mnt/"   #进入chroot虚拟环境

运行以上命令后,就可以进入之前安装完毕的/mnt的虚拟环境,接下来的工作在虚拟环境中操作。

apt update
apt install -y linux-firmware  #安装必要的固件
apt install -y grub-efi-arm64 #安装grub引导器
apt install -y ubuntu-desktop #桌面环境(可选)
apt install -y openssh-server bash-completion network-manager net-tools vim nano #安装一些实用工具(可选)
systemctl enable ssh.service  #如果安装了openssh-server就启用一下服务

添加GPU固件

骁龙8cx gen 3的GPU是adreno 690,由于比较新,固件在linux-firmware里面没有,需要将Thinkpad X13s的对应固件添加到/usr/lib/firmware/qcom目录中:

对应的固件可以在这个仓库里找到:https://github.com/cenunix/x13s-firmware

cd /usr/lib/firmware/qcom
wget https://github.com/cenunix/x13s-firmware/raw/main/a690_gmu.bin
mkdir -p sc8280xp/MICROSOFT/DEVKIT23
cp -r sc8280xp/LENOVO/21BX/* sc8280xp/MICROSOFT/DEVKIT23/

添加用户

useradd -m -g users -s /bin/bash ubuntu #添加ubuntu用户
usermod -a -G sudo ubuntu #给ubuntu用户加入sudo组
passwd ubuntu #设置一下密码

生成initramfs

update-initramfs -c -k 6.3.0+

运行完成后会在/boot/目录下生成对应内核的initrd.img

安装引导器并修改引导选项

由于systemd-nspawn无法访问/dev/loop22设备,所以安装引导器只能手动bind /dev目录进行chroot才行。

exit     #退出虚拟环境
#接下来在主机上操作
sudo mount -o bind /dev /mnt/dev
sudo mount -o bind /proc /mnt/proc
sudo mount -o bind /sys /mnt/sys
sudo chroot /mnt
#接下来进入了chroot环境
grub-install --target=arm64-efi --efi-directory=/boot/efi/ --boot-directory=/boot/ --bootloader-id=Ubuntu /dev/loop22 --recheck  #安装grub引导器
update-grub   #生成grub配置文件
exit  #退出chroot环境

grub-install安装过程会报warning: EFI variables cannot be set on this system. 因为我们在安装时是从U盘启动,不需要将引导项添加到UEFI环境变量中,因此可以忽略这条错误。

update-grub之后就会爱/boot目录下生成/boot/grub目录,我们还需要修改一下grub.cfg,加入MDK2023所需要的内核cmdline参数和设备树加载命令。

退出虚拟环境后,修改/mnt/boot/grub/grub.cfg文件,作如下修改:

删除### BEGIN /etc/grub.d/30_os-prober ###和### END /etc/grub.d/30_os-prober ###中间的内容,因为我们在chroot环境中安装,os-prober会检测到主机的操作系统,这个是对我们没有用的,应该删除。

修改3条menuentry的内容,修改每个menuentry中的linux那一行,按照之前参考的github文章修改,并在initrd下方加上devicetree的加载命令,最终修改成下面的样子:

menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-5bee697a-24e3-4e77-8875-29872732fbea' {
	recordfail
	load_video
	gfxmode $linux_gfx_mode
	insmod gzio
	if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
	insmod part_gpt
	insmod ext2
	search --no-floppy --fs-uuid --set=root 5bee697a-24e3-4e77-8875-29872732fbea
	linux	/boot/vmlinuz-6.3.0+ root=UUID=5bee697a-24e3-4e77-8875-29872732fbea ro clk_ignore_unused efi=novamap earlycon=efifb iommu.strict=0 pd_ignore_unused mitigations=off
	initrd	/boot/initrd.img-6.3.0+
	devicetree	/boot/sc8280xp-microsoft-dev-kit-2023.dtb
}
submenu 'Advanced options for Ubuntu' $menuentry_id_option 'gnulinux-advanced-5bee697a-24e3-4e77-8875-29872732fbea' {
	menuentry 'Ubuntu, with Linux 6.3.0+' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-6.3.0+-advanced-5bee697a-24e3-4e77-8875-29872732fbea' {
		recordfail
		load_video
		gfxmode $linux_gfx_mode
		insmod gzio
		if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
		insmod part_gpt
		insmod ext2
		search --no-floppy --fs-uuid --set=root 5bee697a-24e3-4e77-8875-29872732fbea
		echo	'Loading Linux 6.3.0+ ...'
		linux	/boot/vmlinuz-6.3.0+ root=UUID=5bee697a-24e3-4e77-8875-29872732fbea ro clk_ignore_unused efi=novamap earlycon=efifb iommu.strict=0 pd_ignore_unused mitigations=off
		echo	'Loading initial ramdisk ...'
		initrd	/boot/initrd.img-6.3.0+
		echo	'Loading devicetree blob /boot/sc8280xp-microsoft-dev-kit-2023.dtb ...'
		devicetree	/boot/sc8280xp-microsoft-dev-kit-2023.dtb
	}
	menuentry 'Ubuntu, with Linux 6.3.0+ (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-6.3.0+-recovery-5bee697a-24e3-4e77-8875-29872732fbea' {
		recordfail
		load_video
		insmod gzio
		if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
		insmod part_gpt
		insmod ext2
		search --no-floppy --fs-uuid --set=root 5bee697a-24e3-4e77-8875-29872732fbea
		echo	'Loading Linux 6.3.0+ ...'
		linux	/boot/vmlinuz-6.3.0+ root=UUID=5bee697a-24e3-4e77-8875-29872732fbea ro single nomodeset clk_ignore_unused efi=novamap earlycon=efifb iommu.strict=0 pd_ignore_unused mitigations=off
		echo	'Loading initial ramdisk ...'
		initrd	/boot/initrd.img-6.3.0+
		echo	'Loading devicetree blob /boot/sc8280xp-microsoft-dev-kit-2023.dtb ...'
		devicetree	/boot/sc8280xp-microsoft-dev-kit-2023.dtb
	}
}

最后保存即可。

添加fstab

由于debootstrap安装的文件系统缺少fstab,我们需要手动修改fstab:

修改/mnt/etc/fstab文件,参考下方修改,UUID需要替换为分区实际的uuid,参考/dev/disk/by-uuid下的内容。

# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# / was on /dev/sda1 during installation
UUID=5bee697a-24e3-4e77-8875-29872732fbea /               ext4    errors=remount-ro 0       1
UUID=912C-E9CA /boot/efi vfat defaults 0 2

都完成之后,卸载镜像即可:

sudo umount -R /mnt/test
sudo kpartx -d bootdisk.img
sudo losetup -d /dev/loop22

接下来就可以使用dd命令或者balenaEtcher(windows系统)工具将制作好的bootdisk.img写入U盘了。

启动镜像

插上U盘,按住WDK上的Boot to UEFI(圆形)和电源键开机进入Surface UEFI设置界面,Boot configuration中选择USB Storage启动。

正常情况下,此时应该就可以正常启动进Ubuntu了,如果装了desktop的话,现在应该能看到图形界面:

登录以后就可以先连接一下wifi,如果没有安装ubuntu-desktop可以使用network-manager中的nmcli命令连接网络,或者直接插上网线,这样就方便接下来可以通过网络ssh连接机器完成后续的安装。

安装Ubuntu 2023到内部的NVME硬盘

仅仅通过U盘启动系统并不是我们的最终目的,因为如果后续还要使用Ubuntu系统,不能每次都插U盘,这样十分不方便,但是由于现在我们没有LiveCD中的安装器,所以只能手动安装,不过也不算特别麻烦,只需要调整一下分区然后直接把U盘中的文件系统写入内部硬盘再安装引导器即可。

调整分区

由于原装的windows已经对内部硬盘进行了分区并创建好efi分区了,我们这里只需要重新格式化并将Ubuntu文件系统写入即可:

sudo mkfs.vfat /dev/nvme0n1p1  #格式化EFI分区
sudo mkfs.ext4 /dev/nvme0n1p3  #格式化windows分区
sudo dd if=/dev/sdb2 of=/dev/nvme0n1p3   #直接用dd将U盘里的Ubuntu系统写到nvme磁盘中

注意,上面的/dev/sdb2硬盘号可能在你的系统中有所不同,需要根据lsblk的结果来判断。

完成之后使用resize2fs将文件系统展开到整个分区大小(否则根分区容量会保持和镜像的大小一样只有8G),然后挂载根分区和efi分区:

sudo e2fsck -yf /dev/nvme0n1p3   
sudo resize2fs /dev/nvme0n1p3   
sudo mount /dev/nvme0n1p3 /mnt
sudo mount /dev/nvme0n1p1 /mnt/boot/efi

修改安装完成之后文件系统的fstab,因为nvme磁盘分区的uuid和U盘中不同,需要同时调整fstab,根据/dev/disk/by-uuid的内容修改fstab:

将/mnt/etc/fstab修改为:

# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# / was on /dev/sda1 during installation
UUID=5bee697a-24e3-4e77-8875-29872732fbea /               ext4    errors=remount-ro 0       1
UUID=A8D5-6984 /boot/efi vfat defaults 0 2
                          

修改完成后保存,然后在nvme磁盘上安装引导程序,安装步骤和前面类似,但有一个注意点,为了将引导程序写入UEFI环境变量,此时需要挂载efivarfs,否则会导致无法启动。

sudo mount -o bind /dev /mnt/dev
sudo mount -o bind /proc /mnt/proc
sudo mount -o bind /sys /mnt/sys
sudo chroot /mnt
#接下来在chroot环境中操作
mount -t efivarfs efivarfs /sys/firmware/efi/efivars/ #挂载efivarfs(重要别忘记!)
grub-install --target=arm64-efi --efi-directory=/boot/efi/ --boot-directory=/boot/ --bootloader-id=Ubuntu /dev/nvme0n1 --recheck  #安装grub引导器,磁盘要改为nvme磁盘,不要跟前面照抄
exit
sudo umount -R /mnt

此次安装时,因为挂载了efivarfs,因此不会报之前的EFI variables cannot be set on this system这个waring。

由于我们是使用dd安装的,因此根分区UUID不会变,所以grub.cfg可以不用修改。

完成之后拔下U盘重新启动系统,正常情况下此时WDK已经可以正常从内部磁盘启动了,在UEFI界面中可以看到,此时boot选项多出了之前安装的Ubuntu引导器:

之前windows遗留的Windows Boot Manager引导选项没有用了,可以直删掉,启动以后可以看到已经是nvme硬盘上的Ubuntu系统了:

总结

本次折腾验证了高通骁龙8cx gen 3平台的WDK2023可以安装Linux操作系统,但只能以dtb方式启动,总体看来比较麻烦,这个设备还没有进入Ubuntu官方的支持列表,希望后续能有官方支持。

以及如果你觉得麻烦,想直接抄作业的话,我这里也把我制作的镜像放在这里(先解压再写U盘),如果有需要可以自取:

链接:https://pan.baidu.com/s/1NlALpLpkFaZ9d1xU6iPY3A?pwd=4bzd
提取码:4bzd
–来自百度网盘超级会员V3的分享

在Android中使用ARM Coresight ETM/ETE进行指令流分析的方法及平台选型

上一篇

IPMI清除bios nvram设置

下一篇
评论
发表评论 说点什么
还没有评论

浙公网安备 33011002014706号