computer_knowledge_notes/Software/_模拟器与容器/qemu.md

19 KiB
Raw Blame History

安装

mkdir build && cd build
../configure --target-list=riscv32-softmmu,riscv64-softmmu
sudo make install

ERROR: glib-2.22 gthread-2.0 is required to compile QEMU sudo apt install libglib2.0-dev ERROR: pixman >= 0.21.8 not present. sudo apt install libpixman-1-dev ERROR: Cannot find Ninja sudo apt install ninja-build ERROR: pkg-config binary 'pkg-config' not found sudo apt install pkg-config

名词解释

  • 前端qemu里运行的操作系统所能看到的设备。比如e1000网卡。
  • 后端宿主机所能看到的qemu上的设备。比如网络设备的后端user和tap等。

语法

qemu-system-riscv64 [options] [disk_image]

选项

标准选项
-accel	# 选择加速器的模型
-audiodev [driver=]driver,id=id[,prop[=value][,...]]
	# 添加一个音频后端driver其id为id。
	# 可用的prop有
	# id=identifier : 标识音频后端
	# timer-period=period : 设置音频子系统的计时器周期。默认10000(10ms)
-boot # 定义启动顺序
-cpu	# 选择CPU模型
	# 可用的CPU:
	# Haswell - Intel Core Processor (Haswell)
	# 可以被识别的CPUID:
	# smap - 
	# check - 
	# fsgsbase - 
-device <driver>[,prop[=value][,...]]
	# 添加设备。设备名为driverprop=value用于设置该设备的属性。一个有效的属性取决于该设备本身。
	# 使用"-device help"获取可用的设备名。使用"-device <drive>,help"获取某个设备的可用属性。
	# 可用的prop有
	## Controller/Bridge/Hub设备
	# usb-host:bus usb-bus
	## USB设备
	# qemu-xhci:bus PCI
	## 存储设备
	# virtio-9p-pci:bus PCI, "virtio-9p"的别名
	# virtio-blk-pic:bus PCI, 是"virtio-blk"的别名
	## 网络设备
	# e1000 : bus PCI,"e1000-82540em"的别名,desc "Intel Gigabit Ethernet"
	## 输入设备
	# isa-serial:bus ISA
	# usb-kbd:bus usb-bus
	# usb-mouse:bus usb-bus
	## 显示设备
	## 声音设备
	## Misc设备
	# ich9-intel-hda:bus PCI, desc "Intel HD Audio Controller (ich9)
	# intel-hda:bus PCI, desc "Intel HD Audio Controller (ich6)"
	# intel-iommu : bus系统desc "Intel IOMMU (VT-d) DMA Remapping device"
	# vhost-vsock-pci : bus PCI
	## CPU设备
	## 未分类的设备
-global driver.property=value
-global driver=driver, property=property, value=value
	# 对driver的property设置一个默认的value。此选项用于为自动生成的设备设置属性对于不是自动生成的设备应使用-device选项。
	# 对于q35设备需要设置"-global ICH9-LPC.disable_s3=1 -global ICH9-LPC.disable_s4=1"
	# 对于i440FX设备需要设置"-global PIIX4_PM.disable_s3=1 -global PIIX4_PM.disable_s4=1"
-k language
	# 指定键盘布局默认为en-us。
-M, -machine [type=]name[,prop[=value][,...]]
	# 选择要模拟的机器
	# q35 - alias of pc-q35-5.2
	# pc-q35-5.2 - Standard PC (Q35 + ICH9, 2009)
	# 可用的prop有
	# accel选择加速器支持的加速器有kvm,xen,hax,hvf,whpx或tcg。默认tcg
	# kernel_irqchip选择加速irq芯片的支持选项有on,off或split。默认off
	# vmport
	# kvm_shadow_mem
	# dump-guest-core
	# mem-merge
	# igd-passthru
	# aes-key-wrap
	# dea-key-wrap
	# suppress-vmdesc
	# nvdimm
	# enforce-config-section
	# memory-encryption
-m megs	# 指定内存大小为megs默认128M。
-name string1[,process=string2][,debug-threads=on|off]
	# 设置客户机的名称string1是窗口名string2是进程名
-smp n	# 设置CPU的个数为n默认为1。
-soundhw	# 使能并使用声卡。
-version	# 打印版本信息
块设备选项
-cdrom FILE	# 相当于 -drive file=FILE,index=2,media=cdrom
-blockdev	# 配置一个块设备的后端。
	## 对所有块驱动器都有效的选项
	## file的选项
	## raw的选项
	## qcow2的选项
	## 其它选项
-drive <option>[,option[,option[,...]]
	# 创建一个新的驱动器。相当于-blockdev和-device搭配使用的快捷写法。
	## -drive可以使用-blockdev的所有选项另外还可以使用如下选项
	# file=FILE	 指定磁盘镜像
	# if=		 指定drive要连接的接口类型可用类型有ide,scsi,sd,mtd,floppy,pflash,virtio,none
	# bus= ,unit=	 通过bus number和unit id指定连接位置
	# index=	 通过编号指定连接位置
	# media=	 指定媒介类型disk或cdrom
	# cyls=, heads=, secs= [,trans=]	
	# snapshot=	
	# cache=	
	# aio=	
	# format=<fmt>	指定磁盘格式,这样就不会再探测磁盘格式了。
	# serial=	
	# saddr=	
	# swerror=, rerror=	
	# scopy-on-read=	
	# sbps=, bps_rd=, bps_wr=	
	# sbps_max=, bps_rd_max=, bps_wr_max=	
	# siops=, iops_rd=, iops_wr=	
	# siops_max=, iops_rd_max=, iops_wr_max=	
	# siops_size=
	# sgroup=
-fsdev local,id=id,path=path,security_model=security_model
-fsdev proxy,id=id,socket=socket
-fsdev proxy,id=id,sock_fd=sock_fd
-fsdev synth,id=id
	# 定义一个新的文件系统设备
	# local对文件系统的访问是由QEMU完成的
	# proxy对文件系统的访问是由virtfs-proxy-helper完成的
	# synthSynthetic filesystem, only used by QTests. 
-fda	# 软盘
-fdb	# 软盘
-hda FILE	# 相当于 -drive file=FILE,index=0,media=disk
-hdb FILE	# 相当于 -drive file=FILE,index=1,media=disk
-hdc FILE	# 相当于 -drive file=FILE,index=2,media=disk
-hdd FILE	# 相当于 -drive file=FILE,index=3,media=disk
-hdachs
-mtdblock
-pflash
-sd
-snapshot
USB选项
-usb	# 使能USB驱动器(默认是不使用USB驱动器的)
-usbdevice # 已过时,应使用-device usb-...来代替
显示选项
-display spice-app
-display sdl
-display gtk[,grab_on_hover=on|off][,gl=on|off]
-display vnc=<display>
-display egl-headless
-display none
	# 选择display的后端类型默认为'-display gtk'
	# gtk的意思是在GTK窗口中显示视频输出。该接口提供了下拉菜单和其它UI元素来控制VM。
	# none的意思是不显示视频输出。它类似于-nographic选项的作用但不会重定向串口或并口的数据。
-full-screen	# 以全屏启动
-fnographic	# 禁用图形输出并将串行I/O重定向到控制台
-vga [cirrus|std|vmware|qxl|xenfb|tcx|cg3|virtio|none]
	# 选择显卡类型
	# cirrus指的是GD5446显卡。Windows系统从win95之后都能识别和使用此显卡。为qemu 2.2之前的默认显卡。
	# std是标准VGA显卡。为qemu 2.2之后的默认显卡。
	# none指的是没有显卡。
-vnc display[,options]	# 使用此选项可以让qemu把vga显示重定向到vnc显示<display>。
  host:d	# 只允许主机host通过端口d进行tcp连接。d是vnc端口实际的tcp端口一般是5900+d。host可以省略此时允许所有主机的连接。
i386 target only
-smbios file=binary
	# 从binary文件加载SMBIOS条目
-smbios type=0
	# 定义SMBIOS type 0字段
-smbios type=1
	# 定义SMBIOS type 1字段
-smbios type=2
	# 定义SMBIOS type 2字段
-smbios type=3
	# 定义SMBIOS type 3字段
-smbios type=4
	# 定义SMBIOS type 4字段
-smbios type=17
	# 定义SMBIOS type 17字段
网络选项
-nic [tap|user|...] [,...] [,mac=] [,model=]	# 此选项是一个快捷方式,用来一次性配置网络的前端和后端。网络的后端的选项和-netdev的选项是一样的。
-nic none	# 意味着不配置任何网络设备。它用来覆盖默认配置。默认配置是前端为默认网卡后端为user。当没有提供其它网络选项的时候会激活默认配置。
-netdev user,id=str[,...]	# 设置宿主网络为用户模式,这样就不需要超级用户的权限了。
  hostfwd=[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport
  	# 把主机端口hostport重定向到客户机端口guestport
-netdev tap,id=<str>[,...]	# 设置网络后端为TAP它的ID为str。
	fd=<h>			# 用以指定一个已经打开的TAP接口的句柄这个句柄为<h>。
	ifname=<name>	# 指定接口的名字为<name>。如不指定OS会自动分配一个。
	script=<file>	# 使用网络脚本<file>来配置此后端网络。默认配置脚本为/etc/qemu-ifup。如不使用配置脚本应写成"script=no"。
	downscript=<dfile>	# 使用网络脚本<dfile>来取消对此后端网络的配置。默认取消配置的脚本是/etc/qemu-ifdown。如不使用取消配置的脚本应写成"downscript=no"。
-netdev bridge,id=str[,...]
-netdev l2tpv3,id=str,...
-netdev socket,id=str[,...]	# 
-netdev vde,id=ID[,...]	# 配置VDE后端
-netdev vhost-user,id=str,...	# vhost-user网络设备
-netdev hubport,id=str,...	# 创建hub端口
-net nic[,...]	# 配置或创建网卡(即网络的前端)。古老的配置方式,建议用"-device"或"-nic"取代它。
-net [user|tap|bridge|socket][,...][,name=<name>]	 配置宿主机网络的后端(其选项和对应的-netdev选项是一样的并将其连接到虚拟hub0默认hub。name用来指定hub端口的名字。古老的配置方式建议用"-netdev"或"-nic"取代它。
字符设备选项
-chardev socket,id=id,path=path
蓝牙选项
-bt
TPM设备选项
-tpmdev
启动选项
-kernel		# 指定内核镜像
-append		# 指定内核启动参数
-initrd		# 指定initial ram disk
-dtb file	# 使用file作为设备树镜像
调试选项
-bios FILE	# 为BIOS指定文件
-enable-kvm	# 开启KVM虚拟化支持
-gdb dev	# 等待gdb来连接设备dev。
-monitor <dev>	# 把控制台重定向到宿主机的设备dev。图形模式下默认设备是"vc",非图形模式下默认设备是"stdio"。
-nodefaults	
	# 不要创建默认设备
-parallel DEV	# 将虚拟并口重定向到宿主机的设备DEV。
-serial DEV	# 将虚拟串口重定向到宿主机的字符设备DEV。图形模式下默认设备为vc非图形模式下默认设备为stdio。
	# chardev:id - 使用"-chardev"选项定义的字符设备。
	# none - 不使用串口
	# pty - 伪终端。(会自动分配一个新的TTY)
	# null - 丢弃所有串口输出
	# /dev/ttyS0 - 使用主机的ttyS0
	# file:/tmp/serial.out - 把串口输出写入文件。(无法读取字符)
	# stdio - 重定向到标准输入输出
	# pipe:/tmp/serial	- 重定向到管道,需手动创建/tmp/serial.in和/tmp/serial.out
	# udp::3333 - 重定向到udp使用nc -u -l -p 3333 可访问
	# tcp::3333,servr,nowait - 重定向到tcp使用telnet localhost 3333可访问
	# telnet::3333,server,nowait - 重定向到telnet访问方式同tcp
	# websocket:<host>:<port>,server[,nowait][,nodelay]
	# unix:/tmp/serial.sock,server,nowait - 重定向到socket用socat命令连接
	# mon:<dev> - 允许把监控器多路复用到其它串行端口。
	# vc[:WxH] - 虚拟控制台。W和H分别代表控制台的宽和高。
	# braille - braille设备。
	# msmouse - 三个按钮的串口鼠标。配置guest使用微软的协议。
-S			# 在刚开始的时候别启动CPU需要在管理器里输入“c”才会启动CPU
-s			# 相当于-gdb tcp::1234即在TCP端口1234开启一个gdbserver

QEMU monitor

QEMU的控制台。"Ctrl+Alt+2"进入控制台,"Ctrl+Alt+1"进入QEMU界面。也可用-monitor选项把控制台重定向到某个设备。

辅助类命令
info	# 显示虚拟机的运行信息
	info block [-v]	# 显示块设备的信息(-v显示详细信息)
	info blockstats	# 显示块设备的统计信息
	info chardev	# 显示字符设备的信息
	info cpus		# 显示所有cpu的信息
	info cpustats	# 显示cpu的统计信息
	info lapic		# 显示本地apic的状态
	info mem		# 显示虚拟内存映射
	info memdev		# 显示内存后端
	info memory-devices	# 显示内存设备
	info mtree		# 显示内存树
	info name		# 显示当前虚拟机的名字
	info network	# 显示网络状态
	info numa		# 显示numa的信息
	info pci		# 显示pci信息
	info pic		# 显示PIC的状态
	info profile	# 显示配置信息
	info qdm		# 显示qdev设备模型的列表
	info qom-tree	# 显示qom合成树
	info qtree		# 显示设备树
	info registers	# 显示cpu的寄存器
	info roms		# 显示所有的rom
	info status		# 显示当前虚拟机的状态(运行或暂停)
	info tlb		# 显示虚拟内存到物理内存的映射
help	# 查询某个命令的帮助信息
调试类命令
gdbserver	# 启动qemu内置的gdbserver
x		# 打印虚地址的值
xp		# 打印实地址的值
print	# 数学运算或引用某寄存器的值
sum		# 计算某个内存区域的校验和
memsave	# 内存转储
控制类命令
savevm	# 创建快照
loadvm	# 还原快照
delvm	# 删除快照
commit	# 将缓存中对块设备的操作,立即写到块设备上
system_reset	# 重启
system_powerdown	# 关机
stop/cont	# 进入/退出挂起状态
quit	# 退出qemu
设备类命令
change	# 更改虚拟机的配置
mouse_move	# 移动鼠标
mouse_button	# 按下鼠标左键
sendkey	# 键盘操作

qemu-system-x86_64

-cpu max	// cpu模型为max,意指开启加速器支持的所有特性
-device rtl8139,netdev=tapnet
		//添加设备rtl8139,tapnet是做为后台的netdev的ID
-display none	// 不显示视屏输出,注意它和-nographic的效果是不一样的。
-drive file=arch_disk,format=raw
		//定义一个新的驱动器本驱动使用的磁盘镜像是arch_disk,磁盘格式设为raw用来避免解释不可信的格式头
-kernel		// 指定内核镜像。
-m 1G		//使用1G内存
-M q35,accel=kvm:tcg,kernel-irqchip=split
	# 使用机器类型intel q35使用加速器kvm:tcg加速器的in-kernel irqchip支持为split。
	# Qemu支持的Intel机器类型仅有两种一个是i440FX一个是Q35。i440FX诞生于1996年是北桥芯片其对应的南桥芯片是PIIX。Q35是2007年推出的芯片组它即包括了北桥芯片(MCH),也包括了南桥芯片(ICH9)。Q35相较于i440FX的最大差异在于它支持PCIe。
-net nic	//创建一个新网卡默认是e1000。
-net user	//使用用户模式的网络栈,无需管理员权限。
-net tap,ifname=tap0,script=no,downscript=no
-netdev tap,id=tapnet,ifname=tap0,script=no,downscript=no
		//连接到主机的tap网络接口script和downscript设置为no使脚本文件失效
-object filter-dump,id=filter0,netdev=net0,file=o.x86_64/qemu.pcap
-S	// 在刚开始的时候不启动CPU
-s	// -gdb tcp::1234的缩写
-serial mon:stdio	// 创建多路复用的stdio后端其连接在串行端口和qemu管理器。
-smp cpus=1		// 模拟1个CPU的SMP系统

qemu-system-riscv

-machine 	// 选择要模拟的机器,可选机器如下
  none		# 空机器
  sifive_e		 # 满足SiFive E SDK的开发板
  sifive_u		 # 满足SiFive U SDK的开发板
  spike_v1.10	 # Spike开发板(priv 1.10)
  spikes_v1.9.1	 # Spike开发板(priv 1.9.1)
  virt		# VirtIO开发板(priv 1.10)
-devece	# 对于riscv来说可选设备如下
  # 存储设备
	virtio-blk-device使用virtio-bus总线
		driver=<str>:指定块设备的名称
  # 网络设备
	virtio-net-device:使用virtio-bus总线
  # 输入设备
  # 显示设备
	virtio-gpu-device:使用virtio-bus总线
  # 其它设备
  # 未分类的设备
	loader:desc "Generic Loader"
	virtio-rng-device:使用PCI总线
五种开发板的比较
  • spike_v1.9.1 - HTIF console, config-string

    实现的特权级版本为priv v1.9.1使用config-string将设备配置传递给BBL。

  • spike_v1.10 - HTIF console, device-tree

    实现的特权级版本为priv v1.10使用设备树将设备配置传递给BBL。

  • sifive_e - SiFive UART, HiFive1 compat

  • sifive_u - SiFive UART, device-tree

  • virt - 16550A UART, VirtIO, device-tree

    VirtIO板模拟了完整的计算机系统方便操作系统的开发。它实现了VirtIO MMIO传输支持VirtIO块设备和VirtIO网络设备还有16550a UART用于控制台访问。这样qemu原生的各种块设备和网络实现都可用了。

    通过查看hw/riscv/virt.c可以看到内存的布局可以看到外设的地址也可以看到DRAM是从0x80000000开始的。与virt板子相关的部分是从virt_machine_init开始的首先是注册PLIC中断然后注册系统内存然后创建设备树。

    # 查看virt machine的硬件配置信息
    sudo apt install device-tree-compiler
    qemu-system-riscv64 -M virt -M dumpdtb=riscv64-virt.dtb -bios default
    dtc -I dtb -O dts -o riscv64-virt.dts riscv64-virt.dtb
    view riscv64-virt.dts
    
设备树

描述RISC-V机器的配置。还可以包含非易失性存储的配置信息如控制台输出信息和启动参数。可以用-append选项来让设备树(如根设备和控制台)传递启动命令。

SiFive CLINT

CLINT是单个核心的局部中断控制器SiFive ClINT模块控制着与软件和计时器中断相关的内存映射和状态寄存器。兼容FE310G000 SOCthe SiFive Freedom-E-SDK and the SiFive Freedom-U-SDK。

SiFive PLIC

PLIC是平台级中断控制器。SiFive PLIC对全局中断进行优先级划分和分发。

qemu-img

语法
qemu-img [standard options] <command> [command options]	# 管理镜像
标准选项
-h, --help
-V, --version
-T, --trace
命令
amend
bench
check	# 对磁盘镜像文件进行一致性检查
commit
compare

# 转化镜像的格式
convert	[-f fmt] [-O output_fmt] <filename> <output_filename>

# 创建镜像文件
create [-f fmt] [-b backing_file] [-F backing_fmt] [-u] [-o options] <filename> [size]	

dd
info	# 查看镜像的信息
map
measure
snapshot	# 管理镜像的快照
rebase		# 在已有镜像的基础上创建新的镜像
# 改变镜像的大小
resize [--object ojbdef] [--image-opts] [-f fmt] [--preallocation=prealloc] [-q] [--shrink] <filename> [+|-]<size>
命令选项
filename	# 磁盘镜像的文件名
size	# 镜像的大小。默认单位为byte可带后缀K,M,G,T,P,E。
-b backing_file
-F backing_fmt	# 第二个镜像的格式。
-f fmt			# 第一个镜像的格式。大多数情况下都可以自动检测
-o options	# 格式的定义。是由逗号分割的键值对的列表。使用"-o ?"查看所有支持的键值对。
--object objectdef	# 对用户可创建对象的定义。详见qemu手册
output_filename
output_fmt
-q	# 静默模式。不打印任何输出。
-u	# 允许不安全的backing链。

# snapshot子命令

# compare子命令

# convert子命令

# dd子命令
镜像文件的格式
raw
qcow2
other:包括VMDK, VDI, VHD (vpc), VHDX, qcow1 and QED

参考资料

问题的解决

问题一

问题描述:安装好系统的镜像文件,启动的时候黑屏无反应。

解决方法:加上-enable-kvm选项

原因分析不开kvm硬件加速的情况下可能cpu执行慢或代码进入了某种死循环中。