저는 TTY를 가지고 놀고 있는데 qemu-system-x86_64 -M pc
해당 옵션을 전달할 때마다 Linux와 같은 일련 번호를 -serial
추가할 수 있는 새로운 TTY가 생성됩니다 .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
답변1
이것은 qemu 4.0.1의 virt 보드에 대한 다중 직렬 포트 지원 패치입니다(공식 git 커밋은 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
답변2
Peter는 현재 지원되지 않으며 그 이유를 명확히 했습니다.http://lists.nongnu.org/archive/html/qemu-discuss/2018-11/msg00001.html:
아니요, 가상 보드에는 UART가 하나만 있습니다(코드를 작성할 때 이유를 찾지 못했기 때문입니다). 우리는 이전에 두 번째 UART에 대한 요청을 받았습니다. 이를 추가할 때의 문제는 UEFI 부팅이 중단된다는 것입니다. dtb에 두 개의 UART가 있는 경우 Linux는 나열된 첫 번째 것을 사용하고 UEFI는 두 번째 것을 사용하므로 이전에 작동했던 명령줄이 작동을 멈춥니다.
이는 다음 방법 중 하나로 처리될 수 있습니다.
- -machine 옵션이 지정된 경우에만 두 번째 UART를 생성합니다.
- 전달된 직렬 옵션 수에 따라 요청 시 두 번째 UART를 생성합니다.
하지만 첫 번째는 투박하고 두 번째는 의도하지 않은 부작용(예: libvirt를 통해 QEMU 시작)이 나타날까 조금 걱정됩니다.
따라서 이 기능은 "희망 목록" 기능 목록에 포함됩니다. (필요한 실제 코드는 아마도 12줄 정도일 것이며 두 번째 UART를 생성할지 여부를 결정하는 최상의 메커니즘을 파악하는 것은 어렵습니다.)
답변3
또 다른 해결책은 합계가 options 에 의해 정의된 곳에 -device pci-serial-2x,chardev1=ttyS0,chardev2=ttyS1
옵션을 추가하는 것입니다. 이렇게 하면 제외됩니다.qemu-system-aarch64
ttyS0
ttyS1
-chardev
qemu-system-aarch64
/dev/ttyS0
/dev/ttyS1
/dev/ttyAMA0
답변4
~처럼치로 산틸리말하는,qemu-system-aarch64
직렬 포트는 하나만 있습니다: ttyAMA0
.
하지만 이보다 더 쉬운 방법이 있습니다qemu 패치, PCI 장치를 추가하여 더 많은 직렬 포트를 추가할 수 있습니다.
qemu-system-aarch64 \
-machine virt \
-cpu max \
-m 1024 \
-drive file=arch_aarch64.qcow2,format=qcow2 \
- -serial stdio \
+ -chardev stdio,mux=on,id=char0 \
+ -chardev socket,path=/tmp/qemu_socket.sock,server=on,wait=off,id=gnc0 \
+ -mon chardev=char0,mode=readline \
+ -serial chardev:char0 \
+ -device pci-serial,id=serial0,chardev=gnc0 \
-kernel "<path to linux directory>/arch/arm64/boot/Image.gz" \
- -append "root=/dev/vda2"
+ -append "root=/dev/vda2 console=ttyAMA0 kgdboc=ttyS0 kgdbwait"
이 차이점에서는 pci-serial
장치를 추가하고, 사용 가능한 직렬 포트를 구성하고( stdio
및 socket
), 사용할 직렬 포트를 커널에 알려줍니다( console=ttyAMA0 kgdboc=ttyS0
).
그런 다음 KGDB를 사용하려면 소켓에 연결하기만 하면 됩니다.
gdb ./vmlinux
(gdb) target remote /tmp/qemu_socket.sock
자세히 설명도 해드렸어요여기