arm / aarch64 上的 QEMU -M virt 是否可以有多个串行 TTY,例如 PL011 ttyAMA0 和 ttyAMA1?

Cir*_*lli 3 arm qemu linux-kernel

我正在玩 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
Run Code Online (Sandbox Code Playgroud)

是否可能,如果不可能,是否有特定的设计原因?

我使用的是 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 },
Run Code Online (Sandbox Code Playgroud)

我这样做是因为我想看看从不同的串行连接是否会使 KGDB 工作。在 x86_64 上我可以连接到ttyS0,但我认为值得在 ARM 上尝试一下。另请参阅:/sf/ask/1540323151/#44197715

小智 5

这是我在 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,
Run Code Online (Sandbox Code Playgroud)

配置和构建

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,
Run Code Online (Sandbox Code Playgroud)

跑步

./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
Run Code Online (Sandbox Code Playgroud)