Last Updated: 2023-09-24 06:18:35 Sunday
-- TOC --
Windows平台使用VMware,Linux平台使用Qemu,特别是在需要调试与kernel有关的场景下。
Qemu官网:https://www.qemu.org
Qemu可以做3件事情:
通过Qemu程序的名称,可以知道它对应的ISA架构和应用场景:
$ apt list | grep qemu
$ sudo apt install qemu-system-misc # RISC-V
$ sudo apt install qemu-user # RISC-V user-mode
Or:
$ ll /usr/bin/qemu-*
-rwxr-xr-x. 1 root root 526K Sep 21 16:53 /usr/bin/qemu-ga
-rwxr-xr-x. 1 root root 2.0M Sep 21 16:53 /usr/bin/qemu-img
-rwxr-xr-x. 1 root root 2.0M Sep 21 16:53 /usr/bin/qemu-io
lrwxrwxrwx. 1 root root 18 Sep 21 16:48 /usr/bin/qemu-kvm -> qemu-system-x86_64
-rwxr-xr-x. 1 root root 2.1M Sep 21 16:53 /usr/bin/qemu-nbd
-rwxr-xr-x. 1 root root 915K Sep 21 16:53 /usr/bin/qemu-pr-helper
-rwxr-xr-x. 1 root root 2.9M Sep 21 16:53 /usr/bin/qemu-storage-daemon
-rwxr-xr-x. 1 root root 14M Sep 21 16:53 /usr/bin/qemu-system-i386
-rwxr-xr-x. 1 root root 14M Sep 21 16:53 /usr/bin/qemu-system-x86_64
-name
:指定虚拟机的name。
-kernel
:指定kernel文件。
-initrd
:指定initramfs文件。
-bios
:指定firmware,默认是seabios,可以在此指定OVMF,让qemu按UEFI的方式启动。
-hd[a|b|c|d]
,指定Hard Disk,指向device file或image file,而不是其分区。即要写成/dev/sdc,而不是/dev/sdc1,可以是/dev/loop0这样的loop device。
-cdrom
,指定iso镜像。
-m
:设置qemu虚拟机内存大小,默认单位MiB,默认128MiB,还可在此参数后面配置memory hotplug,暂略。
Optionally, a suffix of "M" or "G" can be used to signify a value in megabytes or gigabytes respectively.
-append
:设置kernel启动参数。console=ttyS0
,将启动期间所有打印重定向到串口,以方便查看,举例如下:
$ qemu-system-x86_64 -kernel bzImage_3rd \
> -initrd initrd_3rd.img \
> -m 1024 -append \
> 'bootenv=1 console=ttyS0'
Linux kernel会将自己不认识的启动参数,传递给init。默认kernel的打印都在vga上,无法向上翻!但串口可以。以上述方式启动kernel,跳过了grub阶段!
-nographic
:启动时没有guest window,qemu成为一个命令行程序
-vga std
:设置VGA为std类型
-smp
:设置cpu core number
-S
:Do not start CPU at startup (you must type 'c' in the monitor).
-s
:Shorthand for -gdb tcp::1234
, i.e. open a gdbserver on TCP port 1234.
-enable-kvm
,表示启动kvm虚拟机,这需要在BIOS中打开支持虚拟化的开关,这种模式下虚拟机运行速度更快
-vnc host:d
,开启VNC,端口号为5900+d,监听在host上(ip地址),开启其参数后,本地的显示就没有了。
-net none
,配置为不支持网络
-boot
,指定虚拟机启动顺序,具体细节见manpage。
-drive
$ sudo qemu-system-x86_64 -drive format=raw,file=helloOS.img
$ sudo ... -drive file=fat:rw:/path/to/esp,index=0,format=vvfat
Ctrl+Alt+g
:将鼠标从qemu虚拟机窗口中弹出来
Ctrl+Alt+f
:focus,去掉qemu窗口的周边,只留下中间部分,分辨率小的时候可以试试。
Ctrl-A, then x
:退出nographic启动的虚拟机
首先,需要创建一块硬盘文件,建议使用qcow2格式:
$ qemu-img create -f qcow2 win10.qcow2 40G
40G表示此文件的size上限,qcow2格式的文件,是动态增长的。
然后启动虚拟机:
$ qemu-system-x86_64 -enable-kvm -m 4G -smp 2 -hda win10.qcow2
记录一下这个过程遇到的问题,以及解决办法。
$ sudo apt install qemu-user
$ sudo apt install crossbuild-essential-riscv64
然后risc-v gnu toolchain就有了,省了自己下载编译,用ll /usr/bin/riscv64-*
查看交叉编译工具箱里的工具。
用C写一个hello world。交叉编译:
$ riscv64-linux-gnu-gcc -static test.c -o test_static
$ riscv64-linux-gnu-gcc test.c -o test -Wl,--dynamic-linker=/usr/riscv64-linux-gnu/lib/ld-linux-riscv64-lp64d.so.1
动态链接的时候,使用-Wl,--dynamic-linker
给ld传递参数,指定ld的版本。(应该叫runtime linker,这个细节很重要)
可执行的elf文件,在.interp section中,存放了runtime linker的路径:
$ riscv64-linux-gnu-readelf -p1 test
String dump of section '.interp':
[ 0] /usr/riscv64-linux-gnu/lib/ld-2.31.so
然后就可以运行了,两个版本都可以用qemu运行:
$ qemu-riscv64 test_static
$ qemu-riscv64 test
OVMF,Open Virutal Machine Firmware
,就是一个用于虚拟机启动的UEFI固件,来自EDK2项目。Qemu默认使用seaBios启动虚拟机,可以通过-bios
参数指定OVMF。
首先在系统中找到OVMF文件:
$ sudo find / -iname '*ovmf*.fd'
如果找不到,可以通过dnf或apt安装软件包得到。
$ sudo qemu-system-x86_64 -bios /usr/share/OVMF/OVMF_CODE.fd -net none ...
如果没有找到启动app,就会进入UEFI Shell(这是个很像Windows cmd的shell)。
用OVMF启动UEFI应用
$ sudo qemu-system-x86_64 -bios /usr/share/OVMF/OVMF_CODE.fd -net none \
-drive file=fat:rw:/path/to/esp,index=0,format=vvfat
QEMU有将目录挂载为虚拟FAT驱动器的功能。例如,创建一个名为esp的目录,将efi文件放到esp/EFI/BOOT/BOOTX64.EFI并使用-drive file=fat:rw:/path/to/esp,index=0,format=vvfat选项运行QEMU。虚拟机将会把esp目录当作是一个FAT分区,并会自动启动到其中的BOOTX64.EFI文件。
这是搭建完全虚拟化测试环境的方法,而且运行速度还飞快!
思路:用dd创建大文件,mkfs,然后mount到某个位置,将grub安装到这个位置。这个位置对应一个loop设备,用df -h可以查看。通过qemu的-hda参数指向此loop设备,启动grub。(UEFI亲测OK,BIOS要稍微复杂一些,此时不能仅用一个分区启动,必须要用大文件模拟整块硬盘)
坑:在编译grub/grub.cfg配置的文件的时候,发现此文件会莫名其妙的被修改成乱码,导致配置文件失效。在U盘上测试,也是这个效果。不明觉厉。。。后来发现,如果将U盘拿到其它电脑上去编辑此文件,再过来启动grub,就OK。如果在编辑了/dev/loop设备文件后,umount,再mount后使用,也OK!规避的策略:编辑完后umount,qemu直接使用image file启动!
本文链接:https://cs.pynote.net/sf/202201121/
-- EOF --
-- MORE --