基础工作
包含:
qemu编译安装
uboot编译安装
内核编译
rootfs编译
dtb编译
xen编译
xen运行
qemu安装
#python3.7
sudo add-apt-repository ppa:deadsnakes/ppa sudo apt update sudo apt install python3.7
sudo ln -s /usr/bin/python3.7 /usr/bin/python3
sudo apt install python3-pip
sudo apt-get install python3.7-gdbm
sudo apt install python3-pip
sudo pip3 install ninja
#gcc安装
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install gcc g++ -y
sudo apt-get install make
sudo apt update
sudo apt install ninja-build
sudo apt-get install pkg-config
#ninja安装
git clone git://github.com/ninja-build/ninja.git && cd ninja
./configure.py --bootstrap
cp ninja /usr/bin/
#安装其他依赖包
sudo apt-get install build-essential zlib1g-dev pkg-config libglib2.0-dev
binutils-dev libboost-all-dev autoconf libtool libssl-dev
libpixman-1-dev libpython-dev python-pip python-capstone virtualenv
sudo apt-get install libpixman*
sudo apt-get install libgstreamer1.0-dev
sudo apt-get install gstreamer-1.0
sudo apt-get install libmount-dev
#下载qemu并编译安装
git clone git://git.qemu-project.org/qemu.git
cd qemu
mkdir -p bin/
cd bin/
../configure --target-list=aarch64-softmmu
make install
#运行qemu检查是否安装成功
qemu-system-aarch64 -h
uboot编译
#uboot源码下载并解压
#这里我下载的是最新的u-boot-2021.07-rc1.tar.bz2源码ftp地址:ftp://ftp.denx.de/pub/u-boot/
wget -c ftp://ftp.denx.de/pub/u-boot/u-boot-2021.07-rc1.tar.bz2
tar xf u-boot-2021.07-rc1.tar.bz2
#下在交叉编译工具
#这里建义下在7.5版本工具(用新的gcc会编译失败,原因未知)
http://releases.linaro.org/components/toolchain/binaries/7.5-2019.12/aarch64-linux-gnu/
#解压并设置环境变量:
tar xf gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu
export CROSS_COMPILE=/mnt/e/source/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
#更新openssl并安装其他依赖库
#下载源码(这里用的是 openssl-1.1.1k)https://www.openssl.org/source/
tar -zxvf openssl-1.1.1k.tar.gz
cd openssl-1.1.1k
./config
make -j8
make install
sudo apt-get install libssl*
#编译uboot
注意检查.config中是否有如下配置:
CONFIG_ARCH_QEMU=y
CONFIG_TARGET_QEMU_ARM_64BIT=y
cd u-boot-2021.07-rc1
make qemu_arm64_defconfig
make -j8
#验证uboot
#这里为了后面调试方便,我们创建了一个目录xen_arm64,后面会将各模块编译出来的最终文件放到该目录下,方便调试与运行:
cp u-boot-2021.07-rc1/u-boot.bin xen_arm64/
cd xen_arm64
qemu-system-aarch64 -machine virt -cpu cortex-a57 -bios u-boot.bin -nographic
编译内核
1 源码下载并解压
#源码网址https://www.kernel.org/ (这里下载的为最新的linux-5.12版本)
tar xf linux-5.12.tar.xz
cd linux-5.12
export CROSS_COMPILE=/mnt/e/source/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
make ARCH=arm64 defconfig
make -j8
cp arch/arm64/boot/Image ../xen_arm64/
cp arch/arm64/boot/Image.gz ../xen_arm64/
cp vmlinux ../xen_arm64/
注意:
检查.config中是否包含了如下配置:
CONFIG_XEN_DOM0=y
CONFIG_XEN=y
可能会报错 libcrypto.so.1.1找不到
cd /usr/lib/
ln -s libcrypto.so.1.1 ../local/lib/libcrypto.so.1.1
2 验证编译后的kernel
由于uboot加载并运行kernel,理论上除了kernel还需要dtb,但是qemu已经提供了默认的dtb且放在0x40000000的位置。
因此大概我们可以获得一个如下的memory map:
#基于此memory map我们运行如下虚拟机命令:
qemu-system-aarch64 -machine virt -cpu cortex-a57 -m 512M -bios u-boot.bin -device loader,file=Image,addr=0x45000000 -nographic
#在uboot命令行里输入:
booti 0x45000000 - 0x40000000
最终会由于没有找到init而panic 如下图:
编译busybox并制作根文件系统
1 源码下载并配置编译
#下载地址:https://busybox.net/downloads/ (这里我使用的是busybox-1.33.0.tar.bz2)
tar -jxvf busybox-1.33.0.tar.bz2
cd busybox-1.33.0
export CROSS_COMPILE=/mnt/e/source/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
make menuconfig ARCH=arm64
配置生成静态库 设置路经如下:
Settings
->Build shared libbusybox
Make -j8
Make install
2 制作根文件系统
#拷贝busybox到指定目录:
mkdir ../xen_arm64/rootfs
cd cp -R _install/* ../xen_arm64/rootfs/
cd ../xen_arm64/rootfs/
mkdir -p proc sys tmp root var mnt dev
#修改fstab 与 rcS
Vim etc/fstab
增加如下内容:
proc /proc proc defaults 0 0
none /tmp ramfs defaults 0 0
mdev /dev ramfs defaults 0 0
sysfs /sys sysfs defaults 0 0
vim etc/init.d/rcS
增加如下内容:
#! /bin/sh
/bin/mount -a
#制作ext4根文件系统
dd if=/dev/zero of=rootfs.ext4 bs=1M count=64
mkfs.ext4 rootfs.ext4
mkdir ramdisk
mount rootfs.ext4 ramdisk
cd ramdisk
cp -R ../rootfs ./
mknod dev/tty1 c 4 1
mknod dev/tty2 c 4 2
mknod dev/tty3 c 4 3
mknod dev/tty4 c 4 4
mknod dev/console c 5 1
mknod dev/null c 1 3
cd ..
umount ramdisk
#制作ramfs根文件系统
cd rootfs
vim etc/init.d/rcS
增加如下内容:
#! /bin/sh
/bin/mount -a
/bin/mknod /dev/tty1 c 4 1
/bin/mknod /dev/tty2 c 4 2
/bin/mknod /dev/tty3 c 4 3
/bin/mknod /dev/tty4 c 4 4
/bin/mknod /dev/console c 5 1
/bin/mknod /dev/null c 1 3
#制作ramfs文件系统
cd rootfs
find . | cpio -o --format=newc > ../rootfs.img
cd ..
gzip -c rootfs.img > rootfs.img.gz
3 验证根文件系统
# Kernel+rootfs.ext4
#注:这里将rootfs.ext4利用qemu提供hda命令挂载到内核里,且在开机log可以看到是挂到了/dev/vda里。因此cmdline需要加下root=/dev/vda rootfstype=ext4;最终会发现已经可以正常走进shell并不会panic了。
qemu-system-aarch64 -machine type=virt -cpu cortex-a57 -nographic -smp 4 -m 2048M -kernel Image -hda rootfs.ext4 -append "root=/dev/vda console=ttyAMA0 rootfstype=ext4 init=/linuxrc rw"
Kernel+rootfs.ext4
#注:我们知道ramfs一般是由uboot或lk将ramdisk或rootfs加载到内存里,然后通过设备树增加inux,initrd-start与 linux,initrd-end来告知内核rootfs的存放的区域和大小。这里我们直接使用qemu的命令initrd来加载,因此要加上root=/dev/ram
qemu-system-aarch64 -machine type=virt -cpu cortex-a57 -nographic -smp 4 -m 2048M -kernel Image -initrd rootfs.img.gz -append "rw root=/dev/ram rdinit=/sbin/init earlyprintk=serial,ttyAMA0 console=ttyAMA0"
gdb调试与生成设备树(dtb)
1 生成设备树
由于上面我们用的一直是qemu的默认设备树,而xen后面会需要修改设备树,所以我们这节简单介绍一下设备树生成和修改;
由于本在这个调试过程中遇到了点问题,最终是用gdb调试定位了来的,所以也做一些简单的介绍。
#qemu提供了dump dtb功能,只需要加上dumpdtb=virt.dtb即可:
qemu-system-aarch64 -machine virt,dumpdtb=virt.dtb -cpu cortex-a57 -nographic -smp 4 -m 2048M -kernel Image -initrd rootfs.img.gz -append "rw root=/dev/ram rdinit=/sbin/init earlyprintk=serial,ttyAMA0 console=ttyAMA0"
#将dump出来的dtb反编译成dts
dtc -I dtb -O dts virt.dtb -o virt.dts
Memory map大致如下:
#修改dts内容如下:
chosen {
linux,initrd-start = <0x49000000>;
linux,initrd-end = <0x4911eb9e>;
bootargs="rw root=/dev/ram rdinit=/sbin/init earlyprintk=serial,ttyAMA0 console=ttyAMA0";stdout-path = "/pl011@9000000";
kaslr-seed = <0xce5ef7a7 0x5e095f9d>;
};
#将dts再次编译成dtb:
dtc -I dts -O dtb virt.dts -o virt.dtb
#启动虚拟机:
qemu-system-aarch64 -machine type=virt -cpu cortex-a57 -nographic -smp 4 -m 2048M -kernel Image -dtb virt.dtb -device loader,file=rootfs.img.gz,addr=0x49000000
2 运行 uboot+kernel+dtb+rootfs
#启动虚拟机:
cd /mnt/e/source/xen_arm64
qemu-system-aarch64 -machine type=virt -cpu cortex-a57 -nographic -smp 4 -m 2048M -bios u-boot.bin -device loader,file=Image,addr=0x47000000 -device loader,file=virt2.dtb,addr=0x44000000 -device loader,file=rootfs.img.gz,addr=0x49000000
#在uboot命令行里输入:
booti 0x47000000 - 0x44000000
3 gdb调试
如果上面可以正常运行,则可跳过此步。因为之前的一些失误导致当时调试时发现虚拟机启动在出现start kernel后一直卡死。
因此这里使用gdb调试一下。
#注意:这里在虚拟机启动命令前加上-s -S就可以了,其标志意义如下:
-s shorthand for -gdb tcp::1234
-S freeze CPU at startup
#终端1-启动虚拟机
cd /mnt/e/source/xen_arm64
qemu-system-aarch64 -s -S -machine type=virt -cpu cortex-a57 -nographic -smp 4 -m 2048M -bios u-boot.bin -device loader,file=Image,addr=0x47000000 -device loader,file=virt2.dtb,addr=0x44000000 -device loader,file=rootfs.img.gz,addr=0x49000000
#终端2-启动gdb
export CROSS_COMPILE=/mnt/e/source/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
${CROSS_COMPILE}gdb vmlinux
#在加载完vmlinux后,输入:
target remote :1234
#然后在start_kernel设个断点:
b start_kernel
#输入c让虚拟机继续运行
c
#终端1-在uboot命令行中输入命令启动kernel
booti 0x47000000 - 0x44000000
#终端2-继续多打几个断点,并抓出log
#这里就可以多打几个断点或停下查看状态,这里由于最终发放是发生了panic,所以我们让系统继续运行到最后,然后#把kernel log存下来。
#我们知道kernel的log是存放在__log_buf的这个数组里,因此我们只要把这断内存内容保存下来即可:
print &__log_buf
$1 = (char (*)[131072]) 0xffff800011eac498 <__log_buf>
dump binary memory ./dump1.bin 0xffff800011eac498 0xffff800011eac498+0x20000
#此时打开dump1.bin可以发现主要原因是系统发生了panic,而panic的地方刚好是console驱动,所以导致没有log输出。Key log如下:
Serial: AMBA PL011 UART driverer
Internal error: synchronous external abort: 96000010 [#1] PREEMPT SMPMP
Modules linked in:c
……
amba_device_try_add+0xf8/0x378
amba_device_add+0x1c/0xe8
of_platform_bus_create+0x310/0x3c0
of_platform_populate+0x80/0x110
of_platform_default_populate_init+0xbc/0xdc
do_one_initcall+0x60/0x1d8
kernel_init_freeable+0x1f8/0x250
kernel_init+0x14/0x118
ret_from_fork+0x10/0x30
#经查主要原因是串口对应的地址与别人重叠了,直接在设备树中去掉重叠的节点,如下:
--pl061@9030000 {
--phandle = <0x8003>;
--clock-names = "apb_pclk";
--clocks = <0x8000>;
--interrupts = <0x0 0x7 0x4>;
--gpio-controller;
--#gpio-cells = <0x2>;
--compatible = "arm,pl061", "arm,primecell";
--reg = <0x0 0x9030000 0x0 0x1000>;
--};
#最终问题修复,可正常启动。
编译xen
1 源码下载&编译
#源码下在地址:https://xenproject.org/xen-project-archives/ (这里下在最新的4.15)
tar -zxvf xen-4.15.0.tar.gz
cd xen-4.15.0
export CROSS_COMPILE=/mnt/e/source/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
make dist-xen XEN_TARGET_ARCH=arm64
cp xen/xen ../xen_arm64
2 运行uboot + xen + kernel + dtb +rootfs.ext4
#重新生成dtb(这里由于要用到虚拟化,所以要打开virtualization=on)
qemu-system-aarch64 -machine type=virt,virtualization=on,dumpdtb=virt.dtb -cpu cortex-a57 -nographic -smp 4 -m 2048M -bios u-boot.bin -device loader,file=xen,force-raw=on,addr=0x50000000 -device loader,file=Image,addr=0x47000000 -device loader,file=virt2.dtb,addr=0x44000000 -hda rootfs.ext4
Meory map如下:
#修改dts
dtc -I dtb -O dts virt.dtb -o virt.dts
chosen {
#size-cells = <0x1>;
#address-cells = <0x1>;
stdout-path = "/pl011@9000000";
kaslr-seed = <0xce5ef7a7 0x5e095f9d>;
module@0x47000000 {
compatible = "multiboot,kernel","multiboot,module";
reg = <0x47000000 0x2000000>;
bootargs = "rw root=/dev/vda init=/linuxrc rootfstype=ext4 earlyprintk=serial,ttyAMA0 console=ttyAMA0 console=hvc0 earlycon=xenboot nokaslr";
};
};
dtc -I dts -O dtb virt.dts -o virt.dtb
#启动虚拟机
qemu-system-aarch64 -machine type=virt,virtualization=on -cpu cortex-a57 -nographic -smp 4 -m 2048M -bios u-boot.bin -device loader,file=xen,force-raw=on,addr=0x50000000 -device loader,file=Image,addr=0x47000000 -device loader,file=virt2.dtb,addr=0x44000000 -hda rootfs.ext4
#加载并启动xen
booti 0x50000000 - 0x44000000
3 运行uboot + xen + kernel + dtb +rootfs.img.gz
Meory map如下:
#修改dts
chosen {
#size-cells = <0x1>;
#address-cells = <0x1>;
stdout-path = "/pl011@9000000";
kaslr-seed = <0xce5ef7a7 0x5e095f9d>;
module@0x47000000 {
compatible = "multiboot,kernel","multiboot,module";
reg = <0x47000000 0x2000000>;
bootargs = "rw root=/dev/ram rdinit=/sbin/init earlyprintk=serial,ttyAMA0 console=hvc0 earlycon=xenboot nokaslr";
};
module@0x49000000 {
compatible = "xen,linux-initrd","multiboot,module";
reg = <0x49000000 0x23d9a5>;
};
};
dtc -I dts -O dtb virt.dts -o virt.dtb
#启动虚拟机
qemu-system-aarch64 -machine type=virt,virtualization=on -cpu cortex-a57 -nographic -smp 4 -m 2048M -bios u-boot.bin -device loader,file=xen,force-raw=on,addr=0x50000000 -device loader,file=Image,addr=0x47000000 -device loader,file=virt2.dtb,addr=0x44000000 -device loader,file=rootfs.img.gz,addr=0x49000000
#加载并启动xen
booti 0x50000000 - 0x44000000
运行xen +d0 + d1
这里为了实验,d0与d1都采用linux,同时分别将Image 、 dts、rootfs等 复制并重命名给d1使用;
为些我们重新设计memory map如下:
#修改dts
chosen {
#size-cells = <0x1>;
#address-cells = <0x1>;
stdout-path = "/pl011@9000000";
kaslr-seed = <0xce5ef7a7 0x5e095f9d>;
xen,xen-bootargs = "dom0_mem=1024M";
module@0x46000000 {
compatible = "multiboot,kernel","multiboot,module";
reg = <0x46000000 0x2000000>;
bootargs = "rw root=/dev/ram rdinit=/sbin/init earlyprintk=serial,ttyAMA0 console=hvc0 earlycon=xenboot nokaslr";
};
module@0x48000000 {
compatible = "xen,linux-initrd","multiboot,module";
reg = <0x48000000 0x23d9a5>;
};
domU1 {
compatible = "xen,domain";
#address-cells = <0x1>;
#size-cells = <0x1>;
memory = <0x0 0x80000>;
cpus = <1>;
vpl011;
module@0x51000000 {
compatible = "multiboot,kernel", "multiboot,module";
reg = <0x51000000 0x2000000>;
bootargs = "rw root=/dev/ram rdinit=/sbin/init console=ttyAMA0";
};
module@0x53000000 {
compatible = "multiboot,ramdisk", "multiboot,module";
reg = <0x53000000 0x23d9a5>;
};
};
};
#编译dtb
dtc -I dts -O dtb virt_d0.dts -o virt_d0.dtb
#启动虚拟机
qemu-system-aarch64 -machine type=virt,virtualization=on -cpu cortex-a57 -nographic -smp 4 -m 2048M -bios u-boot.bin -device loader,file=virt_d0.dtb,addr=0x44000000 -device loader,file=Image0,addr=0x46000000 -device loader,file=rootfs_d0.img.gz,addr=0x48000000 -device loader,file=Image1,addr=0x51000000 -device loader,file=rootfs_d1.img.gz,addr=0x53000000 -device loader,file=xen,force-raw=on,addr=0x55000000
#在uboot中启动xen
booti 0x55000000 - 0x44000000
文件清单
上述工作可以生成下列文件清单:
1)Uboot,已经编译好的u-boot.bin
2)dom0内核,已经编译好的Linux镜像Image
3)dom0设备树,virt-gicv3.dts和virt-gicv3.dtb
4)dom0 rootfs,rootfs.tar.gz和生成脚本rootfs.sh
5)chroot环境,chroot_xen.tar.gz (此项没有,需自己做)
chroot编译xen(带xen-tools)
1.搭建chroot环境
1)将chroot解压
tar -zxvf chroot.tar.gz ./
2)进入chroot环境
sudo chroot chroot/distro_arm64/
2.在chroot环境中获取xen源码
1)将xen源码拷贝到chroot根目录下,或者直接在chroot中通过git clone下载xen源码
3.编译xen源码,生成xen镜像和xen-tool工具
cd xen
make -j8 XEN_TARGET_ARCH=arm64
制作rootfs(带xen-tools)
1.将xen-tool工具安装到rootfs,该rootfs用于启动dom0
1)解压rootfs压缩包,将rootfs解压到目录rootfs
2)在xen/dist/目录下执行脚本,将xen-tool安装到上一步骤的rootfs中
sudo install.sh + rootfs所在目录
2.制作跟文件系统
1)在rootfs所在目录下运行sudo rootfs.sh,会生成rootfs_xen.ext4
rootfs.sh脚本如下:
# !/bin/sh
sudo dd if=/dev/zero of=rootfs_xen.ext4 bs=1M count=2548
sudo mkfs.ext4 rootfs_xen.ext4
sudo rm -rf ramdisk
sudo mkdir ramdisk
sudo mount rootfs_xen.ext4 ramdisk
cd ramdisk
sudo cp -R ../rootfs/* ./
sudo mknod dev/tty1 c 4 1
sudo mknod dev/tty2 c 4 2
sudo mknod dev/tty3 c 4 3
sudo mknod dev/tty4 c 4 4
sudo mknod dev/console c 5 1
sudo mknod dev/null c 1 3
cd ..
sudo umount ramdisk
qemu运行xen+dom0
1.qemu启动uboot
qemu-system-aarch64 -nographic -M virt,gic-version=3,virtualization=on -cpu cortex-a57 -m 3072M -smp 4 -bios u-boot.bin -device loader,file=virt-gicv3.dtb,addr=0x44000000
-device loader,file=Image,addr=0x47000000 -hda rootfs_xen.ext4
-device loader,file=xen,force-raw=on,addr=0x56000000
2.启动xen
booti 0x56000000 - 0x44000000
启动起来之后,系统为xen+dom0,之后想要启动domu,可以使用xl工具启动,
可以将domU需要的镜像放入dom0的跟文件系统中,用于后续启动加载。