virt默认不支持mmc设备,如果只是想引入一个sd/mmc设备,那直接在启动脚本里增加一个sdhci-pci,再在内核里新增sdhci-pci的驱动就可以了。
本篇记录的是,通过修改virt板代码,引入一个pl181(sdhci),从而引入sdcard的流程。
系列文章:
QEMU入门1:ubuntu22.04搭建QEMU运行环境
QEMU入门2:使用qemu简单的运行一个aarch64 linux内核
QEMU入门3:制作initrd、根文件系统
QEMU入门4:aarch64虚拟机安装grub
ubuntu22.04
qemu-8.1.5
本文所用内容已上传github,文章全部内容均在arco-qemu/arco-virt路径下
github仓库地址:https://github.com/ARCO-D/arco-qemu
设备实现(如果需要自己仿真设备
总线连接(将设备挂载到虚拟机
设备配置(内存映射、中断连接
设备树添加
qemu -device help
# 查看某个虚拟机支持的所有设备
qemu -device nvme,help
# 查看指定的某设备的配置
ctrl+a c
# 进入/退出 qemu monitor
ctrl+a h
# 查看所有的ctrl+a系列帮助(包括监视器
qemu -trace xx
# 跟踪xx的调用(-trace help列出可以trace的调用
info block
# 查看块设备
qom-list
# 查看对象(组织结构像目录
qom-get $path $name
# 查看对象属性, 例:
(qemu) qom-get /machine/unattached/device[7]/ card-inserted[0]
"/machine/unattached/device[4]/unnamed-gpio-in[4]"
sd-card:sd卡和emmc都是nand flash设备,因为qemu已经有了sd-card,所以仿真emmc设备可以通过sd-card来替代(/dev下都是mmcblk*
sd-bus:sd卡的电气总线,规定Vcc、Vss、CLK、命令线、数据线DAT0-3,是一种规范(就是sd卡槽的引脚
sdhci:主机上的sd控制器,通过访问这个控制器与sd卡通信(就像spi控制器那样的控制器
sdhci-pci:有时会使用 sd卡-sd读卡器-pci接口-主机 这样的连接方式,sdhci-pci就是实现sd读卡器-pci这一段路的控制器(cpld-spi-iic
pci:并行总线,pcie是它的串行升级版本
pl181:arm实现的一个公版sdhci控制器
在machvirt_init函数中添加 create_sdbus(vms, sysmem);
create_bus函数内容如下:
/* create_sdbus总线说明:
* mmin_map : 内存起始地址是0x40000000 + 0x40000000(1G), 为了不冲突就从0x80000000开始了
* connect_irq: a15irqmap里占用了1-9,16+ 所以这里选了没占用的10和11; 0和1是pl181设备里声明的两根中断线
* cd-inserted: 不需要像vexpress那样配qdev_connect_gpio_out_named, 配了反而不行
*/
static void create_sdbus(const VirtMachineState *vms, MemoryRegion *mem)
{
DeviceState *dev = qdev_new("pl181");
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x80000000);
// interrupt
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic, 10));
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, qdev_get_gpio_in(vms->gic, 11));
}
virt板中的设备是通过qemu_fdt函数生成的设备树节点,这里我们直接修改dts文件:
/*
regulator-name随便配, 但需要有这个供电mmc才能用
*/
vmmc_supply: regulator {
compatible = "regulator-fixed";
regulator-name = "3V3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
/*
interrupts需要配两个, 注意冲突
cd-gpios可以不配
时钟不配两个似乎也行
*/
mmc@80000000 {
compatible = "arm,pl181", "arm,primecell";
reg = <0x00 0x80000000 0x00 0x1000>;
interrupts = <0x00 0x0a 0x04>, <0x00 0x0b 0x04>;
clocks = <0x8000>;
clock-names = "apb_pclk";
bus-width = <4>;
max-frequency = <5000000>;
vmmc-supply = <&vmmc_supply>;
wp-gpios = <0x8007 6 0>;
cd-gpios = <0x8007 7 1>;
};
../build/qemu-system-aarch64 \
-nographic \
-M virt \
-cpu cortex-a55 \
-smp 4 \
-m 1G \
-dtb arco.dtb \
-kernel Image-6.6.57 \
-initrd initrd.cpio.gz \
-append "root=/dev/ram0 console=ttyAMA0 init=/linuxrc ignore_loglevel nokaslr" \
-drive file=arco.img,if=none,id=sdc,format=raw \
-device sd-card,drive=sdc,bus=sd-bus
arco-virt ~ # dmesg |grep mmc
[ 0.250995] mmci-pl18x 80000000.mmc: Got CD GPIO
[ 0.251170] mmci-pl18x 80000000.mmc: Got WP GPIO
[ 0.252818] mmci-pl18x 80000000.mmc: mmc0: PL181 manf 41 rev0 at 0x80000000 irq 20,21 (pio)
[ 0.290216] mmc0: new SD card at address 4567
[ 0.291567] mmcblk0: mmc0:4567 QEMU! 2.00 GiB
[ 0.297904] mmcblk0: p1 p2
输出类似信息,说明检测成功了
关于启动脚本里指定的console=ttyAMA0
这个和virt板的外设无关,是pl011默认使用的终端名,声明在内核的amba-pl011.c驱动里