Linux-Kernel
arm / aarch64 上的 QEMU -M virt 是否可以有多個串列 TTY,例如 PL011 ttyAMA0 和 ttyAMA1?
我在玩 TTY,對於
qemu-system-x86_64 -M pc
,每當我通過-serial
選項時,它都會創建一個新的 TTY,我可以從 Linux附加一個類似ttyS0
和的序列號。ttyS1
但是,對於 ARM,我無法超越第一個
ttyAMA0
. 如果我添加-serial
,它不會顯示,info qtree
核心啟動消息只會找到一個:9000000.pl011: ttyAMA0 at MMIO 0x9000000 (irq = 54, base_baud = 0) is a PL011 rev1
是否有可能,如果沒有,是否有特定的設計原因?
我在 QEMU v3.0.0 上。從源頭看來不可能:https ://github.com/qemu/qemu/blob/v3.0.0/hw/arm/virt.c#L138因為記憶體映射中只有一個UART:
[VIRT_GIC_REDIST] = { 0x080A0000, 0x00F60000 }, [VIRT_UART] = { 0x09000000, 0x00001000 }, [VIRT_RTC] = { 0x09010000, 0x00001000 },
我這樣做是因為我想看看從不同的串列連接是否會使 KGDB 工作。在 x86_64 上我可以連接到
ttyS0
,但我認為值得在 ARM 上嘗試一下。另請參閱:https ://stackoverflow.com/questions/22004616/how-to-debug-the-linux-kernel-with-qemu-and-kgdb/44197715#44197715
這是我在 qemu 4.0.1 中對 virt board 的多串口支持更新檔(官方 git commit 是 f9bec78),請享受它:-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index bf9c0bc..bdc7094 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -474,11 +474,11 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) } static void -build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) +build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms, int uart) { AcpiSerialPortConsoleRedirection *spcr; - const MemMapEntry *uart_memmap = &vms->memmap[VIRT_UART]; - int irq = vms->irqmap[VIRT_UART] + ARM_SPI_BASE; + const MemMapEntry *uart_memmap = &vms->memmap[uart]; + int irq = vms->irqmap[uart] + ARM_SPI_BASE; int spcr_start = table_data->len; spcr = acpi_data_push(table_data, sizeof(*spcr)); @@ -741,8 +741,14 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) */ scope = aml_scope("\\_SB"); acpi_dsdt_add_cpus(scope, vms->smp_cpus); - acpi_dsdt_add_uart(scope, &memmap[VIRT_UART], - (irqmap[VIRT_UART] + ARM_SPI_BASE)); + acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], + (irqmap[VIRT_UART0] + ARM_SPI_BASE)); + acpi_dsdt_add_uart(scope, &memmap[VIRT_UART1], + (irqmap[VIRT_UART1] + ARM_SPI_BASE)); + acpi_dsdt_add_uart(scope, &memmap[VIRT_UART2], + (irqmap[VIRT_UART2] + ARM_SPI_BASE)); + acpi_dsdt_add_uart(scope, &memmap[VIRT_UART3], + (irqmap[VIRT_UART3] + ARM_SPI_BASE)); acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); acpi_dsdt_add_fw_cfg(scope, &memmap[VIRT_FW_CFG]); acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO], @@ -806,7 +812,16 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) build_mcfg(tables_blob, tables->linker, vms); acpi_add_table(table_offsets, tables_blob); - build_spcr(tables_blob, tables->linker, vms); + build_spcr(tables_blob, tables->linker, vms, VIRT_UART0); + + acpi_add_table(table_offsets, tables_blob); + build_spcr(tables_blob, tables->linker, vms, VIRT_UART1); + + acpi_add_table(table_offsets, tables_blob); + build_spcr(tables_blob, tables->linker, vms, VIRT_UART2); + + acpi_add_table(table_offsets, tables_blob); + build_spcr(tables_blob, tables->linker, vms, VIRT_UART3); if (nb_numa_nodes > 0) { acpi_add_table(table_offsets, tables_blob); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index ce2664a..e3006c6 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -125,12 +125,15 @@ static const MemMapEntry base_memmap[] = { [VIRT_GIC_ITS] = { 0x08080000, 0x00020000 }, /* This redistributor space allows up to 2*64kB*123 CPUs */ [VIRT_GIC_REDIST] = { 0x080A0000, 0x00F60000 }, - [VIRT_UART] = { 0x09000000, 0x00001000 }, + [VIRT_UART0] = { 0x09000000, 0x00001000 }, [VIRT_RTC] = { 0x09010000, 0x00001000 }, [VIRT_FW_CFG] = { 0x09020000, 0x00000018 }, [VIRT_GPIO] = { 0x09030000, 0x00001000 }, [VIRT_SECURE_UART] = { 0x09040000, 0x00001000 }, [VIRT_SMMU] = { 0x09050000, 0x00020000 }, + [VIRT_UART1] = { 0x09080000, 0x00001000 }, + [VIRT_UART2] = { 0x09090000, 0x00001000 }, + [VIRT_UART3] = { 0x090a0000, 0x00001000 }, [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ [VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 }, @@ -161,11 +164,14 @@ static MemMapEntry extended_memmap[] = { }; static const int a15irqmap[] = { - [VIRT_UART] = 1, + [VIRT_UART0] = 1, [VIRT_RTC] = 2, [VIRT_PCIE] = 3, /* ... to 6 */ [VIRT_GPIO] = 7, [VIRT_SECURE_UART] = 8, + [VIRT_UART1] = 9, + [VIRT_UART2] = 10, + [VIRT_UART3] = 11, [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */ [VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */ [VIRT_SMMU] = 74, /* ...to 74 + NUM_SMMU_IRQS - 1 */ @@ -684,11 +690,16 @@ static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart, hwaddr base = vms->memmap[uart].base; hwaddr size = vms->memmap[uart].size; int irq = vms->irqmap[uart]; + + if(chr == NULL) + return; + const char compat[] = "arm,pl011\0arm,primecell"; const char clocknames[] = "uartclk\0apb_pclk"; + DeviceState *dev = qdev_create(NULL, "pl011"); SysBusDevice *s = SYS_BUS_DEVICE(dev); - + qdev_prop_set_chr(dev, "chardev", chr); qdev_init_nofail(dev); memory_region_add_subregion(mem, base, @@ -710,9 +721,9 @@ static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart, qemu_fdt_setprop(vms->fdt, nodename, "clock-names", clocknames, sizeof(clocknames)); - if (uart == VIRT_UART) { + if (uart == VIRT_UART0) { qemu_fdt_setprop_string(vms->fdt, "/chosen", "stdout-path", nodename); - } else { + } else if ((uart != VIRT_UART1) && (uart != VIRT_UART2) && (uart != VIRT_UART3)) { /* Mark as not usable by the normal world */ qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled"); qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay"); @@ -1616,11 +1627,14 @@ static void machvirt_init(MachineState *machine) fdt_add_pmu_nodes(vms); - create_uart(vms, pic, VIRT_UART, sysmem, serial_hd(0)); + create_uart(vms, pic, VIRT_UART0, sysmem, serial_hd(0)); + create_uart(vms, pic, VIRT_UART1, sysmem, serial_hd(1)); + create_uart(vms, pic, VIRT_UART2, sysmem, serial_hd(2)); + create_uart(vms, pic, VIRT_UART3, sysmem, serial_hd(3)); if (vms->secure) { create_secure_ram(vms, secure_sysmem); - create_uart(vms, pic, VIRT_SECURE_UART, secure_sysmem, serial_hd(1)); + create_uart(vms, pic, VIRT_SECURE_UART, secure_sysmem, serial_hd(4)); } vms->highmem_ecam &= vms->highmem && (!firmware_loaded || aarch64); diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index 507517c..5f6228f 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -65,7 +65,10 @@ enum { VIRT_GIC_ITS, VIRT_GIC_REDIST, VIRT_SMMU, - VIRT_UART, + VIRT_UART0, + VIRT_UART1, + VIRT_UART2, + VIRT_UART3, VIRT_MMIO, VIRT_RTC, VIRT_FW_CFG,
配置和建構
./configure --enable-kvm --enable-sdl --enable-debug --enable-debug-stack-usage --target-list=aarch64-softmmu,arm-softmmu,x86_64-softmmu,i386-softmmu make && make install
跑
qemu-system-aarch64 \ -cpu cortex-a57 \ -smp 16 \ -m 1G \ -machine virt,gic-version=3,virtualization=on \ -nographic \ -net nic,model=virtio,macaddr=fa:16:3e:4d:58:6f \ -net tap,ifname=tap-jh,script=vm-ifup,downscript=vm-ifdown \ -append "root=/dev/vda mem=768M console=ttyAMA0" \ -kernel arm64-vmlinux.img \ -initrd arm64-initrd.img \ -drive file=arm64-rootfs.img,format=raw,id=disk,if=none \ -device virtio-blk-device,drive=disk \ -monitor tcp::45459,server,nowait \ -serial tcp::45458,server,nowait \ -serial tcp::45457,server,nowait \ -serial tcp::45456,server,nowait \ -serial chardev:s0 -chardev stdio,id=s0,mux=on,logfile=qemu-s0.log,signal=off