diff --git a/ARM-KVM-Check-KVM_CAP_ARM_IRQ_LINE_LAYOUT_2-for-smp_.patch b/ARM-KVM-Check-KVM_CAP_ARM_IRQ_LINE_LAYOUT_2-for-smp.patch similarity index 69% rename from ARM-KVM-Check-KVM_CAP_ARM_IRQ_LINE_LAYOUT_2-for-smp_.patch rename to ARM-KVM-Check-KVM_CAP_ARM_IRQ_LINE_LAYOUT_2-for-smp.patch index 5727a1d482a732c900701024507156a0f999bf40..3012512988402756527c95341aa921a362c9e43e 100644 --- a/ARM-KVM-Check-KVM_CAP_ARM_IRQ_LINE_LAYOUT_2-for-smp_.patch +++ b/ARM-KVM-Check-KVM_CAP_ARM_IRQ_LINE_LAYOUT_2-for-smp.patch @@ -1,8 +1,11 @@ -From f3c1fc4dce1582ccc1754899d5149d233e8629ff Mon Sep 17 00:00:00 2001 -From: Eric Auger -Date: Thu, 3 Oct 2019 17:46:40 +0200 -Subject: [PATCH 3/3] ARM: KVM: Check KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 for - smp_cpus > 256 +From e3a7ec839fa4f823666d726989c375dcf73348a4 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 15 Apr 2020 16:14:50 +0800 +Subject: [PATCH] ARM: KVM: Check KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 for smp_cpus > + 256 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit Host kernel within [4.18, 5.3] report an erroneous KVM_MAX_VCPUS=512 for ARM. The actual capability to instantiate more than 256 vcpus @@ -21,29 +24,30 @@ Message-id: 20191003154640.22451-4-eric.auger@redhat.com Signed-off-by: Peter Maydell (cherry-picked from commit fff9f5558d0e0813d4f80bfe1602acf225eca4fd) [yu: Use the legacy smp_cpus instead of ms->smp.cpus, as we don't have - struct CpuTopology in MachineState at that time. See commit - edeeec911702 for details.] + ¦struct CpuTopology in MachineState at that time. See commit + ¦edeeec911702 for details.] Signed-off-by: Zenghui Yu --- - target/arm/kvm.c | 10 +++++++++- - 1 file changed, 9 insertions(+), 1 deletion(-) + target/arm/kvm.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/target/arm/kvm.c b/target/arm/kvm.c -index f60185ad..383423c4 100644 +index 50e86f8b..cc7a46df 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c -@@ -174,6 +174,7 @@ int kvm_arm_get_max_vm_ipa_size(MachineState *ms) - +@@ -173,6 +173,8 @@ int kvm_arm_get_max_vm_ipa_size(MachineState *ms) + int kvm_arch_init(MachineState *ms, KVMState *s) { + int ret = 0; ++ unsigned int smp_cpus = ms->smp.cpus; /* For ARM interrupt delivery is always asynchronous, * whether we are using an in-kernel VGIC or not. */ -@@ -187,7 +188,14 @@ int kvm_arch_init(MachineState *ms, KVMState *s) - +@@ -186,7 +188,14 @@ int kvm_arch_init(MachineState *ms, KVMState *s) + cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE); - + - return 0; + if (smp_cpus > 256 && + !kvm_check_extension(s, KVM_CAP_ARM_IRQ_LINE_LAYOUT_2)) { @@ -54,8 +58,7 @@ index f60185ad..383423c4 100644 + + return ret; } - - unsigned long kvm_arch_vcpu_id(CPUState *cpu) --- -2.19.1 + unsigned long kvm_arch_vcpu_id(CPUState *cpu) +-- +2.23.0 diff --git a/ARM64-record-vtimer-tick-when-cpu-is-stopped.patch b/ARM64-record-vtimer-tick-when-cpu-is-stopped.patch index b2ad176f8d56fdc71b6663f36bad7cc93ed4429a..4681e9f33f6877f199768b7a06a65df5356e6a7f 100644 --- a/ARM64-record-vtimer-tick-when-cpu-is-stopped.patch +++ b/ARM64-record-vtimer-tick-when-cpu-is-stopped.patch @@ -1,6 +1,6 @@ -From d2fd6d1a5200b9a58863839d21d291cd4f76ac31 Mon Sep 17 00:00:00 2001 +From 4646a24045cf53f2cc5e0ef1974da88ef50ef676 Mon Sep 17 00:00:00 2001 From: Ying Fang -Date: Mon, 29 Jul 2019 15:47:27 +0800 +Date: Wed, 27 May 2020 11:54:31 +0800 Subject: [PATCH] ARM64: record vtimer tick when cpu is stopped The vtimer kick still increases even if the vcpu is stopped when VM has @@ -17,10 +17,10 @@ Signed-off-by: Ying Fang 3 files changed, 61 insertions(+) diff --git a/cpus.c b/cpus.c -index e83f72b4..f6ec48a2 100644 +index 927a00aa..b9aa51f8 100644 --- a/cpus.c +++ b/cpus.c -@@ -1063,6 +1063,28 @@ void cpu_synchronize_all_pre_loadvm(void) +@@ -1066,6 +1066,28 @@ void cpu_synchronize_all_pre_loadvm(void) } } @@ -49,7 +49,7 @@ index e83f72b4..f6ec48a2 100644 static int do_vm_stop(RunState state, bool send_stop) { int ret = 0; -@@ -1070,6 +1092,11 @@ static int do_vm_stop(RunState state, bool send_stop) +@@ -1073,6 +1095,11 @@ static int do_vm_stop(RunState state, bool send_stop) if (runstate_is_running()) { cpu_disable_ticks(); pause_all_vcpus(); @@ -61,7 +61,7 @@ index e83f72b4..f6ec48a2 100644 runstate_set(state); vm_state_notify(0, state); if (send_stop) { -@@ -1909,11 +1936,42 @@ void cpu_resume(CPUState *cpu) +@@ -1918,11 +1945,42 @@ void cpu_resume(CPUState *cpu) qemu_cpu_kick(cpu); } @@ -105,23 +105,23 @@ index e83f72b4..f6ec48a2 100644 cpu_resume(cpu); } diff --git a/target/arm/cpu.h b/target/arm/cpu.h -index d4d28369..e107e395 100644 +index 86eb79cd..aec6a214 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h -@@ -270,6 +270,8 @@ typedef struct CPUARMState { - uint64_t elr_el[4]; /* AArch64 exception link regs */ +@@ -262,6 +262,8 @@ typedef struct CPUARMState { uint64_t sp_el[4]; /* AArch64 banked stack pointers */ + + uint64_t vtimer; /* Timer tick when vcpu stop */ + /* System control coprocessor (cp15) */ struct { uint32_t c0_cpuid; diff --git a/target/arm/machine.c b/target/arm/machine.c -index b2925496..d64a0057 100644 +index ee3c59a6..ec28b839 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c -@@ -792,6 +792,7 @@ const VMStateDescription vmstate_arm_cpu = { +@@ -814,6 +814,7 @@ const VMStateDescription vmstate_arm_cpu = { VMSTATE_UINT32(env.exception.syndrome, ARMCPU), VMSTATE_UINT32(env.exception.fsr, ARMCPU), VMSTATE_UINT64(env.exception.vaddress, ARMCPU), diff --git a/Revert-ide-ahci-Check-for-ECANCELED-in-aio-callbacks.patch b/Revert-ide-ahci-Check-for-ECANCELED-in-aio-callbacks.patch new file mode 100644 index 0000000000000000000000000000000000000000..200e0b2df02607b11e3117863afd00a346419e27 --- /dev/null +++ b/Revert-ide-ahci-Check-for-ECANCELED-in-aio-callbacks.patch @@ -0,0 +1,88 @@ +From 73a5bf472921068e6db10e7e325b7ac46f111834 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 29 Jul 2019 18:36:05 -0400 +Subject: [PATCH] Revert "ide/ahci: Check for -ECANCELED in aio callbacks" + +This reverts commit 0d910cfeaf2076b116b4517166d5deb0fea76394. + +It's not correct to just ignore an error code in a callback; we need to +handle that error and possible report failure to the guest so that they +don't wait indefinitely for an operation that will now never finish. + +This ought to help cases reported by Nutanix where iSCSI returns a +legitimate -ECANCELED for certain operations which should be propagated +normally. + +Reported-by: Shaju Abraham +Signed-off-by: John Snow +Message-id: 20190729223605.7163-1-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 8ec41c4265714255d5a138f8b538faf3583dcff6) +Signed-off-by: Michael Roth +--- + hw/ide/ahci.c | 3 --- + hw/ide/core.c | 14 -------------- + 2 files changed, 17 deletions(-) + +diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c +index 00ba422a48..6aaf66534a 100644 +--- a/hw/ide/ahci.c ++++ b/hw/ide/ahci.c +@@ -1023,9 +1023,6 @@ static void ncq_cb(void *opaque, int ret) + IDEState *ide_state = &ncq_tfs->drive->port.ifs[0]; + + ncq_tfs->aiocb = NULL; +- if (ret == -ECANCELED) { +- return; +- } + + if (ret < 0) { + bool is_read = ncq_tfs->cmd == READ_FPDMA_QUEUED; +diff --git a/hw/ide/core.c b/hw/ide/core.c +index 6afadf894f..8e1624f7ce 100644 +--- a/hw/ide/core.c ++++ b/hw/ide/core.c +@@ -722,9 +722,6 @@ static void ide_sector_read_cb(void *opaque, int ret) + s->pio_aiocb = NULL; + s->status &= ~BUSY_STAT; + +- if (ret == -ECANCELED) { +- return; +- } + if (ret != 0) { + if (ide_handle_rw_error(s, -ret, IDE_RETRY_PIO | + IDE_RETRY_READ)) { +@@ -840,10 +837,6 @@ static void ide_dma_cb(void *opaque, int ret) + uint64_t offset; + bool stay_active = false; + +- if (ret == -ECANCELED) { +- return; +- } +- + if (ret == -EINVAL) { + ide_dma_error(s); + return; +@@ -975,10 +968,6 @@ static void ide_sector_write_cb(void *opaque, int ret) + IDEState *s = opaque; + int n; + +- if (ret == -ECANCELED) { +- return; +- } +- + s->pio_aiocb = NULL; + s->status &= ~BUSY_STAT; + +@@ -1058,9 +1047,6 @@ static void ide_flush_cb(void *opaque, int ret) + + s->pio_aiocb = NULL; + +- if (ret == -ECANCELED) { +- return; +- } + if (ret < 0) { + /* XXX: What sector number to set here? */ + if (ide_handle_rw_error(s, -ret, IDE_RETRY_FLUSH)) { +-- +2.23.0 diff --git a/Revert-vtimer-compat-cross-version-migration-from-v4.patch b/Revert-vtimer-compat-cross-version-migration-from-v4.patch new file mode 100644 index 0000000000000000000000000000000000000000..082f1763f9b445ba3816e2051c47129a6c64528a --- /dev/null +++ b/Revert-vtimer-compat-cross-version-migration-from-v4.patch @@ -0,0 +1,37 @@ +From ced290d644a00e18e70046194d042bcaa2703b65 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 27 May 2020 11:16:53 +0800 +Subject: [PATCH] Revert: "vtimer: compat cross version migration from v4.0.1" + +This reverts commit patch: +vtimer-compat-cross-version-migration-from-v4.0.1.patch + +Signed-off-by: Ying Fang + +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 2609113d..86eb79cd 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -261,7 +261,6 @@ typedef struct CPUARMState { + uint64_t elr_el[4]; /* AArch64 exception link regs */ + uint64_t sp_el[4]; /* AArch64 banked stack pointers */ + +- uint64_t vtimer; /* Timer tick when vcpu is stopped */ + + /* System control coprocessor (cp15) */ + struct { +diff --git a/target/arm/machine.c b/target/arm/machine.c +index ec28b839..ee3c59a6 100644 +--- a/target/arm/machine.c ++++ b/target/arm/machine.c +@@ -814,7 +814,6 @@ const VMStateDescription vmstate_arm_cpu = { + VMSTATE_UINT32(env.exception.syndrome, ARMCPU), + VMSTATE_UINT32(env.exception.fsr, ARMCPU), + VMSTATE_UINT64(env.exception.vaddress, ARMCPU), +- VMSTATE_UINT64(env.vtimer, ARMCPU), + VMSTATE_TIMER_PTR(gt_timer[GTIMER_PHYS], ARMCPU), + VMSTATE_TIMER_PTR(gt_timer[GTIMER_VIRT], ARMCPU), + { +-- +2.23.0 + diff --git a/Typo-Correct-the-name-of-CPU-hotplug-memory-region.patch b/Typo-Correct-the-name-of-CPU-hotplug-memory-region.patch new file mode 100644 index 0000000000000000000000000000000000000000..bc1fd44d163beb57f08c3b58918d305772b0c362 --- /dev/null +++ b/Typo-Correct-the-name-of-CPU-hotplug-memory-region.patch @@ -0,0 +1,27 @@ +From 843f593280b93e03bb7b0d0001da7488d61f13f6 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Mon, 6 Apr 2020 08:55:17 +0800 +Subject: [PATCH] Typo: Correct the name of CPU hotplug memory region + +Replace "acpi-mem-hotplug" with "acpi-cpu-hotplug" + +Signed-off-by: Keqian Zhu +--- + hw/acpi/cpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c +index 7a90c8f82d..0c0bfe479a 100644 +--- a/hw/acpi/cpu.c ++++ b/hw/acpi/cpu.c +@@ -203,7 +203,7 @@ void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner, + state->devs[i].arch_id = id_list->cpus[i].arch_id; + } + memory_region_init_io(&state->ctrl_reg, owner, &cpu_hotplug_ops, state, +- "acpi-mem-hotplug", ACPI_CPU_HOTPLUG_REG_LEN); ++ "acpi-cpu-hotplug", ACPI_CPU_HOTPLUG_REG_LEN); + memory_region_add_subregion(as, base_addr, &state->ctrl_reg); + } + +-- +2.19.1 diff --git a/accel-kvm-Add-pre-park-vCPU-support.patch b/accel-kvm-Add-pre-park-vCPU-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..9bc81178581c30504ca1b32d1f47ba8cbc1a5b85 --- /dev/null +++ b/accel-kvm-Add-pre-park-vCPU-support.patch @@ -0,0 +1,63 @@ +From 135119d2e82e99adc67346572c761fbe54d73e4a Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Fri, 10 Apr 2020 13:04:40 +0800 +Subject: [PATCH] accel/kvm: Add pre-park vCPU support + +For that KVM do not support dynamic adjustment of vCPU count, +we must pre-park all possible vCPU at start. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + accel/kvm/kvm-all.c | 23 +++++++++++++++++++++++ + include/sysemu/kvm.h | 1 + + 2 files changed, 24 insertions(+) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index f450f25295..84edbe8bb1 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -339,6 +339,29 @@ err: + return ret; + } + ++int kvm_create_parked_vcpu(unsigned long vcpu_id) ++{ ++ KVMState *s = kvm_state; ++ struct KVMParkedVcpu *vcpu = NULL; ++ int ret; ++ ++ DPRINTF("kvm_create_parked_vcpu\n"); ++ ++ ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id); ++ if (ret < 0) { ++ DPRINTF("kvm_create_vcpu failed\n"); ++ goto err; ++ } ++ ++ vcpu = g_malloc0(sizeof(*vcpu)); ++ vcpu->vcpu_id = vcpu_id; ++ vcpu->kvm_fd = ret; ++ QLIST_INSERT_HEAD(&s->kvm_parked_vcpus, vcpu, node); ++ ++err: ++ return ret; ++} ++ + static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id) + { + struct KVMParkedVcpu *cpu; +diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h +index acd90aebb6..565adb4e2c 100644 +--- a/include/sysemu/kvm.h ++++ b/include/sysemu/kvm.h +@@ -216,6 +216,7 @@ int kvm_has_many_ioeventfds(void); + int kvm_has_gsi_routing(void); + int kvm_has_intx_set_mask(void); + ++int kvm_create_parked_vcpu(unsigned long vcpu_id); + int kvm_init_vcpu(CPUState *cpu); + int kvm_cpu_exec(CPUState *cpu); + int kvm_destroy_vcpu(CPUState *cpu); +-- +2.19.1 diff --git a/acpi-cpu-Prepare-build_cpus_aml-for-arm-virt.patch b/acpi-cpu-Prepare-build_cpus_aml-for-arm-virt.patch new file mode 100644 index 0000000000000000000000000000000000000000..0506d1b73c1586699dd0fe92254baa5d0af26a7b --- /dev/null +++ b/acpi-cpu-Prepare-build_cpus_aml-for-arm-virt.patch @@ -0,0 +1,128 @@ +From 107c267ebe5b8c461268a4ff8384ad2f2b9e8ce0 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Wed, 22 Apr 2020 16:11:13 +0800 +Subject: [PATCH] acpi/cpu: Prepare build_cpus_aml for arm virt + +We will reuse build_cpus_aml to build DSDT cpus aml in arm/virt +ACPI to realize cpu hotplug. Three points are added. + +1. Make ACPI IO address space configurable, because ARM64 platforms + don't use port IO for ACPI IO space. +2. Add GICC struct building support in _MAT of cpu aml. +3. Let the hotplug method parameter can be NULL, because ACPI GED + will realize it. + +Besides, CPU CPPC building is injected. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/acpi/cpu.c | 32 +++++++++++++++++++++++++------- + hw/i386/acpi-build.c | 2 +- + include/hw/acpi/cpu.h | 3 ++- + 3 files changed, 28 insertions(+), 9 deletions(-) + +diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c +index 0c0bfe479a..72ad1fcff2 100644 +--- a/hw/acpi/cpu.c ++++ b/hw/acpi/cpu.c +@@ -314,7 +314,8 @@ const VMStateDescription vmstate_cpu_hotplug = { + void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, + hwaddr io_base, + const char *res_root, +- const char *event_handler_method) ++ const char *event_handler_method, ++ AmlRegionSpace rs) + { + Aml *ifctx; + Aml *field; +@@ -342,13 +343,18 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, + aml_append(cpu_ctrl_dev, aml_mutex(CPU_LOCK, 0)); + + crs = aml_resource_template(); +- aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1, +- ACPI_CPU_HOTPLUG_REG_LEN)); ++ if (rs == AML_SYSTEM_IO) { ++ aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1, ++ ACPI_CPU_HOTPLUG_REG_LEN)); ++ } else { ++ aml_append(crs, aml_memory32_fixed(io_base, ++ ACPI_CPU_HOTPLUG_REG_LEN, AML_READ_WRITE)); ++ } + aml_append(cpu_ctrl_dev, aml_name_decl("_CRS", crs)); + + /* declare CPU hotplug MMIO region with related access fields */ + aml_append(cpu_ctrl_dev, +- aml_operation_region("PRST", AML_SYSTEM_IO, aml_int(io_base), ++ aml_operation_region("PRST", rs, aml_int(io_base), + ACPI_CPU_HOTPLUG_REG_LEN)); + + field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK, +@@ -517,6 +523,11 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, + aml_append(dev, aml_name_decl("_UID", uid)); + } + ++ assert(adevc); ++ if (adevc->cpu_cppc) { ++ adevc->cpu_cppc(adev, i, arch_ids->len, dev); ++ } ++ + method = aml_method("_STA", 0, AML_SERIALIZED); + aml_append(method, aml_return(aml_call1(CPU_STS_METHOD, uid))); + aml_append(dev, method); +@@ -535,6 +546,11 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, + apic->flags = cpu_to_le32(1); + break; + } ++ case ACPI_APIC_GENERIC_CPU_INTERFACE: { ++ AcpiMadtGenericCpuInterface *gicc = (void *)madt_buf->data; ++ gicc->flags = cpu_to_le32(1); ++ break; ++ } + default: + assert(0); + } +@@ -570,9 +586,11 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, + aml_append(sb_scope, cpus_dev); + aml_append(table, sb_scope); + +- method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED); +- aml_append(method, aml_call0("\\_SB.CPUS." CPU_SCAN_METHOD)); +- aml_append(table, method); ++ if (event_handler_method) { ++ method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED); ++ aml_append(method, aml_call0("\\_SB.CPUS." CPU_SCAN_METHOD)); ++ aml_append(table, method); ++ } + + g_free(cphp_res_path); + } +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index 749218561a..c97731ecb3 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -1869,7 +1869,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, + .acpi_1_compatible = true, .has_legacy_cphp = true + }; + build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base, +- "\\_SB.PCI0", "\\_GPE._E02"); ++ "\\_SB.PCI0", "\\_GPE._E02", AML_SYSTEM_IO); + } + + if (pcms->memhp_io_base && nr_mem) { +diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h +index 62f0278ba2..a30ec84a4f 100644 +--- a/include/hw/acpi/cpu.h ++++ b/include/hw/acpi/cpu.h +@@ -55,7 +55,8 @@ typedef struct CPUHotplugFeatures { + void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, + hwaddr io_base, + const char *res_root, +- const char *event_handler_method); ++ const char *event_handler_method, ++ AmlRegionSpace rs); + + void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list); + +-- +2.19.1 diff --git a/acpi-ged-Add-virt_madt_cpu_entry-to-madt_cpu-hook.patch b/acpi-ged-Add-virt_madt_cpu_entry-to-madt_cpu-hook.patch new file mode 100644 index 0000000000000000000000000000000000000000..f4e0a25c050e7948c1c7e1e2e0721c0b43d27fcc --- /dev/null +++ b/acpi-ged-Add-virt_madt_cpu_entry-to-madt_cpu-hook.patch @@ -0,0 +1,41 @@ +From 3cd6df0b9e7d7b544673ce9a63b405e236d8265b Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Fri, 10 Apr 2020 10:05:54 +0800 +Subject: [PATCH] acpi/ged: Add virt_madt_cpu_entry to madt_cpu hook + +In build_cpus_aml, we will invoke this hook to build _MAT +aml mehtod for cpus. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/acpi/generic_event_device.c | 1 + + include/hw/acpi/generic_event_device.h | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c +index 9cee90cc70..b834ae3ff6 100644 +--- a/hw/acpi/generic_event_device.c ++++ b/hw/acpi/generic_event_device.c +@@ -288,6 +288,7 @@ static void acpi_ged_class_init(ObjectClass *class, void *data) + hc->plug = acpi_ged_device_plug_cb; + + adevc->send_event = acpi_ged_send_event; ++ adevc->madt_cpu = virt_madt_cpu_entry; + } + + static const TypeInfo acpi_ged_info = { +diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h +index d157eac088..f99efad7a3 100644 +--- a/include/hw/acpi/generic_event_device.h ++++ b/include/hw/acpi/generic_event_device.h +@@ -61,6 +61,7 @@ + + #include "hw/sysbus.h" + #include "hw/acpi/memory_hotplug.h" ++#include "hw/arm/virt.h" + + #define ACPI_POWER_BUTTON_DEVICE "PWRB" + +-- +2.19.1 diff --git a/acpi-ged-Extend-ACPI-GED-to-support-CPU-hotplug.patch b/acpi-ged-Extend-ACPI-GED-to-support-CPU-hotplug.patch new file mode 100644 index 0000000000000000000000000000000000000000..57247e6797da5a977685f737e9454427ab2c41df --- /dev/null +++ b/acpi-ged-Extend-ACPI-GED-to-support-CPU-hotplug.patch @@ -0,0 +1,204 @@ +From 05d22b55133db1a2526cfe305102e075e883b5e2 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Fri, 3 Apr 2020 15:41:01 +0800 +Subject: [PATCH] acpi/ged: Extend ACPI GED to support CPU hotplug + +This adds a new GED event called ACPI_GED_CPU_HOTPLUG_EVT. +The basic workflow is that: GED sends this event to guest, +then ACPI driver in guest will call _EVT method of GED aml, +then _EVT will call CSCN method in cpus aml to get status of +all cpus. + +The status of cpus is maintained by CPUHotplugState in GED and +is made accessable to guest through memory region. + +This also adds migration support to CPUHotplugState. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + docs/specs/acpi_hw_reduced_hotplug.rst | 3 ++- + hw/acpi/cpu.c | 1 - + hw/acpi/generic_event_device.c | 35 ++++++++++++++++++++++++++ + hw/arm/Kconfig | 1 + + include/hw/acpi/cpu.h | 2 ++ + include/hw/acpi/generic_event_device.h | 4 +++ + 6 files changed, 44 insertions(+), 2 deletions(-) + +diff --git a/docs/specs/acpi_hw_reduced_hotplug.rst b/docs/specs/acpi_hw_reduced_hotplug.rst +index 911a98255b..deb481555d 100644 +--- a/docs/specs/acpi_hw_reduced_hotplug.rst ++++ b/docs/specs/acpi_hw_reduced_hotplug.rst +@@ -63,7 +63,8 @@ GED IO interface (4 byte access) + bits: + 0: Memory hotplug event + 1: System power down event +- 2-31: Reserved ++ 2: CPU hotplug event ++ 3-31: Reserved + + **write_access:** + +diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c +index 72ad1fcff2..cb6bb67f3c 100644 +--- a/hw/acpi/cpu.c ++++ b/hw/acpi/cpu.c +@@ -6,7 +6,6 @@ + #include "trace.h" + #include "sysemu/numa.h" + +-#define ACPI_CPU_HOTPLUG_REG_LEN 12 + #define ACPI_CPU_SELECTOR_OFFSET_WR 0 + #define ACPI_CPU_FLAGS_OFFSET_RW 4 + #define ACPI_CPU_CMD_OFFSET_WR 5 +diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c +index 82139b4314..478a4ee87c 100644 +--- a/hw/acpi/generic_event_device.c ++++ b/hw/acpi/generic_event_device.c +@@ -23,6 +23,7 @@ + static const uint32_t ged_supported_events[] = { + ACPI_GED_MEM_HOTPLUG_EVT, + ACPI_GED_PWR_DOWN_EVT, ++ ACPI_GED_CPU_HOTPLUG_EVT, + }; + + /* +@@ -110,6 +111,9 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev, + aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE), + aml_int(0x80))); + break; ++ case ACPI_GED_CPU_HOTPLUG_EVT: ++ aml_append(if_ctx, aml_call0("\\_SB.CPUS.CSCN")); ++ break; + default: + /* + * Please make sure all the events in ged_supported_events[] +@@ -176,6 +180,8 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev, + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp); + } else { + error_setg(errp, "virt: device plug request for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); +@@ -192,6 +198,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) + sel = ACPI_GED_MEM_HOTPLUG_EVT; + } else if (ev & ACPI_POWER_DOWN_STATUS) { + sel = ACPI_GED_PWR_DOWN_EVT; ++ } else if (ev & ACPI_CPU_HOTPLUG_STATUS) { ++ sel = ACPI_GED_CPU_HOTPLUG_EVT; + } else { + /* Unknown event. Return without generating interrupt. */ + warn_report("GED: Unsupported event %d. No irq injected", ev); +@@ -224,6 +232,16 @@ static const VMStateDescription vmstate_memhp_state = { + } + }; + ++static const VMStateDescription vmstate_cpuhp_state = { ++ .name = "acpi-ged/cpuhp", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField[]) { ++ VMSTATE_CPU_HOTPLUG(cpuhp_state, AcpiGedState), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ + static const VMStateDescription vmstate_ged_state = { + .name = "acpi-ged-state", + .version_id = 1, +@@ -244,6 +262,7 @@ static const VMStateDescription vmstate_acpi_ged = { + }, + .subsections = (const VMStateDescription * []) { + &vmstate_memhp_state, ++ &vmstate_cpuhp_state, + NULL + } + }; +@@ -254,6 +273,7 @@ static void acpi_ged_initfn(Object *obj) + AcpiGedState *s = ACPI_GED(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + GEDState *ged_st = &s->ged_state; ++ MachineClass *mc; + + memory_region_init_io(&ged_st->io, obj, &ged_ops, ged_st, + TYPE_ACPI_GED, ACPI_GED_EVT_SEL_LEN); +@@ -273,6 +293,21 @@ static void acpi_ged_initfn(Object *obj) + sysbus_init_mmio(sbd, &s->container_memhp); + acpi_memory_hotplug_init(&s->container_memhp, OBJECT(dev), + &s->memhp_state, 0); ++ ++ mc = MACHINE_GET_CLASS(qdev_get_machine()); ++ if (!mc->possible_cpu_arch_ids) { ++ /* ++ * MachineClass should support possible_cpu_arch_ids in ++ * cpu_hotplug_hw_init below. ++ */ ++ return; ++ } ++ ++ memory_region_init(&s->container_cpuhp, OBJECT(dev), "cpuhp container", ++ ACPI_CPU_HOTPLUG_REG_LEN); ++ sysbus_init_mmio(sbd, &s->container_cpuhp); ++ cpu_hotplug_hw_init(&s->container_cpuhp, OBJECT(dev), ++ &s->cpuhp_state, 0); + } + + static void acpi_ged_class_init(ObjectClass *class, void *data) +diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig +index ad7f7c089b..15e18b0a48 100644 +--- a/hw/arm/Kconfig ++++ b/hw/arm/Kconfig +@@ -24,6 +24,7 @@ config ARM_VIRT + select DIMM + select ACPI_MEMORY_HOTPLUG + select ACPI_HW_REDUCED ++ select ACPI_CPU_HOTPLUG + + config CHEETAH + bool +diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h +index a30ec84a4f..e726414459 100644 +--- a/include/hw/acpi/cpu.h ++++ b/include/hw/acpi/cpu.h +@@ -17,6 +17,8 @@ + #include "hw/acpi/aml-build.h" + #include "hw/hotplug.h" + ++#define ACPI_CPU_HOTPLUG_REG_LEN 12 ++ + typedef struct AcpiCpuStatus { + struct CPUState *cpu; + uint64_t arch_id; +diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h +index f99efad7a3..e702ff1e18 100644 +--- a/include/hw/acpi/generic_event_device.h ++++ b/include/hw/acpi/generic_event_device.h +@@ -62,6 +62,7 @@ + #include "hw/sysbus.h" + #include "hw/acpi/memory_hotplug.h" + #include "hw/arm/virt.h" ++#include "hw/acpi/cpu.h" + + #define ACPI_POWER_BUTTON_DEVICE "PWRB" + +@@ -83,6 +84,7 @@ + */ + #define ACPI_GED_MEM_HOTPLUG_EVT 0x1 + #define ACPI_GED_PWR_DOWN_EVT 0x2 ++#define ACPI_GED_CPU_HOTPLUG_EVT 0x4 + + typedef struct GEDState { + MemoryRegion io; +@@ -93,6 +95,8 @@ typedef struct AcpiGedState { + SysBusDevice parent_obj; + MemHotplugState memhp_state; + MemoryRegion container_memhp; ++ CPUHotplugState cpuhp_state; ++ MemoryRegion container_cpuhp; + GEDState ged_state; + uint32_t ged_event_bitmap; + qemu_irq irq; +-- +2.19.1 diff --git a/acpi-madt-Add-pre-sizing-capability-to-MADT-GICC-str.patch b/acpi-madt-Add-pre-sizing-capability-to-MADT-GICC-str.patch new file mode 100644 index 0000000000000000000000000000000000000000..30f210b33b66332cc0c16b5d2ddb706a177a2130 --- /dev/null +++ b/acpi-madt-Add-pre-sizing-capability-to-MADT-GICC-str.patch @@ -0,0 +1,95 @@ +From 0288d98f0ef4d17a73cf2bad1b928cd7c044e318 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Fri, 10 Apr 2020 13:40:44 +0800 +Subject: [PATCH] acpi/madt: Add pre-sizing capability to MADT GICC struct + +The count of possible CPUs is exposed to guest through the count +of MADT GICC struct, so we should pre-sizing MADT GICC too. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt-acpi-build.c | 26 +++++++++++++++++++++----- + include/hw/acpi/acpi-defs.h | 1 + + 2 files changed, 22 insertions(+), 5 deletions(-) + +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index dbe9acb148..efac788ba1 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -678,6 +678,13 @@ void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid, + const MemMapEntry *memmap = vms->memmap; + AcpiMadtGenericCpuInterface *gicc = acpi_data_push(entry, sizeof(*gicc)); + ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(uid)); ++ static bool pmu; ++ ++ if (uid == 0) { ++ pmu = arm_feature(&armcpu->env, ARM_FEATURE_PMU); ++ } ++ /* FEATURE_PMU should be all enabled or disabled for CPUs */ ++ assert(!armcpu || arm_feature(&armcpu->env, ARM_FEATURE_PMU) == pmu); + + gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE; + gicc->length = sizeof(*gicc); +@@ -687,11 +694,15 @@ void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid, + gicc->gicv_base_address = cpu_to_le64(memmap[VIRT_GIC_VCPU].base); + } + gicc->cpu_interface_number = cpu_to_le32(uid); +- gicc->arm_mpidr = cpu_to_le64(armcpu->mp_affinity); ++ gicc->arm_mpidr = possible_cpus->cpus[uid].arch_id; + gicc->uid = cpu_to_le32(uid); +- gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED); ++ if (armcpu) { ++ gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED); ++ } else { ++ gicc->flags = cpu_to_le32(ACPI_MADT_GICC_DISABLED); ++ } + +- if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { ++ if (pmu) { + gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ)); + } + if (vms->virt) { +@@ -704,12 +715,17 @@ static void + build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + { + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); ++ MachineClass *mc = MACHINE_GET_CLASS(vms); ++ MachineState *ms = MACHINE(vms); ++ const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); + int madt_start = table_data->len; + const MemMapEntry *memmap = vms->memmap; + const int *irqmap = vms->irqmap; + AcpiMultipleApicTable *madt; + AcpiMadtGenericDistributor *gicd; + AcpiMadtGenericMsiFrame *gic_msi; ++ /* The MADT GICC numbers */ ++ int num_cpu = vms->smp_cpus; + int i; + + madt = acpi_data_push(table_data, sizeof *madt); +@@ -720,8 +736,8 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + gicd->base_address = cpu_to_le64(memmap[VIRT_GIC_DIST].base); + gicd->version = vms->gic_version; + +- for (i = 0; i < vms->smp_cpus; i++) { +- virt_madt_cpu_entry(NULL, i, NULL, table_data); ++ for (i = 0; i < num_cpu; i++) { ++ virt_madt_cpu_entry(NULL, i, possible_cpus, table_data); + } + + if (vms->gic_version == 3) { +diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h +index 39ae91d3b8..6bfa7f9152 100644 +--- a/include/hw/acpi/acpi-defs.h ++++ b/include/hw/acpi/acpi-defs.h +@@ -306,6 +306,7 @@ typedef struct AcpiMadtGenericCpuInterface AcpiMadtGenericCpuInterface; + + /* GICC CPU Interface Flags */ + #define ACPI_MADT_GICC_ENABLED 1 ++#define ACPI_MADT_GICC_DISABLED 0 + + struct AcpiMadtGenericDistributor { + ACPI_SUB_HEADER_DEF +-- +2.19.1 diff --git a/acpi-madt-Factor-out-the-building-of-MADT-GICC-struc.patch b/acpi-madt-Factor-out-the-building-of-MADT-GICC-struc.patch new file mode 100644 index 0000000000000000000000000000000000000000..6bda35c51a3952121a155081bf0a37ce3534da25 --- /dev/null +++ b/acpi-madt-Factor-out-the-building-of-MADT-GICC-struc.patch @@ -0,0 +1,108 @@ +From a3097eed8b642dc6fe891112340821e869b90cc2 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Mon, 13 Jan 2020 19:02:20 +0800 +Subject: [PATCH] acpi/madt: Factor out the building of MADT GICC struct + +To realize CPU hotplug, the cpus aml within ACPI DSDT should contain +_MAT mathod, which is equal to the GICC struct in ACPI MADT. Factor +out the GICC building code from ACPI MADT and reuse it in build_cpus_aml. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt-acpi-build.c | 51 +++++++++++++++++++++++----------------- + include/hw/arm/virt.h | 3 +++ + 2 files changed, 32 insertions(+), 22 deletions(-) + +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index f48733d9f2..4b6aace433 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -664,6 +664,34 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + table_data->len - gtdt_start, 2, NULL, NULL); + } + ++void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid, ++ const CPUArchIdList *possible_cpus, GArray *entry) ++{ ++ VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine()); ++ const MemMapEntry *memmap = vms->memmap; ++ AcpiMadtGenericCpuInterface *gicc = acpi_data_push(entry, sizeof(*gicc)); ++ ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(uid)); ++ ++ gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE; ++ gicc->length = sizeof(*gicc); ++ if (vms->gic_version == 2) { ++ gicc->base_address = cpu_to_le64(memmap[VIRT_GIC_CPU].base); ++ gicc->gich_base_address = cpu_to_le64(memmap[VIRT_GIC_HYP].base); ++ gicc->gicv_base_address = cpu_to_le64(memmap[VIRT_GIC_VCPU].base); ++ } ++ gicc->cpu_interface_number = cpu_to_le32(uid); ++ gicc->arm_mpidr = cpu_to_le64(armcpu->mp_affinity); ++ gicc->uid = cpu_to_le32(uid); ++ gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED); ++ ++ if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { ++ gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ)); ++ } ++ if (vms->virt) { ++ gicc->vgic_interrupt = cpu_to_le32(PPI(ARCH_GIC_MAINT_IRQ)); ++ } ++} ++ + /* MADT */ + static void + build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) +@@ -686,28 +714,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + gicd->version = vms->gic_version; + + for (i = 0; i < vms->smp_cpus; i++) { +- AcpiMadtGenericCpuInterface *gicc = acpi_data_push(table_data, +- sizeof(*gicc)); +- ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i)); +- +- gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE; +- gicc->length = sizeof(*gicc); +- if (vms->gic_version == 2) { +- gicc->base_address = cpu_to_le64(memmap[VIRT_GIC_CPU].base); +- gicc->gich_base_address = cpu_to_le64(memmap[VIRT_GIC_HYP].base); +- gicc->gicv_base_address = cpu_to_le64(memmap[VIRT_GIC_VCPU].base); +- } +- gicc->cpu_interface_number = cpu_to_le32(i); +- gicc->arm_mpidr = cpu_to_le64(armcpu->mp_affinity); +- gicc->uid = cpu_to_le32(i); +- gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED); +- +- if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { +- gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ)); +- } +- if (vms->virt) { +- gicc->vgic_interrupt = cpu_to_le32(PPI(ARCH_GIC_MAINT_IRQ)); +- } ++ virt_madt_cpu_entry(NULL, i, NULL, table_data); + } + + if (vms->gic_version == 3) { +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index 3dfefca93b..6b1f10b231 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -37,6 +37,7 @@ + #include "hw/block/flash.h" + #include "sysemu/kvm.h" + #include "hw/intc/arm_gicv3_common.h" ++#include "hw/acpi/acpi_dev_interface.h" + + #define NUM_GICV2M_SPIS 64 + #define NUM_VIRTIO_TRANSPORTS 32 +@@ -154,6 +155,8 @@ typedef struct { + OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE) + + void virt_acpi_setup(VirtMachineState *vms); ++void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid, ++ const CPUArchIdList *cpu_list, GArray *entry); + + /* Return the number of used redistributor regions */ + static inline int virt_gicv3_redist_region_count(VirtMachineState *vms) +-- +2.19.1 diff --git a/aio-wait-delegate-polling-of-main-AioContext-if-BQL-not-held.patch b/aio-wait-delegate-polling-of-main-AioContext-if-BQL-not-held.patch new file mode 100644 index 0000000000000000000000000000000000000000..7926e7fa0db4ef16737a89782ea661273ef8c4d3 --- /dev/null +++ b/aio-wait-delegate-polling-of-main-AioContext-if-BQL-not-held.patch @@ -0,0 +1,116 @@ +From 929d29ec7bf9dd6ec3802bea2148a041ff30d59b Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Tue, 14 Apr 2020 21:17:09 +0800 +Subject: [PATCH] aio-wait: delegate polling of main AioContext if BQL not held + +Any thread that is not a iothread returns NULL for qemu_get_current_aio_context(). +As a result, it would also return true for +in_aio_context_home_thread(qemu_get_aio_context()), causing +AIO_WAIT_WHILE to invoke aio_poll() directly. This is incorrect +if the BQL is not held, because aio_poll() does not expect to +run concurrently from multiple threads, and it can actually +happen when savevm writes to the vmstate file from the +migration thread. + +Therefore, restrict in_aio_context_home_thread to return true +for the main AioContext only if the BQL is held. + +The function is moved to aio-wait.h because it is mostly used +there and to avoid a circular reference between main-loop.h +and block/aio.h. + +Signed-off-by: Paolo Bonzini +Message-Id: <20200407140746.8041-5-pbonzini@redhat.com> +Signed-off-by: Stefan Hajnoczi +--- + include/block/aio-wait.h | 22 ++++++++++++++++++++++ + include/block/aio.h | 29 ++++++++++------------------- + 2 files changed, 32 insertions(+), 19 deletions(-) + +diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h +index afeeb18f..716d2639 100644 +--- a/include/block/aio-wait.h ++++ b/include/block/aio-wait.h +@@ -26,6 +26,7 @@ + #define QEMU_AIO_WAIT_H + + #include "block/aio.h" ++#include "qemu/main-loop.h" + + /** + * AioWait: +@@ -124,4 +125,25 @@ void aio_wait_kick(void); + */ + void aio_wait_bh_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque); + ++/** ++ * in_aio_context_home_thread: ++ * @ctx: the aio context ++ * ++ * Return whether we are running in the thread that normally runs @ctx. Note ++ * that acquiring/releasing ctx does not affect the outcome, each AioContext ++ * still only has one home thread that is responsible for running it. ++ */ ++static inline bool in_aio_context_home_thread(AioContext *ctx) ++{ ++ if (ctx == qemu_get_current_aio_context()) { ++ return true; ++ } ++ ++ if (ctx == qemu_get_aio_context()) { ++ return qemu_mutex_iothread_locked(); ++ } else { ++ return false; ++ } ++} ++ + #endif /* QEMU_AIO_WAIT_H */ +diff --git a/include/block/aio.h b/include/block/aio.h +index 6b0d52f7..9d28e247 100644 +--- a/include/block/aio.h ++++ b/include/block/aio.h +@@ -60,12 +60,16 @@ struct AioContext { + QLIST_HEAD(, AioHandler) aio_handlers; + + /* Used to avoid unnecessary event_notifier_set calls in aio_notify; +- * accessed with atomic primitives. If this field is 0, everything +- * (file descriptors, bottom halves, timers) will be re-evaluated +- * before the next blocking poll(), thus the event_notifier_set call +- * can be skipped. If it is non-zero, you may need to wake up a +- * concurrent aio_poll or the glib main event loop, making +- * event_notifier_set necessary. ++ * only written from the AioContext home thread, or under the BQL in ++ * the case of the main AioContext. However, it is read from any ++ * thread so it is still accessed with atomic primitives. ++ * ++ * If this field is 0, everything (file descriptors, bottom halves, ++ * timers) will be re-evaluated before the next blocking poll() or ++ * io_uring wait; therefore, the event_notifier_set call can be ++ * skipped. If it is non-zero, you may need to wake up a concurrent ++ * aio_poll or the glib main event loop, making event_notifier_set ++ * necessary. + * + * Bit 0 is reserved for GSource usage of the AioContext, and is 1 + * between a call to aio_ctx_prepare and the next call to aio_ctx_check. +@@ -580,19 +584,6 @@ void aio_co_enter(AioContext *ctx, struct Coroutine *co); + */ + AioContext *qemu_get_current_aio_context(void); + +-/** +- * in_aio_context_home_thread: +- * @ctx: the aio context +- * +- * Return whether we are running in the thread that normally runs @ctx. Note +- * that acquiring/releasing ctx does not affect the outcome, each AioContext +- * still only has one home thread that is responsible for running it. +- */ +-static inline bool in_aio_context_home_thread(AioContext *ctx) +-{ +- return ctx == qemu_get_current_aio_context(); +-} +- + /** + * aio_context_setup: + * @ctx: the aio context +-- +2.23.0 diff --git a/arm-cpu-assign-arm_get_arch_id-handler-to-get_arch_i.patch b/arm-cpu-assign-arm_get_arch_id-handler-to-get_arch_i.patch new file mode 100644 index 0000000000000000000000000000000000000000..84903c34d5a86cac12aadf7d35271295b49f143d --- /dev/null +++ b/arm-cpu-assign-arm_get_arch_id-handler-to-get_arch_i.patch @@ -0,0 +1,42 @@ +From d8e0b51447d8c64788cd7f9b0fa75c4ccb06f8eb Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Fri, 10 Apr 2020 10:17:27 +0800 +Subject: [PATCH] arm/cpu: assign arm_get_arch_id handler to get_arch_id hook + +This hook will be called in get_cpu_status, which is called +during cpu hotplug. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + target/arm/cpu.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 39bbe7e2d7..1ccb30e5eb 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -2575,6 +2575,13 @@ static gchar *arm_gdb_arch_name(CPUState *cs) + return g_strdup("arm"); + } + ++static int64_t arm_cpu_get_arch_id(CPUState *cs) ++{ ++ ARMCPU *cpu = ARM_CPU(cs); ++ ++ return cpu->mp_affinity; ++} ++ + static void arm_cpu_class_init(ObjectClass *oc, void *data) + { + ARMCPUClass *acc = ARM_CPU_CLASS(oc); +@@ -2596,6 +2603,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) + cc->synchronize_from_tb = arm_cpu_synchronize_from_tb; + cc->gdb_read_register = arm_cpu_gdb_read_register; + cc->gdb_write_register = arm_cpu_gdb_write_register; ++ cc->get_arch_id = arm_cpu_get_arch_id; + #ifndef CONFIG_USER_ONLY + cc->do_interrupt = arm_cpu_do_interrupt; + cc->get_phys_page_attrs_debug = arm_cpu_get_phys_page_attrs_debug; +-- +2.19.1 diff --git a/arm-virt-Add-CPU-hotplug-framework.patch b/arm-virt-Add-CPU-hotplug-framework.patch new file mode 100644 index 0000000000000000000000000000000000000000..5de672afeab55fe5af5da3d2ce58aa2e9ae1435d --- /dev/null +++ b/arm-virt-Add-CPU-hotplug-framework.patch @@ -0,0 +1,66 @@ +From 6d287b3f1d961cc4adda1c6a452f41db84466f5a Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Fri, 3 Apr 2020 16:16:18 +0800 +Subject: [PATCH] arm/virt: Add CPU hotplug framework + +Establish the CPU hotplug framework for arm/virt, we will add +necessary code legs to this framework gradually to realize CPU +hotplug finally. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index d09a5773df..0bd37af26c 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2077,11 +2077,25 @@ out: + error_propagate(errp, local_err); + } + ++static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ /* Currently nothing to do */ ++} ++ ++static void virt_cpu_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ /* Currently nothing to do */ ++} ++ + static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + virt_memory_pre_plug(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ virt_cpu_pre_plug(hotplug_dev, dev, errp); + } + } + +@@ -2098,6 +2112,8 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev, + } + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + virt_memory_plug(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ virt_cpu_plug(hotplug_dev, dev, errp); + } + } + +@@ -2112,7 +2128,8 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine, + DeviceState *dev) + { + if (object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE) || +- (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM))) { ++ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) || ++ object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + return HOTPLUG_HANDLER(machine); + } + +-- +2.19.1 diff --git a/arm-virt-Add-CPU-topology-support.patch b/arm-virt-Add-CPU-topology-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..c7813c637449328c5fecf7575d27a06fa1fa0700 --- /dev/null +++ b/arm-virt-Add-CPU-topology-support.patch @@ -0,0 +1,219 @@ +From cde57fcae2ed16a10e1ef7f2da0ec368883988ba Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Mon, 6 Apr 2020 10:54:35 +0800 +Subject: [PATCH] arm/virt: Add CPU topology support + +The CPU topology specified by user (through -smp options) is used in +ACPI PPTT. Now we will use this information to locate which CPU to +plug or unplug. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt.c | 68 +++++++++++++++++++++++++++++++++++++-- + include/hw/arm/topology.h | 61 +++++++++++++++++++++++++++++++++++ + target/arm/cpu.c | 3 ++ + target/arm/cpu.h | 3 ++ + 4 files changed, 133 insertions(+), 2 deletions(-) + create mode 100644 include/hw/arm/topology.h + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 0bd37af26c..64532b61b2 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -36,6 +36,7 @@ + #include "hw/sysbus.h" + #include "hw/arm/boot.h" + #include "hw/arm/primecell.h" ++#include "hw/arm/topology.h" + #include "hw/arm/virt.h" + #include "hw/block/flash.h" + #include "hw/vfio/vfio-calxeda-xgmac.h" +@@ -2020,6 +2021,7 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) + int n; + unsigned int max_cpus = ms->smp.max_cpus; + VirtMachineState *vms = VIRT_MACHINE(ms); ++ ARMCPUTopoInfo topo; + + if (ms->possible_cpus) { + assert(ms->possible_cpus->len == max_cpus); +@@ -2031,10 +2033,17 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) + ms->possible_cpus->len = max_cpus; + for (n = 0; n < ms->possible_cpus->len; n++) { + ms->possible_cpus->cpus[n].type = ms->cpu_type; ++ ms->possible_cpus->cpus[n].vcpus_count = 1; + ms->possible_cpus->cpus[n].arch_id = + virt_cpu_mp_affinity(vms, n); ++ ++ topo_ids_from_idx(n, ms->smp.cores, ms->smp.threads, &topo); ++ ms->possible_cpus->cpus[n].props.has_socket_id = true; ++ ms->possible_cpus->cpus[n].props.socket_id = topo.pkg_id; ++ ms->possible_cpus->cpus[n].props.has_core_id = true; ++ ms->possible_cpus->cpus[n].props.core_id = topo.core_id; + ms->possible_cpus->cpus[n].props.has_thread_id = true; +- ms->possible_cpus->cpus[n].props.thread_id = n; ++ ms->possible_cpus->cpus[n].props.thread_id = topo.smt_id; + } + return ms->possible_cpus; + } +@@ -2080,7 +2089,62 @@ out: + static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- /* Currently nothing to do */ ++ CPUState *cs = CPU(dev); ++ ARMCPUTopoInfo topo; ++ ARMCPU *cpu = ARM_CPU(dev); ++ MachineState *ms = MACHINE(hotplug_dev); ++ int smp_cores = ms->smp.cores; ++ int smp_threads = ms->smp.threads; ++ ++ /* if cpu idx is not set, set it based on socket/core/thread properties */ ++ if (cs->cpu_index == UNASSIGNED_CPU_INDEX) { ++ int max_socket = ms->smp.max_cpus / smp_threads / smp_cores; ++ if (cpu->socket_id < 0 || cpu->socket_id >= max_socket) { ++ error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u", ++ cpu->socket_id, max_socket - 1); ++ return; ++ } ++ if (cpu->core_id < 0 || cpu->core_id >= smp_cores) { ++ error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u", ++ cpu->core_id, smp_cores - 1); ++ return; ++ } ++ if (cpu->thread_id < 0 || cpu->thread_id >= smp_threads) { ++ error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u", ++ cpu->thread_id, smp_threads - 1); ++ return; ++ } ++ ++ topo.pkg_id = cpu->socket_id; ++ topo.core_id = cpu->core_id; ++ topo.smt_id = cpu->thread_id; ++ cs->cpu_index = idx_from_topo_ids(smp_cores, smp_threads, &topo); ++ } ++ ++ /* if 'address' properties socket-id/core-id/thread-id are not set, set them ++ * so that machine_query_hotpluggable_cpus would show correct values ++ */ ++ topo_ids_from_idx(cs->cpu_index, smp_cores, smp_threads, &topo); ++ if (cpu->socket_id != -1 && cpu->socket_id != topo.pkg_id) { ++ error_setg(errp, "property socket-id: %u doesn't match set idx:" ++ " 0x%x (socket-id: %u)", cpu->socket_id, cs->cpu_index, topo.pkg_id); ++ return; ++ } ++ cpu->socket_id = topo.pkg_id; ++ ++ if (cpu->core_id != -1 && cpu->core_id != topo.core_id) { ++ error_setg(errp, "property core-id: %u doesn't match set idx:" ++ " 0x%x (core-id: %u)", cpu->core_id, cs->cpu_index, topo.core_id); ++ return; ++ } ++ cpu->core_id = topo.core_id; ++ ++ if (cpu->thread_id != -1 && cpu->thread_id != topo.smt_id) { ++ error_setg(errp, "property thread-id: %u doesn't match set idx:" ++ " 0x%x (thread-id: %u)", cpu->thread_id, cs->cpu_index, topo.smt_id); ++ return; ++ } ++ cpu->thread_id = topo.smt_id; + } + + static void virt_cpu_plug(HotplugHandler *hotplug_dev, +diff --git a/include/hw/arm/topology.h b/include/hw/arm/topology.h +new file mode 100644 +index 0000000000..a3e5f436c5 +--- /dev/null ++++ b/include/hw/arm/topology.h +@@ -0,0 +1,61 @@ ++/* ++ * ARM CPU topology data structures and functions ++ * ++ * Copyright (c) 2020 HUAWEI TECHNOLOGIES CO.,LTD. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, see . ++ */ ++ ++#ifndef HW_ARM_TOPOLOGY_H ++#define HW_ARM_TOPOLOGY_H ++ ++typedef struct ARMCPUTopoInfo { ++ unsigned pkg_id; ++ unsigned core_id; ++ unsigned smt_id; ++} ARMCPUTopoInfo; ++ ++/* Calculate (contiguous) CPU index based on topology */ ++static inline unsigned idx_from_topo_ids(unsigned nr_cores, ++ unsigned nr_threads, ++ const ARMCPUTopoInfo *topo) ++{ ++ assert(nr_cores > 0); ++ assert(nr_threads > 0); ++ assert(topo != NULL); ++ ++ return topo->pkg_id * nr_cores * nr_threads + ++ topo->core_id * nr_threads + ++ topo->smt_id; ++} ++ ++/* Calculate thread/core/package topology ++ * based on (contiguous) CPU index ++ */ ++static inline void topo_ids_from_idx(unsigned cpu_index, ++ unsigned nr_cores, ++ unsigned nr_threads, ++ ARMCPUTopoInfo *topo) ++{ ++ assert(nr_cores > 0); ++ assert(nr_threads > 0); ++ assert(topo != NULL); ++ ++ topo->smt_id = cpu_index % nr_threads; ++ topo->core_id = cpu_index / nr_threads % nr_cores; ++ topo->pkg_id = cpu_index / nr_threads / nr_cores; ++} ++ ++#endif /* HW_ARM_TOPOLOGY_H */ ++ +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 1ccb30e5eb..91f1e36cd8 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -2560,6 +2560,9 @@ static Property arm_cpu_properties[] = { + DEFINE_PROP_UINT64("mp-affinity", ARMCPU, + mp_affinity, ARM64_AFFINITY_INVALID), + DEFINE_PROP_INT32("node-id", ARMCPU, node_id, CPU_UNSET_NUMA_NODE_ID), ++ DEFINE_PROP_INT32("socket-id", ARMCPU, socket_id, -1), ++ DEFINE_PROP_INT32("core-id", ARMCPU, core_id, -1), ++ DEFINE_PROP_INT32("thread-id", ARMCPU, thread_id, -1), + DEFINE_PROP_INT32("core-count", ARMCPU, core_count, -1), + DEFINE_PROP_END_OF_LIST() + }; +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index e19531a77b..219c222b89 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -916,6 +916,9 @@ struct ARMCPU { + QLIST_HEAD(, ARMELChangeHook) el_change_hooks; + + int32_t node_id; /* NUMA node this CPU belongs to */ ++ int32_t socket_id; ++ int32_t core_id; ++ int32_t thread_id; + + /* Used to synchronize KVM and QEMU in-kernel device levels */ + uint8_t device_irq_level; +-- +2.19.1 diff --git a/arm-virt-Add-cpu_hotplug_enabled-field.patch b/arm-virt-Add-cpu_hotplug_enabled-field.patch new file mode 100644 index 0000000000000000000000000000000000000000..0b8bc47f6d31dba63e1148c22cc803204ce82e70 --- /dev/null +++ b/arm-virt-Add-cpu_hotplug_enabled-field.patch @@ -0,0 +1,61 @@ +From 31873c4c0454fb17654f57adece2bc396415f8bf Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Fri, 10 Apr 2020 13:50:40 +0800 +Subject: [PATCH] arm/virt: Add cpu_hotplug_enabled field + +Some conditions must be satisfied to support CPU hotplug, including +ACPI, GED, 64bit CPU, GICv3. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt.c | 7 +++++++ + include/hw/arm/virt.h | 1 + + 2 files changed, 8 insertions(+) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index dda22194b5..304a4c2d31 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -1645,6 +1645,7 @@ static void machvirt_init(MachineState *machine) + { + VirtMachineState *vms = VIRT_MACHINE(machine); + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(machine); ++ MachineState *ms = MACHINE(machine); + MachineClass *mc = MACHINE_GET_CLASS(machine); + const CPUArchIdList *possible_cpus; + MemoryRegion *sysmem = get_system_memory(); +@@ -1655,6 +1656,7 @@ static void machvirt_init(MachineState *machine) + bool has_ged = !vmc->no_ged; + unsigned int smp_cpus = machine->smp.cpus; + unsigned int max_cpus = machine->smp.max_cpus; ++ ObjectClass *cpu_class; + + /* + * In accelerated mode, the memory map is computed earlier in kvm_type() +@@ -1760,6 +1762,11 @@ static void machvirt_init(MachineState *machine) + + create_fdt(vms); + ++ cpu_class = object_class_by_name(ms->cpu_type); ++ vms->cpu_hotplug_enabled = has_ged && firmware_loaded && ++ acpi_enabled && vms->gic_version == 3 && ++ !!object_class_dynamic_cast(cpu_class, TYPE_AARCH64_CPU); ++ + possible_cpus = mc->possible_cpu_arch_ids(machine); + for (n = 0; n < possible_cpus->len; n++) { + Object *cpuobj; +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index beef4c8002..b4c53d920e 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -126,6 +126,7 @@ typedef struct { + bool highmem_ecam; + bool its; + bool virt; ++ bool cpu_hotplug_enabled; + int32_t gic_version; + VirtIOMMUType iommu; + struct arm_boot_info bootinfo; +-- +2.19.1 diff --git a/arm-virt-Add-some-sanity-checks-in-cpu_pre_plug-hook.patch b/arm-virt-Add-some-sanity-checks-in-cpu_pre_plug-hook.patch new file mode 100644 index 0000000000000000000000000000000000000000..c81227d8a3ef4ff3ffc74f7b848b42e8cc79c762 --- /dev/null +++ b/arm-virt-Add-some-sanity-checks-in-cpu_pre_plug-hook.patch @@ -0,0 +1,66 @@ +From 7cfb37c50209208f853c6fbd0df6673a95e03ef9 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Fri, 10 Apr 2020 14:16:40 +0800 +Subject: [PATCH] arm/virt: Add some sanity checks in cpu_pre_plug hook + +For that user will try to hotplug a CPU when preconditions +are not satisfied, check these CPU hotplug preconditions in +pre_plug hook. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt.c | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 983084c459..c6a99e683a 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2086,10 +2086,30 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, + VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(hotplug_dev); + const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); ++ const CPUArchId *cpu_slot = NULL; + MemoryRegion *sysmem = get_system_memory(); + int smp_cores = ms->smp.cores; + int smp_threads = ms->smp.threads; + ++ /* Some hotplug capability checks */ ++ ++ if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { ++ error_setg(errp, "Invalid CPU type, expected cpu type: '%s'", ++ ms->cpu_type); ++ return; ++ } ++ ++ if (dev->hotplugged && !vms->acpi_dev) { ++ error_setg(errp, "CPU hotplug is disabled: missing acpi device."); ++ return; ++ } ++ ++ if (dev->hotplugged && !vms->cpu_hotplug_enabled) { ++ error_setg(errp, "CPU hotplug is disabled: " ++ "should use AArch64 CPU and GICv3."); ++ return; ++ } ++ + /* if cpu idx is not set, set it based on socket/core/thread properties */ + if (cs->cpu_index == UNASSIGNED_CPU_INDEX) { + int max_socket = ms->smp.max_cpus / smp_threads / smp_cores; +@@ -2145,6 +2165,13 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, + object_property_set_int(cpuobj, possible_cpus->cpus[cs->cpu_index].arch_id, + "mp-affinity", NULL); + ++ cpu_slot = &possible_cpus->cpus[cs->cpu_index]; ++ if (cpu_slot->cpu) { ++ error_setg(errp, "CPU[%d] with mp_affinity %" PRIu64 " exists", ++ cs->cpu_index, cpu->mp_affinity); ++ return; ++ } ++ + numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpuobj), + &error_fatal); + +-- +2.19.1 diff --git a/arm-virt-Attach-ACPI-CPU-hotplug-support-to-virt.patch b/arm-virt-Attach-ACPI-CPU-hotplug-support-to-virt.patch new file mode 100644 index 0000000000000000000000000000000000000000..ade3ccfd9fe50a78c8ef33ded3463e52b5f6d6c3 --- /dev/null +++ b/arm-virt-Attach-ACPI-CPU-hotplug-support-to-virt.patch @@ -0,0 +1,100 @@ +From d38d1d4e859450535ddc6bf0c7a59f6217b1403c Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Sun, 5 Apr 2020 16:03:15 +0800 +Subject: [PATCH] arm/virt: Attach ACPI CPU hotplug support to virt + +Attach cpus aml building and GED support for CPU hotplug to +arm/virt, but currently we make it diabled by not add CPU +hotplug event to GED. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt-acpi-build.c | 15 ++++++++++++++- + hw/arm/virt.c | 6 ++++++ + include/hw/arm/virt.h | 1 + + 3 files changed, 21 insertions(+), 1 deletion(-) + +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index 8b68a15d76..dbe9acb148 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -806,6 +806,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + MachineState *ms = MACHINE(vms); + const MemMapEntry *memmap = vms->memmap; + const int *irqmap = vms->irqmap; ++ bool cpu_aml_built = false; + + dsdt = init_aml_allocator(); + /* Reserve space for header */ +@@ -817,7 +818,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + * the RTC ACPI device at all when using UEFI. + */ + scope = aml_scope("\\_SB"); +- acpi_dsdt_add_cpus(scope, vms->smp_cpus, vms); + acpi_dsdt_add_uart(scope, &memmap[VIRT_UART], + (irqmap[VIRT_UART] + ARM_SPI_BASE)); + acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); +@@ -845,6 +845,19 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + AML_SYSTEM_MEMORY, + memmap[VIRT_PCDIMM_ACPI].base); + } ++ ++ if (event & ACPI_GED_CPU_HOTPLUG_EVT) { ++ CPUHotplugFeatures opts = { ++ .acpi_1_compatible = false, .has_legacy_cphp = false ++ }; ++ build_cpus_aml(dsdt, ms, opts, memmap[VIRT_CPU_ACPI].base, ++ "\\_SB", NULL, AML_SYSTEM_MEMORY); ++ cpu_aml_built = true; ++ } ++ } ++ ++ if (!cpu_aml_built) { ++ acpi_dsdt_add_cpus(scope, vms->smp_cpus, vms); + } + + acpi_dsdt_add_power_button(scope); +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 8638aeedb7..d09a5773df 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -140,6 +140,7 @@ static const MemMapEntry base_memmap[] = { + [VIRT_SMMU] = { 0x09050000, 0x00020000 }, + [VIRT_PCDIMM_ACPI] = { 0x09070000, MEMORY_HOTPLUG_IO_LEN }, + [VIRT_ACPI_GED] = { 0x09080000, ACPI_GED_EVT_SEL_LEN }, ++ [VIRT_CPU_ACPI] = { 0x09090000, ACPI_CPU_HOTPLUG_REG_LEN }, + [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, + [VIRT_CPUFREQ] = { 0x0b000000, 0x00010000 }, + /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ +@@ -645,11 +646,16 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) + event |= ACPI_GED_MEM_HOTPLUG_EVT; + } + ++ /* event |= ACPI_GED_CPU_HOTPLUG_EVT; ++ * Currently CPU hotplug is not enabled. ++ */ ++ + dev = qdev_create(NULL, TYPE_ACPI_GED); + qdev_prop_set_uint32(dev, "ged-event", event); + + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base); ++ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, vms->memmap[VIRT_CPU_ACPI].base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic, irq)); + + qdev_init_nofail(dev); +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index cbdea7ff32..6880ebe07c 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -81,6 +81,7 @@ enum { + VIRT_SECURE_MEM, + VIRT_PCDIMM_ACPI, + VIRT_ACPI_GED, ++ VIRT_CPU_ACPI, + VIRT_LOWMEMMAP_LAST, + }; + +-- +2.19.1 diff --git a/arm-virt-Pre-sizing-MADT-GICC-PPTT-GICv3-and-Pre-par.patch b/arm-virt-Pre-sizing-MADT-GICC-PPTT-GICv3-and-Pre-par.patch new file mode 100644 index 0000000000000000000000000000000000000000..c2d9a3cb0a48436433a30670e8517d7dafb9bca4 --- /dev/null +++ b/arm-virt-Pre-sizing-MADT-GICC-PPTT-GICv3-and-Pre-par.patch @@ -0,0 +1,124 @@ +From bf47ef282bfe8b0a98e1f87d8708051ffa7192a1 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Fri, 10 Apr 2020 13:55:11 +0800 +Subject: [PATCH] arm/virt: Pre-sizing MADT-GICC PPTT GICv3 and Pre-park KVM + vCPU + +Establish all pre-sizing facilities based on cpu_hotplug_enabled +field. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt-acpi-build.c | 12 +++++++++++- + hw/arm/virt.c | 14 ++++++++++++-- + target/arm/kvm.c | 6 +++--- + 3 files changed, 26 insertions(+), 6 deletions(-) + +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index efac788ba1..2cfac7b84f 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -736,6 +736,9 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + gicd->base_address = cpu_to_le64(memmap[VIRT_GIC_DIST].base); + gicd->version = vms->gic_version; + ++ if (vms->cpu_hotplug_enabled) { ++ num_cpu = ms->smp.max_cpus; ++ } + for (i = 0; i < num_cpu; i++) { + virt_madt_cpu_entry(NULL, i, possible_cpus, table_data); + } +@@ -902,9 +905,11 @@ static + void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) + { + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); ++ MachineState *ms = MACHINE(vms); + GArray *table_offsets; + unsigned dsdt, xsdt; + GArray *tables_blob = tables->table_data; ++ int num_cpus; + + table_offsets = g_array_new(false, true /* clear */, + sizeof(uint32_t)); +@@ -923,7 +928,12 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) + + acpi_add_table(table_offsets, tables_blob); + +- build_pptt(tables_blob, tables->linker, vms->smp_cpus); ++ if (vms->cpu_hotplug_enabled) { ++ num_cpus = ms->smp.max_cpus; ++ } else { ++ num_cpus = ms->smp.cpus; ++ } ++ build_pptt(tables_blob, tables->linker, num_cpus); + + acpi_add_table(table_offsets, tables_blob); + build_madt(tables_blob, tables->linker, vms); +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 304a4c2d31..983084c459 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -767,6 +767,9 @@ static void create_gic(VirtMachineState *vms) + unsigned int smp_cpus = ms->smp.cpus; + uint32_t nb_redist_regions = 0; + ++ if (vms->cpu_hotplug_enabled) { ++ num_cpus = ms->smp.max_cpus; ++ } + assert(num_cpus >= smp_cpus); + + gictype = (type == 3) ? gicv3_class_name() : gic_class_name(); +@@ -1772,8 +1775,15 @@ static void machvirt_init(MachineState *machine) + Object *cpuobj; + CPUState *cs; + ++ if (kvm_enabled() && vms->cpu_hotplug_enabled) { ++ if (kvm_create_parked_vcpu(n) < 0) { ++ error_report("mach-virt: Create KVM parked vCPU failed"); ++ exit(1); ++ } ++ } ++ + if (n >= smp_cpus) { +- break; ++ continue; + } + + cpuobj = object_new(possible_cpus->cpus[n].type); +@@ -1857,7 +1867,7 @@ static void machvirt_init(MachineState *machine) + vms->bootinfo.kernel_filename = machine->kernel_filename; + vms->bootinfo.kernel_cmdline = machine->kernel_cmdline; + vms->bootinfo.initrd_filename = machine->initrd_filename; +- vms->bootinfo.nb_cpus = smp_cpus; ++ vms->bootinfo.nb_cpus = vms->cpu_hotplug_enabled ? max_cpus : smp_cpus; + vms->bootinfo.board_id = -1; + vms->bootinfo.loader_start = vms->memmap[VIRT_MEM].base; + vms->bootinfo.get_dtb = machvirt_dtb; +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index 327b3bc338..4f131f687d 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -202,7 +202,7 @@ int kvm_arm_get_max_vm_ipa_size(MachineState *ms) + int kvm_arch_init(MachineState *ms, KVMState *s) + { + int ret = 0; +- unsigned int smp_cpus = ms->smp.cpus; ++ unsigned int max_cpus = ms->smp.max_cpus; + /* For ARM interrupt delivery is always asynchronous, + * whether we are using an in-kernel VGIC or not. + */ +@@ -216,9 +216,9 @@ int kvm_arch_init(MachineState *ms, KVMState *s) + + cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE); + +- if (smp_cpus > 256 && ++ if (max_cpus > 256 && + !kvm_check_extension(s, KVM_CAP_ARM_IRQ_LINE_LAYOUT_2)) { +- error_report("Using more than 256 vcpus requires a host kernel " ++ error_report("Using more than max 256 vcpus requires a host kernel " + "with KVM_CAP_ARM_IRQ_LINE_LAYOUT_2"); + ret = -EINVAL; + } +-- +2.19.1 diff --git a/arm-virt-Start-up-CPU-hot-plug.patch b/arm-virt-Start-up-CPU-hot-plug.patch new file mode 100644 index 0000000000000000000000000000000000000000..5ba620a2215710682afa4ccdfd0d5cad53556680 --- /dev/null +++ b/arm-virt-Start-up-CPU-hot-plug.patch @@ -0,0 +1,159 @@ +From 11f9628ceff019259ff12ce469deafbf50eb3075 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Fri, 10 Apr 2020 14:20:59 +0800 +Subject: [PATCH] arm/virt: Start up CPU hot-plug + +All the CPU hotplug facilities are ready. Assemble them +to start up CPU hot-plug capability for arm/virt. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt.c | 61 ++++++++++++++++++++++++++++++++++++++++--- + include/hw/arm/virt.h | 1 + + qom/cpu.c | 5 ++++ + target/arm/cpu.c | 2 ++ + 4 files changed, 65 insertions(+), 4 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index c6a99e683a..112a6ae7cb 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -48,6 +48,8 @@ + #include "sysemu/cpus.h" + #include "sysemu/sysemu.h" + #include "sysemu/kvm.h" ++#include "sysemu/cpus.h" ++#include "sysemu/hw_accel.h" + #include "hw/loader.h" + #include "exec/address-spaces.h" + #include "qemu/bitops.h" +@@ -649,9 +651,9 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) + event |= ACPI_GED_MEM_HOTPLUG_EVT; + } + +- /* event |= ACPI_GED_CPU_HOTPLUG_EVT; +- * Currently CPU hotplug is not enabled. +- */ ++ if (vms->cpu_hotplug_enabled) { ++ event |= ACPI_GED_CPU_HOTPLUG_EVT; ++ } + + dev = qdev_create(NULL, TYPE_ACPI_GED); + qdev_prop_set_uint32(dev, "ged-event", event); +@@ -2214,12 +2216,62 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, + object_property_set_link(cpuobj, OBJECT(secure_sysmem), + "secure-memory", &error_abort); + } ++ ++ /* If we use KVM accel, we should pause all vcpus to ++ * allow hot access of vcpu registers. ++ */ ++ if (dev->hotplugged && kvm_enabled()) { ++ pause_all_vcpus(); ++ } + } + + static void virt_cpu_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- /* Currently nothing to do */ ++ CPUArchId *cpu_slot; ++ CPUState *cs = CPU(dev); ++ int ncpu = cs->cpu_index; ++ MachineState *ms = MACHINE(hotplug_dev); ++ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); ++ GICv3State *gicv3; ++ ARMGICv3CommonClass *agcc; ++ Error *local_err = NULL; ++ ++ if (dev->hotplugged) { ++ /* Realize GIC related parts of CPU */ ++ assert(vms->gic_version == 3); ++ gicv3 = ARM_GICV3_COMMON(vms->gic); ++ agcc = ARM_GICV3_COMMON_GET_CLASS(gicv3); ++ agcc->cpu_hotplug_realize(gicv3, ncpu); ++ connect_gic_cpu_irqs(vms, ncpu); ++ ++ /* Register CPU reset and trigger it manually */ ++ cpu_synchronize_state(cs); ++ cpu_hotplug_register_reset(ncpu); ++ cpu_hotplug_reset_manually(ncpu); ++ cpu_synchronize_post_reset(cs); ++ ++ if (kvm_enabled()) { ++ resume_all_vcpus(); ++ } ++ } ++ ++ if (vms->acpi_dev) { ++ hotplug_handler_plug(HOTPLUG_HANDLER(vms->acpi_dev), dev, &local_err); ++ if (local_err) { ++ goto out; ++ } ++ } ++ ++ vms->boot_cpus++; ++ if (vms->fw_cfg) { ++ fw_cfg_modify_i16(vms->fw_cfg, FW_CFG_NB_CPUS, vms->boot_cpus); ++ } ++ ++ cpu_slot = &ms->possible_cpus->cpus[ncpu]; ++ cpu_slot->cpu = OBJECT(dev); ++out: ++ error_propagate(errp, local_err); + } + + static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, +@@ -2324,6 +2376,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) + mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15"); + mc->get_default_cpu_node_id = virt_get_default_cpu_node_id; + mc->kvm_type = virt_kvm_type; ++ mc->has_hotpluggable_cpus = true; + assert(!mc->get_hotplug_handler); + mc->get_hotplug_handler = virt_machine_get_hotplug_handler; + hc->pre_plug = virt_machine_device_pre_plug_cb; +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index b4c53d920e..a9429bed25 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -140,6 +140,7 @@ typedef struct { + uint32_t msi_phandle; + uint32_t iommu_phandle; + int psci_conduit; ++ uint32_t boot_cpus; + hwaddr highest_gpa; + DeviceState *gic; + DeviceState *acpi_dev; +diff --git a/qom/cpu.c b/qom/cpu.c +index f376f782d8..58cd9d5bbc 100644 +--- a/qom/cpu.c ++++ b/qom/cpu.c +@@ -342,7 +342,12 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp) + + if (dev->hotplugged) { + cpu_synchronize_post_init(cpu); ++ ++#ifdef __aarch64__ ++ if (!kvm_enabled()) ++#endif + cpu_resume(cpu); ++ + } + + /* NOTE: latest generic point where the cpu is fully realized */ +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 91f1e36cd8..811e5c6365 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -2598,6 +2598,8 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) + acc->parent_reset = cc->reset; + cc->reset = arm_cpu_reset; + ++ dc->user_creatable = true; ++ + cc->class_by_name = arm_cpu_class_by_name; + cc->has_work = arm_cpu_has_work; + cc->cpu_exec_interrupt = arm_cpu_exec_interrupt; +-- +2.19.1 diff --git a/arm-virt-Support-CPU-cold-plug.patch b/arm-virt-Support-CPU-cold-plug.patch new file mode 100644 index 0000000000000000000000000000000000000000..3f96fede24c1e4f18d0f05c1987b20cc5a883b93 --- /dev/null +++ b/arm-virt-Support-CPU-cold-plug.patch @@ -0,0 +1,92 @@ +From e3a1af72fca5bbcc840fba44d512bbe69ec55ca9 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Tue, 12 May 2020 15:05:06 +0800 +Subject: [PATCH] arm/virt: Support CPU cold plug + +This adds CPU cold plug support to arm virt machine board. +CPU cold plug means adding CPU by using "-device xx-arm-cpu" +when we bring up Qemu. + +Signed-off-by: Keqian Zhu +--- + hw/arm/virt.c | 36 +++++++++++++++++++----------------- + 1 file changed, 19 insertions(+), 17 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 112a6ae7cb..4c7279392f 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2093,25 +2093,12 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, + int smp_cores = ms->smp.cores; + int smp_threads = ms->smp.threads; + +- /* Some hotplug capability checks */ +- + if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { + error_setg(errp, "Invalid CPU type, expected cpu type: '%s'", + ms->cpu_type); + return; + } + +- if (dev->hotplugged && !vms->acpi_dev) { +- error_setg(errp, "CPU hotplug is disabled: missing acpi device."); +- return; +- } +- +- if (dev->hotplugged && !vms->cpu_hotplug_enabled) { +- error_setg(errp, "CPU hotplug is disabled: " +- "should use AArch64 CPU and GICv3."); +- return; +- } +- + /* if cpu idx is not set, set it based on socket/core/thread properties */ + if (cs->cpu_index == UNASSIGNED_CPU_INDEX) { + int max_socket = ms->smp.max_cpus / smp_threads / smp_cores; +@@ -2137,6 +2124,20 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, + cs->cpu_index = idx_from_topo_ids(smp_cores, smp_threads, &topo); + } + ++ /* Some hotplug capability checks */ ++ if (cs->cpu_index >= ms->smp.cpus) { ++ if (!vms->acpi_dev) { ++ error_setg(errp, "CPU cold/hot plug is disabled: " ++ "missing acpi device."); ++ return; ++ } ++ if (!vms->cpu_hotplug_enabled) { ++ error_setg(errp, "CPU cold/hot plug is disabled: " ++ "should use AArch64 CPU and GICv3."); ++ return; ++ } ++ } ++ + /* if 'address' properties socket-id/core-id/thread-id are not set, set them + * so that machine_query_hotpluggable_cpus would show correct values + */ +@@ -2237,7 +2238,8 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, + ARMGICv3CommonClass *agcc; + Error *local_err = NULL; + +- if (dev->hotplugged) { ++ /* For CPU that is cold/hot plugged */ ++ if (ncpu >= ms->smp.cpus) { + /* Realize GIC related parts of CPU */ + assert(vms->gic_version == 3); + gicv3 = ARM_GICV3_COMMON(vms->gic); +@@ -2250,10 +2252,10 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, + cpu_hotplug_register_reset(ncpu); + cpu_hotplug_reset_manually(ncpu); + cpu_synchronize_post_reset(cs); ++ } + +- if (kvm_enabled()) { +- resume_all_vcpus(); +- } ++ if (dev->hotplugged && kvm_enabled()) { ++ resume_all_vcpus(); + } + + if (vms->acpi_dev) { +-- +2.19.1 + diff --git a/arm-virt-acpi-Extend-cpufreq-to-support-max_cpus.patch b/arm-virt-acpi-Extend-cpufreq-to-support-max_cpus.patch new file mode 100644 index 0000000000000000000000000000000000000000..297ccf633fe69840b863f10109ee4271f16c11a1 --- /dev/null +++ b/arm-virt-acpi-Extend-cpufreq-to-support-max_cpus.patch @@ -0,0 +1,65 @@ +From 91fed8840b004ec7bc91969afa10f03e13f311c4 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Wed, 22 Apr 2020 19:52:58 +0800 +Subject: [PATCH] arm/virt/acpi: Extend cpufreq to support max_cpus + +We will support CPU hotplug soon, so extend memory region size to +allow hotplugged CPU access cpufreq space. + +Signed-off-by: Keqian Zhu +--- + hw/acpi/cpufreq.c | 15 ++++++--------- + 1 file changed, 6 insertions(+), 9 deletions(-) + +diff --git a/hw/acpi/cpufreq.c b/hw/acpi/cpufreq.c +index d02a25a6de..38dcab5683 100644 +--- a/hw/acpi/cpufreq.c ++++ b/hw/acpi/cpufreq.c +@@ -84,6 +84,7 @@ typedef struct CpuhzState { + uint32_t PerformanceLimited; + uint32_t LowestFreq; + uint32_t NominalFreq; ++ uint32_t num_cpu; + uint32_t reg_size; + } CpuhzState; + +@@ -95,10 +96,7 @@ static uint64_t cpufreq_read(void *opaque, hwaddr offset, + uint64_t r; + uint64_t n; + +- MachineState *ms = MACHINE(qdev_get_machine()); +- unsigned int smp_cpus = ms->smp.cpus; +- +- if (offset >= smp_cpus * CPPC_REG_PER_CPU_STRIDE) { ++ if (offset >= s->num_cpu * CPPC_REG_PER_CPU_STRIDE) { + warn_report("cpufreq_read: offset 0x%lx out of range", offset); + return 0; + } +@@ -166,11 +164,10 @@ static uint64_t cpufreq_read(void *opaque, hwaddr offset, + static void cpufreq_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) + { ++ CpuhzState *s = CPUFREQ(opaque); + uint64_t n; +- MachineState *ms = MACHINE(qdev_get_machine()); +- unsigned int smp_cpus = ms->smp.cpus; + +- if (offset >= smp_cpus * CPPC_REG_PER_CPU_STRIDE) { ++ if (offset >= s->num_cpu * CPPC_REG_PER_CPU_STRIDE) { + error_printf("cpufreq_write: offset 0x%lx out of range", offset); + return; + } +@@ -251,9 +248,9 @@ static void cpufreq_init(Object *obj) + CpuhzState *s = CPUFREQ(obj); + + MachineState *ms = MACHINE(qdev_get_machine()); +- unsigned int smp_cpus = ms->smp.cpus; ++ s->num_cpu = ms->smp.max_cpus; + +- s->reg_size = smp_cpus * CPPC_REG_PER_CPU_STRIDE; ++ s->reg_size = s->num_cpu * CPPC_REG_PER_CPU_STRIDE; + if (s->reg_size > MAX_SUPPORT_SPACE) { + error_report("Required space 0x%x excesses the max support 0x%x", + s->reg_size, MAX_SUPPORT_SPACE); +-- +2.19.1 diff --git a/arm-virt-acpi-Factor-out-CPPC-building-from-DSDT-CPU.patch b/arm-virt-acpi-Factor-out-CPPC-building-from-DSDT-CPU.patch new file mode 100644 index 0000000000000000000000000000000000000000..f08f83de6505d7810cb7b6753bd00034e3921862 --- /dev/null +++ b/arm-virt-acpi-Factor-out-CPPC-building-from-DSDT-CPU.patch @@ -0,0 +1,121 @@ +From 2fdece10dac6161cb6c1f0f05247391aa3269eed Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Wed, 22 Apr 2020 15:58:27 +0800 +Subject: [PATCH] arm/virt/acpi: Factor out CPPC building from DSDT CPU aml + +When CPU hotplug is enabled, we will use build_cpus_aml instead of +acpi_dsdt_add_cpus, so factor out CPPC building and we can reuse it +in build_cpus_aml. + +Signed-off-by: Keqian Zhu +--- + hw/acpi/generic_event_device.c | 1 + + hw/arm/virt-acpi-build.c | 33 +++++++++++++++++----------- + include/hw/acpi/acpi_dev_interface.h | 2 ++ + include/hw/arm/virt.h | 2 ++ + 4 files changed, 25 insertions(+), 13 deletions(-) + +diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c +index b834ae3ff6..82139b4314 100644 +--- a/hw/acpi/generic_event_device.c ++++ b/hw/acpi/generic_event_device.c +@@ -289,6 +289,7 @@ static void acpi_ged_class_init(ObjectClass *class, void *data) + + adevc->send_event = acpi_ged_send_event; + adevc->madt_cpu = virt_madt_cpu_entry; ++ adevc->cpu_cppc = virt_acpi_dsdt_cpu_cppc; + } + + static const TypeInfo acpi_ged_info = { +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index 4b6aace433..8b68a15d76 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -111,8 +111,24 @@ static void acpi_dsdt_add_cppc(Aml *dev, uint64_t cpu_base, int *regs_offset) + aml_append(dev, aml_name_decl("_CPC", cpc)); + } + +-static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus, +- const MemMapEntry *cppc_memmap) ++void virt_acpi_dsdt_cpu_cppc(AcpiDeviceIf *adev, int ncpu, int num_cpu, Aml *dev) ++{ ++ VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine()); ++ const MemMapEntry *cppc_memmap = &vms->memmap[VIRT_CPUFREQ]; ++ ++ /* ++ * Append _CPC and _PSD to support CPU frequence show ++ * Check CPPC available by DESIRED_PERF register ++ */ ++ if (cppc_regs_offset[DESIRED_PERF] != -1) { ++ acpi_dsdt_add_cppc(dev, ++ cppc_memmap->base + ncpu * CPPC_REG_PER_CPU_STRIDE, ++ cppc_regs_offset); ++ acpi_dsdt_add_psd(dev, num_cpu); ++ } ++} ++ ++static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus, VirtMachineState *vms) + { + uint16_t i; + +@@ -121,16 +137,7 @@ static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus, + aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007"))); + aml_append(dev, aml_name_decl("_UID", aml_int(i))); + +- /* +- * Append _CPC and _PSD to support CPU frequence show +- * Check CPPC available by DESIRED_PERF register +- */ +- if (cppc_regs_offset[DESIRED_PERF] != -1) { +- acpi_dsdt_add_cppc(dev, +- cppc_memmap->base + i * CPPC_REG_PER_CPU_STRIDE, +- cppc_regs_offset); +- acpi_dsdt_add_psd(dev, smp_cpus); +- } ++ virt_acpi_dsdt_cpu_cppc(NULL, i, smp_cpus, dev); + + aml_append(scope, dev); + } +@@ -810,7 +817,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + * the RTC ACPI device at all when using UEFI. + */ + scope = aml_scope("\\_SB"); +- acpi_dsdt_add_cpus(scope, vms->smp_cpus, &memmap[VIRT_CPUFREQ]); ++ acpi_dsdt_add_cpus(scope, vms->smp_cpus, vms); + acpi_dsdt_add_uart(scope, &memmap[VIRT_UART], + (irqmap[VIRT_UART] + ARM_SPI_BASE)); + acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); +diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h +index adcb3a816c..2952914569 100644 +--- a/include/hw/acpi/acpi_dev_interface.h ++++ b/include/hw/acpi/acpi_dev_interface.h +@@ -3,6 +3,7 @@ + + #include "qom/object.h" + #include "hw/boards.h" ++#include "hw/acpi/aml-build.h" + + /* These values are part of guest ABI, and can not be changed */ + typedef enum { +@@ -55,5 +56,6 @@ typedef struct AcpiDeviceIfClass { + void (*send_event)(AcpiDeviceIf *adev, AcpiEventStatusBits ev); + void (*madt_cpu)(AcpiDeviceIf *adev, int uid, + const CPUArchIdList *apic_ids, GArray *entry); ++ void (*cpu_cppc)(AcpiDeviceIf *adev, int uid, int num_cpu, Aml *dev); + } AcpiDeviceIfClass; + #endif +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index 6b1f10b231..cbdea7ff32 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -157,6 +157,8 @@ typedef struct { + void virt_acpi_setup(VirtMachineState *vms); + void virt_madt_cpu_entry(AcpiDeviceIf *adev, int uid, + const CPUArchIdList *cpu_list, GArray *entry); ++void virt_acpi_dsdt_cpu_cppc(AcpiDeviceIf *adev, int uid, ++ int num_cpu, Aml *dev); + + /* Return the number of used redistributor regions */ + static inline int virt_gicv3_redist_region_count(VirtMachineState *vms) +-- +2.19.1 diff --git a/arm-virt-gic-Construct-irqs-connection-from-create_g.patch b/arm-virt-gic-Construct-irqs-connection-from-create_g.patch new file mode 100644 index 0000000000000000000000000000000000000000..7e9506425f1de938d2ba70a3fb31a83561a4154e --- /dev/null +++ b/arm-virt-gic-Construct-irqs-connection-from-create_g.patch @@ -0,0 +1,123 @@ +From 92124743f4560c490780a229f53ea5881f706383 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Sun, 5 Apr 2020 15:29:16 +0800 +Subject: [PATCH] arm/virt/gic: Construct irqs connection from create_gic + +Make the irqs can be connected to for individual CPU. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt.c | 90 ++++++++++++++++++++++++++++----------------------- + 1 file changed, 49 insertions(+), 41 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 83f4887e57..55d403bad6 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -706,6 +706,54 @@ static void create_v2m(VirtMachineState *vms) + fdt_add_v2m_gic_node(vms); + } + ++static void connect_gic_cpu_irqs(VirtMachineState *vms, int i) ++{ ++ DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); ++ SysBusDevice *gicbusdev = SYS_BUS_DEVICE(vms->gic); ++ int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS; ++ int num_cpus = object_property_get_uint(OBJECT(vms->gic), "num-cpu", NULL); ++ int gic_type = vms->gic_version; ++ int irq; ++ /* Mapping from the output timer irq lines from the CPU to the ++ * GIC PPI inputs we use for the virt board. ++ */ ++ const int timer_irq[] = { ++ [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ, ++ [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ, ++ [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ, ++ [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ, ++ }; ++ ++ for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { ++ qdev_connect_gpio_out(cpudev, irq, ++ qdev_get_gpio_in(vms->gic, ++ ppibase + timer_irq[irq])); ++ } ++ ++ if (gic_type == 3) { ++ qemu_irq irq = qdev_get_gpio_in(vms->gic, ++ ppibase + ARCH_GIC_MAINT_IRQ); ++ qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", ++ 0, irq); ++ } else if (vms->virt) { ++ qemu_irq irq = qdev_get_gpio_in(vms->gic, ++ ppibase + ARCH_GIC_MAINT_IRQ); ++ sysbus_connect_irq(gicbusdev, i + 4 * num_cpus, irq); ++ } ++ ++ qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, ++ qdev_get_gpio_in(vms->gic, ppibase ++ + VIRTUAL_PMU_IRQ)); ++ ++ sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); ++ sysbus_connect_irq(gicbusdev, i + num_cpus, ++ qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); ++ sysbus_connect_irq(gicbusdev, i + 2 * num_cpus, ++ qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ)); ++ sysbus_connect_irq(gicbusdev, i + 3 * num_cpus, ++ qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); ++} ++ + static void create_gic(VirtMachineState *vms) + { + MachineState *ms = MACHINE(vms); +@@ -775,47 +823,7 @@ static void create_gic(VirtMachineState *vms) + * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs. + */ + for (i = 0; i < smp_cpus; i++) { +- DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); +- int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS; +- int irq; +- /* Mapping from the output timer irq lines from the CPU to the +- * GIC PPI inputs we use for the virt board. +- */ +- const int timer_irq[] = { +- [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ, +- [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ, +- [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ, +- [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ, +- }; +- +- for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { +- qdev_connect_gpio_out(cpudev, irq, +- qdev_get_gpio_in(vms->gic, +- ppibase + timer_irq[irq])); +- } +- +- if (type == 3) { +- qemu_irq irq = qdev_get_gpio_in(vms->gic, +- ppibase + ARCH_GIC_MAINT_IRQ); +- qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", +- 0, irq); +- } else if (vms->virt) { +- qemu_irq irq = qdev_get_gpio_in(vms->gic, +- ppibase + ARCH_GIC_MAINT_IRQ); +- sysbus_connect_irq(gicbusdev, i + 4 * smp_cpus, irq); +- } +- +- qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, +- qdev_get_gpio_in(vms->gic, ppibase +- + VIRTUAL_PMU_IRQ)); +- +- sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); +- sysbus_connect_irq(gicbusdev, i + smp_cpus, +- qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); +- sysbus_connect_irq(gicbusdev, i + 2 * smp_cpus, +- qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ)); +- sysbus_connect_irq(gicbusdev, i + 3 * smp_cpus, +- qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); ++ connect_gic_cpu_irqs(vms, i); + } + + fdt_add_gic_node(vms); +-- +2.19.1 diff --git a/async-use-explicit-memory-barriers.patch b/async-use-explicit-memory-barriers.patch new file mode 100644 index 0000000000000000000000000000000000000000..7fb68c949ad4e95cc0f908c44042096b69cf9295 --- /dev/null +++ b/async-use-explicit-memory-barriers.patch @@ -0,0 +1,171 @@ +From 787af8ed2bc86dc8688727d62a251965d9c42e00 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Fri, 10 Apr 2020 16:19:50 +0000 +Subject: [PATCH 2/2] async: use explicit memory barriers + +When using C11 atomics, non-seqcst reads and writes do not participate +in the total order of seqcst operations. In util/async.c and util/aio-posix.c, +in particular, the pattern that we use + + write ctx->notify_me write bh->scheduled + read bh->scheduled read ctx->notify_me + if !bh->scheduled, sleep if ctx->notify_me, notify + +needs to use seqcst operations for both the write and the read. In +general this is something that we do not want, because there can be +many sources that are polled in addition to bottom halves. The +alternative is to place a seqcst memory barrier between the write +and the read. This also comes with a disadvantage, in that the +memory barrier is implicit on strongly-ordered architectures and +it wastes a few dozen clock cycles. + +Fortunately, ctx->notify_me is never written concurrently by two +threads, so we can assert that and relax the writes to ctx->notify_me. +The resulting solution works and performs well on both aarch64 and x86. + +Note that the atomic_set/atomic_read combination is not an atomic +read-modify-write, and therefore it is even weaker than C11 ATOMIC_RELAXED; +on x86, ATOMIC_RELAXED compiles to a locked operation. + +upstream_url: https://patchwork.kernel.org/patch/11482103/ + +Analyzed-by: Ying Fang +Signed-off-by: Paolo Bonzini +Tested-by: Ying Fang +Message-Id: <20200407140746.8041-6-pbonzini@redhat.com> +Signed-off-by: Stefan Hajnoczi +--- + util/aio-posix.c | 16 ++++++++++++++-- + util/aio-win32.c | 17 ++++++++++++++--- + util/async.c | 16 ++++++++++++---- + 3 files changed, 40 insertions(+), 9 deletions(-) + +diff --git a/util/aio-posix.c b/util/aio-posix.c +index 6fbfa792..ca58b9a4 100644 +--- a/util/aio-posix.c ++++ b/util/aio-posix.c +@@ -613,6 +613,11 @@ bool aio_poll(AioContext *ctx, bool blocking) + int64_t timeout; + int64_t start = 0; + ++ /* ++ * There cannot be two concurrent aio_poll calls for the same AioContext (or ++ * an aio_poll concurrent with a GSource prepare/check/dispatch callback). ++ * We rely on this below to avoid slow locked accesses to ctx->notify_me. ++ */ + assert(in_aio_context_home_thread(ctx)); + + /* aio_notify can avoid the expensive event_notifier_set if +@@ -623,7 +628,13 @@ bool aio_poll(AioContext *ctx, bool blocking) + * so disable the optimization now. + */ + if (blocking) { +- atomic_add(&ctx->notify_me, 2); ++ atomic_set(&ctx->notify_me, atomic_read(&ctx->notify_me) + 2); ++ /* ++ * Write ctx->notify_me before computing the timeout ++ * (reading bottom half flags, etc.). Pairs with ++ * smp_mb in aio_notify(). ++ */ ++ smp_mb(); + } + + qemu_lockcnt_inc(&ctx->list_lock); +@@ -668,7 +679,8 @@ bool aio_poll(AioContext *ctx, bool blocking) + } + + if (blocking) { +- atomic_sub(&ctx->notify_me, 2); ++ /* Finish the poll before clearing the flag. */ ++ atomic_store_release(&ctx->notify_me, atomic_read(&ctx->notify_me) - 2); + aio_notify_accept(ctx); + } + +diff --git a/util/aio-win32.c b/util/aio-win32.c +index a23b9c36..729d533f 100644 +--- a/util/aio-win32.c ++++ b/util/aio-win32.c +@@ -321,6 +321,12 @@ bool aio_poll(AioContext *ctx, bool blocking) + int count; + int timeout; + ++ /* ++ * There cannot be two concurrent aio_poll calls for the same AioContext (or ++ * an aio_poll concurrent with a GSource prepare/check/dispatch callback). ++ * We rely on this below to avoid slow locked accesses to ctx->notify_me. ++ */ ++ assert(in_aio_context_home_thread(ctx)); + progress = false; + + /* aio_notify can avoid the expensive event_notifier_set if +@@ -331,7 +337,13 @@ bool aio_poll(AioContext *ctx, bool blocking) + * so disable the optimization now. + */ + if (blocking) { +- atomic_add(&ctx->notify_me, 2); ++ atomic_set(&ctx->notify_me, atomic_read(&ctx->notify_me) + 2); ++ /* ++ * Write ctx->notify_me before computing the timeout ++ * (reading bottom half flags, etc.). Pairs with ++ * smp_mb in aio_notify(). ++ */ ++ smp_mb(); + } + + qemu_lockcnt_inc(&ctx->list_lock); +@@ -364,8 +376,7 @@ bool aio_poll(AioContext *ctx, bool blocking) + ret = WaitForMultipleObjects(count, events, FALSE, timeout); + if (blocking) { + assert(first); +- assert(in_aio_context_home_thread(ctx)); +- atomic_sub(&ctx->notify_me, 2); ++ atomic_store_release(&ctx->notify_me, atomic_read(&ctx->notify_me) - 2); + aio_notify_accept(ctx); + } + +diff --git a/util/async.c b/util/async.c +index afc17fb3..12b33204 100644 +--- a/util/async.c ++++ b/util/async.c +@@ -221,7 +221,14 @@ aio_ctx_prepare(GSource *source, gint *timeout) + { + AioContext *ctx = (AioContext *) source; + +- atomic_or(&ctx->notify_me, 1); ++ atomic_set(&ctx->notify_me, atomic_read(&ctx->notify_me) | 1); ++ ++ /* ++ * Write ctx->notify_me before computing the timeout ++ * (reading bottom half flags, etc.). Pairs with ++ * smp_mb in aio_notify(). ++ */ ++ smp_mb(); + + /* We assume there is no timeout already supplied */ + *timeout = qemu_timeout_ns_to_ms(aio_compute_timeout(ctx)); +@@ -239,7 +246,8 @@ aio_ctx_check(GSource *source) + AioContext *ctx = (AioContext *) source; + QEMUBH *bh; + +- atomic_and(&ctx->notify_me, ~1); ++ /* Finish computing the timeout before clearing the flag. */ ++ atomic_store_release(&ctx->notify_me, atomic_read(&ctx->notify_me) & ~1); + aio_notify_accept(ctx); + + for (bh = ctx->first_bh; bh; bh = bh->next) { +@@ -344,10 +352,10 @@ LinuxAioState *aio_get_linux_aio(AioContext *ctx) + void aio_notify(AioContext *ctx) + { + /* Write e.g. bh->scheduled before reading ctx->notify_me. Pairs +- * with atomic_or in aio_ctx_prepare or atomic_add in aio_poll. ++ * with smp_mb in aio_ctx_prepare or aio_poll. + */ + smp_mb(); +- if (ctx->notify_me) { ++ if (atomic_read(&ctx->notify_me)) { + event_notifier_set(&ctx->notifier); + atomic_mb_set(&ctx->notified, true); + } +-- +2.25.2 + diff --git a/ati-vga-Fix-checks-in-ati_2d_blt-to-avoid-crash.patch b/ati-vga-Fix-checks-in-ati_2d_blt-to-avoid-crash.patch new file mode 100644 index 0000000000000000000000000000000000000000..ef1d8b646c607a5afb6278ab229efc4a5a15965f --- /dev/null +++ b/ati-vga-Fix-checks-in-ati_2d_blt-to-avoid-crash.patch @@ -0,0 +1,91 @@ +From ac2071c3791b67fc7af78b8ceb320c01ca1b5df7 Mon Sep 17 00:00:00 2001 +From: BALATON Zoltan +Date: Mon, 6 Apr 2020 22:34:26 +0200 +Subject: [PATCH] ati-vga: Fix checks in ati_2d_blt() to avoid crash + +In some corner cases (that never happen during normal operation but a +malicious guest could program wrong values) pixman functions were +called with parameters that result in a crash. Fix this and add more +checks to disallow such cases. + +Reported-by: Ziming Zhang +Signed-off-by: BALATON Zoltan +Message-id: 20200406204029.19559747D5D@zero.eik.bme.hu +Signed-off-by: Gerd Hoffmann + +diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c +index 42e82311eb..23a8ae0cd8 100644 +--- a/hw/display/ati_2d.c ++++ b/hw/display/ati_2d.c +@@ -53,12 +53,20 @@ void ati_2d_blt(ATIVGAState *s) + s->vga.vbe_start_addr, surface_data(ds), surface_stride(ds), + surface_bits_per_pixel(ds), + (s->regs.dp_mix & GMC_ROP3_MASK) >> 16); +- int dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? +- s->regs.dst_x : s->regs.dst_x + 1 - s->regs.dst_width); +- int dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? +- s->regs.dst_y : s->regs.dst_y + 1 - s->regs.dst_height); ++ unsigned dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? ++ s->regs.dst_x : s->regs.dst_x + 1 - s->regs.dst_width); ++ unsigned dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? ++ s->regs.dst_y : s->regs.dst_y + 1 - s->regs.dst_height); + int bpp = ati_bpp_from_datatype(s); ++ if (!bpp) { ++ qemu_log_mask(LOG_GUEST_ERROR, "Invalid bpp\n"); ++ return; ++ } + int dst_stride = DEFAULT_CNTL ? s->regs.dst_pitch : s->regs.default_pitch; ++ if (!dst_stride) { ++ qemu_log_mask(LOG_GUEST_ERROR, "Zero dest pitch\n"); ++ return; ++ } + uint8_t *dst_bits = s->vga.vram_ptr + (DEFAULT_CNTL ? + s->regs.dst_offset : s->regs.default_offset); + +@@ -82,12 +90,16 @@ void ati_2d_blt(ATIVGAState *s) + switch (s->regs.dp_mix & GMC_ROP3_MASK) { + case ROP3_SRCCOPY: + { +- int src_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? +- s->regs.src_x : s->regs.src_x + 1 - s->regs.dst_width); +- int src_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? +- s->regs.src_y : s->regs.src_y + 1 - s->regs.dst_height); ++ unsigned src_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? ++ s->regs.src_x : s->regs.src_x + 1 - s->regs.dst_width); ++ unsigned src_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? ++ s->regs.src_y : s->regs.src_y + 1 - s->regs.dst_height); + int src_stride = DEFAULT_CNTL ? + s->regs.src_pitch : s->regs.default_pitch; ++ if (!src_stride) { ++ qemu_log_mask(LOG_GUEST_ERROR, "Zero source pitch\n"); ++ return; ++ } + uint8_t *src_bits = s->vga.vram_ptr + (DEFAULT_CNTL ? + s->regs.src_offset : s->regs.default_offset); + +@@ -137,8 +149,10 @@ void ati_2d_blt(ATIVGAState *s) + dst_y * surface_stride(ds), + s->regs.dst_height * surface_stride(ds)); + } +- s->regs.dst_x += s->regs.dst_width; +- s->regs.dst_y += s->regs.dst_height; ++ s->regs.dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? ++ dst_x + s->regs.dst_width : dst_x); ++ s->regs.dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? ++ dst_y + s->regs.dst_height : dst_y); + break; + } + case ROP3_PATCOPY: +@@ -179,7 +193,8 @@ void ati_2d_blt(ATIVGAState *s) + dst_y * surface_stride(ds), + s->regs.dst_height * surface_stride(ds)); + } +- s->regs.dst_y += s->regs.dst_height; ++ s->regs.dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? ++ dst_y + s->regs.dst_height : dst_y); + break; + } + default: +-- +2.23.0 + diff --git a/ati-vga-check-mm_index-before-recursive-call-CVE-202.patch b/ati-vga-check-mm_index-before-recursive-call-CVE-202.patch new file mode 100644 index 0000000000000000000000000000000000000000..b80c9dc973015dd83e3d9c0c000dd0b15b303608 --- /dev/null +++ b/ati-vga-check-mm_index-before-recursive-call-CVE-202.patch @@ -0,0 +1,59 @@ +From 89554d2f71d4c79c5d8e804d90d74f3985d7ded5 Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit +Date: Thu, 4 Jun 2020 14:38:30 +0530 +Subject: [PATCH 3/9] ati-vga: check mm_index before recursive call + (CVE-2020-13800) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +While accessing VGA registers via ati_mm_read/write routines, +a guest may set 's->regs.mm_index' such that it leads to infinite +recursion. Check mm_index value to avoid such recursion. Log an +error message for wrong values. + +Reported-by: Ren Ding +Reported-by: Hanqing Zhao +Reported-by: Yi Ren +Message-id: 20200604090830.33885-1-ppandit@redhat.com +Suggested-by: BALATON Zoltan +Suggested-by: Philippe Mathieu-Daudé +Signed-off-by: Prasad J Pandit +Signed-off-by: Gerd Hoffmann +--- + hw/display/ati.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/hw/display/ati.c b/hw/display/ati.c +index a747c4cc98..5943040416 100644 +--- a/hw/display/ati.c ++++ b/hw/display/ati.c +@@ -261,8 +261,11 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size) + if (idx <= s->vga.vram_size - size) { + val = ldn_le_p(s->vga.vram_ptr + idx, size); + } +- } else { ++ } else if (s->regs.mm_index > MM_DATA + 3) { + val = ati_mm_read(s, s->regs.mm_index + addr - MM_DATA, size); ++ } else { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "ati_mm_read: mm_index too small: %u\n", s->regs.mm_index); + } + break; + case BIOS_0_SCRATCH ... BUS_CNTL - 1: +@@ -472,8 +475,11 @@ static void ati_mm_write(void *opaque, hwaddr addr, + if (idx <= s->vga.vram_size - size) { + stn_le_p(s->vga.vram_ptr + idx, size, data); + } +- } else { ++ } else if (s->regs.mm_index > MM_DATA + 3) { + ati_mm_write(s, s->regs.mm_index + addr - MM_DATA, data, size); ++ } else { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "ati_mm_write: mm_index too small: %u\n", s->regs.mm_index); + } + break; + case BIOS_0_SCRATCH ... BUS_CNTL - 1: +-- +2.25.1 + diff --git a/bios-tables-test-prepare-to-change-ARM-virt-ACPI-DSDT.patch b/bios-tables-test-prepare-to-change-ARM-virt-ACPI-DSDT.patch new file mode 100644 index 0000000000000000000000000000000000000000..1dc656892b5f124d3ad732aed9c31b0f71a3363b --- /dev/null +++ b/bios-tables-test-prepare-to-change-ARM-virt-ACPI-DSDT.patch @@ -0,0 +1,24 @@ +From 2892a4b1f7dfc75e06d0ce770d44a062b6334eb0 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 15 Apr 2020 17:03:54 +0800 +Subject: [PATCH] bios-tables-test: prepare to change ARM virt ACPI DSDT + +We will change ARM virt ACPI DSDT table in order to add the cpufreq device, +which use ACPI CPPC to show CPU frequency info to guest. + +Signed-off-by: Ying Fang +--- + tests/bios-tables-test-allowed-diff.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tests/bios-tables-test-allowed-diff.h b/tests/bios-tables-test-allowed-diff.h +index dfb8523c..32a401ae 100644 +--- a/tests/bios-tables-test-allowed-diff.h ++++ b/tests/bios-tables-test-allowed-diff.h +@@ -1 +1,4 @@ + /* List of comma-separated changed AML files to ignore */ ++"tests/data/acpi/virt/DSDT", ++"tests/data/acpi/virt/DSDT.memhp", ++"tests/data/acpi/virt/DSDT.numamem", +-- +2.23.0 diff --git a/block-Add-bdrv_co_get_self_request.patch b/block-Add-bdrv_co_get_self_request.patch new file mode 100644 index 0000000000000000000000000000000000000000..4972f084649f70253978ad8fb1d3842bbf741d81 --- /dev/null +++ b/block-Add-bdrv_co_get_self_request.patch @@ -0,0 +1,59 @@ +From d9b88f7e0d56feb4d7daa2506e2756fc48e975a1 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Fri, 1 Nov 2019 16:25:09 +0100 +Subject: [PATCH] block: Add bdrv_co_get_self_request() + +Cc: qemu-stable@nongnu.org +Signed-off-by: Max Reitz +Message-id: 20191101152510.11719-3-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit c28107e9e55b11cd35cf3dc2505e3e69d10dcf13) +Signed-off-by: Michael Roth +--- + block/io.c | 18 ++++++++++++++++++ + include/block/block_int.h | 1 + + 2 files changed, 19 insertions(+) + +diff --git a/block/io.c b/block/io.c +index d4ceaaa2ce..65b5102714 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -721,6 +721,24 @@ static bool is_request_serialising_and_aligned(BdrvTrackedRequest *req) + (req->bytes == req->overlap_bytes); + } + ++/** ++ * Return the tracked request on @bs for the current coroutine, or ++ * NULL if there is none. ++ */ ++BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs) ++{ ++ BdrvTrackedRequest *req; ++ Coroutine *self = qemu_coroutine_self(); ++ ++ QLIST_FOREACH(req, &bs->tracked_requests, list) { ++ if (req->co == self) { ++ return req; ++ } ++ } ++ ++ return NULL; ++} ++ + /** + * Round a region to cluster boundaries + */ +diff --git a/include/block/block_int.h b/include/block/block_int.h +index 4465b02242..05ee6b4866 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -964,6 +964,7 @@ void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent); + + bool coroutine_fn bdrv_wait_serialising_requests(BdrvTrackedRequest *self); + void bdrv_mark_request_serialising(BdrvTrackedRequest *req, uint64_t align); ++BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs); + + int get_tmp_filename(char *filename, int size); + BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, +-- +2.23.0 diff --git a/block-Make-wait-mark-serialising-requests-public.patch b/block-Make-wait-mark-serialising-requests-public.patch new file mode 100644 index 0000000000000000000000000000000000000000..162463c7769093014562846d9d7c0da4e131b5e3 --- /dev/null +++ b/block-Make-wait-mark-serialising-requests-public.patch @@ -0,0 +1,131 @@ +From 590cff8230749794ba09b38f3ea4eb6b0f2f73b5 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Fri, 1 Nov 2019 16:25:08 +0100 +Subject: [PATCH] block: Make wait/mark serialising requests public + +Make both bdrv_mark_request_serialising() and +bdrv_wait_serialising_requests() public so they can be used from block +drivers. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Max Reitz +Message-id: 20191101152510.11719-2-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 304d9d7f034ff7f5e1e66a65b7f720f63a72c57e) + Conflicts: + block/io.c +*drop context dependency on 1acc3466a2 +Signed-off-by: Michael Roth +--- + block/io.c | 24 ++++++++++++------------ + include/block/block_int.h | 3 +++ + 2 files changed, 15 insertions(+), 12 deletions(-) + +diff --git a/block/io.c b/block/io.c +index 07d2d825c3..d4ceaaa2ce 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -694,7 +694,7 @@ static void tracked_request_begin(BdrvTrackedRequest *req, + qemu_co_mutex_unlock(&bs->reqs_lock); + } + +-static void mark_request_serialising(BdrvTrackedRequest *req, uint64_t align) ++void bdrv_mark_request_serialising(BdrvTrackedRequest *req, uint64_t align) + { + int64_t overlap_offset = req->offset & ~(align - 1); + uint64_t overlap_bytes = ROUND_UP(req->offset + req->bytes, align) +@@ -784,7 +784,7 @@ void bdrv_dec_in_flight(BlockDriverState *bs) + bdrv_wakeup(bs); + } + +-static bool coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self) ++bool coroutine_fn bdrv_wait_serialising_requests(BdrvTrackedRequest *self) + { + BlockDriverState *bs = self->bs; + BdrvTrackedRequest *req; +@@ -1340,14 +1340,14 @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child, + * with each other for the same cluster. For example, in copy-on-read + * it ensures that the CoR read and write operations are atomic and + * guest writes cannot interleave between them. */ +- mark_request_serialising(req, bdrv_get_cluster_size(bs)); ++ bdrv_mark_request_serialising(req, bdrv_get_cluster_size(bs)); + } + + /* BDRV_REQ_SERIALISING is only for write operation */ + assert(!(flags & BDRV_REQ_SERIALISING)); + + if (!(flags & BDRV_REQ_NO_SERIALISING)) { +- wait_serialising_requests(req); ++ bdrv_wait_serialising_requests(req); + } + + if (flags & BDRV_REQ_COPY_ON_READ) { +@@ -1736,10 +1736,10 @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, uint64_t bytes, + assert(!(flags & ~BDRV_REQ_MASK)); + + if (flags & BDRV_REQ_SERIALISING) { +- mark_request_serialising(req, bdrv_get_cluster_size(bs)); ++ bdrv_mark_request_serialising(req, bdrv_get_cluster_size(bs)); + } + +- waited = wait_serialising_requests(req); ++ waited = bdrv_wait_serialising_requests(req); + + assert(!waited || !req->serialising || + is_request_serialising_and_aligned(req)); +@@ -1905,8 +1905,8 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child, + + padding = bdrv_init_padding(bs, offset, bytes, &pad); + if (padding) { +- mark_request_serialising(req, align); +- wait_serialising_requests(req); ++ bdrv_mark_request_serialising(req, align); ++ bdrv_wait_serialising_requests(req); + + bdrv_padding_rmw_read(child, req, &pad, true); + +@@ -1993,8 +1993,8 @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child, + } + + if (bdrv_pad_request(bs, &qiov, &offset, &bytes, &pad)) { +- mark_request_serialising(&req, align); +- wait_serialising_requests(&req); ++ bdrv_mark_request_serialising(&req, align); ++ bdrv_wait_serialising_requests(&req); + bdrv_padding_rmw_read(child, &req, &pad, false); + } + +@@ -3078,7 +3078,7 @@ static int coroutine_fn bdrv_co_copy_range_internal( + /* BDRV_REQ_SERIALISING is only for write operation */ + assert(!(read_flags & BDRV_REQ_SERIALISING)); + if (!(read_flags & BDRV_REQ_NO_SERIALISING)) { +- wait_serialising_requests(&req); ++ bdrv_wait_serialising_requests(&req); + } + + ret = src->bs->drv->bdrv_co_copy_range_from(src->bs, +@@ -3205,7 +3205,7 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, + * new area, we need to make sure that no write requests are made to it + * concurrently or they might be overwritten by preallocation. */ + if (new_bytes) { +- mark_request_serialising(&req, 1); ++ bdrv_mark_request_serialising(&req, 1); + } + if (bs->read_only) { + error_setg(errp, "Image is read-only"); +diff --git a/include/block/block_int.h b/include/block/block_int.h +index 3aa1e832a8..4465b02242 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -962,6 +962,9 @@ extern unsigned int bdrv_drain_all_count; + void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent); + void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent); + ++bool coroutine_fn bdrv_wait_serialising_requests(BdrvTrackedRequest *self); ++void bdrv_mark_request_serialising(BdrvTrackedRequest *req, uint64_t align); ++ + int get_tmp_filename(char *filename, int size); + BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, + const char *filename); +-- +2.23.0 diff --git a/block-create-Do-not-abort-if-a-block-driver-is-not-a.patch b/block-create-Do-not-abort-if-a-block-driver-is-not-a.patch new file mode 100644 index 0000000000000000000000000000000000000000..73d2b9d0e5e490c3f855304e692ed68fd4029468 --- /dev/null +++ b/block-create-Do-not-abort-if-a-block-driver-is-not-a.patch @@ -0,0 +1,95 @@ +From 088f1e8fd9e790bc5766bd43af134230abcff6dd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Thu, 12 Sep 2019 00:08:49 +0200 +Subject: [PATCH] block/create: Do not abort if a block driver is not available +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The 'blockdev-create' QMP command was introduced as experimental +feature in commit b0292b851b8, using the assert() debug call. +It got promoted to 'stable' command in 3fb588a0f2c, but the +assert call was not removed. + +Some block drivers are optional, and bdrv_find_format() might +return a NULL value, triggering the assertion. + +Stable code is not expected to abort, so return an error instead. + +This is easily reproducible when libnfs is not installed: + + ./configure + [...] + module support no + Block whitelist (rw) + Block whitelist (ro) + libiscsi support yes + libnfs support no + [...] + +Start QEMU: + + $ qemu-system-x86_64 -S -qmp unix:/tmp/qemu.qmp,server,nowait + +Send the 'blockdev-create' with the 'nfs' driver: + + $ ( cat << 'EOF' + {'execute': 'qmp_capabilities'} + {'execute': 'blockdev-create', 'arguments': {'job-id': 'x', 'options': {'size': 0, 'driver': 'nfs', 'location': {'path': '/', 'server': {'host': '::1', 'type': 'inet'}}}}, 'id': 'x'} + EOF + ) | socat STDIO UNIX:/tmp/qemu.qmp + {"QMP": {"version": {"qemu": {"micro": 50, "minor": 1, "major": 4}, "package": "v4.1.0-733-g89ea03a7dc"}, "capabilities": ["oob"]}} + {"return": {}} + +QEMU crashes: + + $ gdb qemu-system-x86_64 core + Program received signal SIGSEGV, Segmentation fault. + (gdb) bt + #0 0x00007ffff510957f in raise () at /lib64/libc.so.6 + #1 0x00007ffff50f3895 in abort () at /lib64/libc.so.6 + #2 0x00007ffff50f3769 in _nl_load_domain.cold.0 () at /lib64/libc.so.6 + #3 0x00007ffff5101a26 in .annobin_assert.c_end () at /lib64/libc.so.6 + #4 0x0000555555d7e1f1 in qmp_blockdev_create (job_id=0x555556baee40 "x", options=0x555557666610, errp=0x7fffffffc770) at block/create.c:69 + #5 0x0000555555c96b52 in qmp_marshal_blockdev_create (args=0x7fffdc003830, ret=0x7fffffffc7f8, errp=0x7fffffffc7f0) at qapi/qapi-commands-block-core.c:1314 + #6 0x0000555555deb0a0 in do_qmp_dispatch (cmds=0x55555645de70 , request=0x7fffdc005c70, allow_oob=false, errp=0x7fffffffc898) at qapi/qmp-dispatch.c:131 + #7 0x0000555555deb2a1 in qmp_dispatch (cmds=0x55555645de70 , request=0x7fffdc005c70, allow_oob=false) at qapi/qmp-dispatch.c:174 + +With this patch applied, QEMU returns a QMP error: + + {'execute': 'blockdev-create', 'arguments': {'job-id': 'x', 'options': {'size': 0, 'driver': 'nfs', 'location': {'path': '/', 'server': {'host': '::1', 'type': 'inet'}}}}, 'id': 'x'} + {"id": "x", "error": {"class": "GenericError", "desc": "Block driver 'nfs' not found or not supported"}} + +Cc: qemu-stable@nongnu.org +Reported-by: Xu Tian +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Eric Blake +Reviewed-by: John Snow +Signed-off-by: Kevin Wolf +(cherry picked from commit d90d5cae2b10efc0e8d0b3cc91ff16201853d3ba) +Signed-off-by: Michael Roth +--- + block/create.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/block/create.c b/block/create.c +index 95341219ef..de5e97bb18 100644 +--- a/block/create.c ++++ b/block/create.c +@@ -63,9 +63,13 @@ void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options, + const char *fmt = BlockdevDriver_str(options->driver); + BlockDriver *drv = bdrv_find_format(fmt); + ++ if (!drv) { ++ error_setg(errp, "Block driver '%s' not found or not supported", fmt); ++ return; ++ } ++ + /* If the driver is in the schema, we know that it exists. But it may not + * be whitelisted. */ +- assert(drv); + if (bdrv_uses_whitelist() && !bdrv_is_whitelisted(drv, false)) { + error_setg(errp, "Driver is not whitelisted"); + return; +-- +2.23.0 diff --git a/block-file-posix-Let-post-EOF-fallocate-serialize.patch b/block-file-posix-Let-post-EOF-fallocate-serialize.patch new file mode 100644 index 0000000000000000000000000000000000000000..bf7d34a3e54ffe24356a16185d1dfcaef603c455 --- /dev/null +++ b/block-file-posix-Let-post-EOF-fallocate-serialize.patch @@ -0,0 +1,69 @@ +From 7db05c8a732fbdc986a40aadf0de6dd23057d044 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Fri, 1 Nov 2019 16:25:10 +0100 +Subject: [PATCH] block/file-posix: Let post-EOF fallocate serialize + +The XFS kernel driver has a bug that may cause data corruption for qcow2 +images as of qemu commit c8bb23cbdbe32f. We can work around it by +treating post-EOF fallocates as serializing up until infinity (INT64_MAX +in practice). + +Cc: qemu-stable@nongnu.org +Signed-off-by: Max Reitz +Message-id: 20191101152510.11719-4-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 292d06b925b2787ee6f2430996b95651cae42fce) +Signed-off-by: Michael Roth +--- + block/file-posix.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/block/file-posix.c b/block/file-posix.c +index 992eb4a798..c5df61b477 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -2623,6 +2623,42 @@ raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes, + RawPosixAIOData acb; + ThreadPoolFunc *handler; + ++#ifdef CONFIG_FALLOCATE ++ if (offset + bytes > bs->total_sectors * BDRV_SECTOR_SIZE) { ++ BdrvTrackedRequest *req; ++ uint64_t end; ++ ++ /* ++ * This is a workaround for a bug in the Linux XFS driver, ++ * where writes submitted through the AIO interface will be ++ * discarded if they happen beyond a concurrently running ++ * fallocate() that increases the file length (i.e., both the ++ * write and the fallocate() happen beyond the EOF). ++ * ++ * To work around it, we extend the tracked request for this ++ * zero write until INT64_MAX (effectively infinity), and mark ++ * it as serializing. ++ * ++ * We have to enable this workaround for all filesystems and ++ * AIO modes (not just XFS with aio=native), because for ++ * remote filesystems we do not know the host configuration. ++ */ ++ ++ req = bdrv_co_get_self_request(bs); ++ assert(req); ++ assert(req->type == BDRV_TRACKED_WRITE); ++ assert(req->offset <= offset); ++ assert(req->offset + req->bytes >= offset + bytes); ++ ++ end = INT64_MAX & -(uint64_t)bs->bl.request_alignment; ++ req->bytes = end - req->offset; ++ req->overlap_bytes = req->bytes; ++ ++ bdrv_mark_request_serialising(req, bs->bl.request_alignment); ++ bdrv_wait_serialising_requests(req); ++ } ++#endif ++ + acb = (RawPosixAIOData) { + .bs = bs, + .aio_fildes = s->fd, +-- +2.23.0 diff --git a/block-file-posix-Reduce-xfsctl-use.patch b/block-file-posix-Reduce-xfsctl-use.patch new file mode 100644 index 0000000000000000000000000000000000000000..69ceb453efac39a1fcfcc26488e04a7bb8eee0df --- /dev/null +++ b/block-file-posix-Reduce-xfsctl-use.patch @@ -0,0 +1,165 @@ +From 6f1a94035b02d3676a897ea5fa4cda4c62128228 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Fri, 23 Aug 2019 15:03:40 +0200 +Subject: [PATCH] block/file-posix: Reduce xfsctl() use +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch removes xfs_write_zeroes() and xfs_discard(). Both functions +have been added just before the same feature was present through +fallocate(): + +- fallocate() has supported PUNCH_HOLE for XFS since Linux 2.6.38 (March + 2011); xfs_discard() was added in December 2010. + +- fallocate() has supported ZERO_RANGE for XFS since Linux 3.15 (June + 2014); xfs_write_zeroes() was added in November 2013. + +Nowadays, all systems that qemu runs on should support both fallocate() +features (RHEL 7's kernel does). + +xfsctl() is still useful for getting the request alignment for O_DIRECT, +so this patch does not remove our dependency on it completely. + +Note that xfs_write_zeroes() had a bug: It calls ftruncate() when the +file is shorter than the specified range (because ZERO_RANGE does not +increase the file length). ftruncate() may yield and then discard data +that parallel write requests have written past the EOF in the meantime. +Dropping the function altogether fixes the bug. + +Suggested-by: Paolo Bonzini +Fixes: 50ba5b2d994853b38fed10e0841b119da0f8b8e5 +Reported-by: Lukáš Doktor +Cc: qemu-stable@nongnu.org +Signed-off-by: Max Reitz +Reviewed-by: Stefano Garzarella +Reviewed-by: John Snow +Tested-by: Stefano Garzarella +Tested-by: John Snow +Signed-off-by: Kevin Wolf +(cherry picked from commit b2c6f23f4a9f6d8f1b648705cd46d3713b78d6a2) +Signed-off-by: Michael Roth +--- + block/file-posix.c | 77 +--------------------------------------------- + 1 file changed, 1 insertion(+), 76 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index 4479cc7ab4..992eb4a798 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -1445,59 +1445,6 @@ out: + } + } + +-#ifdef CONFIG_XFS +-static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes) +-{ +- int64_t len; +- struct xfs_flock64 fl; +- int err; +- +- len = lseek(s->fd, 0, SEEK_END); +- if (len < 0) { +- return -errno; +- } +- +- if (offset + bytes > len) { +- /* XFS_IOC_ZERO_RANGE does not increase the file length */ +- if (ftruncate(s->fd, offset + bytes) < 0) { +- return -errno; +- } +- } +- +- memset(&fl, 0, sizeof(fl)); +- fl.l_whence = SEEK_SET; +- fl.l_start = offset; +- fl.l_len = bytes; +- +- if (xfsctl(NULL, s->fd, XFS_IOC_ZERO_RANGE, &fl) < 0) { +- err = errno; +- trace_file_xfs_write_zeroes(strerror(errno)); +- return -err; +- } +- +- return 0; +-} +- +-static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes) +-{ +- struct xfs_flock64 fl; +- int err; +- +- memset(&fl, 0, sizeof(fl)); +- fl.l_whence = SEEK_SET; +- fl.l_start = offset; +- fl.l_len = bytes; +- +- if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) { +- err = errno; +- trace_file_xfs_discard(strerror(errno)); +- return -err; +- } +- +- return 0; +-} +-#endif +- + static int translate_err(int err) + { + if (err == -ENODEV || err == -ENOSYS || err == -EOPNOTSUPP || +@@ -1553,10 +1500,8 @@ static ssize_t handle_aiocb_write_zeroes_block(RawPosixAIOData *aiocb) + static int handle_aiocb_write_zeroes(void *opaque) + { + RawPosixAIOData *aiocb = opaque; +-#if defined(CONFIG_FALLOCATE) || defined(CONFIG_XFS) +- BDRVRawState *s = aiocb->bs->opaque; +-#endif + #ifdef CONFIG_FALLOCATE ++ BDRVRawState *s = aiocb->bs->opaque; + int64_t len; + #endif + +@@ -1564,12 +1509,6 @@ static int handle_aiocb_write_zeroes(void *opaque) + return handle_aiocb_write_zeroes_block(aiocb); + } + +-#ifdef CONFIG_XFS +- if (s->is_xfs) { +- return xfs_write_zeroes(s, aiocb->aio_offset, aiocb->aio_nbytes); +- } +-#endif +- + #ifdef CONFIG_FALLOCATE_ZERO_RANGE + if (s->has_write_zeroes) { + int ret = do_fallocate(s->fd, FALLOC_FL_ZERO_RANGE, +@@ -1632,14 +1571,6 @@ static int handle_aiocb_write_zeroes_unmap(void *opaque) + } + #endif + +-#ifdef CONFIG_XFS +- if (s->is_xfs) { +- /* xfs_discard() guarantees that the discarded area reads as all-zero +- * afterwards, so we can use it here. */ +- return xfs_discard(s, aiocb->aio_offset, aiocb->aio_nbytes); +- } +-#endif +- + /* If we couldn't manage to unmap while guaranteed that the area reads as + * all-zero afterwards, just write zeroes without unmapping */ + ret = handle_aiocb_write_zeroes(aiocb); +@@ -1716,12 +1647,6 @@ static int handle_aiocb_discard(void *opaque) + ret = -errno; + #endif + } else { +-#ifdef CONFIG_XFS +- if (s->is_xfs) { +- return xfs_discard(s, aiocb->aio_offset, aiocb->aio_nbytes); +- } +-#endif +- + #ifdef CONFIG_FALLOCATE_PUNCH_HOLE + ret = do_fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + aiocb->aio_offset, aiocb->aio_nbytes); +-- +2.23.0 diff --git a/block-io-refactor-padding.patch b/block-io-refactor-padding.patch new file mode 100644 index 0000000000000000000000000000000000000000..7a267147f5b5fbfa908edf342c02bd17481b3d70 --- /dev/null +++ b/block-io-refactor-padding.patch @@ -0,0 +1,481 @@ +From 2e2ad02f2cecf419eaad0df982ceb5b41170cc7e Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Tue, 4 Jun 2019 19:15:05 +0300 +Subject: [PATCH] block/io: refactor padding + +We have similar padding code in bdrv_co_pwritev, +bdrv_co_do_pwrite_zeroes and bdrv_co_preadv. Let's combine and unify +it. + +[Squashed in Vladimir's qemu-iotests 077 fix +--Stefan] + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Acked-by: Stefan Hajnoczi +Message-id: 20190604161514.262241-4-vsementsov@virtuozzo.com +Message-Id: <20190604161514.262241-4-vsementsov@virtuozzo.com> +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 7a3f542fbdfd799be4fa6f8b96dc8c1e6933fce4) +*prereq for 292d06b9 +Signed-off-by: Michael Roth +--- + block/io.c | 365 +++++++++++++++++++++++++++++------------------------ + 1 file changed, 200 insertions(+), 165 deletions(-) + +diff --git a/block/io.c b/block/io.c +index dccf687acc..07d2d825c3 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -1408,28 +1408,177 @@ out: + } + + /* +- * Handle a read request in coroutine context ++ * Request padding ++ * ++ * |<---- align ----->| |<----- align ---->| ++ * |<- head ->|<------------- bytes ------------->|<-- tail -->| ++ * | | | | | | ++ * -*----------$-------*-------- ... --------*-----$------------*--- ++ * | | | | | | ++ * | offset | | end | ++ * ALIGN_DOWN(offset) ALIGN_UP(offset) ALIGN_DOWN(end) ALIGN_UP(end) ++ * [buf ... ) [tail_buf ) ++ * ++ * @buf is an aligned allocation needed to store @head and @tail paddings. @head ++ * is placed at the beginning of @buf and @tail at the @end. ++ * ++ * @tail_buf is a pointer to sub-buffer, corresponding to align-sized chunk ++ * around tail, if tail exists. ++ * ++ * @merge_reads is true for small requests, ++ * if @buf_len == @head + bytes + @tail. In this case it is possible that both ++ * head and tail exist but @buf_len == align and @tail_buf == @buf. ++ */ ++typedef struct BdrvRequestPadding { ++ uint8_t *buf; ++ size_t buf_len; ++ uint8_t *tail_buf; ++ size_t head; ++ size_t tail; ++ bool merge_reads; ++ QEMUIOVector local_qiov; ++} BdrvRequestPadding; ++ ++static bool bdrv_init_padding(BlockDriverState *bs, ++ int64_t offset, int64_t bytes, ++ BdrvRequestPadding *pad) ++{ ++ uint64_t align = bs->bl.request_alignment; ++ size_t sum; ++ ++ memset(pad, 0, sizeof(*pad)); ++ ++ pad->head = offset & (align - 1); ++ pad->tail = ((offset + bytes) & (align - 1)); ++ if (pad->tail) { ++ pad->tail = align - pad->tail; ++ } ++ ++ if ((!pad->head && !pad->tail) || !bytes) { ++ return false; ++ } ++ ++ sum = pad->head + bytes + pad->tail; ++ pad->buf_len = (sum > align && pad->head && pad->tail) ? 2 * align : align; ++ pad->buf = qemu_blockalign(bs, pad->buf_len); ++ pad->merge_reads = sum == pad->buf_len; ++ if (pad->tail) { ++ pad->tail_buf = pad->buf + pad->buf_len - align; ++ } ++ ++ return true; ++} ++ ++static int bdrv_padding_rmw_read(BdrvChild *child, ++ BdrvTrackedRequest *req, ++ BdrvRequestPadding *pad, ++ bool zero_middle) ++{ ++ QEMUIOVector local_qiov; ++ BlockDriverState *bs = child->bs; ++ uint64_t align = bs->bl.request_alignment; ++ int ret; ++ ++ assert(req->serialising && pad->buf); ++ ++ if (pad->head || pad->merge_reads) { ++ uint64_t bytes = pad->merge_reads ? pad->buf_len : align; ++ ++ qemu_iovec_init_buf(&local_qiov, pad->buf, bytes); ++ ++ if (pad->head) { ++ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD); ++ } ++ if (pad->merge_reads && pad->tail) { ++ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); ++ } ++ ret = bdrv_aligned_preadv(child, req, req->overlap_offset, bytes, ++ align, &local_qiov, 0); ++ if (ret < 0) { ++ return ret; ++ } ++ if (pad->head) { ++ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD); ++ } ++ if (pad->merge_reads && pad->tail) { ++ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); ++ } ++ ++ if (pad->merge_reads) { ++ goto zero_mem; ++ } ++ } ++ ++ if (pad->tail) { ++ qemu_iovec_init_buf(&local_qiov, pad->tail_buf, align); ++ ++ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); ++ ret = bdrv_aligned_preadv( ++ child, req, ++ req->overlap_offset + req->overlap_bytes - align, ++ align, align, &local_qiov, 0); ++ if (ret < 0) { ++ return ret; ++ } ++ bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); ++ } ++ ++zero_mem: ++ if (zero_middle) { ++ memset(pad->buf + pad->head, 0, pad->buf_len - pad->head - pad->tail); ++ } ++ ++ return 0; ++} ++ ++static void bdrv_padding_destroy(BdrvRequestPadding *pad) ++{ ++ if (pad->buf) { ++ qemu_vfree(pad->buf); ++ qemu_iovec_destroy(&pad->local_qiov); ++ } ++} ++ ++/* ++ * bdrv_pad_request ++ * ++ * Exchange request parameters with padded request if needed. Don't include RMW ++ * read of padding, bdrv_padding_rmw_read() should be called separately if ++ * needed. ++ * ++ * All parameters except @bs are in-out: they represent original request at ++ * function call and padded (if padding needed) at function finish. ++ * ++ * Function always succeeds. + */ ++static bool bdrv_pad_request(BlockDriverState *bs, QEMUIOVector **qiov, ++ int64_t *offset, unsigned int *bytes, ++ BdrvRequestPadding *pad) ++{ ++ if (!bdrv_init_padding(bs, *offset, *bytes, pad)) { ++ return false; ++ } ++ ++ qemu_iovec_init_extended(&pad->local_qiov, pad->buf, pad->head, ++ *qiov, 0, *bytes, ++ pad->buf + pad->buf_len - pad->tail, pad->tail); ++ *bytes += pad->head + pad->tail; ++ *offset -= pad->head; ++ *qiov = &pad->local_qiov; ++ ++ return true; ++} ++ + int coroutine_fn bdrv_co_preadv(BdrvChild *child, + int64_t offset, unsigned int bytes, QEMUIOVector *qiov, + BdrvRequestFlags flags) + { + BlockDriverState *bs = child->bs; +- BlockDriver *drv = bs->drv; + BdrvTrackedRequest req; +- +- uint64_t align = bs->bl.request_alignment; +- uint8_t *head_buf = NULL; +- uint8_t *tail_buf = NULL; +- QEMUIOVector local_qiov; +- bool use_local_qiov = false; ++ BdrvRequestPadding pad; + int ret; + +- trace_bdrv_co_preadv(child->bs, offset, bytes, flags); +- +- if (!drv) { +- return -ENOMEDIUM; +- } ++ trace_bdrv_co_preadv(bs, offset, bytes, flags); + + ret = bdrv_check_byte_request(bs, offset, bytes); + if (ret < 0) { +@@ -1443,43 +1592,16 @@ int coroutine_fn bdrv_co_preadv(BdrvChild *child, + flags |= BDRV_REQ_COPY_ON_READ; + } + +- /* Align read if necessary by padding qiov */ +- if (offset & (align - 1)) { +- head_buf = qemu_blockalign(bs, align); +- qemu_iovec_init(&local_qiov, qiov->niov + 2); +- qemu_iovec_add(&local_qiov, head_buf, offset & (align - 1)); +- qemu_iovec_concat(&local_qiov, qiov, 0, qiov->size); +- use_local_qiov = true; +- +- bytes += offset & (align - 1); +- offset = offset & ~(align - 1); +- } +- +- if ((offset + bytes) & (align - 1)) { +- if (!use_local_qiov) { +- qemu_iovec_init(&local_qiov, qiov->niov + 1); +- qemu_iovec_concat(&local_qiov, qiov, 0, qiov->size); +- use_local_qiov = true; +- } +- tail_buf = qemu_blockalign(bs, align); +- qemu_iovec_add(&local_qiov, tail_buf, +- align - ((offset + bytes) & (align - 1))); +- +- bytes = ROUND_UP(bytes, align); +- } ++ bdrv_pad_request(bs, &qiov, &offset, &bytes, &pad); + + tracked_request_begin(&req, bs, offset, bytes, BDRV_TRACKED_READ); +- ret = bdrv_aligned_preadv(child, &req, offset, bytes, align, +- use_local_qiov ? &local_qiov : qiov, +- flags); ++ ret = bdrv_aligned_preadv(child, &req, offset, bytes, ++ bs->bl.request_alignment, ++ qiov, flags); + tracked_request_end(&req); + bdrv_dec_in_flight(bs); + +- if (use_local_qiov) { +- qemu_iovec_destroy(&local_qiov); +- qemu_vfree(head_buf); +- qemu_vfree(tail_buf); +- } ++ bdrv_padding_destroy(&pad); + + return ret; + } +@@ -1775,44 +1897,34 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child, + BdrvTrackedRequest *req) + { + BlockDriverState *bs = child->bs; +- uint8_t *buf = NULL; + QEMUIOVector local_qiov; + uint64_t align = bs->bl.request_alignment; +- unsigned int head_padding_bytes, tail_padding_bytes; + int ret = 0; ++ bool padding; ++ BdrvRequestPadding pad; + +- head_padding_bytes = offset & (align - 1); +- tail_padding_bytes = (align - (offset + bytes)) & (align - 1); +- +- +- assert(flags & BDRV_REQ_ZERO_WRITE); +- if (head_padding_bytes || tail_padding_bytes) { +- buf = qemu_blockalign(bs, align); +- qemu_iovec_init_buf(&local_qiov, buf, align); +- } +- if (head_padding_bytes) { +- uint64_t zero_bytes = MIN(bytes, align - head_padding_bytes); +- +- /* RMW the unaligned part before head. */ ++ padding = bdrv_init_padding(bs, offset, bytes, &pad); ++ if (padding) { + mark_request_serialising(req, align); + wait_serialising_requests(req); +- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD); +- ret = bdrv_aligned_preadv(child, req, offset & ~(align - 1), align, +- align, &local_qiov, 0); +- if (ret < 0) { +- goto fail; +- } +- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD); + +- memset(buf + head_padding_bytes, 0, zero_bytes); +- ret = bdrv_aligned_pwritev(child, req, offset & ~(align - 1), align, +- align, &local_qiov, +- flags & ~BDRV_REQ_ZERO_WRITE); +- if (ret < 0) { +- goto fail; ++ bdrv_padding_rmw_read(child, req, &pad, true); ++ ++ if (pad.head || pad.merge_reads) { ++ int64_t aligned_offset = offset & ~(align - 1); ++ int64_t write_bytes = pad.merge_reads ? pad.buf_len : align; ++ ++ qemu_iovec_init_buf(&local_qiov, pad.buf, write_bytes); ++ ret = bdrv_aligned_pwritev(child, req, aligned_offset, write_bytes, ++ align, &local_qiov, ++ flags & ~BDRV_REQ_ZERO_WRITE); ++ if (ret < 0 || pad.merge_reads) { ++ /* Error or all work is done */ ++ goto out; ++ } ++ offset += write_bytes - pad.head; ++ bytes -= write_bytes - pad.head; + } +- offset += zero_bytes; +- bytes -= zero_bytes; + } + + assert(!bytes || (offset & (align - 1)) == 0); +@@ -1822,7 +1934,7 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child, + ret = bdrv_aligned_pwritev(child, req, offset, aligned_bytes, align, + NULL, flags); + if (ret < 0) { +- goto fail; ++ goto out; + } + bytes -= aligned_bytes; + offset += aligned_bytes; +@@ -1830,26 +1942,17 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child, + + assert(!bytes || (offset & (align - 1)) == 0); + if (bytes) { +- assert(align == tail_padding_bytes + bytes); +- /* RMW the unaligned part after tail. */ +- mark_request_serialising(req, align); +- wait_serialising_requests(req); +- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); +- ret = bdrv_aligned_preadv(child, req, offset, align, +- align, &local_qiov, 0); +- if (ret < 0) { +- goto fail; +- } +- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); ++ assert(align == pad.tail + bytes); + +- memset(buf, 0, bytes); ++ qemu_iovec_init_buf(&local_qiov, pad.tail_buf, align); + ret = bdrv_aligned_pwritev(child, req, offset, align, align, + &local_qiov, flags & ~BDRV_REQ_ZERO_WRITE); + } +-fail: +- qemu_vfree(buf); +- return ret; + ++out: ++ bdrv_padding_destroy(&pad); ++ ++ return ret; + } + + /* +@@ -1862,10 +1965,7 @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child, + BlockDriverState *bs = child->bs; + BdrvTrackedRequest req; + uint64_t align = bs->bl.request_alignment; +- uint8_t *head_buf = NULL; +- uint8_t *tail_buf = NULL; +- QEMUIOVector local_qiov; +- bool use_local_qiov = false; ++ BdrvRequestPadding pad; + int ret; + + trace_bdrv_co_pwritev(child->bs, offset, bytes, flags); +@@ -1892,86 +1992,21 @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child, + goto out; + } + +- if (offset & (align - 1)) { +- QEMUIOVector head_qiov; +- ++ if (bdrv_pad_request(bs, &qiov, &offset, &bytes, &pad)) { + mark_request_serialising(&req, align); + wait_serialising_requests(&req); +- +- head_buf = qemu_blockalign(bs, align); +- qemu_iovec_init_buf(&head_qiov, head_buf, align); +- +- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD); +- ret = bdrv_aligned_preadv(child, &req, offset & ~(align - 1), align, +- align, &head_qiov, 0); +- if (ret < 0) { +- goto fail; +- } +- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD); +- +- qemu_iovec_init(&local_qiov, qiov->niov + 2); +- qemu_iovec_add(&local_qiov, head_buf, offset & (align - 1)); +- qemu_iovec_concat(&local_qiov, qiov, 0, qiov->size); +- use_local_qiov = true; +- +- bytes += offset & (align - 1); +- offset = offset & ~(align - 1); +- +- /* We have read the tail already if the request is smaller +- * than one aligned block. +- */ +- if (bytes < align) { +- qemu_iovec_add(&local_qiov, head_buf + bytes, align - bytes); +- bytes = align; +- } +- } +- +- if ((offset + bytes) & (align - 1)) { +- QEMUIOVector tail_qiov; +- size_t tail_bytes; +- bool waited; +- +- mark_request_serialising(&req, align); +- waited = wait_serialising_requests(&req); +- assert(!waited || !use_local_qiov); +- +- tail_buf = qemu_blockalign(bs, align); +- qemu_iovec_init_buf(&tail_qiov, tail_buf, align); +- +- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); +- ret = bdrv_aligned_preadv(child, &req, (offset + bytes) & ~(align - 1), +- align, align, &tail_qiov, 0); +- if (ret < 0) { +- goto fail; +- } +- bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); +- +- if (!use_local_qiov) { +- qemu_iovec_init(&local_qiov, qiov->niov + 1); +- qemu_iovec_concat(&local_qiov, qiov, 0, qiov->size); +- use_local_qiov = true; +- } +- +- tail_bytes = (offset + bytes) & (align - 1); +- qemu_iovec_add(&local_qiov, tail_buf + tail_bytes, align - tail_bytes); +- +- bytes = ROUND_UP(bytes, align); ++ bdrv_padding_rmw_read(child, &req, &pad, false); + } + + ret = bdrv_aligned_pwritev(child, &req, offset, bytes, align, +- use_local_qiov ? &local_qiov : qiov, +- flags); ++ qiov, flags); + +-fail: ++ bdrv_padding_destroy(&pad); + +- if (use_local_qiov) { +- qemu_iovec_destroy(&local_qiov); +- } +- qemu_vfree(head_buf); +- qemu_vfree(tail_buf); + out: + tracked_request_end(&req); + bdrv_dec_in_flight(bs); ++ + return ret; + } + +-- +2.23.0 diff --git a/block-nfs-tear-down-aio-before-nfs_close.patch b/block-nfs-tear-down-aio-before-nfs_close.patch new file mode 100644 index 0000000000000000000000000000000000000000..ea116d0a381c18521da88b94d3ea914f0357939d --- /dev/null +++ b/block-nfs-tear-down-aio-before-nfs_close.patch @@ -0,0 +1,41 @@ +From 0694c489cd240620fee5675e8d24c7ce02d1d67d Mon Sep 17 00:00:00 2001 +From: Peter Lieven +Date: Tue, 10 Sep 2019 17:41:09 +0200 +Subject: [PATCH] block/nfs: tear down aio before nfs_close + +nfs_close is a sync call from libnfs and has its own event +handler polling on the nfs FD. Avoid that both QEMU and libnfs +are intefering here. + +CC: qemu-stable@nongnu.org +Signed-off-by: Peter Lieven +Signed-off-by: Kevin Wolf +(cherry picked from commit 601dc6559725f7a614b6f893611e17ff0908e914) +Signed-off-by: Michael Roth +--- + block/nfs.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/block/nfs.c b/block/nfs.c +index d93241b3bb..2b7a078241 100644 +--- a/block/nfs.c ++++ b/block/nfs.c +@@ -390,12 +390,14 @@ static void nfs_attach_aio_context(BlockDriverState *bs, + static void nfs_client_close(NFSClient *client) + { + if (client->context) { ++ qemu_mutex_lock(&client->mutex); ++ aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context), ++ false, NULL, NULL, NULL, NULL); ++ qemu_mutex_unlock(&client->mutex); + if (client->fh) { + nfs_close(client->context, client->fh); + client->fh = NULL; + } +- aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context), +- false, NULL, NULL, NULL, NULL); + nfs_destroy_context(client->context); + client->context = NULL; + } +-- +2.23.0 diff --git a/block-posix-Always-allocate-the-first-block.patch b/block-posix-Always-allocate-the-first-block.patch new file mode 100644 index 0000000000000000000000000000000000000000..166d73957ce0569929276d446a1934be17cad612 --- /dev/null +++ b/block-posix-Always-allocate-the-first-block.patch @@ -0,0 +1,343 @@ +From 3d018ff3bdd8aec260254036b600cfa8d694ced4 Mon Sep 17 00:00:00 2001 +From: Nir Soffer +Date: Tue, 27 Aug 2019 04:05:27 +0300 +Subject: [PATCH] block: posix: Always allocate the first block + +When creating an image with preallocation "off" or "falloc", the first +block of the image is typically not allocated. When using Gluster +storage backed by XFS filesystem, reading this block using direct I/O +succeeds regardless of request length, fooling alignment detection. + +In this case we fallback to a safe value (4096) instead of the optimal +value (512), which may lead to unneeded data copying when aligning +requests. Allocating the first block avoids the fallback. + +Since we allocate the first block even with preallocation=off, we no +longer create images with zero disk size: + + $ ./qemu-img create -f raw test.raw 1g + Formatting 'test.raw', fmt=raw size=1073741824 + + $ ls -lhs test.raw + 4.0K -rw-r--r--. 1 nsoffer nsoffer 1.0G Aug 16 23:48 test.raw + +And converting the image requires additional cluster: + + $ ./qemu-img measure -f raw -O qcow2 test.raw + required size: 458752 + fully allocated size: 1074135040 + +When using format like vmdk with multiple files per image, we allocate +one block per file: + + $ ./qemu-img create -f vmdk -o subformat=twoGbMaxExtentFlat test.vmdk 4g + Formatting 'test.vmdk', fmt=vmdk size=4294967296 compat6=off hwversion=undefined subformat=twoGbMaxExtentFlat + + $ ls -lhs test*.vmdk + 4.0K -rw-r--r--. 1 nsoffer nsoffer 2.0G Aug 27 03:23 test-f001.vmdk + 4.0K -rw-r--r--. 1 nsoffer nsoffer 2.0G Aug 27 03:23 test-f002.vmdk + 4.0K -rw-r--r--. 1 nsoffer nsoffer 353 Aug 27 03:23 test.vmdk + +I did quick performance test for copying disks with qemu-img convert to +new raw target image to Gluster storage with sector size of 512 bytes: + + for i in $(seq 10); do + rm -f dst.raw + sleep 10 + time ./qemu-img convert -f raw -O raw -t none -T none src.raw dst.raw + done + +Here is a table comparing the total time spent: + +Type Before(s) After(s) Diff(%) +--------------------------------------- +real 530.028 469.123 -11.4 +user 17.204 10.768 -37.4 +sys 17.881 7.011 -60.7 + +We can see very clear improvement in CPU usage. + +Signed-off-by: Nir Soffer +Message-id: 20190827010528.8818-2-nsoffer@redhat.com +Reviewed-by: Max Reitz +Signed-off-by: Max Reitz + +(cherry picked from commit 3a20013fbb26d2a1bd11ef148eefdb1508783787) + +Signed-off-by: Michael Roth +--- + block/file-posix.c | 51 +++++++++++++++++++ + tests/qemu-iotests/059.out | 2 +- + tests/qemu-iotests/{150.out => 150.out.qcow2} | 0 + tests/qemu-iotests/150.out.raw | 12 +++++ + tests/qemu-iotests/175 | 19 ++++--- + tests/qemu-iotests/175.out | 8 +-- + tests/qemu-iotests/178.out.qcow2 | 4 +- + tests/qemu-iotests/221.out | 12 +++-- + tests/qemu-iotests/253.out | 12 +++-- + 9 files changed, 99 insertions(+), 21 deletions(-) + rename tests/qemu-iotests/{150.out => 150.out.qcow2} (100%) + create mode 100644 tests/qemu-iotests/150.out.raw + +diff --git a/block/file-posix.c b/block/file-posix.c +index be32dd8c51..2184aa980c 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -1674,6 +1674,43 @@ static int handle_aiocb_discard(void *opaque) + return ret; + } + ++/* ++ * Help alignment probing by allocating the first block. ++ * ++ * When reading with direct I/O from unallocated area on Gluster backed by XFS, ++ * reading succeeds regardless of request length. In this case we fallback to ++ * safe alignment which is not optimal. Allocating the first block avoids this ++ * fallback. ++ * ++ * fd may be opened with O_DIRECT, but we don't know the buffer alignment or ++ * request alignment, so we use safe values. ++ * ++ * Returns: 0 on success, -errno on failure. Since this is an optimization, ++ * caller may ignore failures. ++ */ ++static int allocate_first_block(int fd, size_t max_size) ++{ ++ size_t write_size = (max_size < MAX_BLOCKSIZE) ++ ? BDRV_SECTOR_SIZE ++ : MAX_BLOCKSIZE; ++ size_t max_align = MAX(MAX_BLOCKSIZE, getpagesize()); ++ void *buf; ++ ssize_t n; ++ int ret; ++ ++ buf = qemu_memalign(max_align, write_size); ++ memset(buf, 0, write_size); ++ ++ do { ++ n = pwrite(fd, buf, write_size, 0); ++ } while (n == -1 && errno == EINTR); ++ ++ ret = (n == -1) ? -errno : 0; ++ ++ qemu_vfree(buf); ++ return ret; ++} ++ + static int handle_aiocb_truncate(void *opaque) + { + RawPosixAIOData *aiocb = opaque; +@@ -1713,6 +1750,17 @@ static int handle_aiocb_truncate(void *opaque) + /* posix_fallocate() doesn't set errno. */ + error_setg_errno(errp, -result, + "Could not preallocate new data"); ++ } else if (current_length == 0) { ++ /* ++ * posix_fallocate() uses fallocate() if the filesystem ++ * supports it, or fallback to manually writing zeroes. If ++ * fallocate() was used, unaligned reads from the fallocated ++ * area in raw_probe_alignment() will succeed, hence we need to ++ * allocate the first block. ++ * ++ * Optimize future alignment probing; ignore failures. ++ */ ++ allocate_first_block(fd, offset); + } + } else { + result = 0; +@@ -1774,6 +1822,9 @@ static int handle_aiocb_truncate(void *opaque) + if (ftruncate(fd, offset) != 0) { + result = -errno; + error_setg_errno(errp, -result, "Could not resize file"); ++ } else if (current_length == 0 && offset > current_length) { ++ /* Optimize future alignment probing; ignore failures. */ ++ allocate_first_block(fd, offset); + } + return result; + default: +diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out +index 4fab42a28c..fe3f861f3c 100644 +--- a/tests/qemu-iotests/059.out ++++ b/tests/qemu-iotests/059.out +@@ -27,7 +27,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000 subformat=twoGbMax + image: TEST_DIR/t.vmdk + file format: vmdk + virtual size: 0.977 TiB (1073741824000 bytes) +-disk size: 16 KiB ++disk size: 1.97 MiB + Format specific information: + cid: XXXXXXXX + parent cid: XXXXXXXX +diff --git a/tests/qemu-iotests/150.out b/tests/qemu-iotests/150.out.qcow2 +similarity index 100% +rename from tests/qemu-iotests/150.out +rename to tests/qemu-iotests/150.out.qcow2 +diff --git a/tests/qemu-iotests/150.out.raw b/tests/qemu-iotests/150.out.raw +new file mode 100644 +index 0000000000..3cdc7727a5 +--- /dev/null ++++ b/tests/qemu-iotests/150.out.raw +@@ -0,0 +1,12 @@ ++QA output created by 150 ++ ++=== Mapping sparse conversion === ++ ++Offset Length File ++0 0x1000 TEST_DIR/t.IMGFMT ++ ++=== Mapping non-sparse conversion === ++ ++Offset Length File ++0 0x100000 TEST_DIR/t.IMGFMT ++*** done +diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175 +index 51e62c8276..7ba28b3c1b 100755 +--- a/tests/qemu-iotests/175 ++++ b/tests/qemu-iotests/175 +@@ -37,14 +37,16 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 + # the file size. This function hides the resulting difference in the + # stat -c '%b' output. + # Parameter 1: Number of blocks an empty file occupies +-# Parameter 2: Image size in bytes ++# Parameter 2: Minimal number of blocks in an image ++# Parameter 3: Image size in bytes + _filter_blocks() + { + extra_blocks=$1 +- img_size=$2 ++ min_blocks=$2 ++ img_size=$3 + +- sed -e "s/blocks=$extra_blocks\\(\$\\|[^0-9]\\)/nothing allocated/" \ +- -e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/everything allocated/" ++ sed -e "s/blocks=$min_blocks\\(\$\\|[^0-9]\\)/min allocation/" \ ++ -e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/max allocation/" + } + + # get standard environment, filters and checks +@@ -60,16 +62,21 @@ size=$((1 * 1024 * 1024)) + touch "$TEST_DIR/empty" + extra_blocks=$(stat -c '%b' "$TEST_DIR/empty") + ++# We always write the first byte; check how many blocks this filesystem ++# allocates to match empty image alloation. ++printf "\0" > "$TEST_DIR/empty" ++min_blocks=$(stat -c '%b' "$TEST_DIR/empty") ++ + echo + echo "== creating image with default preallocation ==" + _make_test_img $size | _filter_imgfmt +-stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size ++stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size + + for mode in off full falloc; do + echo + echo "== creating image with preallocation $mode ==" + IMGOPTS=preallocation=$mode _make_test_img $size | _filter_imgfmt +- stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size ++ stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size + done + + # success, all done +diff --git a/tests/qemu-iotests/175.out b/tests/qemu-iotests/175.out +index 6d9a5ed84e..263e521262 100644 +--- a/tests/qemu-iotests/175.out ++++ b/tests/qemu-iotests/175.out +@@ -2,17 +2,17 @@ QA output created by 175 + + == creating image with default preallocation == + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +-size=1048576, nothing allocated ++size=1048576, min allocation + + == creating image with preallocation off == + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=off +-size=1048576, nothing allocated ++size=1048576, min allocation + + == creating image with preallocation full == + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=full +-size=1048576, everything allocated ++size=1048576, max allocation + + == creating image with preallocation falloc == + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=falloc +-size=1048576, everything allocated ++size=1048576, max allocation + *** done +diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2 +index 55a8dc926f..9e7d8c44df 100644 +--- a/tests/qemu-iotests/178.out.qcow2 ++++ b/tests/qemu-iotests/178.out.qcow2 +@@ -101,7 +101,7 @@ converted image file size in bytes: 196608 + == raw input image with data (human) == + + Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824 +-required size: 393216 ++required size: 458752 + fully allocated size: 1074135040 + wrote 512/512 bytes at offset 512 + 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +@@ -257,7 +257,7 @@ converted image file size in bytes: 196608 + + Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824 + { +- "required": 393216, ++ "required": 458752, + "fully-allocated": 1074135040 + } + wrote 512/512 bytes at offset 512 +diff --git a/tests/qemu-iotests/221.out b/tests/qemu-iotests/221.out +index 9f9dd52bb0..dca024a0c3 100644 +--- a/tests/qemu-iotests/221.out ++++ b/tests/qemu-iotests/221.out +@@ -3,14 +3,18 @@ QA output created by 221 + === Check mapping of unaligned raw image === + + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65537 +-[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] +-[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] ++[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, ++{ "start": 4096, "length": 61952, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] ++[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, ++{ "start": 4096, "length": 61952, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] + wrote 1/1 bytes at offset 65536 + 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +-[{ "start": 0, "length": 65536, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, ++[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, ++{ "start": 4096, "length": 61440, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, + { "start": 65536, "length": 1, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, + { "start": 65537, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] +-[{ "start": 0, "length": 65536, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, ++[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, ++{ "start": 4096, "length": 61440, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, + { "start": 65536, "length": 1, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, + { "start": 65537, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] + *** done +diff --git a/tests/qemu-iotests/253.out b/tests/qemu-iotests/253.out +index 607c0baa0b..3d08b305d7 100644 +--- a/tests/qemu-iotests/253.out ++++ b/tests/qemu-iotests/253.out +@@ -3,12 +3,16 @@ QA output created by 253 + === Check mapping of unaligned raw image === + + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048575 +-[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] +-[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] ++[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, ++{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] ++[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, ++{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] + wrote 65535/65535 bytes at offset 983040 + 63.999 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +-[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, ++[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, ++{ "start": 4096, "length": 978944, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, + { "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] +-[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, ++[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, ++{ "start": 4096, "length": 978944, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, + { "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] + *** done +-- +2.23.0 diff --git a/block-qcow2-Fix-corruption-introduced-by-commit-8ac0.patch b/block-qcow2-Fix-corruption-introduced-by-commit-8ac0.patch new file mode 100644 index 0000000000000000000000000000000000000000..f77cc06c60dd36ccd84a5ad5c5e9748bb2126c08 --- /dev/null +++ b/block-qcow2-Fix-corruption-introduced-by-commit-8ac0.patch @@ -0,0 +1,66 @@ +From 84f22c728520792f1010074e0d5ac2ec8e2e372c Mon Sep 17 00:00:00 2001 +From: Maxim Levitsky +Date: Sun, 15 Sep 2019 23:36:53 +0300 +Subject: [PATCH] block/qcow2: Fix corruption introduced by commit 8ac0f15f335 + +This fixes subtle corruption introduced by luks threaded encryption +in commit 8ac0f15f335 + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1745922 + +The corruption happens when we do a write that + * writes to two or more unallocated clusters at once + * doesn't fully cover the first sector + * doesn't fully cover the last sector + * uses luks encryption + +In this case, when allocating the new clusters we COW both areas +prior to the write and after the write, and we encrypt them. + +The above mentioned commit accidentally made it so we encrypt the +second COW area using the physical cluster offset of the first area. + +The problem is that offset_in_cluster in do_perform_cow_encrypt +can be larger that the cluster size, thus cluster_offset +will no longer point to the start of the cluster at which encrypted +area starts. + +Next patch in this series will refactor the code to avoid all these +assumptions. + +In the bugreport that was triggered by rebasing a luks image to new, +zero filled base, which lot of such writes, and causes some files +with zero areas to contain garbage there instead. +But as described above it can happen elsewhere as well + +Signed-off-by: Maxim Levitsky +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190915203655.21638-2-mlevitsk@redhat.com +Reviewed-by: Max Reitz +Signed-off-by: Max Reitz +(cherry picked from commit 38e7d54bdc518b5a05a922467304bcace2396945) +Signed-off-by: Michael Roth +--- + block/qcow2-cluster.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c +index cc5609e27a..760564c8fb 100644 +--- a/block/qcow2-cluster.c ++++ b/block/qcow2-cluster.c +@@ -473,9 +473,10 @@ static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs, + assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0); + assert((bytes & ~BDRV_SECTOR_MASK) == 0); + assert(s->crypto); +- if (qcow2_co_encrypt(bs, cluster_offset, +- src_cluster_offset + offset_in_cluster, +- buffer, bytes) < 0) { ++ if (qcow2_co_encrypt(bs, ++ start_of_cluster(s, cluster_offset + offset_in_cluster), ++ src_cluster_offset + offset_in_cluster, ++ buffer, bytes) < 0) { + return false; + } + } +-- +2.23.0 diff --git a/block-snapshot-Restrict-set-of-snapshot-nodes.patch b/block-snapshot-Restrict-set-of-snapshot-nodes.patch new file mode 100644 index 0000000000000000000000000000000000000000..c29f30adc897f5b60bf8004b7f317b6e6257bf3a --- /dev/null +++ b/block-snapshot-Restrict-set-of-snapshot-nodes.patch @@ -0,0 +1,124 @@ +From 7a8aa6c734bb1c2927ad0cc1d10bcacb53cf4ae3 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 17 Sep 2019 12:26:23 +0200 +Subject: [PATCH] block/snapshot: Restrict set of snapshot nodes + +Nodes involved in internal snapshots were those that were returned by +bdrv_next(), inserted and not read-only. bdrv_next() in turn returns all +nodes that are either the root node of a BlockBackend or monitor-owned +nodes. + +With the typical -drive use, this worked well enough. However, in the +typical -blockdev case, the user defines one node per option, making all +nodes monitor-owned nodes. This includes protocol nodes etc. which often +are not snapshottable, so "savevm" only returns an error. + +Change the conditions so that internal snapshot still include all nodes +that have a BlockBackend attached (we definitely want to snapshot +anything attached to a guest device and probably also the built-in NBD +server; snapshotting block job BlockBackends is more of an accident, but +a preexisting one), but other monitor-owned nodes are only included if +they have no parents. + +This makes internal snapshots usable again with typical -blockdev +configurations. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Reviewed-by: Peter Krempa +Tested-by: Peter Krempa +(cherry picked from commit 05f4aced658a02b02d3e89a6c7a2281008fcf26c) +Signed-off-by: Michael Roth +--- + block/snapshot.c | 26 +++++++++++++++++++------- + 1 file changed, 19 insertions(+), 7 deletions(-) + +diff --git a/block/snapshot.c b/block/snapshot.c +index f2f48f926a..8081616ae9 100644 +--- a/block/snapshot.c ++++ b/block/snapshot.c +@@ -31,6 +31,7 @@ + #include "qapi/qmp/qerror.h" + #include "qapi/qmp/qstring.h" + #include "qemu/option.h" ++#include "sysemu/block-backend.h" + + QemuOptsList internal_snapshot_opts = { + .name = "snapshot", +@@ -384,6 +385,16 @@ int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs, + return ret; + } + ++static bool bdrv_all_snapshots_includes_bs(BlockDriverState *bs) ++{ ++ if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { ++ return false; ++ } ++ ++ /* Include all nodes that are either in use by a BlockBackend, or that ++ * aren't attached to any node, but owned by the monitor. */ ++ return bdrv_has_blk(bs) || QLIST_EMPTY(&bs->parents); ++} + + /* Group operations. All block drivers are involved. + * These functions will properly handle dataplane (take aio_context_acquire +@@ -399,7 +410,7 @@ bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs) + AioContext *ctx = bdrv_get_aio_context(bs); + + aio_context_acquire(ctx); +- if (bdrv_is_inserted(bs) && !bdrv_is_read_only(bs)) { ++ if (bdrv_all_snapshots_includes_bs(bs)) { + ok = bdrv_can_snapshot(bs); + } + aio_context_release(ctx); +@@ -426,8 +437,9 @@ int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bad_bs, + AioContext *ctx = bdrv_get_aio_context(bs); + + aio_context_acquire(ctx); +- if (bdrv_can_snapshot(bs) && +- bdrv_snapshot_find(bs, snapshot, name) >= 0) { ++ if (bdrv_all_snapshots_includes_bs(bs) && ++ bdrv_snapshot_find(bs, snapshot, name) >= 0) ++ { + ret = bdrv_snapshot_delete(bs, snapshot->id_str, + snapshot->name, err); + } +@@ -455,7 +467,7 @@ int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bad_bs, + AioContext *ctx = bdrv_get_aio_context(bs); + + aio_context_acquire(ctx); +- if (bdrv_can_snapshot(bs)) { ++ if (bdrv_all_snapshots_includes_bs(bs)) { + ret = bdrv_snapshot_goto(bs, name, errp); + } + aio_context_release(ctx); +@@ -481,7 +493,7 @@ int bdrv_all_find_snapshot(const char *name, BlockDriverState **first_bad_bs) + AioContext *ctx = bdrv_get_aio_context(bs); + + aio_context_acquire(ctx); +- if (bdrv_can_snapshot(bs)) { ++ if (bdrv_all_snapshots_includes_bs(bs)) { + err = bdrv_snapshot_find(bs, &sn, name); + } + aio_context_release(ctx); +@@ -512,7 +524,7 @@ int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn, + if (bs == vm_state_bs) { + sn->vm_state_size = vm_state_size; + err = bdrv_snapshot_create(bs, sn); +- } else if (bdrv_can_snapshot(bs)) { ++ } else if (bdrv_all_snapshots_includes_bs(bs)) { + sn->vm_state_size = 0; + err = bdrv_snapshot_create(bs, sn); + } +@@ -538,7 +550,7 @@ BlockDriverState *bdrv_all_find_vmstate_bs(void) + bool found; + + aio_context_acquire(ctx); +- found = bdrv_can_snapshot(bs); ++ found = bdrv_all_snapshots_includes_bs(bs) && bdrv_can_snapshot(bs); + aio_context_release(ctx); + + if (found) { +-- +2.23.0 diff --git a/blockjob-update-nodes-head-while-removing-all-bdrv.patch b/blockjob-update-nodes-head-while-removing-all-bdrv.patch new file mode 100644 index 0000000000000000000000000000000000000000..36cedc77f7d38b124263a6f5d09e5f1dc97de5b8 --- /dev/null +++ b/blockjob-update-nodes-head-while-removing-all-bdrv.patch @@ -0,0 +1,61 @@ +From 86b0f4022bb43b16979ba5300e8d40a1e6d44b79 Mon Sep 17 00:00:00 2001 +From: Sergio Lopez +Date: Wed, 11 Sep 2019 12:03:16 +0200 +Subject: [PATCH] blockjob: update nodes head while removing all bdrv + +block_job_remove_all_bdrv() iterates through job->nodes, calling +bdrv_root_unref_child() for each entry. The call to the latter may +reach child_job_[can_]set_aio_ctx(), which will also attempt to +traverse job->nodes, potentially finding entries that where freed +on previous iterations. + +To avoid this situation, update job->nodes head on each iteration to +ensure that already freed entries are no longer linked to the list. + +RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1746631 +Signed-off-by: Sergio Lopez +Cc: qemu-stable@nongnu.org +Signed-off-by: Max Reitz +Message-id: 20190911100316.32282-1-mreitz@redhat.com +Reviewed-by: Sergio Lopez +Signed-off-by: Max Reitz +(cherry picked from commit d876bf676f5e7c6aa9ac64555e48cba8734ecb2f) +Signed-off-by: Michael Roth +--- + blockjob.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/blockjob.c b/blockjob.c +index 20b7f557da..74abb97bfd 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -186,14 +186,23 @@ static const BdrvChildRole child_job = { + + void block_job_remove_all_bdrv(BlockJob *job) + { +- GSList *l; +- for (l = job->nodes; l; l = l->next) { ++ /* ++ * bdrv_root_unref_child() may reach child_job_[can_]set_aio_ctx(), ++ * which will also traverse job->nodes, so consume the list one by ++ * one to make sure that such a concurrent access does not attempt ++ * to process an already freed BdrvChild. ++ */ ++ while (job->nodes) { ++ GSList *l = job->nodes; + BdrvChild *c = l->data; ++ ++ job->nodes = l->next; ++ + bdrv_op_unblock_all(c->bs, job->blocker); + bdrv_root_unref_child(c); ++ ++ g_slist_free_1(l); + } +- g_slist_free(job->nodes); +- job->nodes = NULL; + } + + bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs) +-- +2.23.0 diff --git a/bt-use-size_t-type-for-length-parameters-instead-of-.patch b/bt-use-size_t-type-for-length-parameters-instead-of-.patch new file mode 100644 index 0000000000000000000000000000000000000000..2005979aec4f4401b512bd0ea72d6c12493f5ea1 --- /dev/null +++ b/bt-use-size_t-type-for-length-parameters-instead-of-.patch @@ -0,0 +1,794 @@ +From f9ab92373813cfccd31f29c0d963232f65cb5f88 Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit +Date: Fri, 22 May 2020 12:22:26 +0800 +Subject: [PATCH] bt: use size_t type for length parameters instead of int + +From: Prasad J Pandit + +The length parameter values are not negative, thus use an unsigned +type 'size_t' for them. Many routines pass 'len' values to memcpy(3) +calls. If it was negative, it could lead to memory corruption issues. +Add check to avoid it. + +Reported-by: Arash TC +Signed-off-by: Prasad J Pandit + +diff --git a/bt-host.c b/bt-host.c +index 2f8f631..b73a44d 100644 +--- a/bt-host.c ++++ b/bt-host.c +@@ -43,7 +43,7 @@ struct bt_host_hci_s { + }; + + static void bt_host_send(struct HCIInfo *hci, +- int type, const uint8_t *data, int len) ++ int type, const uint8_t *data, size_t len) + { + struct bt_host_hci_s *s = (struct bt_host_hci_s *) hci; + uint8_t pkt = type; +@@ -63,17 +63,17 @@ static void bt_host_send(struct HCIInfo *hci, + } + } + +-static void bt_host_cmd(struct HCIInfo *hci, const uint8_t *data, int len) ++static void bt_host_cmd(struct HCIInfo *hci, const uint8_t *data, size_t len) + { + bt_host_send(hci, HCI_COMMAND_PKT, data, len); + } + +-static void bt_host_acl(struct HCIInfo *hci, const uint8_t *data, int len) ++static void bt_host_acl(struct HCIInfo *hci, const uint8_t *data, size_t len) + { + bt_host_send(hci, HCI_ACLDATA_PKT, data, len); + } + +-static void bt_host_sco(struct HCIInfo *hci, const uint8_t *data, int len) ++static void bt_host_sco(struct HCIInfo *hci, const uint8_t *data, size_t len) + { + bt_host_send(hci, HCI_SCODATA_PKT, data, len); + } +diff --git a/bt-vhci.c b/bt-vhci.c +index 886e146..32ef1c5 100644 +--- a/bt-vhci.c ++++ b/bt-vhci.c +@@ -89,7 +89,7 @@ static void vhci_read(void *opaque) + } + + static void vhci_host_send(void *opaque, +- int type, const uint8_t *data, int len) ++ int type, const uint8_t *data, size_t len) + { + struct bt_vhci_s *s = (struct bt_vhci_s *) opaque; + #if 0 +@@ -112,6 +112,7 @@ static void vhci_host_send(void *opaque, + static uint8_t buf[4096]; + + buf[0] = type; ++ assert(len < sizeof(buf)); + memcpy(buf + 1, data, len); + + while (write(s->fd, buf, len + 1) < 0) +@@ -124,13 +125,13 @@ static void vhci_host_send(void *opaque, + } + + static void vhci_out_hci_packet_event(void *opaque, +- const uint8_t *data, int len) ++ const uint8_t *data, size_t len) + { + vhci_host_send(opaque, HCI_EVENT_PKT, data, len); + } + + static void vhci_out_hci_packet_acl(void *opaque, +- const uint8_t *data, int len) ++ const uint8_t *data, size_t len) + { + vhci_host_send(opaque, HCI_ACLDATA_PKT, data, len); + } +diff --git a/hw/bt/core.c b/hw/bt/core.c +index dfb196e..f548b3d 100644 +--- a/hw/bt/core.c ++++ b/hw/bt/core.c +@@ -44,7 +44,7 @@ static void bt_dummy_lmp_disconnect_master(struct bt_link_s *link) + } + + static void bt_dummy_lmp_acl_resp(struct bt_link_s *link, +- const uint8_t *data, int start, int len) ++ const uint8_t *data, int start, size_t len) + { + error_report("%s: stray ACL response PDU, fixme", __func__); + exit(-1); +diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c +index 3d60654..f7a74c0 100644 +--- a/hw/bt/hci-csr.c ++++ b/hw/bt/hci-csr.c +@@ -103,7 +103,7 @@ static inline void csrhci_fifo_wake(struct csrhci_s *s) + } + + #define csrhci_out_packetz(s, len) memset(csrhci_out_packet(s, len), 0, len) +-static uint8_t *csrhci_out_packet(struct csrhci_s *s, int len) ++static uint8_t *csrhci_out_packet(struct csrhci_s *s, size_t len) + { + int off = s->out_start + s->out_len; + +@@ -112,14 +112,14 @@ static uint8_t *csrhci_out_packet(struct csrhci_s *s, int len) + + if (off < FIFO_LEN) { + if (off + len > FIFO_LEN && (s->out_size = off + len) > FIFO_LEN * 2) { +- error_report("%s: can't alloc %i bytes", __func__, len); ++ error_report("%s: can't alloc %zu bytes", __func__, len); + exit(-1); + } + return s->outfifo + off; + } + + if (s->out_len > s->out_size) { +- error_report("%s: can't alloc %i bytes", __func__, len); ++ error_report("%s: can't alloc %zu bytes", __func__, len); + exit(-1); + } + +@@ -127,7 +127,7 @@ static uint8_t *csrhci_out_packet(struct csrhci_s *s, int len) + } + + static inline uint8_t *csrhci_out_packet_csr(struct csrhci_s *s, +- int type, int len) ++ int type, size_t len) + { + uint8_t *ret = csrhci_out_packetz(s, len + 2); + +@@ -138,7 +138,7 @@ static inline uint8_t *csrhci_out_packet_csr(struct csrhci_s *s, + } + + static inline uint8_t *csrhci_out_packet_event(struct csrhci_s *s, +- int evt, int len) ++ int evt, size_t len) + { + uint8_t *ret = csrhci_out_packetz(s, + len + 1 + sizeof(struct hci_event_hdr)); +@@ -151,7 +151,7 @@ static inline uint8_t *csrhci_out_packet_event(struct csrhci_s *s, + } + + static void csrhci_in_packet_vendor(struct csrhci_s *s, int ocf, +- uint8_t *data, int len) ++ uint8_t *data, size_t len) + { + int offset; + uint8_t *rpkt; +@@ -320,18 +320,18 @@ static int csrhci_write(struct Chardev *chr, + struct csrhci_s *s = (struct csrhci_s *)chr; + int total = 0; + +- if (!s->enable) ++ if (!s->enable || len <= 0) + return 0; + + for (;;) { + int cnt = MIN(len, s->in_needed - s->in_len); +- if (cnt) { +- memcpy(s->inpkt + s->in_len, buf, cnt); +- s->in_len += cnt; +- buf += cnt; +- len -= cnt; +- total += cnt; +- } ++ assert(cnt > 0); ++ ++ memcpy(s->inpkt + s->in_len, buf, cnt); ++ s->in_len += cnt; ++ buf += cnt; ++ len -= cnt; ++ total += cnt; + + if (s->in_len < s->in_needed) { + break; +@@ -363,7 +363,7 @@ static int csrhci_write(struct Chardev *chr, + } + + static void csrhci_out_hci_packet_event(void *opaque, +- const uint8_t *data, int len) ++ const uint8_t *data, size_t len) + { + struct csrhci_s *s = (struct csrhci_s *) opaque; + uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1); /* Align */ +@@ -375,7 +375,7 @@ static void csrhci_out_hci_packet_event(void *opaque, + } + + static void csrhci_out_hci_packet_acl(void *opaque, +- const uint8_t *data, int len) ++ const uint8_t *data, size_t len) + { + struct csrhci_s *s = (struct csrhci_s *) opaque; + uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1); /* Align */ +diff --git a/hw/bt/hci.c b/hw/bt/hci.c +index c7958f6..9c4f957 100644 +--- a/hw/bt/hci.c ++++ b/hw/bt/hci.c +@@ -31,7 +31,7 @@ + + struct bt_hci_s { + uint8_t *(*evt_packet)(void *opaque); +- void (*evt_submit)(void *opaque, int len); ++ void (*evt_submit)(void *opaque, size_t len); + void *opaque; + uint8_t evt_buf[256]; + +@@ -61,7 +61,7 @@ struct bt_hci_s { + struct bt_hci_master_link_s { + struct bt_link_s *link; + void (*lmp_acl_data)(struct bt_link_s *link, +- const uint8_t *data, int start, int len); ++ const uint8_t *data, int start, size_t len); + QEMUTimer *acl_mode_timer; + } handle[HCI_HANDLES_MAX]; + uint32_t role_bmp; +@@ -433,7 +433,7 @@ static const uint8_t bt_event_reserved_mask[8] = { + }; + + +-static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, int len) ++static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, size_t len) + { + } + +@@ -451,13 +451,13 @@ struct HCIInfo null_hci = { + + + static inline uint8_t *bt_hci_event_start(struct bt_hci_s *hci, +- int evt, int len) ++ int evt, size_t len) + { + uint8_t *packet, mask; + int mask_byte; + + if (len > 255) { +- error_report("%s: HCI event params too long (%ib)", __func__, len); ++ error_report("%s: HCI event params too long (%zub)", __func__, len); + exit(-1); + } + +@@ -474,7 +474,7 @@ static inline uint8_t *bt_hci_event_start(struct bt_hci_s *hci, + } + + static inline void bt_hci_event(struct bt_hci_s *hci, int evt, +- void *params, int len) ++ void *params, size_t len) + { + uint8_t *packet = bt_hci_event_start(hci, evt, len); + +@@ -499,7 +499,7 @@ static inline void bt_hci_event_status(struct bt_hci_s *hci, int status) + } + + static inline void bt_hci_event_complete(struct bt_hci_s *hci, +- void *ret, int len) ++ void *ret, size_t len) + { + uint8_t *packet = bt_hci_event_start(hci, EVT_CMD_COMPLETE, + len + EVT_CMD_COMPLETE_SIZE); +@@ -1476,7 +1476,7 @@ static inline void bt_hci_event_num_comp_pkts(struct bt_hci_s *hci, + } + + static void bt_submit_hci(struct HCIInfo *info, +- const uint8_t *data, int length) ++ const uint8_t *data, size_t length) + { + struct bt_hci_s *hci = hci_from_info(info); + uint16_t cmd; +@@ -1970,7 +1970,7 @@ static void bt_submit_hci(struct HCIInfo *info, + break; + + short_hci: +- error_report("%s: HCI packet too short (%iB)", __func__, length); ++ error_report("%s: HCI packet too short (%zuB)", __func__, length); + bt_hci_event_status(hci, HCI_INVALID_PARAMETERS); + break; + } +@@ -1981,7 +1981,7 @@ static void bt_submit_hci(struct HCIInfo *info, + * know that a packet contained the last fragment of the SDU when the next + * SDU starts. */ + static inline void bt_hci_lmp_acl_data(struct bt_hci_s *hci, uint16_t handle, +- const uint8_t *data, int start, int len) ++ const uint8_t *data, int start, size_t len) + { + struct hci_acl_hdr *pkt = (void *) hci->acl_buf; + +@@ -1989,7 +1989,7 @@ static inline void bt_hci_lmp_acl_data(struct bt_hci_s *hci, uint16_t handle, + /* TODO: avoid memcpy'ing */ + + if (len + HCI_ACL_HDR_SIZE > sizeof(hci->acl_buf)) { +- error_report("%s: can't take ACL packets %i bytes long", ++ error_report("%s: can't take ACL packets %zu bytes long", + __func__, len); + return; + } +@@ -2003,7 +2003,7 @@ static inline void bt_hci_lmp_acl_data(struct bt_hci_s *hci, uint16_t handle, + } + + static void bt_hci_lmp_acl_data_slave(struct bt_link_s *btlink, +- const uint8_t *data, int start, int len) ++ const uint8_t *data, int start, size_t len) + { + struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink; + +@@ -2012,14 +2012,14 @@ static void bt_hci_lmp_acl_data_slave(struct bt_link_s *btlink, + } + + static void bt_hci_lmp_acl_data_host(struct bt_link_s *link, +- const uint8_t *data, int start, int len) ++ const uint8_t *data, int start, size_t len) + { + bt_hci_lmp_acl_data(hci_from_device(link->host), + link->handle, data, start, len); + } + + static void bt_submit_acl(struct HCIInfo *info, +- const uint8_t *data, int length) ++ const uint8_t *data, size_t length) + { + struct bt_hci_s *hci = hci_from_info(info); + uint16_t handle; +@@ -2027,7 +2027,7 @@ static void bt_submit_acl(struct HCIInfo *info, + struct bt_link_s *link; + + if (length < HCI_ACL_HDR_SIZE) { +- error_report("%s: ACL packet too short (%iB)", __func__, length); ++ error_report("%s: ACL packet too short (%zuB)", __func__, length); + return; + } + +@@ -2045,7 +2045,7 @@ static void bt_submit_acl(struct HCIInfo *info, + handle &= ~HCI_HANDLE_OFFSET; + + if (datalen > length) { +- error_report("%s: ACL packet too short (%iB < %iB)", ++ error_report("%s: ACL packet too short (%zuB < %iB)", + __func__, length, datalen); + return; + } +@@ -2087,7 +2087,7 @@ static void bt_submit_acl(struct HCIInfo *info, + } + + static void bt_submit_sco(struct HCIInfo *info, +- const uint8_t *data, int length) ++ const uint8_t *data, size_t length) + { + struct bt_hci_s *hci = hci_from_info(info); + uint16_t handle; +@@ -2106,7 +2106,7 @@ static void bt_submit_sco(struct HCIInfo *info, + } + + if (datalen > length) { +- error_report("%s: SCO packet too short (%iB < %iB)", ++ error_report("%s: SCO packet too short (%zuB < %iB)", + __func__, length, datalen); + return; + } +@@ -2127,7 +2127,7 @@ static uint8_t *bt_hci_evt_packet(void *opaque) + return s->evt_buf; + } + +-static void bt_hci_evt_submit(void *opaque, int len) ++static void bt_hci_evt_submit(void *opaque, size_t len) + { + /* TODO: notify upper layer */ + struct bt_hci_s *s = opaque; +diff --git a/hw/bt/hid.c b/hw/bt/hid.c +index 066ca99..fe15434 100644 +--- a/hw/bt/hid.c ++++ b/hw/bt/hid.c +@@ -95,7 +95,7 @@ struct bt_hid_device_s { + int data_type; + int intr_state; + struct { +- int len; ++ size_t len; + uint8_t buffer[1024]; + } dataother, datain, dataout, feature, intrdataout; + enum { +@@ -168,7 +168,7 @@ static void bt_hid_disconnect(struct bt_hid_device_s *s) + } + + static void bt_hid_send_data(struct bt_l2cap_conn_params_s *ch, int type, +- const uint8_t *data, int len) ++ const uint8_t *data, size_t len) + { + uint8_t *pkt, hdr = (BT_DATA << 4) | type; + int plen; +@@ -189,7 +189,7 @@ static void bt_hid_send_data(struct bt_l2cap_conn_params_s *ch, int type, + } + + static void bt_hid_control_transaction(struct bt_hid_device_s *s, +- const uint8_t *data, int len) ++ const uint8_t *data, size_t len) + { + uint8_t type, parameter; + int rlen, ret = -1; +@@ -361,7 +361,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s, + bt_hid_send_handshake(s, ret); + } + +-static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len) ++static void bt_hid_control_sdu(void *opaque, const uint8_t *data, size_t len) + { + struct bt_hid_device_s *hid = opaque; + +@@ -387,7 +387,7 @@ static void bt_hid_datain(HIDState *hs) + hid->datain.buffer, hid->datain.len); + } + +-static void bt_hid_interrupt_sdu(void *opaque, const uint8_t *data, int len) ++static void bt_hid_interrupt_sdu(void *opaque, const uint8_t *data, size_t len) + { + struct bt_hid_device_s *hid = opaque; + +diff --git a/hw/bt/l2cap.c b/hw/bt/l2cap.c +index d67098a..2f70a03 100644 +--- a/hw/bt/l2cap.c ++++ b/hw/bt/l2cap.c +@@ -31,10 +31,10 @@ struct l2cap_instance_s { + int role; + + uint8_t frame_in[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4))); +- int frame_in_len; ++ uint32_t frame_in_len; + + uint8_t frame_out[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4))); +- int frame_out_len; ++ uint32_t frame_out_len; + + /* Signalling channel timers. They exist per-request but we can make + * sure we have no more than one outstanding request at any time. */ +@@ -48,7 +48,7 @@ struct l2cap_instance_s { + struct bt_l2cap_conn_params_s params; + + void (*frame_in)(struct l2cap_chan_s *chan, uint16_t cid, +- const l2cap_hdr *hdr, int len); ++ const l2cap_hdr *hdr, size_t len); + int mps; + int min_mtu; + +@@ -67,7 +67,7 @@ struct l2cap_instance_s { + + /* Only flow-controlled, connection-oriented channels */ + uint8_t sdu[65536]; /* TODO: dynamically allocate */ +- int len_cur, len_total; ++ uint32_t len_cur, len_total; + int rexmit; + int monitor_timeout; + QEMUTimer *monitor_timer; +@@ -139,7 +139,7 @@ static const uint16_t l2cap_fcs16_table[256] = { + 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040, + }; + +-static uint16_t l2cap_fcs16(const uint8_t *message, int len) ++static uint16_t l2cap_fcs16(const uint8_t *message, size_t len) + { + uint16_t fcs = 0x0000; + +@@ -185,7 +185,7 @@ static void l2cap_monitor_timer_update(struct l2cap_chan_s *ch) + } + + static void l2cap_command_reject(struct l2cap_instance_s *l2cap, int id, +- uint16_t reason, const void *data, int plen) ++ uint16_t reason, const void *data, size_t plen) + { + uint8_t *pkt; + l2cap_cmd_hdr *hdr; +@@ -246,7 +246,7 @@ static void l2cap_connection_response(struct l2cap_instance_s *l2cap, + } + + static void l2cap_configuration_request(struct l2cap_instance_s *l2cap, +- int dcid, int flag, const uint8_t *data, int len) ++ int dcid, int flag, const uint8_t *data, size_t len) + { + uint8_t *pkt; + l2cap_cmd_hdr *hdr; +@@ -274,7 +274,7 @@ static void l2cap_configuration_request(struct l2cap_instance_s *l2cap, + } + + static void l2cap_configuration_response(struct l2cap_instance_s *l2cap, +- int scid, int flag, int result, const uint8_t *data, int len) ++ int scid, int flag, int result, const uint8_t *data, size_t len) + { + uint8_t *pkt; + l2cap_cmd_hdr *hdr; +@@ -321,7 +321,7 @@ static void l2cap_disconnection_response(struct l2cap_instance_s *l2cap, + } + + static void l2cap_echo_response(struct l2cap_instance_s *l2cap, +- const uint8_t *data, int len) ++ const uint8_t *data, size_t len) + { + uint8_t *pkt; + l2cap_cmd_hdr *hdr; +@@ -342,7 +342,7 @@ static void l2cap_echo_response(struct l2cap_instance_s *l2cap, + } + + static void l2cap_info_response(struct l2cap_instance_s *l2cap, int type, +- int result, const uint8_t *data, int len) ++ int result, const uint8_t *data, size_t len) + { + uint8_t *pkt; + l2cap_cmd_hdr *hdr; +@@ -365,16 +365,18 @@ static void l2cap_info_response(struct l2cap_instance_s *l2cap, int type, + l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params); + } + +-static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len); ++static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, ++ size_t len); + static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms); + #if 0 +-static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len); ++static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, ++ size_t len); + static void l2cap_iframe_submit(struct bt_l2cap_conn_params_s *parm); + #endif + static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid, +- const l2cap_hdr *hdr, int len); ++ const l2cap_hdr *hdr, size_t len); + static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid, +- const l2cap_hdr *hdr, int len); ++ const l2cap_hdr *hdr, size_t len); + + static int l2cap_cid_new(struct l2cap_instance_s *l2cap) + { +@@ -498,7 +500,7 @@ static void l2cap_channel_config_req_event(struct l2cap_instance_s *l2cap, + + static int l2cap_channel_config(struct l2cap_instance_s *l2cap, + struct l2cap_chan_s *ch, int flag, +- const uint8_t *data, int len) ++ const uint8_t *data, size_t len) + { + l2cap_conf_opt *opt; + l2cap_conf_opt_qos *qos; +@@ -683,7 +685,7 @@ static int l2cap_channel_config(struct l2cap_instance_s *l2cap, + } + + static void l2cap_channel_config_req_msg(struct l2cap_instance_s *l2cap, +- int flag, int cid, const uint8_t *data, int len) ++ int flag, int cid, const uint8_t *data, size_t len) + { + struct l2cap_chan_s *ch; + +@@ -715,7 +717,7 @@ static void l2cap_channel_config_req_msg(struct l2cap_instance_s *l2cap, + } + + static int l2cap_channel_config_rsp_msg(struct l2cap_instance_s *l2cap, +- int result, int flag, int cid, const uint8_t *data, int len) ++ int result, int flag, int cid, const uint8_t *data, size_t len) + { + struct l2cap_chan_s *ch; + +@@ -783,7 +785,7 @@ static void l2cap_info(struct l2cap_instance_s *l2cap, int type) + } + + static void l2cap_command(struct l2cap_instance_s *l2cap, int code, int id, +- const uint8_t *params, int len) ++ const uint8_t *params, size_t len) + { + int err; + +@@ -938,7 +940,7 @@ static void l2cap_rexmit_enable(struct l2cap_chan_s *ch, int enable) + } + + /* Command frame SDU */ +-static void l2cap_cframe_in(void *opaque, const uint8_t *data, int len) ++static void l2cap_cframe_in(void *opaque, const uint8_t *data, size_t len) + { + struct l2cap_instance_s *l2cap = opaque; + const l2cap_cmd_hdr *hdr; +@@ -966,7 +968,7 @@ static void l2cap_cframe_in(void *opaque, const uint8_t *data, int len) + } + + /* Group frame SDU */ +-static void l2cap_gframe_in(void *opaque, const uint8_t *data, int len) ++static void l2cap_gframe_in(void *opaque, const uint8_t *data, size_t len) + { + } + +@@ -977,7 +979,7 @@ static void l2cap_sframe_in(struct l2cap_chan_s *ch, uint16_t ctrl) + + /* Basic L2CAP mode Information frame */ + static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid, +- const l2cap_hdr *hdr, int len) ++ const l2cap_hdr *hdr, size_t len) + { + /* We have a full SDU, no further processing */ + ch->params.sdu_in(ch->params.opaque, hdr->data, len); +@@ -985,7 +987,7 @@ static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid, + + /* Flow Control and Retransmission mode frame */ + static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid, +- const l2cap_hdr *hdr, int len) ++ const l2cap_hdr *hdr, size_t len) + { + uint16_t fcs = lduw_le_p(hdr->data + len - 2); + +@@ -1076,7 +1078,7 @@ static void l2cap_frame_in(struct l2cap_instance_s *l2cap, + + /* "Recombination" */ + static void l2cap_pdu_in(struct l2cap_instance_s *l2cap, +- const uint8_t *data, int len) ++ const uint8_t *data, size_t len) + { + const l2cap_hdr *hdr = (void *) l2cap->frame_in; + +@@ -1123,7 +1125,7 @@ static inline void l2cap_pdu_submit(struct l2cap_instance_s *l2cap) + (l2cap->link, l2cap->frame_out, 1, l2cap->frame_out_len); + } + +-static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len) ++static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, size_t len) + { + struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm; + +@@ -1146,7 +1148,7 @@ static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms) + + #if 0 + /* Stub: Only used if an emulated device requests outgoing flow control */ +-static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len) ++static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, size_t len) + { + struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm; + +@@ -1291,7 +1293,7 @@ static void l2cap_lmp_disconnect_slave(struct bt_link_s *link) + } + + static void l2cap_lmp_acl_data_slave(struct bt_link_s *link, +- const uint8_t *data, int start, int len) ++ const uint8_t *data, int start, size_t len) + { + struct slave_l2cap_instance_s *l2cap = + (struct slave_l2cap_instance_s *) link; +@@ -1304,7 +1306,7 @@ static void l2cap_lmp_acl_data_slave(struct bt_link_s *link, + + /* Stub */ + static void l2cap_lmp_acl_data_host(struct bt_link_s *link, +- const uint8_t *data, int start, int len) ++ const uint8_t *data, int start, size_t len) + { + struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host; + struct l2cap_instance_s *l2cap = +diff --git a/hw/bt/sdp.c b/hw/bt/sdp.c +index 2860d76..6bfb174 100644 +--- a/hw/bt/sdp.c ++++ b/hw/bt/sdp.c +@@ -496,7 +496,7 @@ static ssize_t sdp_svc_search_attr_get(struct bt_l2cap_sdp_state_s *sdp, + return end + 2; + } + +-static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len) ++static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, size_t len) + { + struct bt_l2cap_sdp_state_s *sdp = opaque; + enum bt_sdp_cmd pdu_id; +@@ -506,7 +506,7 @@ static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len) + int rsp_len = 0; + + if (len < 5) { +- error_report("%s: short SDP PDU (%iB).", __func__, len); ++ error_report("%s: short SDP PDU (%zuB).", __func__, len); + return; + } + +@@ -517,7 +517,7 @@ static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len) + len -= 5; + + if (len != plen) { +- error_report("%s: wrong SDP PDU length (%iB != %iB).", ++ error_report("%s: wrong SDP PDU length (%iB != %zuB).", + __func__, plen, len); + err = SDP_INVALID_PDU_SIZE; + goto respond; +diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c +index 670ba32..240a901 100644 +--- a/hw/usb/dev-bluetooth.c ++++ b/hw/usb/dev-bluetooth.c +@@ -265,7 +265,7 @@ static void usb_bt_fifo_reset(struct usb_hci_in_fifo_s *fifo) + } + + static void usb_bt_fifo_enqueue(struct usb_hci_in_fifo_s *fifo, +- const uint8_t *data, int len) ++ const uint8_t *data, size_t len) + { + int off = fifo->dstart + fifo->dlen; + uint8_t *buf; +@@ -274,13 +274,13 @@ static void usb_bt_fifo_enqueue(struct usb_hci_in_fifo_s *fifo, + if (off <= DFIFO_LEN_MASK) { + if (off + len > DFIFO_LEN_MASK + 1 && + (fifo->dsize = off + len) > (DFIFO_LEN_MASK + 1) * 2) { +- fprintf(stderr, "%s: can't alloc %i bytes\n", __func__, len); ++ fprintf(stderr, "%s: can't alloc %zu bytes\n", __func__, len); + exit(-1); + } + buf = fifo->data + off; + } else { + if (fifo->dlen > fifo->dsize) { +- fprintf(stderr, "%s: can't alloc %i bytes\n", __func__, len); ++ fprintf(stderr, "%s: can't alloc %zu bytes\n", __func__, len); + exit(-1); + } + buf = fifo->data + off - fifo->dsize; +@@ -319,7 +319,7 @@ static inline void usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo, + + static inline void usb_bt_fifo_out_enqueue(struct USBBtState *s, + struct usb_hci_out_fifo_s *fifo, +- void (*send)(struct HCIInfo *, const uint8_t *, int), ++ void (*send)(struct HCIInfo *, const uint8_t *, size_t), + int (*complete)(const uint8_t *, int), + USBPacket *p) + { +@@ -478,7 +478,7 @@ static void usb_bt_handle_data(USBDevice *dev, USBPacket *p) + } + + static void usb_bt_out_hci_packet_event(void *opaque, +- const uint8_t *data, int len) ++ const uint8_t *data, size_t len) + { + struct USBBtState *s = (struct USBBtState *) opaque; + +@@ -489,7 +489,7 @@ static void usb_bt_out_hci_packet_event(void *opaque, + } + + static void usb_bt_out_hci_packet_acl(void *opaque, +- const uint8_t *data, int len) ++ const uint8_t *data, size_t len) + { + struct USBBtState *s = (struct USBBtState *) opaque; + +diff --git a/include/hw/bt.h b/include/hw/bt.h +index b5e11d4..bc362aa 100644 +--- a/include/hw/bt.h ++++ b/include/hw/bt.h +@@ -94,9 +94,9 @@ struct bt_device_s { + void (*lmp_disconnect_master)(struct bt_link_s *link); + void (*lmp_disconnect_slave)(struct bt_link_s *link); + void (*lmp_acl_data)(struct bt_link_s *link, const uint8_t *data, +- int start, int len); ++ int start, size_t len); + void (*lmp_acl_resp)(struct bt_link_s *link, const uint8_t *data, +- int start, int len); ++ int start, size_t len); + void (*lmp_mode_change)(struct bt_link_s *link); + + void (*handle_destroy)(struct bt_device_s *device); +@@ -148,12 +148,12 @@ struct bt_l2cap_device_s { + + struct bt_l2cap_conn_params_s { + /* Input */ +- uint8_t *(*sdu_out)(struct bt_l2cap_conn_params_s *chan, int len); ++ uint8_t *(*sdu_out)(struct bt_l2cap_conn_params_s *chan, size_t len); + void (*sdu_submit)(struct bt_l2cap_conn_params_s *chan); + int remote_mtu; + /* Output */ + void *opaque; +- void (*sdu_in)(void *opaque, const uint8_t *data, int len); ++ void (*sdu_in)(void *opaque, const uint8_t *data, size_t len); + void (*close)(void *opaque); + }; + +diff --git a/include/sysemu/bt.h b/include/sysemu/bt.h +index 2fd8c0f..df8fb63 100644 +--- a/include/sysemu/bt.h ++++ b/include/sysemu/bt.h +@@ -5,12 +5,12 @@ + + typedef struct HCIInfo { + int (*bdaddr_set)(struct HCIInfo *hci, const uint8_t *bd_addr); +- void (*cmd_send)(struct HCIInfo *hci, const uint8_t *data, int len); +- void (*sco_send)(struct HCIInfo *hci, const uint8_t *data, int len); +- void (*acl_send)(struct HCIInfo *hci, const uint8_t *data, int len); ++ void (*cmd_send)(struct HCIInfo *hci, const uint8_t *data, size_t len); ++ void (*sco_send)(struct HCIInfo *hci, const uint8_t *data, size_t len); ++ void (*acl_send)(struct HCIInfo *hci, const uint8_t *data, size_t len); + void *opaque; +- void (*evt_recv)(void *opaque, const uint8_t *data, int len); +- void (*acl_recv)(void *opaque, const uint8_t *data, int len); ++ void (*evt_recv)(void *opaque, const uint8_t *data, size_t len); ++ void (*acl_recv)(void *opaque, const uint8_t *data, size_t len); + } HCIInfo; + + /* bt-host.c */ +-- +1.8.3.1 + diff --git a/bugfix-Use-gicr_typer-in-arm_gicv3_icc_reset.patch b/bugfix-Use-gicr_typer-in-arm_gicv3_icc_reset.patch new file mode 100644 index 0000000000000000000000000000000000000000..e714cb10bef351cd6ed6df71d08f3666df879ed5 --- /dev/null +++ b/bugfix-Use-gicr_typer-in-arm_gicv3_icc_reset.patch @@ -0,0 +1,44 @@ +From b9e4a4ff6f3292927adb1463777c86cd4063a6ef Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Sat, 18 Apr 2020 12:10:11 +0800 +Subject: [PATCH] bugfix: Use gicr_typer in arm_gicv3_icc_reset + +The KVM_VGIC_ATTR macro expect the second parameter as gicr_typer, +of which high 32bit is constructed by mp_affinity. For most case, +the high 32bit of mp_affinity is zero, so it will always access the +ICC_CTLR_EL1 of CPU0. + +Signed-off-by: Keqian Zhu +--- + hw/intc/arm_gicv3_kvm.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c +index d9c72f85be..b1e74147ba 100644 +--- a/hw/intc/arm_gicv3_kvm.c ++++ b/hw/intc/arm_gicv3_kvm.c +@@ -661,13 +661,11 @@ static void kvm_arm_gicv3_get(GICv3State *s) + + static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) + { +- ARMCPU *cpu; + GICv3State *s; + GICv3CPUState *c; + + c = (GICv3CPUState *)env->gicv3state; + s = c->gic; +- cpu = ARM_CPU(c->cpu); + + c->icc_pmr_el1 = 0; + c->icc_bpr[GICV3_G0] = GIC_MIN_BPR; +@@ -684,7 +682,7 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) + + /* Initialize to actual HW supported configuration */ + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, +- KVM_VGIC_ATTR(ICC_CTLR_EL1, cpu->mp_affinity), ++ KVM_VGIC_ATTR(ICC_CTLR_EL1, c->gicr_typer), + &c->icc_ctlr_el1[GICV3_NS], false, &error_abort); + + c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS]; +-- +2.19.1 diff --git a/build-smt-processor-structure-to-support-smt-topolog.patch b/build-smt-processor-structure-to-support-smt-topolog.patch new file mode 100644 index 0000000000000000000000000000000000000000..ed01d38bb17dd4931a1f23b5a21127a2c5dd0425 --- /dev/null +++ b/build-smt-processor-structure-to-support-smt-topolog.patch @@ -0,0 +1,104 @@ +From af8740502815be450709e88df44ad322da2b071f Mon Sep 17 00:00:00 2001 +From: Henglong Fan +Date: Tue, 18 Aug 2020 21:42:33 +0800 +Subject: [PATCH] build smt processor structure to support smt topology + +if vcpu support smt, create new smt hierarchy according to +Processor Properties Topology Table(PPTT) in acpi spec 6.3. +Threads sharing a core must be grouped under a unique Processor +hierarchy node structure for each group of threads + +Signed-off-by: Henglong Fan +--- + hw/acpi/aml-build.c | 40 ++++++++++++++++++++++++++++++++-------- + 1 file changed, 32 insertions(+), 8 deletions(-) + +diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c +index 74e95005..8a3b51c8 100644 +--- a/hw/acpi/aml-build.c ++++ b/hw/acpi/aml-build.c +@@ -53,7 +53,7 @@ static void build_append_array(GArray *array, GArray *val) + } + + /* +- * ACPI 6.2 Processor Properties Topology Table (PPTT) ++ * ACPI 6.3 Processor Properties Topology Table (PPTT) + */ + #ifdef __aarch64__ + static void build_cache_head(GArray *tbl, uint32_t next_level) +@@ -126,7 +126,7 @@ static void build_arm_socket_hierarchy(GArray *tbl, + build_append_int_noprefix(tbl, offset, 4); + } + +-static void build_arm_cpu_hierarchy(GArray *tbl, ++static void build_arm_core_hierarchy(GArray *tbl, + struct offset_status *offset, uint32_t id) + { + if (!offset) { +@@ -144,18 +144,35 @@ static void build_arm_cpu_hierarchy(GArray *tbl, + build_append_int_noprefix(tbl, offset->l2_offset, 4); + } + ++static void build_arm_smt_hierarchy(GArray *tbl, ++ uint32_t offset, uint32_t id) ++{ ++ if (!offset) { ++ return; ++ } ++ build_append_byte(tbl, 0); /* Type 0 - processor */ ++ build_append_byte(tbl, 20); /* Length, add private resources */ ++ build_append_int_noprefix(tbl, 0, 2); /* Reserved */ ++ build_append_int_noprefix(tbl, 14, 4); /* Valid id*/ ++ build_append_int_noprefix(tbl, offset, 4); ++ build_append_int_noprefix(tbl, id, 4); ++ build_append_int_noprefix(tbl, 0, 4); /* Num private resources */ ++} ++ + void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus) + { + int pptt_start = table_data->len; +- int uid = 0, cpus = 0, socket; ++ int uid = 0, socket; ++ uint32_t core_offset; + struct offset_status offset; + const MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cores = ms->smp.cores; ++ unsigned int smp_sockets = ms->smp.cpus / (smp_cores * ms->smp.threads); + + acpi_data_push(table_data, sizeof(AcpiTableHeader)); + +- for (socket = 0; cpus < possible_cpus; socket++) { +- int core; ++ for (socket = 0; socket < smp_sockets; socket++) { ++ int core,thread; + uint32_t l3_offset = table_data->len - pptt_start; + build_cache_hierarchy(table_data, 0, ARM_L3_CACHE); + +@@ -169,14 +186,21 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus) + build_cache_hierarchy(table_data, offset.l2_offset, ARM_L1D_CACHE); + offset.l1i_offset = table_data->len - pptt_start; + build_cache_hierarchy(table_data, offset.l2_offset, ARM_L1I_CACHE); +- build_arm_cpu_hierarchy(table_data, &offset, uid++); +- cpus++; ++ core_offset = table_data->len - pptt_start; ++ if (ms->smp.threads <= 1) { ++ build_arm_core_hierarchy(table_data, &offset, uid++); ++ } else { ++ build_arm_core_hierarchy(table_data, &offset, core); ++ for (thread = 0; thread < ms->smp.threads; thread++) { ++ build_arm_smt_hierarchy(table_data, core_offset, uid++); ++ } ++ } + } + } + + build_header(linker, table_data, + (void *)(table_data->data + pptt_start), "PPTT", +- table_data->len - pptt_start, 1, NULL, NULL); ++ table_data->len - pptt_start, 2, NULL, NULL); + } + + #else +-- +2.23.0 + diff --git a/coroutine-Add-qemu_co_mutex_assert_locked.patch b/coroutine-Add-qemu_co_mutex_assert_locked.patch new file mode 100644 index 0000000000000000000000000000000000000000..fb1f2589f3edd987f0311288d049951c726ddeb8 --- /dev/null +++ b/coroutine-Add-qemu_co_mutex_assert_locked.patch @@ -0,0 +1,50 @@ +From e9bb3d942e268a19e03fc5d404586d2ed1564282 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Thu, 24 Oct 2019 16:26:57 +0200 +Subject: [PATCH] coroutine: Add qemu_co_mutex_assert_locked() + +Some functions require that the caller holds a certain CoMutex for them +to operate correctly. Add a function so that they can assert the lock is +really held. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +Tested-by: Michael Weiser +Reviewed-by: Michael Weiser +Reviewed-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Denis V. Lunev +Reviewed-by: Max Reitz +(cherry picked from commit 944f3d5dd216fcd8cb007eddd4f82dced0a15b3d) +Signed-off-by: Michael Roth +--- + include/qemu/coroutine.h | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h +index 9801e7f5a4..f4843b5f59 100644 +--- a/include/qemu/coroutine.h ++++ b/include/qemu/coroutine.h +@@ -167,6 +167,21 @@ void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex); + */ + void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex); + ++/** ++ * Assert that the current coroutine holds @mutex. ++ */ ++static inline coroutine_fn void qemu_co_mutex_assert_locked(CoMutex *mutex) ++{ ++ /* ++ * mutex->holder doesn't need any synchronisation if the assertion holds ++ * true because the mutex protects it. If it doesn't hold true, we still ++ * don't mind if another thread takes or releases mutex behind our back, ++ * because the condition will be false no matter whether we read NULL or ++ * the pointer for any other coroutine. ++ */ ++ assert(atomic_read(&mutex->locked) && ++ mutex->holder == qemu_coroutine_self()); ++} + + /** + * CoQueues are a mechanism to queue coroutines in order to continue executing +-- +2.23.0 diff --git a/cpu-add-Kunpeng-920-cpu-support.patch b/cpu-add-Kunpeng-920-cpu-support.patch index 149a1a123e8deae9de1e634aa025618518c7f56f..74e27645ac18a07c00a04283f428bec515cf259e 100644 --- a/cpu-add-Kunpeng-920-cpu-support.patch +++ b/cpu-add-Kunpeng-920-cpu-support.patch @@ -3,6 +3,8 @@ From: Xu Yandong Date: Wed, 28 Aug 2019 01:36:21 -0400 Subject: [PATCH] cpu: add Kunpeng-920 cpu support +Add the Kunpeng-920 CPU model. + Signed-off-by: Xu Yandong --- hw/arm/virt.c | 1 + @@ -28,7 +30,7 @@ index 228906f2..5581d5e1 100644 @@ -258,6 +258,26 @@ static void aarch64_a72_initfn(Object *obj) define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); } - + +static void aarch64_kunpeng_920_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); @@ -60,6 +62,5 @@ index 228906f2..5581d5e1 100644 { .name = "max", .initfn = aarch64_max_initfn }, { .name = NULL } }; --- +-- 2.19.1 - diff --git a/cpu-parse-feature-to-avoid-failure.patch b/cpu-parse-feature-to-avoid-failure.patch index a241a5f140c371f792a75839c53fb5b8779f7060..78178bfa3dd2a9dd1413dd3c12bbc8e6ed6d2869 100644 --- a/cpu-parse-feature-to-avoid-failure.patch +++ b/cpu-parse-feature-to-avoid-failure.patch @@ -1,8 +1,11 @@ From ba1ca232cfa2ca273c610beda40bee2143f11964 Mon Sep 17 00:00:00 2001 -From: rpm-build +From: Xu Yandong Date: Tue, 3 Sep 2019 16:27:39 +0800 Subject: [PATCH] cpu: parse +/- feature to avoid failure +To avoid cpu feature parse failuer, +/- feature is added. + +Signed-off-by: Xu Yandong --- target/arm/cpu64.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/delete-the-in-tpm.txt.patch b/delete-the-in-tpm.txt.patch new file mode 100644 index 0000000000000000000000000000000000000000..01ce3ace541aca115bccd47100f5dbd954643764 --- /dev/null +++ b/delete-the-in-tpm.txt.patch @@ -0,0 +1,26 @@ +From 3020ae141ef40f06b17eb0f16d2a3c6d5872ff89 Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Wed, 29 Jul 2020 08:45:50 +0000 +Subject: [PATCH 05/19] delete the in tpm.txt + +Signed-off-by: jiangfangjie +--- + docs/specs/tpm.txt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt +index 5d8c26b1..9c8cca04 100644 +--- a/docs/specs/tpm.txt ++++ b/docs/specs/tpm.txt +@@ -89,7 +89,7 @@ TPM upon reboot. The PPI specification defines the operation requests and the + actions the firmware has to take. The system administrator passes the operation + request number to the firmware through an ACPI interface which writes this + number to a memory location that the firmware knows. Upon reboot, the firmware +-finds the number and sends commands to the the TPM. The firmware writes the TPM ++finds the number and sends commands to the TPM. The firmware writes the TPM + result code and the operation request number to a memory location that ACPI can + read from and pass the result on to the administrator. + +-- +2.23.0 + diff --git a/dma-helpers-ensure-AIO-callback-is-invoked-after-can.patch b/dma-helpers-ensure-AIO-callback-is-invoked-after-can.patch new file mode 100644 index 0000000000000000000000000000000000000000..c61c9fd848c4e1d68baa778388c8440a8d28ec32 --- /dev/null +++ b/dma-helpers-ensure-AIO-callback-is-invoked-after-can.patch @@ -0,0 +1,79 @@ +From fbde196c30e4797a51bda046ba514b187963d4ba Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Mon, 29 Jul 2019 23:34:16 +0200 +Subject: [PATCH] dma-helpers: ensure AIO callback is invoked after + cancellation + +dma_aio_cancel unschedules the BH if there is one, which corresponds +to the reschedule_dma case of dma_blk_cb. This can stall the DMA +permanently, because dma_complete will never get invoked and therefore +nobody will ever invoke the original AIO callback in dbs->common.cb. + +Fix this by invoking the callback (which is ensured to happen after +a bdrv_aio_cancel_async, or done manually in the dbs->bh case), and +add assertions to check that the DMA state machine is indeed waiting +for dma_complete or reschedule_dma, but never both. + +Reported-by: John Snow +Signed-off-by: Paolo Bonzini +Message-id: 20190729213416.1972-1-pbonzini@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 539343c0a47e19d5dd64d846d64d084d9793681f) +Signed-off-by: Michael Roth +--- + dma-helpers.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/dma-helpers.c b/dma-helpers.c +index 2d7e02d35e..d3871dc61e 100644 +--- a/dma-helpers.c ++++ b/dma-helpers.c +@@ -90,6 +90,7 @@ static void reschedule_dma(void *opaque) + { + DMAAIOCB *dbs = (DMAAIOCB *)opaque; + ++ assert(!dbs->acb && dbs->bh); + qemu_bh_delete(dbs->bh); + dbs->bh = NULL; + dma_blk_cb(dbs, 0); +@@ -111,15 +112,12 @@ static void dma_complete(DMAAIOCB *dbs, int ret) + { + trace_dma_complete(dbs, ret, dbs->common.cb); + ++ assert(!dbs->acb && !dbs->bh); + dma_blk_unmap(dbs); + if (dbs->common.cb) { + dbs->common.cb(dbs->common.opaque, ret); + } + qemu_iovec_destroy(&dbs->iov); +- if (dbs->bh) { +- qemu_bh_delete(dbs->bh); +- dbs->bh = NULL; +- } + qemu_aio_unref(dbs); + } + +@@ -179,14 +177,21 @@ static void dma_aio_cancel(BlockAIOCB *acb) + + trace_dma_aio_cancel(dbs); + ++ assert(!(dbs->acb && dbs->bh)); + if (dbs->acb) { ++ /* This will invoke dma_blk_cb. */ + blk_aio_cancel_async(dbs->acb); ++ return; + } ++ + if (dbs->bh) { + cpu_unregister_map_client(dbs->bh); + qemu_bh_delete(dbs->bh); + dbs->bh = NULL; + } ++ if (dbs->common.cb) { ++ dbs->common.cb(dbs->common.opaque, -ECANCELED); ++ } + } + + static AioContext *dma_get_aio_context(BlockAIOCB *acb) +-- +2.23.0 diff --git a/docs-specs-Add-ACPI-GED-documentation.patch b/docs-specs-Add-ACPI-GED-documentation.patch new file mode 100644 index 0000000000000000000000000000000000000000..46e8c17483ba33af2b75e954233c3cbdc5c7cddc --- /dev/null +++ b/docs-specs-Add-ACPI-GED-documentation.patch @@ -0,0 +1,107 @@ +From 9c1752703fb8a5b70985cf4c9caabc3388c5953b Mon Sep 17 00:00:00 2001 +From: Shameer Kolothum +Date: Wed, 18 Sep 2019 14:06:31 +0100 +Subject: [PATCH] docs/specs: Add ACPI GED documentation + +Documents basic concepts of ACPI Generic Event device(GED) +and interface between QEMU and the ACPI BIOS. + +Signed-off-by: Shameer Kolothum +Reviewed-by: Eric Auger +Message-Id: <20190918130633.4872-10-shameerali.kolothum.thodi@huawei.com> +Acked-by: Peter Maydell +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + docs/specs/acpi_hw_reduced_hotplug.rst | 70 ++++++++++++++++++++++++++ + docs/specs/index.rst | 1 + + 2 files changed, 71 insertions(+) + create mode 100644 docs/specs/acpi_hw_reduced_hotplug.rst + +diff --git a/docs/specs/acpi_hw_reduced_hotplug.rst b/docs/specs/acpi_hw_reduced_hotplug.rst +new file mode 100644 +index 0000000000..911a98255b +--- /dev/null ++++ b/docs/specs/acpi_hw_reduced_hotplug.rst +@@ -0,0 +1,70 @@ ++================================================== ++QEMU and ACPI BIOS Generic Event Device interface ++================================================== ++ ++The ACPI *Generic Event Device* (GED) is a HW reduced platform ++specific device introduced in ACPI v6.1 that handles all platform ++events, including the hotplug ones. GED is modelled as a device ++in the namespace with a _HID defined to be ACPI0013. This document ++describes the interface between QEMU and the ACPI BIOS. ++ ++GED allows HW reduced platforms to handle interrupts in ACPI ASL ++statements. It follows a very similar approach to the _EVT method ++from GPIO events. All interrupts are listed in _CRS and the handler ++is written in _EVT method. However, the QEMU implementation uses a ++single interrupt for the GED device, relying on an IO memory region ++to communicate the type of device affected by the interrupt. This way, ++we can support up to 32 events with a unique interrupt. ++ ++**Here is an example,** ++ ++:: ++ ++ Device (\_SB.GED) ++ { ++ Name (_HID, "ACPI0013") ++ Name (_UID, Zero) ++ Name (_CRS, ResourceTemplate () ++ { ++ Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, ) ++ { ++ 0x00000029, ++ } ++ }) ++ OperationRegion (EREG, SystemMemory, 0x09080000, 0x04) ++ Field (EREG, DWordAcc, NoLock, WriteAsZeros) ++ { ++ ESEL, 32 ++ } ++ Method (_EVT, 1, Serialized) ++ { ++ Local0 = ESEL // ESEL = IO memory region which specifies the ++ // device type. ++ If (((Local0 & One) == One)) ++ { ++ MethodEvent1() ++ } ++ If ((Local0 & 0x2) == 0x2) ++ { ++ MethodEvent2() ++ } ++ ... ++ } ++ } ++ ++GED IO interface (4 byte access) ++-------------------------------- ++**read access:** ++ ++:: ++ ++ [0x0-0x3] Event selector bit field (32 bit) set by QEMU. ++ ++ bits: ++ 0: Memory hotplug event ++ 1: System power down event ++ 2-31: Reserved ++ ++**write_access:** ++ ++Nothing is expected to be written into GED IO memory +diff --git a/docs/specs/index.rst b/docs/specs/index.rst +index 40adb97c5e..984ba44029 100644 +--- a/docs/specs/index.rst ++++ b/docs/specs/index.rst +@@ -12,3 +12,4 @@ Contents: + + ppc-xive + ppc-spapr-xive ++ acpi_hw_reduced_hotplug +-- +2.19.1 diff --git a/docs-specs-tpm-Document-TPM_TIS-sysbus-device-for-AR.patch b/docs-specs-tpm-Document-TPM_TIS-sysbus-device-for-AR.patch new file mode 100644 index 0000000000000000000000000000000000000000..f0be64a937fd5b1f78c54f5f74854f388c023786 --- /dev/null +++ b/docs-specs-tpm-Document-TPM_TIS-sysbus-device-for-AR.patch @@ -0,0 +1,66 @@ +From dd7f6cc3bcd71681920e3530f2c53041c812c5d3 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 5 Mar 2020 17:51:46 +0100 +Subject: [PATCH 16/19] docs/specs/tpm: Document TPM_TIS sysbus device for ARM + +Update the documentation with recent changes related to the +sysbus TPM_TIS device addition and add the command line +to be used with arm VIRT. + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Message-id: 20200305165149.618-8-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + docs/specs/tpm.rst | 25 ++++++++++++++++++++++++- + 1 file changed, 24 insertions(+), 1 deletion(-) + +diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst +index 2bdf637f..da9eb39c 100644 +--- a/docs/specs/tpm.rst ++++ b/docs/specs/tpm.rst +@@ -18,9 +18,15 @@ The TIS interface makes a memory mapped IO region in the area + 0xfed40000-0xfed44fff available to the guest operating system. + + QEMU files related to TPM TIS interface: +- - ``hw/tpm/tpm_tis.c`` ++ - ``hw/tpm/tpm_tis_common.c`` ++ - ``hw/tpm/tpm_tis_isa.c`` ++ - ``hw/tpm/tpm_tis_sysbus.c`` + - ``hw/tpm/tpm_tis.h`` + ++Both an ISA device and a sysbus device are available. The former is ++used with pc/q35 machine while the latter can be instantiated in the ++ARM virt machine. ++ + CRB interface + ------------- + +@@ -325,6 +331,23 @@ In case a pSeries machine is emulated, use the following command line: + -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \ + -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0 + ++In case an ARM virt machine is emulated, use the following command line: ++ ++.. code-block:: console ++ ++ qemu-system-aarch64 -machine virt,gic-version=3,accel=kvm \ ++ -cpu host -m 4G \ ++ -nographic -no-acpi \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-tis-device,tpmdev=tpm0 \ ++ -device virtio-blk-pci,drive=drv0 \ ++ -drive format=qcow2,file=hda.qcow2,if=none,id=drv0 \ ++ -drive if=pflash,format=raw,file=flash0.img,readonly \ ++ -drive if=pflash,format=raw,file=flash1.img ++ ++ On ARM, ACPI boot with TPM is not yet supported. ++ + In case SeaBIOS is used as firmware, it should show the TPM menu item + after entering the menu with 'ESC'. + +-- +2.23.0 + diff --git a/docs-specs-tpm-reST-ify-TPM-documentation.patch b/docs-specs-tpm-reST-ify-TPM-documentation.patch new file mode 100644 index 0000000000000000000000000000000000000000..d4648994bde2fc4b68ce49f28f4a612f53e65551 --- /dev/null +++ b/docs-specs-tpm-reST-ify-TPM-documentation.patch @@ -0,0 +1,993 @@ +From 5d1865496ca39f08142a0c1eb2c9b14ec1ec9140 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 21 Jan 2020 10:29:35 -0500 +Subject: [PATCH 09/19] docs/specs/tpm: reST-ify TPM documentation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Marc-André Lureau +Reviewed-by: Stefan Berger +Message-Id: <20200121152935.649898-7-stefanb@linux.ibm.com> +Signed-off-by: David Gibson +Signed-off-by: jiangfangjie +--- + docs/specs/index.rst | 1 + + docs/specs/tpm.rst | 503 +++++++++++++++++++++++++++++++++++++++++++ + docs/specs/tpm.txt | 445 -------------------------------------- + 3 files changed, 504 insertions(+), 445 deletions(-) + create mode 100644 docs/specs/tpm.rst + delete mode 100644 docs/specs/tpm.txt + +diff --git a/docs/specs/index.rst b/docs/specs/index.rst +index 984ba440..de46a8b5 100644 +--- a/docs/specs/index.rst ++++ b/docs/specs/index.rst +@@ -13,3 +13,4 @@ Contents: + ppc-xive + ppc-spapr-xive + acpi_hw_reduced_hotplug ++ tpm +diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst +new file mode 100644 +index 00000000..2bdf637f +--- /dev/null ++++ b/docs/specs/tpm.rst +@@ -0,0 +1,503 @@ ++=============== ++QEMU TPM Device ++=============== ++ ++Guest-side hardware interface ++============================= ++ ++TIS interface ++------------- ++ ++The QEMU TPM emulation implements a TPM TIS hardware interface ++following the Trusted Computing Group's specification "TCG PC Client ++Specific TPM Interface Specification (TIS)", Specification Version ++1.3, 21 March 2013. (see the `TIS specification`_, or a later version ++of it). ++ ++The TIS interface makes a memory mapped IO region in the area ++0xfed40000-0xfed44fff available to the guest operating system. ++ ++QEMU files related to TPM TIS interface: ++ - ``hw/tpm/tpm_tis.c`` ++ - ``hw/tpm/tpm_tis.h`` ++ ++CRB interface ++------------- ++ ++QEMU also implements a TPM CRB interface following the Trusted ++Computing Group's specification "TCG PC Client Platform TPM Profile ++(PTP) Specification", Family "2.0", Level 00 Revision 01.03 v22, May ++22, 2017. (see the `CRB specification`_, or a later version of it) ++ ++The CRB interface makes a memory mapped IO region in the area ++0xfed40000-0xfed40fff (1 locality) available to the guest ++operating system. ++ ++QEMU files related to TPM CRB interface: ++ - ``hw/tpm/tpm_crb.c`` ++ ++SPAPR interface ++--------------- ++ ++pSeries (ppc64) machines offer a tpm-spapr device model. ++ ++QEMU files related to the SPAPR interface: ++ - ``hw/tpm/tpm_spapr.c`` ++ ++fw_cfg interface ++================ ++ ++The bios/firmware may read the ``"etc/tpm/config"`` fw_cfg entry for ++configuring the guest appropriately. ++ ++The entry of 6 bytes has the following content, in little-endian: ++ ++.. code-block:: c ++ ++ #define TPM_VERSION_UNSPEC 0 ++ #define TPM_VERSION_1_2 1 ++ #define TPM_VERSION_2_0 2 ++ ++ #define TPM_PPI_VERSION_NONE 0 ++ #define TPM_PPI_VERSION_1_30 1 ++ ++ struct FwCfgTPMConfig { ++ uint32_t tpmppi_address; /* PPI memory location */ ++ uint8_t tpm_version; /* TPM version */ ++ uint8_t tpmppi_version; /* PPI version */ ++ }; ++ ++ACPI interface ++============== ++ ++The TPM device is defined with ACPI ID "PNP0C31". QEMU builds a SSDT ++and passes it into the guest through the fw_cfg device. The device ++description contains the base address of the TIS interface 0xfed40000 ++and the size of the MMIO area (0x5000). In case a TPM2 is used by ++QEMU, a TPM2 ACPI table is also provided. The device is described to ++be used in polling mode rather than interrupt mode primarily because ++no unused IRQ could be found. ++ ++To support measurement logs to be written by the firmware, ++e.g. SeaBIOS, a TCPA table is implemented. This table provides a 64kb ++buffer where the firmware can write its log into. For TPM 2 only a ++more recent version of the TPM2 table provides support for ++measurements logs and a TCPA table does not need to be created. ++ ++The TCPA and TPM2 ACPI tables follow the Trusted Computing Group ++specification "TCG ACPI Specification" Family "1.2" and "2.0", Level ++00 Revision 00.37. (see the `ACPI specification`_, or a later version ++of it) ++ ++ACPI PPI Interface ++------------------ ++ ++QEMU supports the Physical Presence Interface (PPI) for TPM 1.2 and ++TPM 2. This interface requires ACPI and firmware support. (see the ++`PPI specification`_) ++ ++PPI enables a system administrator (root) to request a modification to ++the TPM upon reboot. The PPI specification defines the operation ++requests and the actions the firmware has to take. The system ++administrator passes the operation request number to the firmware ++through an ACPI interface which writes this number to a memory ++location that the firmware knows. Upon reboot, the firmware finds the ++number and sends commands to the TPM. The firmware writes the TPM ++result code and the operation request number to a memory location that ++ACPI can read from and pass the result on to the administrator. ++ ++The PPI specification defines a set of mandatory and optional ++operations for the firmware to implement. The ACPI interface also ++allows an administrator to list the supported operations. In QEMU the ++ACPI code is generated by QEMU, yet the firmware needs to implement ++support on a per-operations basis, and different firmwares may support ++a different subset. Therefore, QEMU introduces the virtual memory ++device for PPI where the firmware can indicate which operations it ++supports and ACPI can enable the ones that are supported and disable ++all others. This interface lies in main memory and has the following ++layout: ++ ++ +-------------+--------+--------+-------------------------------------------+ ++ | Field | Length | Offset | Description | ++ +=============+========+========+===========================================+ ++ | ``func`` | 0x100 | 0x000 | Firmware sets values for each supported | ++ | | | | operation. See defined values below. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``ppin`` | 0x1 | 0x100 | SMI interrupt to use. Set by firmware. | ++ | | | | Not supported. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``ppip`` | 0x4 | 0x101 | ACPI function index to pass to SMM code. | ++ | | | | Set by ACPI. Not supported. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``pprp`` | 0x4 | 0x105 | Result of last executed operation. Set by | ++ | | | | firmware. See function index 5 for values.| ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``pprq`` | 0x4 | 0x109 | Operation request number to execute. See | ++ | | | | 'Physical Presence Interface Operation | ++ | | | | Summary' tables in specs. Set by ACPI. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``pprm`` | 0x4 | 0x10d | Operation request optional parameter. | ++ | | | | Values depend on operation. Set by ACPI. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``lppr`` | 0x4 | 0x111 | Last executed operation request number. | ++ | | | | Copied from pprq field by firmware. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``fret`` | 0x4 | 0x115 | Result code from SMM function. | ++ | | | | Not supported. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``res1`` | 0x40 | 0x119 | Reserved for future use | ++ +-------------+--------+--------+-------------------------------------------+ ++ |``next_step``| 0x1 | 0x159 | Operation to execute after reboot by | ++ | | | | firmware. Used by firmware. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``movv`` | 0x1 | 0x15a | Memory overwrite variable | ++ +-------------+--------+--------+-------------------------------------------+ ++ ++The following values are supported for the ``func`` field. They ++correspond to the values used by ACPI function index 8. ++ ++ +----------+-------------------------------------------------------------+ ++ | Value | Description | ++ +==========+=============================================================+ ++ | 0 | Operation is not implemented. | ++ +----------+-------------------------------------------------------------+ ++ | 1 | Operation is only accessible through firmware. | ++ +----------+-------------------------------------------------------------+ ++ | 2 | Operation is blocked for OS by firmware configuration. | ++ +----------+-------------------------------------------------------------+ ++ | 3 | Operation is allowed and physically present user required. | ++ +----------+-------------------------------------------------------------+ ++ | 4 | Operation is allowed and physically present user is not | ++ | | required. | ++ +----------+-------------------------------------------------------------+ ++ ++The location of the table is given by the fw_cfg ``tpmppi_address`` ++field. The PPI memory region size is 0x400 (``TPM_PPI_ADDR_SIZE``) to ++leave enough room for future updates. ++ ++QEMU files related to TPM ACPI tables: ++ - ``hw/i386/acpi-build.c`` ++ - ``include/hw/acpi/tpm.h`` ++ ++TPM backend devices ++=================== ++ ++The TPM implementation is split into two parts, frontend and ++backend. The frontend part is the hardware interface, such as the TPM ++TIS interface described earlier, and the other part is the TPM backend ++interface. The backend interfaces implement the interaction with a TPM ++device, which may be a physical or an emulated device. The split ++between the front- and backend devices allows a frontend to be ++connected with any available backend. This enables the TIS interface ++to be used with the passthrough backend or the swtpm backend. ++ ++QEMU files related to TPM backends: ++ - ``backends/tpm.c`` ++ - ``include/sysemu/tpm_backend.h`` ++ - ``include/sysemu/tpm_backend_int.h`` ++ ++The QEMU TPM passthrough device ++------------------------------- ++ ++In case QEMU is run on Linux as the host operating system it is ++possible to make the hardware TPM device available to a single QEMU ++guest. In this case the user must make sure that no other program is ++using the device, e.g., /dev/tpm0, before trying to start QEMU with ++it. ++ ++The passthrough driver uses the host's TPM device for sending TPM ++commands and receiving responses from. Besides that it accesses the ++TPM device's sysfs entry for support of command cancellation. Since ++none of the state of a hardware TPM can be migrated between hosts, ++virtual machine migration is disabled when the TPM passthrough driver ++is used. ++ ++Since the host's TPM device will already be initialized by the host's ++firmware, certain commands, e.g. ``TPM_Startup()``, sent by the ++virtual firmware for device initialization, will fail. In this case ++the firmware should not use the TPM. ++ ++Sharing the device with the host is generally not a recommended usage ++scenario for a TPM device. The primary reason for this is that two ++operating systems can then access the device's single set of ++resources, such as platform configuration registers ++(PCRs). Applications or kernel security subsystems, such as the Linux ++Integrity Measurement Architecture (IMA), are not expecting to share ++PCRs. ++ ++QEMU files related to the TPM passthrough device: ++ - ``hw/tpm/tpm_passthrough.c`` ++ - ``hw/tpm/tpm_util.c`` ++ - ``hw/tpm/tpm_util.h`` ++ ++ ++Command line to start QEMU with the TPM passthrough device using the host's ++hardware TPM ``/dev/tpm0``: ++ ++.. code-block:: console ++ ++ qemu-system-x86_64 -display sdl -accel kvm \ ++ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ ++ -tpmdev passthrough,id=tpm0,path=/dev/tpm0 \ ++ -device tpm-tis,tpmdev=tpm0 test.img ++ ++ ++The following commands should result in similar output inside the VM ++with a Linux kernel that either has the TPM TIS driver built-in or ++available as a module: ++ ++.. code-block:: console ++ ++ # dmesg | grep -i tpm ++ [ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) ++ ++ # dmesg | grep TCPA ++ [ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ ++ BXPCTCPA 0000001 BXPC 00000001) ++ ++ # ls -l /dev/tpm* ++ crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 ++ ++ # find /sys/devices/ | grep pcrs$ | xargs cat ++ PCR-00: 35 4E 3B CE 23 9F 38 59 ... ++ ... ++ PCR-23: 00 00 00 00 00 00 00 00 ... ++ ++The QEMU TPM emulator device ++---------------------------- ++ ++The TPM emulator device uses an external TPM emulator called 'swtpm' ++for sending TPM commands to and receiving responses from. The swtpm ++program must have been started before trying to access it through the ++TPM emulator with QEMU. ++ ++The TPM emulator implements a command channel for transferring TPM ++commands and responses as well as a control channel over which control ++commands can be sent. (see the `SWTPM protocol`_ specification) ++ ++The control channel serves the purpose of resetting, initializing, and ++migrating the TPM state, among other things. ++ ++The swtpm program behaves like a hardware TPM and therefore needs to ++be initialized by the firmware running inside the QEMU virtual ++machine. One necessary step for initializing the device is to send ++the TPM_Startup command to it. SeaBIOS, for example, has been ++instrumented to initialize a TPM 1.2 or TPM 2 device using this ++command. ++ ++QEMU files related to the TPM emulator device: ++ - ``hw/tpm/tpm_emulator.c`` ++ - ``hw/tpm/tpm_util.c`` ++ - ``hw/tpm/tpm_util.h`` ++ ++The following commands start the swtpm with a UnixIO control channel over ++a socket interface. They do not need to be run as root. ++ ++.. code-block:: console ++ ++ mkdir /tmp/mytpm1 ++ swtpm socket --tpmstate dir=/tmp/mytpm1 \ ++ --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ ++ --log level=20 ++ ++Command line to start QEMU with the TPM emulator device communicating ++with the swtpm (x86): ++ ++.. code-block:: console ++ ++ qemu-system-x86_64 -display sdl -accel kvm \ ++ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-tis,tpmdev=tpm0 test.img ++ ++In case a pSeries machine is emulated, use the following command line: ++ ++.. code-block:: console ++ ++ qemu-system-ppc64 -display sdl -machine pseries,accel=kvm \ ++ -m 1024 -bios slof.bin -boot menu=on \ ++ -nodefaults -device VGA -device pci-ohci -device usb-kbd \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-spapr,tpmdev=tpm0 \ ++ -device spapr-vscsi,id=scsi0,reg=0x00002000 \ ++ -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \ ++ -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0 ++ ++In case SeaBIOS is used as firmware, it should show the TPM menu item ++after entering the menu with 'ESC'. ++ ++.. code-block:: console ++ ++ Select boot device: ++ 1. DVD/CD [ata1-0: QEMU DVD-ROM ATAPI-4 DVD/CD] ++ [...] ++ 5. Legacy option rom ++ ++ t. TPM Configuration ++ ++The following commands should result in similar output inside the VM ++with a Linux kernel that either has the TPM TIS driver built-in or ++available as a module: ++ ++.. code-block:: console ++ ++ # dmesg | grep -i tpm ++ [ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) ++ ++ # dmesg | grep TCPA ++ [ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ ++ BXPCTCPA 0000001 BXPC 00000001) ++ ++ # ls -l /dev/tpm* ++ crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 ++ ++ # find /sys/devices/ | grep pcrs$ | xargs cat ++ PCR-00: 35 4E 3B CE 23 9F 38 59 ... ++ ... ++ PCR-23: 00 00 00 00 00 00 00 00 ... ++ ++Migration with the TPM emulator ++=============================== ++ ++The TPM emulator supports the following types of virtual machine ++migration: ++ ++- VM save / restore (migration into a file) ++- Network migration ++- Snapshotting (migration into storage like QoW2 or QED) ++ ++The following command sequences can be used to test VM save / restore. ++ ++In a 1st terminal start an instance of a swtpm using the following command: ++ ++.. code-block:: console ++ ++ mkdir /tmp/mytpm1 ++ swtpm socket --tpmstate dir=/tmp/mytpm1 \ ++ --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ ++ --log level=20 --tpm2 ++ ++In a 2nd terminal start the VM: ++ ++.. code-block:: console ++ ++ qemu-system-x86_64 -display sdl -accel kvm \ ++ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-tis,tpmdev=tpm0 \ ++ -monitor stdio \ ++ test.img ++ ++Verify that the attached TPM is working as expected using applications ++inside the VM. ++ ++To store the state of the VM use the following command in the QEMU ++monitor in the 2nd terminal: ++ ++.. code-block:: console ++ ++ (qemu) migrate "exec:cat > testvm.bin" ++ (qemu) quit ++ ++At this point a file called ``testvm.bin`` should exists and the swtpm ++and QEMU processes should have ended. ++ ++To test 'VM restore' you have to start the swtpm with the same ++parameters as before. If previously a TPM 2 [--tpm2] was saved, --tpm2 ++must now be passed again on the command line. ++ ++In the 1st terminal restart the swtpm with the same command line as ++before: ++ ++.. code-block:: console ++ ++ swtpm socket --tpmstate dir=/tmp/mytpm1 \ ++ --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ ++ --log level=20 --tpm2 ++ ++In the 2nd terminal restore the state of the VM using the additional ++'-incoming' option. ++ ++.. code-block:: console ++ ++ qemu-system-x86_64 -display sdl -accel kvm \ ++ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-tis,tpmdev=tpm0 \ ++ -incoming "exec:cat < testvm.bin" \ ++ test.img ++ ++Troubleshooting migration ++------------------------- ++ ++There are several reasons why migration may fail. In case of problems, ++please ensure that the command lines adhere to the following rules ++and, if possible, that identical versions of QEMU and swtpm are used ++at all times. ++ ++VM save and restore: ++ ++ - QEMU command line parameters should be identical apart from the ++ '-incoming' option on VM restore ++ ++ - swtpm command line parameters should be identical ++ ++VM migration to 'localhost': ++ ++ - QEMU command line parameters should be identical apart from the ++ '-incoming' option on the destination side ++ ++ - swtpm command line parameters should point to two different ++ directories on the source and destination swtpm (--tpmstate dir=...) ++ (especially if different versions of libtpms were to be used on the ++ same machine). ++ ++VM migration across the network: ++ ++ - QEMU command line parameters should be identical apart from the ++ '-incoming' option on the destination side ++ ++ - swtpm command line parameters should be identical ++ ++VM Snapshotting: ++ - QEMU command line parameters should be identical ++ ++ - swtpm command line parameters should be identical ++ ++ ++Besides that, migration failure reasons on the swtpm level may include ++the following: ++ ++ - the versions of the swtpm on the source and destination sides are ++ incompatible ++ ++ - downgrading of TPM state may not be supported ++ ++ - the source and destination libtpms were compiled with different ++ compile-time options and the destination side refuses to accept the ++ state ++ ++ - different migration keys are used on the source and destination side ++ and the destination side cannot decrypt the migrated state ++ (swtpm ... --migration-key ... ) ++ ++ ++.. _TIS specification: ++ https://trustedcomputinggroup.org/pc-client-work-group-pc-client-specific-tpm-interface-specification-tis/ ++ ++.. _CRB specification: ++ https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/ ++ ++ ++.. _ACPI specification: ++ https://trustedcomputinggroup.org/tcg-acpi-specification/ ++ ++.. _PPI specification: ++ https://trustedcomputinggroup.org/resource/tcg-physical-presence-interface-specification/ ++ ++.. _SWTPM protocol: ++ https://github.com/stefanberger/swtpm/blob/master/man/man3/swtpm_ioctls.pod +diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt +deleted file mode 100644 +index 9c3e67d8..00000000 +--- a/docs/specs/tpm.txt ++++ /dev/null +@@ -1,445 +0,0 @@ +-QEMU TPM Device +-=============== +- +-= Guest-side Hardware Interface = +- +-The QEMU TPM emulation implements a TPM TIS hardware interface following the +-Trusted Computing Group's specification "TCG PC Client Specific TPM Interface +-Specification (TIS)", Specification Version 1.3, 21 March 2013. This +-specification, or a later version of it, can be accessed from the following +-URL: +- +-https://trustedcomputinggroup.org/pc-client-work-group-pc-client-specific-tpm-interface-specification-tis/ +- +-The TIS interface makes a memory mapped IO region in the area 0xfed40000 - +-0xfed44fff available to the guest operating system. +- +- +-QEMU files related to TPM TIS interface: +- - hw/tpm/tpm_tis.c +- - hw/tpm/tpm_tis.h +- +- +-QEMU also implements a TPM CRB interface following the Trusted Computing +-Group's specification "TCG PC Client Platform TPM Profile (PTP) +-Specification", Family "2.0", Level 00 Revision 01.03 v22, May 22, 2017. +-This specification, or a later version of it, can be accessed from the +-following URL: +- +-https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/ +- +-The CRB interface makes a memory mapped IO region in the area 0xfed40000 - +-0xfed40fff (1 locality) available to the guest operating system. +- +-QEMU files related to TPM CRB interface: +- - hw/tpm/tpm_crb.c +- +- +-pSeries (ppc64) machines offer a tpm-spapr device model. +- +-QEMU files related to the SPAPR interface: +- - hw/tpm/tpm_spapr.c +- +-= fw_cfg interface = +- +-The bios/firmware may read the "etc/tpm/config" fw_cfg entry for +-configuring the guest appropriately. +- +-The entry of 6 bytes has the following content, in little-endian: +- +- #define TPM_VERSION_UNSPEC 0 +- #define TPM_VERSION_1_2 1 +- #define TPM_VERSION_2_0 2 +- +- #define TPM_PPI_VERSION_NONE 0 +- #define TPM_PPI_VERSION_1_30 1 +- +- struct FwCfgTPMConfig { +- uint32_t tpmppi_address; /* PPI memory location */ +- uint8_t tpm_version; /* TPM version */ +- uint8_t tpmppi_version; /* PPI version */ +- }; +- +-= ACPI Interface = +- +-The TPM device is defined with ACPI ID "PNP0C31". QEMU builds a SSDT and passes +-it into the guest through the fw_cfg device. The device description contains +-the base address of the TIS interface 0xfed40000 and the size of the MMIO area +-(0x5000). In case a TPM2 is used by QEMU, a TPM2 ACPI table is also provided. +-The device is described to be used in polling mode rather than interrupt mode +-primarily because no unused IRQ could be found. +- +-To support measurement logs to be written by the firmware, e.g. SeaBIOS, a TCPA +-table is implemented. This table provides a 64kb buffer where the firmware can +-write its log into. For TPM 2 only a more recent version of the TPM2 table +-provides support for measurements logs and a TCPA table does not need to be +-created. +- +-The TCPA and TPM2 ACPI tables follow the Trusted Computing Group specification +-"TCG ACPI Specification" Family "1.2" and "2.0", Level 00 Revision 00.37. This +-specification, or a later version of it, can be accessed from the following +-URL: +- +-https://trustedcomputinggroup.org/tcg-acpi-specification/ +- +-== ACPI PPI Interface == +- +-QEMU supports the Physical Presence Interface (PPI) for TPM 1.2 and TPM 2. This +-interface requires ACPI and firmware support. The specification can be found at +-the following URL: +- +-https://trustedcomputinggroup.org/resource/tcg-physical-presence-interface-specification/ +- +-PPI enables a system administrator (root) to request a modification to the +-TPM upon reboot. The PPI specification defines the operation requests and the +-actions the firmware has to take. The system administrator passes the operation +-request number to the firmware through an ACPI interface which writes this +-number to a memory location that the firmware knows. Upon reboot, the firmware +-finds the number and sends commands to the TPM. The firmware writes the TPM +-result code and the operation request number to a memory location that ACPI can +-read from and pass the result on to the administrator. +- +-The PPI specification defines a set of mandatory and optional operations for +-the firmware to implement. The ACPI interface also allows an administrator to +-list the supported operations. In QEMU the ACPI code is generated by QEMU, yet +-the firmware needs to implement support on a per-operations basis, and +-different firmwares may support a different subset. Therefore, QEMU introduces +-the virtual memory device for PPI where the firmware can indicate which +-operations it supports and ACPI can enable the ones that are supported and +-disable all others. This interface lies in main memory and has the following +-layout: +- +- +----------+--------+--------+-------------------------------------------+ +- | Field | Length | Offset | Description | +- +----------+--------+--------+-------------------------------------------+ +- | func | 0x100 | 0x000 | Firmware sets values for each supported | +- | | | | operation. See defined values below. | +- +----------+--------+--------+-------------------------------------------+ +- | ppin | 0x1 | 0x100 | SMI interrupt to use. Set by firmware. | +- | | | | Not supported. | +- +----------+--------+--------+-------------------------------------------+ +- | ppip | 0x4 | 0x101 | ACPI function index to pass to SMM code. | +- | | | | Set by ACPI. Not supported. | +- +----------+--------+--------+-------------------------------------------+ +- | pprp | 0x4 | 0x105 | Result of last executed operation. Set by | +- | | | | firmware. See function index 5 for values.| +- +----------+--------+--------+-------------------------------------------+ +- | pprq | 0x4 | 0x109 | Operation request number to execute. See | +- | | | | 'Physical Presence Interface Operation | +- | | | | Summary' tables in specs. Set by ACPI. | +- +----------+--------+--------+-------------------------------------------+ +- | pprm | 0x4 | 0x10d | Operation request optional parameter. | +- | | | | Values depend on operation. Set by ACPI. | +- +----------+--------+--------+-------------------------------------------+ +- | lppr | 0x4 | 0x111 | Last executed operation request number. | +- | | | | Copied from pprq field by firmware. | +- +----------+--------+--------+-------------------------------------------+ +- | fret | 0x4 | 0x115 | Result code from SMM function. | +- | | | | Not supported. | +- +----------+--------+--------+-------------------------------------------+ +- | res1 | 0x40 | 0x119 | Reserved for future use | +- +----------+--------+--------+-------------------------------------------+ +- | next_step| 0x1 | 0x159 | Operation to execute after reboot by | +- | | | | firmware. Used by firmware. | +- +----------+--------+--------+-------------------------------------------+ +- | movv | 0x1 | 0x15a | Memory overwrite variable | +- +----------+--------+--------+-------------------------------------------+ +- +- The following values are supported for the 'func' field. They correspond +- to the values used by ACPI function index 8. +- +- +----------+-------------------------------------------------------------+ +- | value | Description | +- +----------+-------------------------------------------------------------+ +- | 0 | Operation is not implemented. | +- +----------+-------------------------------------------------------------+ +- | 1 | Operation is only accessible through firmware. | +- +----------+-------------------------------------------------------------+ +- | 2 | Operation is blocked for OS by firmware configuration. | +- +----------+-------------------------------------------------------------+ +- | 3 | Operation is allowed and physically present user required. | +- +----------+-------------------------------------------------------------+ +- | 4 | Operation is allowed and physically present user is not | +- | | required. | +- +----------+-------------------------------------------------------------+ +- +-The location of the table is given by the fw_cfg tpmppi_address field. +-The PPI memory region size is 0x400 (TPM_PPI_ADDR_SIZE) to leave +-enough room for future updates. +- +- +-QEMU files related to TPM ACPI tables: +- - hw/i386/acpi-build.c +- - include/hw/acpi/tpm.h +- +- +-= TPM backend devices = +- +-The TPM implementation is split into two parts, frontend and backend. The +-frontend part is the hardware interface, such as the TPM TIS interface +-described earlier, and the other part is the TPM backend interface. The backend +-interfaces implement the interaction with a TPM device, which may be a physical +-or an emulated device. The split between the front- and backend devices allows +-a frontend to be connected with any available backend. This enables the TIS +-interface to be used with the passthrough backend or the (future) swtpm backend. +- +- +-QEMU files related to TPM backends: +- - backends/tpm.c +- - include/sysemu/tpm_backend.h +- - include/sysemu/tpm_backend_int.h +- +- +-== The QEMU TPM passthrough device == +- +-In case QEMU is run on Linux as the host operating system it is possible to +-make the hardware TPM device available to a single QEMU guest. In this case the +-user must make sure that no other program is using the device, e.g., /dev/tpm0, +-before trying to start QEMU with it. +- +-The passthrough driver uses the host's TPM device for sending TPM commands +-and receiving responses from. Besides that it accesses the TPM device's sysfs +-entry for support of command cancellation. Since none of the state of a +-hardware TPM can be migrated between hosts, virtual machine migration is +-disabled when the TPM passthrough driver is used. +- +-Since the host's TPM device will already be initialized by the host's firmware, +-certain commands, e.g. TPM_Startup(), sent by the virtual firmware for device +-initialization, will fail. In this case the firmware should not use the TPM. +- +-Sharing the device with the host is generally not a recommended usage scenario +-for a TPM device. The primary reason for this is that two operating systems can +-then access the device's single set of resources, such as platform configuration +-registers (PCRs). Applications or kernel security subsystems, such as the +-Linux Integrity Measurement Architecture (IMA), are not expecting to share PCRs. +- +- +-QEMU files related to the TPM passthrough device: +- - hw/tpm/tpm_passthrough.c +- - hw/tpm/tpm_util.c +- - hw/tpm/tpm_util.h +- +- +-Command line to start QEMU with the TPM passthrough device using the host's +-hardware TPM /dev/tpm0: +- +-qemu-system-x86_64 -display sdl -accel kvm \ +- -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ +- -tpmdev passthrough,id=tpm0,path=/dev/tpm0 \ +- -device tpm-tis,tpmdev=tpm0 test.img +- +-The following commands should result in similar output inside the VM with a +-Linux kernel that either has the TPM TIS driver built-in or available as a +-module: +- +-#> dmesg | grep -i tpm +-[ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) +- +-#> dmesg | grep TCPA +-[ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ +- BXPCTCPA 0000001 BXPC 00000001) +- +-#> ls -l /dev/tpm* +-crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 +- +-#> find /sys/devices/ | grep pcrs$ | xargs cat +-PCR-00: 35 4E 3B CE 23 9F 38 59 ... +-... +-PCR-23: 00 00 00 00 00 00 00 00 ... +- +- +-== The QEMU TPM emulator device == +- +-The TPM emulator device uses an external TPM emulator called 'swtpm' for +-sending TPM commands to and receiving responses from. The swtpm program +-must have been started before trying to access it through the TPM emulator +-with QEMU. +- +-The TPM emulator implements a command channel for transferring TPM commands +-and responses as well as a control channel over which control commands can +-be sent. The specification for the control channel can be found here: +- +-https://github.com/stefanberger/swtpm/blob/master/man/man3/swtpm_ioctls.pod +- +- +-The control channel serves the purpose of resetting, initializing, and +-migrating the TPM state, among other things. +- +-The swtpm program behaves like a hardware TPM and therefore needs to be +-initialized by the firmware running inside the QEMU virtual machine. +-One necessary step for initializing the device is to send the TPM_Startup +-command to it. SeaBIOS, for example, has been instrumented to initialize +-a TPM 1.2 or TPM 2 device using this command. +- +- +-QEMU files related to the TPM emulator device: +- - hw/tpm/tpm_emulator.c +- - hw/tpm/tpm_util.c +- - hw/tpm/tpm_util.h +- +- +-The following commands start the swtpm with a UnixIO control channel over +-a socket interface. They do not need to be run as root. +- +-mkdir /tmp/mytpm1 +-swtpm socket --tpmstate dir=/tmp/mytpm1 \ +- --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ +- --log level=20 +- +-Command line to start QEMU with the TPM emulator device communicating with +-the swtpm (x86): +- +-qemu-system-x86_64 -display sdl -accel kvm \ +- -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ +- -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ +- -tpmdev emulator,id=tpm0,chardev=chrtpm \ +- -device tpm-tis,tpmdev=tpm0 test.img +- +-In case a pSeries machine is emulated, use the following command line: +- +-qemu-system-ppc64 -display sdl -machine pseries,accel=kvm \ +- -m 1024 -bios slof.bin -boot menu=on \ +- -nodefaults -device VGA -device pci-ohci -device usb-kbd \ +- -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ +- -tpmdev emulator,id=tpm0,chardev=chrtpm \ +- -device tpm-spapr,tpmdev=tpm0 \ +- -device spapr-vscsi,id=scsi0,reg=0x00002000 \ +- -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \ +- -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0 +- +- +-In case SeaBIOS is used as firmware, it should show the TPM menu item +-after entering the menu with 'ESC'. +- +-Select boot device: +-1. DVD/CD [ata1-0: QEMU DVD-ROM ATAPI-4 DVD/CD] +-[...] +-5. Legacy option rom +- +-t. TPM Configuration +- +- +-The following commands should result in similar output inside the VM with a +-Linux kernel that either has the TPM TIS driver built-in or available as a +-module: +- +-#> dmesg | grep -i tpm +-[ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) +- +-#> dmesg | grep TCPA +-[ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ +- BXPCTCPA 0000001 BXPC 00000001) +- +-#> ls -l /dev/tpm* +-crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 +- +-#> find /sys/devices/ | grep pcrs$ | xargs cat +-PCR-00: 35 4E 3B CE 23 9F 38 59 ... +-... +-PCR-23: 00 00 00 00 00 00 00 00 ... +- +- +-=== Migration with the TPM emulator === +- +-The TPM emulator supports the following types of virtual machine migration: +- +-- VM save / restore (migration into a file) +-- Network migration +-- Snapshotting (migration into storage like QoW2 or QED) +- +-The following command sequences can be used to test VM save / restore. +- +- +-In a 1st terminal start an instance of a swtpm using the following command: +- +-mkdir /tmp/mytpm1 +-swtpm socket --tpmstate dir=/tmp/mytpm1 \ +- --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ +- --log level=20 --tpm2 +- +-In a 2nd terminal start the VM: +- +-qemu-system-x86_64 -display sdl -accel kvm \ +- -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ +- -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ +- -tpmdev emulator,id=tpm0,chardev=chrtpm \ +- -device tpm-tis,tpmdev=tpm0 \ +- -monitor stdio \ +- test.img +- +-Verify that the attached TPM is working as expected using applications inside +-the VM. +- +-To store the state of the VM use the following command in the QEMU monitor in +-the 2nd terminal: +- +-(qemu) migrate "exec:cat > testvm.bin" +-(qemu) quit +- +-At this point a file called 'testvm.bin' should exists and the swtpm and QEMU +-processes should have ended. +- +-To test 'VM restore' you have to start the swtpm with the same parameters +-as before. If previously a TPM 2 [--tpm2] was saved, --tpm2 must now be +-passed again on the command line. +- +-In the 1st terminal restart the swtpm with the same command line as before: +- +-swtpm socket --tpmstate dir=/tmp/mytpm1 \ +- --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ +- --log level=20 --tpm2 +- +-In the 2nd terminal restore the state of the VM using the additional +-'-incoming' option. +- +-qemu-system-x86_64 -display sdl -accel kvm \ +- -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ +- -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ +- -tpmdev emulator,id=tpm0,chardev=chrtpm \ +- -device tpm-tis,tpmdev=tpm0 \ +- -incoming "exec:cat < testvm.bin" \ +- test.img +- +- +-Troubleshooting migration: +- +-There are several reasons why migration may fail. In case of problems, +-please ensure that the command lines adhere to the following rules and, +-if possible, that identical versions of QEMU and swtpm are used at all +-times. +- +-VM save and restore: +- - QEMU command line parameters should be identical apart from the +- '-incoming' option on VM restore +- - swtpm command line parameters should be identical +- +-VM migration to 'localhost': +- - QEMU command line parameters should be identical apart from the +- '-incoming' option on the destination side +- - swtpm command line parameters should point to two different +- directories on the source and destination swtpm (--tpmstate dir=...) +- (especially if different versions of libtpms were to be used on the +- same machine). +- +-VM migration across the network: +- - QEMU command line parameters should be identical apart from the +- '-incoming' option on the destination side +- - swtpm command line parameters should be identical +- +-VM Snapshotting: +- - QEMU command line parameters should be identical +- - swtpm command line parameters should be identical +- +- +-Besides that, migration failure reasons on the swtpm level may include +-the following: +- +- - the versions of the swtpm on the source and destination sides are +- incompatible +- - downgrading of TPM state may not be supported +- - the source and destination libtpms were compiled with different +- compile-time options and the destination side refuses to accept the +- state +- - different migration keys are used on the source and destination side +- and the destination side cannot decrypt the migrated state +- (swtpm ... --migration-key ... ) +-- +2.23.0 + diff --git a/es1370-check-total-frame-count-against-current-frame.patch b/es1370-check-total-frame-count-against-current-frame.patch new file mode 100644 index 0000000000000000000000000000000000000000..fb1e7a7cdfa6f8046b6aa2ebb270b557dcae14a5 --- /dev/null +++ b/es1370-check-total-frame-count-against-current-frame.patch @@ -0,0 +1,60 @@ +From 22bbf1a90ac11fe30e1665c09f9ad904683b6ddc Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit +Date: Fri, 15 May 2020 01:36:08 +0530 +Subject: [PATCH 1/9] es1370: check total frame count against current frame + +A guest user may set channel frame count via es1370_write() +such that, in es1370_transfer_audio(), total frame count +'size' is lesser than the number of frames that are processed +'cnt'. + + int cnt = d->frame_cnt >> 16; + int size = d->frame_cnt & 0xffff; + +if (size < cnt), it results in incorrect calculations leading +to OOB access issue(s). Add check to avoid it. + +Reported-by: Ren Ding +Reported-by: Hanqing Zhao +Signed-off-by: Prasad J Pandit +Message-id: 20200514200608.1744203-1-ppandit@redhat.com +Signed-off-by: Gerd Hoffmann +--- + hw/audio/es1370.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c +index 260c142b70..eff7d03ae1 100644 +--- a/hw/audio/es1370.c ++++ b/hw/audio/es1370.c +@@ -643,6 +643,9 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, + int csc_bytes = (csc + 1) << d->shift; + int cnt = d->frame_cnt >> 16; + int size = d->frame_cnt & 0xffff; ++ if (size < cnt) { ++ return; ++ } + int left = ((size - cnt + 1) << 2) + d->leftover; + int transferred = 0; + int temp = audio_MIN (max, audio_MIN (left, csc_bytes)); +@@ -651,7 +654,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, + addr += (cnt << 2) + d->leftover; + + if (index == ADC_CHANNEL) { +- while (temp) { ++ while (temp > 0) { + int acquired, to_copy; + + to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf)); +@@ -669,7 +672,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, + else { + SWVoiceOut *voice = s->dac_voice[index]; + +- while (temp) { ++ while (temp > 0) { + int copied, to_copy; + + to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf)); +-- +2.25.1 + diff --git a/exec-set-map-length-to-zero-when-returning-NULL.patch b/exec-set-map-length-to-zero-when-returning-NULL.patch new file mode 100644 index 0000000000000000000000000000000000000000..64c918e8d9de6eb3dd357c955d75488ff5f11c48 --- /dev/null +++ b/exec-set-map-length-to-zero-when-returning-NULL.patch @@ -0,0 +1,54 @@ +From a1a9d6f908b21878daa7868313243c30b7a90fcf Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit +Date: Tue, 26 May 2020 16:47:43 +0530 +Subject: [PATCH 2/9] exec: set map length to zero when returning NULL +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When mapping physical memory into host's virtual address space, +'address_space_map' may return NULL if BounceBuffer is in_use. +Set and return '*plen = 0' to avoid later NULL pointer dereference. + +Reported-by: Alexander Bulekov +Fixes: https://bugs.launchpad.net/qemu/+bug/1878259 +Suggested-by: Paolo Bonzini +Suggested-by: Peter Maydell +Signed-off-by: Prasad J Pandit +Message-Id: <20200526111743.428367-1-ppandit@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Paolo Bonzini +--- + exec.c | 1 + + include/exec/memory.h | 3 ++- + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/exec.c b/exec.c +index 3e78de3b8f..85c6d80353 100644 +--- a/exec.c ++++ b/exec.c +@@ -3739,6 +3739,7 @@ void *address_space_map(AddressSpace *as, + if (!memory_access_is_direct(mr, is_write)) { + if (atomic_xchg(&bounce.in_use, true)) { + rcu_read_unlock(); ++ *plen = 0; + return NULL; + } + /* Avoid unbounded allocations */ +diff --git a/include/exec/memory.h b/include/exec/memory.h +index 611a89122d..dca8184277 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -2064,7 +2064,8 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, hwaddr len, + /* address_space_map: map a physical memory region into a host virtual address + * + * May map a subset of the requested range, given by and returned in @plen. +- * May return %NULL if resources needed to perform the mapping are exhausted. ++ * May return %NULL and set *@plen to zero(0), if resources needed to perform ++ * the mapping are exhausted. + * Use only for reads OR writes - not for read-modify-write operations. + * Use cpu_register_map_client() to know when retrying the map operation is + * likely to succeed. +-- +2.25.1 + diff --git a/hbitmap-handle-set-reset-with-zero-length.patch b/hbitmap-handle-set-reset-with-zero-length.patch new file mode 100644 index 0000000000000000000000000000000000000000..b346a970d8594e2fae6a730c8c66370dc66af0da --- /dev/null +++ b/hbitmap-handle-set-reset-with-zero-length.patch @@ -0,0 +1,50 @@ +From c0b35d87de345bd3b59a44c604b247a0497f2fc0 Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Fri, 11 Oct 2019 12:07:07 +0300 +Subject: [PATCH] hbitmap: handle set/reset with zero length + +Passing zero length to these functions leads to unpredicted results. +Zero-length set/reset may occur in active-mirror, on zero-length write +(which is unlikely, but not guaranteed to never happen). + +Let's just do nothing on zero-length request. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-id: 20191011090711.19940-2-vsementsov@virtuozzo.com +Reviewed-by: Max Reitz +Cc: qemu-stable@nongnu.org +Signed-off-by: Max Reitz +(cherry picked from commit fed33bd175f663cc8c13f8a490a4f35a19756cfe) +Signed-off-by: Michael Roth +--- + util/hbitmap.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/util/hbitmap.c b/util/hbitmap.c +index 71c6ba2c52..c059313b9e 100644 +--- a/util/hbitmap.c ++++ b/util/hbitmap.c +@@ -387,6 +387,10 @@ void hbitmap_set(HBitmap *hb, uint64_t start, uint64_t count) + uint64_t first, n; + uint64_t last = start + count - 1; + ++ if (count == 0) { ++ return; ++ } ++ + trace_hbitmap_set(hb, start, count, + start >> hb->granularity, last >> hb->granularity); + +@@ -478,6 +482,10 @@ void hbitmap_reset(HBitmap *hb, uint64_t start, uint64_t count) + uint64_t last = start + count - 1; + uint64_t gran = 1ULL << hb->granularity; + ++ if (count == 0) { ++ return; ++ } ++ + assert(QEMU_IS_ALIGNED(start, gran)); + assert(QEMU_IS_ALIGNED(count, gran) || (start + count == hb->orig_size)); + +-- +2.23.0 diff --git a/hw-acpi-Add-ACPI-Generic-Event-Device-Support.patch b/hw-acpi-Add-ACPI-Generic-Event-Device-Support.patch new file mode 100644 index 0000000000000000000000000000000000000000..dc57aa64dd12427afc1e59af0476206317065d1b --- /dev/null +++ b/hw-acpi-Add-ACPI-Generic-Event-Device-Support.patch @@ -0,0 +1,478 @@ +From b12d9edd0079d4ee136c25e95333918b0c6d3cd9 Mon Sep 17 00:00:00 2001 +From: Samuel Ortiz +Date: Wed, 18 Sep 2019 14:06:25 +0100 +Subject: [PATCH] hw/acpi: Add ACPI Generic Event Device Support + +The ACPI Generic Event Device (GED) is a hardware-reduced specific +device[ACPI v6.1 Section 5.6.9] that handles all platform events, +including the hotplug ones. This patch generates the AML code that +defines GEDs. + +Platforms need to specify their own GED Event bitmap to describe +what kind of events they want to support through GED. Also this +uses a a single interrupt for the GED device, relying on IO +memory region to communicate the type of device affected by the +interrupt. This way, we can support up to 32 events with a unique +interrupt. + +This supports only memory hotplug for now. + +Signed-off-by: Samuel Ortiz +Signed-off-by: Sebastien Boeuf +Signed-off-by: Shameer Kolothum +Reviewed-by: Eric Auger +Message-Id: <20190918130633.4872-4-shameerali.kolothum.thodi@huawei.com> +Acked-by: Peter Maydell +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Igor Mammedov +--- + hw/acpi/Kconfig | 4 + + hw/acpi/Makefile.objs | 1 + + hw/acpi/generic_event_device.c | 303 +++++++++++++++++++++++++ + include/hw/acpi/generic_event_device.h | 100 ++++++++ + 4 files changed, 408 insertions(+) + create mode 100644 hw/acpi/generic_event_device.c + create mode 100644 include/hw/acpi/generic_event_device.h + +diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig +index 7c59cf900b..12e3f1e86e 100644 +--- a/hw/acpi/Kconfig ++++ b/hw/acpi/Kconfig +@@ -31,3 +31,7 @@ config ACPI_VMGENID + bool + default y + depends on PC ++ ++config ACPI_HW_REDUCED ++ bool ++ depends on ACPI +diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs +index 1a720c381e..e4b5d101a4 100644 +--- a/hw/acpi/Makefile.objs ++++ b/hw/acpi/Makefile.objs +@@ -6,6 +6,7 @@ common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o + common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o + common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o + common-obj-$(CONFIG_ACPI_VMGENID) += vmgenid.o ++common-obj-$(CONFIG_ACPI_HW_REDUCED) += generic_event_device.o + common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o + + common-obj-y += acpi_interface.o +diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c +new file mode 100644 +index 0000000000..b94500b08d +--- /dev/null ++++ b/hw/acpi/generic_event_device.c +@@ -0,0 +1,303 @@ ++/* ++ * ++ * Copyright (c) 2018 Intel Corporation ++ * Copyright (c) 2019 Huawei Technologies R & D (UK) Ltd ++ * Written by Samuel Ortiz, Shameer Kolothum ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ */ ++ ++#include "qemu/osdep.h" ++#include "qapi/error.h" ++#include "exec/address-spaces.h" ++#include "hw/acpi/acpi.h" ++#include "hw/acpi/generic_event_device.h" ++#include "hw/irq.h" ++#include "hw/mem/pc-dimm.h" ++#include "hw/qdev-properties.h" ++#include "migration/vmstate.h" ++#include "qemu/error-report.h" ++ ++static const uint32_t ged_supported_events[] = { ++ ACPI_GED_MEM_HOTPLUG_EVT, ++}; ++ ++/* ++ * The ACPI Generic Event Device (GED) is a hardware-reduced specific ++ * device[ACPI v6.1 Section 5.6.9] that handles all platform events, ++ * including the hotplug ones. Platforms need to specify their own ++ * GED Event bitmap to describe what kind of events they want to support ++ * through GED. This routine uses a single interrupt for the GED device, ++ * relying on IO memory region to communicate the type of device ++ * affected by the interrupt. This way, we can support up to 32 events ++ * with a unique interrupt. ++ */ ++void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev, ++ uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base) ++{ ++ AcpiGedState *s = ACPI_GED(hotplug_dev); ++ Aml *crs = aml_resource_template(); ++ Aml *evt, *field; ++ Aml *dev = aml_device("%s", name); ++ Aml *evt_sel = aml_local(0); ++ Aml *esel = aml_name(AML_GED_EVT_SEL); ++ ++ /* _CRS interrupt */ ++ aml_append(crs, aml_interrupt(AML_CONSUMER, AML_EDGE, AML_ACTIVE_HIGH, ++ AML_EXCLUSIVE, &ged_irq, 1)); ++ ++ aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0013"))); ++ aml_append(dev, aml_name_decl("_UID", aml_string(GED_DEVICE))); ++ aml_append(dev, aml_name_decl("_CRS", crs)); ++ ++ /* Append IO region */ ++ aml_append(dev, aml_operation_region(AML_GED_EVT_REG, rs, ++ aml_int(ged_base + ACPI_GED_EVT_SEL_OFFSET), ++ ACPI_GED_EVT_SEL_LEN)); ++ field = aml_field(AML_GED_EVT_REG, AML_DWORD_ACC, AML_NOLOCK, ++ AML_WRITE_AS_ZEROS); ++ aml_append(field, aml_named_field(AML_GED_EVT_SEL, ++ ACPI_GED_EVT_SEL_LEN * BITS_PER_BYTE)); ++ aml_append(dev, field); ++ ++ /* ++ * For each GED event we: ++ * - Add a conditional block for each event, inside a loop. ++ * - Call a method for each supported GED event type. ++ * ++ * The resulting ASL code looks like: ++ * ++ * Local0 = ESEL ++ * If ((Local0 & One) == One) ++ * { ++ * MethodEvent0() ++ * } ++ * ++ * If ((Local0 & 0x2) == 0x2) ++ * { ++ * MethodEvent1() ++ * } ++ * ... ++ */ ++ evt = aml_method("_EVT", 1, AML_SERIALIZED); ++ { ++ Aml *if_ctx; ++ uint32_t i; ++ uint32_t ged_events = ctpop32(s->ged_event_bitmap); ++ ++ /* Local0 = ESEL */ ++ aml_append(evt, aml_store(esel, evt_sel)); ++ ++ for (i = 0; i < ARRAY_SIZE(ged_supported_events) && ged_events; i++) { ++ uint32_t event = s->ged_event_bitmap & ged_supported_events[i]; ++ ++ if (!event) { ++ continue; ++ } ++ ++ if_ctx = aml_if(aml_equal(aml_and(evt_sel, aml_int(event), NULL), ++ aml_int(event))); ++ switch (event) { ++ case ACPI_GED_MEM_HOTPLUG_EVT: ++ aml_append(if_ctx, aml_call0(MEMORY_DEVICES_CONTAINER "." ++ MEMORY_SLOT_SCAN_METHOD)); ++ break; ++ default: ++ /* ++ * Please make sure all the events in ged_supported_events[] ++ * are handled above. ++ */ ++ g_assert_not_reached(); ++ } ++ ++ aml_append(evt, if_ctx); ++ ged_events--; ++ } ++ ++ if (ged_events) { ++ error_report("Unsupported events specified"); ++ abort(); ++ } ++ } ++ ++ /* Append _EVT method */ ++ aml_append(dev, evt); ++ ++ aml_append(table, dev); ++} ++ ++/* Memory read by the GED _EVT AML dynamic method */ ++static uint64_t ged_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ uint64_t val = 0; ++ GEDState *ged_st = opaque; ++ ++ switch (addr) { ++ case ACPI_GED_EVT_SEL_OFFSET: ++ /* Read the selector value and reset it */ ++ val = ged_st->sel; ++ ged_st->sel = 0; ++ break; ++ default: ++ break; ++ } ++ ++ return val; ++} ++ ++/* Nothing is expected to be written to the GED memory region */ ++static void ged_write(void *opaque, hwaddr addr, uint64_t data, ++ unsigned int size) ++{ ++} ++ ++static const MemoryRegionOps ged_ops = { ++ .read = ged_read, ++ .write = ged_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = { ++ .min_access_size = 4, ++ .max_access_size = 4, ++ }, ++}; ++ ++static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ AcpiGedState *s = ACPI_GED(hotplug_dev); ++ ++ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { ++ acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp); ++ } else { ++ error_setg(errp, "virt: device plug request for unsupported device" ++ " type: %s", object_get_typename(OBJECT(dev))); ++ } ++} ++ ++static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) ++{ ++ AcpiGedState *s = ACPI_GED(adev); ++ GEDState *ged_st = &s->ged_state; ++ uint32_t sel; ++ ++ if (ev & ACPI_MEMORY_HOTPLUG_STATUS) { ++ sel = ACPI_GED_MEM_HOTPLUG_EVT; ++ } else { ++ /* Unknown event. Return without generating interrupt. */ ++ warn_report("GED: Unsupported event %d. No irq injected", ev); ++ return; ++ } ++ ++ /* ++ * Set the GED selector field to communicate the event type. ++ * This will be read by GED aml code to select the appropriate ++ * event method. ++ */ ++ ged_st->sel |= sel; ++ ++ /* Trigger the event by sending an interrupt to the guest. */ ++ qemu_irq_pulse(s->irq); ++} ++ ++static Property acpi_ged_properties[] = { ++ DEFINE_PROP_UINT32("ged-event", AcpiGedState, ged_event_bitmap, 0), ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ ++static const VMStateDescription vmstate_memhp_state = { ++ .name = "acpi-ged/memhp", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField[]) { ++ VMSTATE_MEMORY_HOTPLUG(memhp_state, AcpiGedState), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++static const VMStateDescription vmstate_ged_state = { ++ .name = "acpi-ged-state", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT32(sel, GEDState), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++static const VMStateDescription vmstate_acpi_ged = { ++ .name = "acpi-ged", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField[]) { ++ VMSTATE_STRUCT(ged_state, AcpiGedState, 1, vmstate_ged_state, GEDState), ++ VMSTATE_END_OF_LIST(), ++ }, ++ .subsections = (const VMStateDescription * []) { ++ &vmstate_memhp_state, ++ NULL ++ } ++}; ++ ++static void acpi_ged_initfn(Object *obj) ++{ ++ DeviceState *dev = DEVICE(obj); ++ AcpiGedState *s = ACPI_GED(dev); ++ SysBusDevice *sbd = SYS_BUS_DEVICE(obj); ++ GEDState *ged_st = &s->ged_state; ++ ++ memory_region_init_io(&ged_st->io, obj, &ged_ops, ged_st, ++ TYPE_ACPI_GED, ACPI_GED_EVT_SEL_LEN); ++ sysbus_init_mmio(sbd, &ged_st->io); ++ ++ sysbus_init_irq(sbd, &s->irq); ++ ++ s->memhp_state.is_enabled = true; ++ /* ++ * GED handles memory hotplug event and acpi-mem-hotplug ++ * memory region gets initialized here. Create an exclusive ++ * container for memory hotplug IO and expose it as GED sysbus ++ * MMIO so that boards can map it separately. ++ */ ++ memory_region_init(&s->container_memhp, OBJECT(dev), "memhp container", ++ MEMORY_HOTPLUG_IO_LEN); ++ sysbus_init_mmio(sbd, &s->container_memhp); ++ acpi_memory_hotplug_init(&s->container_memhp, OBJECT(dev), ++ &s->memhp_state, 0); ++} ++ ++static void acpi_ged_class_init(ObjectClass *class, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(class); ++ HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(class); ++ AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class); ++ ++ dc->desc = "ACPI Generic Event Device"; ++ dc->props = acpi_ged_properties; ++ dc->vmsd = &vmstate_acpi_ged; ++ ++ hc->plug = acpi_ged_device_plug_cb; ++ ++ adevc->send_event = acpi_ged_send_event; ++} ++ ++static const TypeInfo acpi_ged_info = { ++ .name = TYPE_ACPI_GED, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(AcpiGedState), ++ .instance_init = acpi_ged_initfn, ++ .class_init = acpi_ged_class_init, ++ .interfaces = (InterfaceInfo[]) { ++ { TYPE_HOTPLUG_HANDLER }, ++ { TYPE_ACPI_DEVICE_IF }, ++ { } ++ } ++}; ++ ++static void acpi_ged_register_types(void) ++{ ++ type_register_static(&acpi_ged_info); ++} ++ ++type_init(acpi_ged_register_types) +diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h +new file mode 100644 +index 0000000000..2049e8d873 +--- /dev/null ++++ b/include/hw/acpi/generic_event_device.h +@@ -0,0 +1,100 @@ ++/* ++ * ++ * Copyright (c) 2018 Intel Corporation ++ * Copyright (c) 2019 Huawei Technologies R & D (UK) Ltd ++ * Written by Samuel Ortiz, Shameer Kolothum ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2 or later, as published by the Free Software Foundation. ++ * ++ * The ACPI Generic Event Device (GED) is a hardware-reduced specific ++ * device[ACPI v6.1 Section 5.6.9] that handles all platform events, ++ * including the hotplug ones. Generic Event Device allows platforms ++ * to handle interrupts in ACPI ASL statements. It follows a very ++ * similar approach like the _EVT method from GPIO events. All ++ * interrupts are listed in _CRS and the handler is written in _EVT ++ * method. Here, we use a single interrupt for the GED device, relying ++ * on IO memory region to communicate the type of device affected by ++ * the interrupt. This way, we can support up to 32 events with a ++ * unique interrupt. ++ * ++ * Here is an example. ++ * ++ * Device (\_SB.GED) ++ * { ++ * Name (_HID, "ACPI0013") ++ * Name (_UID, Zero) ++ * Name (_CRS, ResourceTemplate () ++ * { ++ * Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, ) ++ * { ++ * 0x00000029, ++ * } ++ * }) ++ * OperationRegion (EREG, SystemMemory, 0x09080000, 0x04) ++ * Field (EREG, DWordAcc, NoLock, WriteAsZeros) ++ * { ++ * ESEL, 32 ++ * } ++ * ++ * Method (_EVT, 1, Serialized) // _EVT: Event ++ * { ++ * Local0 = ESEL // ESEL = IO memory region which specifies the ++ * // device type. ++ * If (((Local0 & One) == One)) ++ * { ++ * MethodEvent1() ++ * } ++ * If ((Local0 & 0x2) == 0x2) ++ * { ++ * MethodEvent2() ++ * } ++ * ... ++ * } ++ * } ++ * ++ */ ++ ++#ifndef HW_ACPI_GED_H ++#define HW_ACPI_GED_H ++ ++#include "hw/sysbus.h" ++#include "hw/acpi/memory_hotplug.h" ++ ++#define TYPE_ACPI_GED "acpi-ged" ++#define ACPI_GED(obj) \ ++ OBJECT_CHECK(AcpiGedState, (obj), TYPE_ACPI_GED) ++ ++#define ACPI_GED_EVT_SEL_OFFSET 0x0 ++#define ACPI_GED_EVT_SEL_LEN 0x4 ++ ++#define GED_DEVICE "GED" ++#define AML_GED_EVT_REG "EREG" ++#define AML_GED_EVT_SEL "ESEL" ++ ++/* ++ * Platforms need to specify the GED event bitmap ++ * to describe what kind of events they want to support ++ * through GED. ++ */ ++#define ACPI_GED_MEM_HOTPLUG_EVT 0x1 ++ ++typedef struct GEDState { ++ MemoryRegion io; ++ uint32_t sel; ++} GEDState; ++ ++typedef struct AcpiGedState { ++ SysBusDevice parent_obj; ++ MemHotplugState memhp_state; ++ MemoryRegion container_memhp; ++ GEDState ged_state; ++ uint32_t ged_event_bitmap; ++ qemu_irq irq; ++} AcpiGedState; ++ ++void build_ged_aml(Aml *table, const char* name, HotplugHandler *hotplug_dev, ++ uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base); ++ ++#endif +-- +2.19.1 diff --git a/hw-acpi-Do-not-create-memory-hotplug-method-when-han.patch b/hw-acpi-Do-not-create-memory-hotplug-method-when-han.patch new file mode 100644 index 0000000000000000000000000000000000000000..292687199fbe797b86b25ac2fb56063f7080a0f0 --- /dev/null +++ b/hw-acpi-Do-not-create-memory-hotplug-method-when-han.patch @@ -0,0 +1,46 @@ +From 7a08983315bf4d624966a89112259e2b4949de91 Mon Sep 17 00:00:00 2001 +From: Samuel Ortiz +Date: Wed, 18 Sep 2019 14:06:24 +0100 +Subject: [PATCH] hw/acpi: Do not create memory hotplug method when handler is + not defined + +With Hardware-reduced ACPI, the GED device will manage ACPI +hotplug entirely. As a consequence, make the memory specific +events AML generation optional. The code will only be added +when the method name is not NULL. + +Signed-off-by: Samuel Ortiz +Signed-off-by: Shameer Kolothum +Reviewed-by: Eric Auger +Reviewed-by: Igor Mammedov +Message-Id: <20190918130633.4872-3-shameerali.kolothum.thodi@huawei.com> +Acked-by: Peter Maydell +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/acpi/memory_hotplug.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c +index 9a515c0484..8b30356c1a 100644 +--- a/hw/acpi/memory_hotplug.c ++++ b/hw/acpi/memory_hotplug.c +@@ -711,10 +711,12 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, + } + aml_append(table, dev_container); + +- method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED); +- aml_append(method, +- aml_call0(MEMORY_DEVICES_CONTAINER "." MEMORY_SLOT_SCAN_METHOD)); +- aml_append(table, method); ++ if (event_handler_method) { ++ method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED); ++ aml_append(method, aml_call0(MEMORY_DEVICES_CONTAINER "." ++ MEMORY_SLOT_SCAN_METHOD)); ++ aml_append(table, method); ++ } + + g_free(mhp_res_path); + } +-- +2.19.1 diff --git a/hw-acpi-Make-ACPI-IO-address-space-configurable.patch b/hw-acpi-Make-ACPI-IO-address-space-configurable.patch new file mode 100644 index 0000000000000000000000000000000000000000..cdf597b51566400b17ddac3e27dc93cb65a61bd6 --- /dev/null +++ b/hw-acpi-Make-ACPI-IO-address-space-configurable.patch @@ -0,0 +1,196 @@ +From 6cd7281c73ca462b2f27969f1e28f1afd3ebe82d Mon Sep 17 00:00:00 2001 +From: Shameer Kolothum +Date: Wed, 18 Sep 2019 14:06:23 +0100 +Subject: [PATCH] hw/acpi: Make ACPI IO address space configurable + +This is in preparation for adding support for ARM64 platforms +where it doesn't use port mapped IO for ACPI IO space. We are +making changes so that MMIO region can be accommodated +and board can pass the base address into the aml build function. + +Also move few MEMORY_* definitions to header so that other memory +hotplug event signalling mechanisms (eg. Generic Event Device on +HW-reduced acpi platforms) can use the same from their respective +event handler code. + +Signed-off-by: Shameer Kolothum +Reviewed-by: Eric Auger +Reviewed-by: Igor Mammedov +Message-Id: <20190918130633.4872-2-shameerali.kolothum.thodi@huawei.com> +Acked-by: Peter Maydell +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/acpi/memory_hotplug.c | 33 ++++++++++++++------------------ + hw/i386/acpi-build.c | 7 ++++++- + hw/i386/pc.c | 3 +++ + include/hw/acpi/memory_hotplug.h | 9 +++++++-- + include/hw/i386/pc.h | 3 +++ + 5 files changed, 33 insertions(+), 22 deletions(-) + +diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c +index 297812d5f7..9a515c0484 100644 +--- a/hw/acpi/memory_hotplug.c ++++ b/hw/acpi/memory_hotplug.c +@@ -29,12 +29,7 @@ + #define MEMORY_SLOT_PROXIMITY_METHOD "MPXM" + #define MEMORY_SLOT_EJECT_METHOD "MEJ0" + #define MEMORY_SLOT_NOTIFY_METHOD "MTFY" +-#define MEMORY_SLOT_SCAN_METHOD "MSCN" + #define MEMORY_HOTPLUG_DEVICE "MHPD" +-#define MEMORY_HOTPLUG_IO_LEN 24 +-#define MEMORY_DEVICES_CONTAINER "\\_SB.MHPC" +- +-static uint16_t memhp_io_base; + + static ACPIOSTInfo *acpi_memory_device_status(int slot, MemStatus *mdev) + { +@@ -209,7 +204,7 @@ static const MemoryRegionOps acpi_memory_hotplug_ops = { + }; + + void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner, +- MemHotplugState *state, uint16_t io_base) ++ MemHotplugState *state, hwaddr io_base) + { + MachineState *machine = MACHINE(qdev_get_machine()); + +@@ -218,12 +213,10 @@ void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner, + return; + } + +- assert(!memhp_io_base); +- memhp_io_base = io_base; + state->devs = g_malloc0(sizeof(*state->devs) * state->dev_count); + memory_region_init_io(&state->io, owner, &acpi_memory_hotplug_ops, state, + "acpi-mem-hotplug", MEMORY_HOTPLUG_IO_LEN); +- memory_region_add_subregion(as, memhp_io_base, &state->io); ++ memory_region_add_subregion(as, io_base, &state->io); + } + + /** +@@ -342,7 +335,8 @@ const VMStateDescription vmstate_memory_hotplug = { + + void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, + const char *res_root, +- const char *event_handler_method) ++ const char *event_handler_method, ++ AmlRegionSpace rs, hwaddr memhp_io_base) + { + int i; + Aml *ifctx; +@@ -351,10 +345,6 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, + Aml *mem_ctrl_dev; + char *mhp_res_path; + +- if (!memhp_io_base) { +- return; +- } +- + mhp_res_path = g_strdup_printf("%s." MEMORY_HOTPLUG_DEVICE, res_root); + mem_ctrl_dev = aml_device("%s", mhp_res_path); + { +@@ -365,14 +355,19 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, + aml_name_decl("_UID", aml_string("Memory hotplug resources"))); + + crs = aml_resource_template(); +- aml_append(crs, +- aml_io(AML_DECODE16, memhp_io_base, memhp_io_base, 0, +- MEMORY_HOTPLUG_IO_LEN) +- ); ++ if (rs == AML_SYSTEM_IO) { ++ aml_append(crs, ++ aml_io(AML_DECODE16, memhp_io_base, memhp_io_base, 0, ++ MEMORY_HOTPLUG_IO_LEN) ++ ); ++ } else { ++ aml_append(crs, aml_memory32_fixed(memhp_io_base, ++ MEMORY_HOTPLUG_IO_LEN, AML_READ_WRITE)); ++ } + aml_append(mem_ctrl_dev, aml_name_decl("_CRS", crs)); + + aml_append(mem_ctrl_dev, aml_operation_region( +- MEMORY_HOTPLUG_IO_REGION, AML_SYSTEM_IO, ++ MEMORY_HOTPLUG_IO_REGION, rs, + aml_int(memhp_io_base), MEMORY_HOTPLUG_IO_LEN) + ); + +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index f3fdfefcd5..749218561a 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -1871,7 +1871,12 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, + build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base, + "\\_SB.PCI0", "\\_GPE._E02"); + } +- build_memory_hotplug_aml(dsdt, nr_mem, "\\_SB.PCI0", "\\_GPE._E03"); ++ ++ if (pcms->memhp_io_base && nr_mem) { ++ build_memory_hotplug_aml(dsdt, nr_mem, "\\_SB.PCI0", ++ "\\_GPE._E03", AML_SYSTEM_IO, ++ pcms->memhp_io_base); ++ } + + scope = aml_scope("_GPE"); + { +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index d011733ff7..8a914130b0 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -1936,6 +1936,9 @@ void pc_memory_init(PCMachineState *pcms, + + /* Init default IOAPIC address space */ + pcms->ioapic_as = &address_space_memory; ++ ++ /* Init ACPI memory hotplug IO base address */ ++ pcms->memhp_io_base = ACPI_MEMORY_HOTPLUG_BASE; + } + + /* +diff --git a/include/hw/acpi/memory_hotplug.h b/include/hw/acpi/memory_hotplug.h +index 77c65765d6..dfe9cf3fde 100644 +--- a/include/hw/acpi/memory_hotplug.h ++++ b/include/hw/acpi/memory_hotplug.h +@@ -5,6 +5,10 @@ + #include "hw/acpi/acpi.h" + #include "hw/acpi/aml-build.h" + ++#define MEMORY_SLOT_SCAN_METHOD "MSCN" ++#define MEMORY_DEVICES_CONTAINER "\\_SB.MHPC" ++#define MEMORY_HOTPLUG_IO_LEN 24 ++ + /** + * MemStatus: + * @is_removing: the memory device in slot has been requested to be ejected. +@@ -29,7 +33,7 @@ typedef struct MemHotplugState { + } MemHotplugState; + + void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner, +- MemHotplugState *state, uint16_t io_base); ++ MemHotplugState *state, hwaddr io_base); + + void acpi_memory_plug_cb(HotplugHandler *hotplug_dev, MemHotplugState *mem_st, + DeviceState *dev, Error **errp); +@@ -48,5 +52,6 @@ void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list); + + void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, + const char *res_root, +- const char *event_handler_method); ++ const char *event_handler_method, ++ AmlRegionSpace rs, hwaddr memhp_io_base); + #endif +diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h +index 859b64c51d..49b47535cf 100644 +--- a/include/hw/i386/pc.h ++++ b/include/hw/i386/pc.h +@@ -69,6 +69,9 @@ struct PCMachineState { + /* Address space used by IOAPIC device. All IOAPIC interrupts + * will be translated to MSI messages in the address space. */ + AddressSpace *ioapic_as; ++ ++ /* ACPI Memory hotplug IO base address */ ++ hwaddr memhp_io_base; + }; + + #define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device" +-- +2.19.1 diff --git a/hw-arm-Factor-out-powerdown-notifier-from-GPIO.patch b/hw-arm-Factor-out-powerdown-notifier-from-GPIO.patch new file mode 100644 index 0000000000000000000000000000000000000000..f2c0f3900d05652a977be13df0babb8210c65b1b --- /dev/null +++ b/hw-arm-Factor-out-powerdown-notifier-from-GPIO.patch @@ -0,0 +1,72 @@ +From e6b1fd7bfbfe116e9d5df590f7069336c1eb1983 Mon Sep 17 00:00:00 2001 +From: Shameer Kolothum +Date: Wed, 18 Sep 2019 14:06:29 +0100 +Subject: [PATCH] hw/arm: Factor out powerdown notifier from GPIO + +This is in preparation of using GED device for +system_powerdown event. Make the powerdown notifier +registration independent of create_gpio() fn. + +Signed-off-by: Shameer Kolothum +Reviewed-by: Eric Auger +Reviewed-by: Igor Mammedov +Message-Id: <20190918130633.4872-8-shameerali.kolothum.thodi@huawei.com> +Acked-by: Peter Maydell +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/arm/virt.c | 12 ++++-------- + include/hw/arm/virt.h | 1 + + 2 files changed, 5 insertions(+), 8 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index ab33cce4b3..aaefa5578e 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -910,10 +910,6 @@ static void virt_powerdown_req(Notifier *n, void *opaque) + qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1); + } + +-static Notifier virt_system_powerdown_notifier = { +- .notify = virt_powerdown_req +-}; +- + static void create_gpio(const VirtMachineState *vms, qemu_irq *pic) + { + char *nodename; +@@ -954,10 +950,6 @@ static void create_gpio(const VirtMachineState *vms, qemu_irq *pic) + KEY_POWER); + qemu_fdt_setprop_cells(vms->fdt, "/gpio-keys/poweroff", + "gpios", phandle, 3, 0); +- +- /* connect powerdown request */ +- qemu_register_powerdown_notifier(&virt_system_powerdown_notifier); +- + g_free(nodename); + } + +@@ -1856,6 +1848,10 @@ static void machvirt_init(MachineState *machine) + vms->acpi_dev = create_acpi_ged(vms, pic); + } + ++ /* connect powerdown request */ ++ vms->powerdown_notifier.notify = virt_powerdown_req; ++ qemu_register_powerdown_notifier(&vms->powerdown_notifier); ++ + /* Create mmio transports, so the user can create virtio backends + * (which will be automatically plugged in to the transports). If + * no backend is created the transport will just sit harmlessly idle. +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index 0350285136..dcceb9c615 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -139,6 +139,7 @@ typedef struct { + int psci_conduit; + hwaddr highest_gpa; + DeviceState *acpi_dev; ++ Notifier powerdown_notifier; + } VirtMachineState; + + #define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM) +-- +2.19.1 diff --git a/hw-arm-Use-GED-for-system_powerdown-event.patch b/hw-arm-Use-GED-for-system_powerdown-event.patch new file mode 100644 index 0000000000000000000000000000000000000000..140f59a2c71da40f47a2edd2bd2dd529227c3ddc --- /dev/null +++ b/hw-arm-Use-GED-for-system_powerdown-event.patch @@ -0,0 +1,167 @@ +From 0b77f242b180f1ae40b9752999cef4894113df8e Mon Sep 17 00:00:00 2001 +From: Shameer Kolothum +Date: Wed, 18 Sep 2019 14:06:30 +0100 +Subject: [PATCH] hw/arm: Use GED for system_powerdown event + +For machines 4.2 or higher with ACPI boot use GED for system_powerdown +event instead of GPIO. Guest boot with DT still uses GPIO. + +Signed-off-by: Shameer Kolothum +Reviewed-by: Eric Auger +Reviewed-by: Igor Mammedov +Message-Id: <20190918130633.4872-9-shameerali.kolothum.thodi@huawei.com> +Acked-by: Peter Maydell +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/acpi/generic_event_device.c | 8 ++++++++ + hw/arm/virt-acpi-build.c | 6 +++--- + hw/arm/virt.c | 18 ++++++++++++------ + include/hw/acpi/acpi_dev_interface.h | 1 + + include/hw/acpi/generic_event_device.h | 3 +++ + 5 files changed, 27 insertions(+), 9 deletions(-) + +diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c +index b94500b08d..9cee90cc70 100644 +--- a/hw/acpi/generic_event_device.c ++++ b/hw/acpi/generic_event_device.c +@@ -22,6 +22,7 @@ + + static const uint32_t ged_supported_events[] = { + ACPI_GED_MEM_HOTPLUG_EVT, ++ ACPI_GED_PWR_DOWN_EVT, + }; + + /* +@@ -104,6 +105,11 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev, + aml_append(if_ctx, aml_call0(MEMORY_DEVICES_CONTAINER "." + MEMORY_SLOT_SCAN_METHOD)); + break; ++ case ACPI_GED_PWR_DOWN_EVT: ++ aml_append(if_ctx, ++ aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE), ++ aml_int(0x80))); ++ break; + default: + /* + * Please make sure all the events in ged_supported_events[] +@@ -184,6 +190,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) + + if (ev & ACPI_MEMORY_HOTPLUG_STATUS) { + sel = ACPI_GED_MEM_HOTPLUG_EVT; ++ } else if (ev & ACPI_POWER_DOWN_STATUS) { ++ sel = ACPI_GED_PWR_DOWN_EVT; + } else { + /* Unknown event. Return without generating interrupt. */ + warn_report("GED: Unsupported event %d. No irq injected", ev); +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index 9622994e50..f48733d9f2 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -50,7 +50,6 @@ + #include "hw/acpi/acpi-defs.h" + + #define ARM_SPI_BASE 32 +-#define ACPI_POWER_BUTTON_DEVICE "PWRB" + + static void acpi_dsdt_add_psd(Aml *dev, int cpus) + { +@@ -813,13 +812,14 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS); + acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE), + vms->highmem, vms->highmem_ecam); +- acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO], +- (irqmap[VIRT_GPIO] + ARM_SPI_BASE)); + if (vms->acpi_dev) { + build_ged_aml(scope, "\\_SB."GED_DEVICE, + HOTPLUG_HANDLER(vms->acpi_dev), + irqmap[VIRT_ACPI_GED] + ARM_SPI_BASE, AML_SYSTEM_MEMORY, + memmap[VIRT_ACPI_GED].base); ++ } else { ++ acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO], ++ (irqmap[VIRT_GPIO] + ARM_SPI_BASE)); + } + + if (vms->acpi_dev) { +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index aaefa5578e..18321e522b 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -639,10 +639,10 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms, qemu_irq *pic) + DeviceState *dev; + MachineState *ms = MACHINE(vms); + int irq = vms->irqmap[VIRT_ACPI_GED]; +- uint32_t event = 0; ++ uint32_t event = ACPI_GED_PWR_DOWN_EVT; + + if (ms->ram_slots) { +- event = ACPI_GED_MEM_HOTPLUG_EVT; ++ event |= ACPI_GED_MEM_HOTPLUG_EVT; + } + + dev = qdev_create(NULL, TYPE_ACPI_GED); +@@ -906,8 +906,14 @@ static void create_rtc(const VirtMachineState *vms, qemu_irq *pic) + static DeviceState *gpio_key_dev; + static void virt_powerdown_req(Notifier *n, void *opaque) + { +- /* use gpio Pin 3 for power button event */ +- qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1); ++ VirtMachineState *s = container_of(n, VirtMachineState, powerdown_notifier); ++ ++ if (s->acpi_dev) { ++ acpi_send_event(s->acpi_dev, ACPI_POWER_DOWN_STATUS); ++ } else { ++ /* use gpio Pin 3 for power button event */ ++ qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1); ++ } + } + + static void create_gpio(const VirtMachineState *vms, qemu_irq *pic) +@@ -1842,10 +1848,10 @@ static void machvirt_init(MachineState *machine) + + create_pcie(vms, pic); + +- create_gpio(vms, pic); +- + if (has_ged && aarch64 && firmware_loaded && acpi_enabled) { + vms->acpi_dev = create_acpi_ged(vms, pic); ++ } else { ++ create_gpio(vms, pic); + } + + /* connect powerdown request */ +diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h +index 43ff119179..adcb3a816c 100644 +--- a/include/hw/acpi/acpi_dev_interface.h ++++ b/include/hw/acpi/acpi_dev_interface.h +@@ -11,6 +11,7 @@ typedef enum { + ACPI_MEMORY_HOTPLUG_STATUS = 8, + ACPI_NVDIMM_HOTPLUG_STATUS = 16, + ACPI_VMGENID_CHANGE_STATUS = 32, ++ ACPI_POWER_DOWN_STATUS = 64, + } AcpiEventStatusBits; + + #define TYPE_ACPI_DEVICE_IF "acpi-device-interface" +diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h +index 2049e8d873..d157eac088 100644 +--- a/include/hw/acpi/generic_event_device.h ++++ b/include/hw/acpi/generic_event_device.h +@@ -62,6 +62,8 @@ + #include "hw/sysbus.h" + #include "hw/acpi/memory_hotplug.h" + ++#define ACPI_POWER_BUTTON_DEVICE "PWRB" ++ + #define TYPE_ACPI_GED "acpi-ged" + #define ACPI_GED(obj) \ + OBJECT_CHECK(AcpiGedState, (obj), TYPE_ACPI_GED) +@@ -79,6 +81,7 @@ + * through GED. + */ + #define ACPI_GED_MEM_HOTPLUG_EVT 0x1 ++#define ACPI_GED_PWR_DOWN_EVT 0x2 + + typedef struct GEDState { + MemoryRegion io; +-- +2.19.1 diff --git a/hw-arm-acpi-enable-SHPC-native-hot-plug.patch b/hw-arm-acpi-enable-SHPC-native-hot-plug.patch new file mode 100644 index 0000000000000000000000000000000000000000..2b2e530bb8e3555b4f9cf2a807b060ac62ccd9de --- /dev/null +++ b/hw-arm-acpi-enable-SHPC-native-hot-plug.patch @@ -0,0 +1,45 @@ +From 1ad2e774f4fd3f720d5db07e86fe60df13f21a6d Mon Sep 17 00:00:00 2001 +From: Heyi Guo +Date: Mon, 9 Dec 2019 14:37:19 +0800 +Subject: [PATCH] hw/arm/acpi: enable SHPC native hot plug + +After the introduction of generic PCIe root port and PCIe-PCI bridge, +we will also have SHPC controller on ARM, so just enable SHPC native +hot plug. + +Also update tests/data/acpi/virt/DSDT* to pass "make check". + +Cc: Shannon Zhao +Cc: Peter Maydell +Cc: "Michael S. Tsirkin" +Cc: Igor Mammedov +Reviewed-by: Michael S. Tsirkin +Reviewed-by: Igor Mammedov +Signed-off-by: Heyi Guo +Message-id: 20191209063719.23086-3-guoheyi@huawei.com +Signed-off-by: Peter Maydell +--- + hw/arm/virt-acpi-build.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index 2cfac7b84f..588e7f2680 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -347,7 +347,12 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, + aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); + aml_append(ifctx, aml_store(aml_name("CDW2"), aml_name("SUPP"))); + aml_append(ifctx, aml_store(aml_name("CDW3"), aml_name("CTRL"))); +- aml_append(ifctx, aml_store(aml_and(aml_name("CTRL"), aml_int(0x1D), NULL), ++ ++ /* ++ * Allow OS control for all 5 features: ++ * PCIeHotplug SHPCHotplug PME AER PCIeCapability. ++ */ ++ aml_append(ifctx, aml_store(aml_and(aml_name("CTRL"), aml_int(0x1F), NULL), + aml_name("CTRL"))); + + ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1)))); +-- +2.23.0 + diff --git a/hw-arm-boot-Add-manually-register-and-trigger-of-CPU.patch b/hw-arm-boot-Add-manually-register-and-trigger-of-CPU.patch new file mode 100644 index 0000000000000000000000000000000000000000..95abd07e5a2b62acd14c1a45e61ce471707f173e --- /dev/null +++ b/hw-arm-boot-Add-manually-register-and-trigger-of-CPU.patch @@ -0,0 +1,115 @@ +From de86ba0ff72a51b0c1cdbebf790869aea73ae9d3 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Thu, 9 Apr 2020 09:31:22 +0800 +Subject: [PATCH] hw/arm/boot: Add manually register and trigger of CPU reset + +We need to register and trigger CPU reset manually for hotplugged +CPU. Besides, we gather CPU reset handlers of all CPUs because CPU +reset should happen before GIC reset. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/boot.c | 18 ++++++++++++++++++ + hw/core/reset.c | 25 +++++++++++++++++++++++++ + include/hw/arm/boot.h | 3 +++ + include/sysemu/reset.h | 4 ++++ + 4 files changed, 50 insertions(+) + +diff --git a/hw/arm/boot.c b/hw/arm/boot.c +index fc4e021a38..3ab9de6456 100644 +--- a/hw/arm/boot.c ++++ b/hw/arm/boot.c +@@ -789,6 +789,24 @@ static void do_cpu_reset(void *opaque) + } + } + ++void cpu_hotplug_register_reset(int ncpu) ++{ ++ CPUState *cpu_0 = qemu_get_cpu(0); ++ CPUState *cpu = qemu_get_cpu(ncpu); ++ QEMUResetEntry *entry = qemu_get_reset_entry(do_cpu_reset, cpu_0); ++ ++ assert(entry); ++ /* Gather the reset handlers of all CPUs */ ++ qemu_register_reset_after(entry, do_cpu_reset, cpu); ++} ++ ++void cpu_hotplug_reset_manually(int ncpu) ++{ ++ CPUState *cpu = qemu_get_cpu(ncpu); ++ ++ do_cpu_reset(cpu); ++} ++ + /** + * load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified + * by key. +diff --git a/hw/core/reset.c b/hw/core/reset.c +index 9c477f2bf5..0efaf2d76c 100644 +--- a/hw/core/reset.c ++++ b/hw/core/reset.c +@@ -47,6 +47,31 @@ void qemu_register_reset(QEMUResetHandler *func, void *opaque) + QTAILQ_INSERT_TAIL(&reset_handlers, re, entry); + } + ++QEMUResetEntry *qemu_get_reset_entry(QEMUResetHandler *func, ++ void *opaque) ++{ ++ QEMUResetEntry *re; ++ ++ QTAILQ_FOREACH(re, &reset_handlers, entry) { ++ if (re->func == func && re->opaque == opaque) { ++ return re; ++ } ++ } ++ ++ return NULL; ++} ++ ++void qemu_register_reset_after(QEMUResetEntry *entry, ++ QEMUResetHandler *func, ++ void *opaque) ++{ ++ QEMUResetEntry *re = g_malloc0(sizeof(QEMUResetEntry)); ++ ++ re->func = func; ++ re->opaque = opaque; ++ QTAILQ_INSERT_AFTER(&reset_handlers, entry, re, entry); ++} ++ + void qemu_unregister_reset(QEMUResetHandler *func, void *opaque) + { + QEMUResetEntry *re; +diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h +index c48cc4c2bc..9452ccd1fa 100644 +--- a/include/hw/arm/boot.h ++++ b/include/hw/arm/boot.h +@@ -118,6 +118,9 @@ struct arm_boot_info { + arm_endianness endianness; + }; + ++void cpu_hotplug_register_reset(int ncpu); ++void cpu_hotplug_reset_manually(int ncpu); ++ + /** + * arm_load_kernel - Loads memory with everything needed to boot + * +diff --git a/include/sysemu/reset.h b/include/sysemu/reset.h +index 0b0d6d7598..f3ff26c637 100644 +--- a/include/sysemu/reset.h ++++ b/include/sysemu/reset.h +@@ -2,7 +2,11 @@ + #define QEMU_SYSEMU_RESET_H + + typedef void QEMUResetHandler(void *opaque); ++typedef struct QEMUResetEntry QEMUResetEntry; + ++QEMUResetEntry *qemu_get_reset_entry(QEMUResetHandler *func, void *opaque); ++void qemu_register_reset_after(QEMUResetEntry *entry, ++ QEMUResetHandler *func, void *opaque); + void qemu_register_reset(QEMUResetHandler *func, void *opaque); + void qemu_unregister_reset(QEMUResetHandler *func, void *opaque); + void qemu_devices_reset(void); +-- +2.19.1 diff --git a/hw-arm-boot.c-Set-NSACR.-CP11-CP10-for-NS-kernel-boo.patch b/hw-arm-boot.c-Set-NSACR.-CP11-CP10-for-NS-kernel-boo.patch new file mode 100644 index 0000000000000000000000000000000000000000..e7ca51a5deb7146de6d6b05aa1d8391b0c08adac --- /dev/null +++ b/hw-arm-boot.c-Set-NSACR.-CP11-CP10-for-NS-kernel-boo.patch @@ -0,0 +1,47 @@ +From 220816989c1e3d490d293b8d7ac85dbc41a4c321 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 20 Sep 2019 18:40:39 +0100 +Subject: [PATCH] hw/arm/boot.c: Set NSACR.{CP11,CP10} for NS kernel boots + +If we're booting a Linux kernel directly into Non-Secure +state on a CPU which has Secure state, then make sure we +set the NSACR CP11 and CP10 bits, so that Non-Secure is allowed +to access the FPU. Otherwise an AArch32 kernel will UNDEF as +soon as it tries to use the FPU. + +It used to not matter that we didn't do this until commit +fc1120a7f5f2d4b6, where we implemented actually honouring +these NSACR bits. + +The problem only exists for CPUs where EL3 is AArch32; the +equivalent AArch64 trap bits are in CPTR_EL3 and are "0 to +not trap, 1 to trap", so the reset value of the register +permits NS access, unlike NSACR. + +Fixes: fc1120a7f5 +Fixes: https://bugs.launchpad.net/qemu/+bug/1844597 +Cc: qemu-stable@nongnu.org +Signed-off-by: Peter Maydell +Reviewed-by: Richard Henderson +Message-id: 20190920174039.3916-1-peter.maydell@linaro.org +(cherry picked from commit ece628fcf69cbbd4b3efb6fbd203af07609467a2) +Signed-off-by: Michael Roth +--- + hw/arm/boot.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/arm/boot.c b/hw/arm/boot.c +index c2b89b3bb9..fc4e021a38 100644 +--- a/hw/arm/boot.c ++++ b/hw/arm/boot.c +@@ -754,6 +754,8 @@ static void do_cpu_reset(void *opaque) + (cs != first_cpu || !info->secure_board_setup)) { + /* Linux expects non-secure state */ + env->cp15.scr_el3 |= SCR_NS; ++ /* Set NSACR.{CP11,CP10} so NS can access the FPU */ ++ env->cp15.nsacr |= 3 << 10; + } + } + +-- +2.23.0 diff --git a/hw-arm-expose-host-CPU-frequency-info-to-guest.patch b/hw-arm-expose-host-CPU-frequency-info-to-guest.patch index 0b04076e5478d671dc55937313d677e603d23720..f0093812ed61e769afec350993e0298a4c5f9e10 100644 --- a/hw-arm-expose-host-CPU-frequency-info-to-guest.patch +++ b/hw-arm-expose-host-CPU-frequency-info-to-guest.patch @@ -1,54 +1,57 @@ -From 773b25c55c7428b64d21b23a6b08fc629a665ca5 Mon Sep 17 00:00:00 2001 -From: zhanghailiang -Date: Mon, 29 Jul 2019 09:54:43 +0800 -Subject: [PATCH] hw/arm: expose host CPU frequency info to guest +From b70d020dba72283d7b16a77c377512c84aab5f81 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Mon, 20 Apr 2020 10:38:12 +0800 +Subject: [PATCH] arm64: Add the cpufreq device to show cpufreq info to guest -On ARM64, CPU frequency is fetched by ACPI CPPC, so we add virtual -CPPC registers and ACPI _CPC objects. +On ARM64 platform, cpu frequency is retrieved via ACPI CPPC. +A virtual cpufreq device based on ACPI CPPC is created to +present cpu frequency info to the guest. -The default frequency is set to the nominal frequency of Hi1616, which -will not support CPPC in future. On Hi1620 we are fetching the value -from Host CPPC sys file. +The default frequency is set to host cpu nominal frequency, +which is obtained from the host CPPC sysfs. Other performance +data are set to the same value, since we don't support guest +performance scaling here. -All performance data are set to the same value for we don't support -guest initiating performance scaling. - -We don't emulate performance counters and simply return 1 for all -counter readings, and guest Linux should fall back to use the desired +Performance counters are also not emulated and they simply +return 1 if read, and guest should fallback to use desired performance value as the current performance. -Signed-off-by: Heyi Guo -Signed-off-by: zhanghailiang +Guest kernel version above 4.18 is required to make it work. + +This series is backported from: +https://patchwork.kernel.org/cover/11379943/ + +Signed-off-by: Ying Fang --- default-configs/aarch64-softmmu.mak | 1 + hw/acpi/Makefile.objs | 1 + hw/acpi/aml-build.c | 22 +++ - hw/acpi/cpufreq.c | 278 ++++++++++++++++++++++++++++ + hw/acpi/cpufreq.c | 287 ++++++++++++++++++++++++++++ hw/arm/virt-acpi-build.c | 78 +++++++- hw/arm/virt.c | 13 ++ hw/char/Kconfig | 4 + include/hw/acpi/acpi-defs.h | 38 ++++ include/hw/acpi/aml-build.h | 3 + include/hw/arm/virt.h | 1 + - 10 files changed, 437 insertions(+), 2 deletions(-) + 10 files changed, 446 insertions(+), 2 deletions(-) create mode 100644 hw/acpi/cpufreq.c diff --git a/default-configs/aarch64-softmmu.mak b/default-configs/aarch64-softmmu.mak -index 4ea9add0..37399c14 100644 +index 958b1e08..0a030e85 100644 --- a/default-configs/aarch64-softmmu.mak +++ b/default-configs/aarch64-softmmu.mak -@@ -10,3 +10,4 @@ CONFIG_XLNX_ZYNQMP=y +@@ -6,3 +6,4 @@ include arm-softmmu.mak CONFIG_XLNX_ZYNQMP_ARM=y CONFIG_XLNX_VERSAL=y - CONFIG_ARM_SMMUV3=y + CONFIG_SBSA_REF=y +CONFIG_CPUFREQ=y diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs -index 2d46e378..60979db9 100644 +index 9bb2101e..1a720c38 100644 --- a/hw/acpi/Makefile.objs +++ b/hw/acpi/Makefile.objs -@@ -12,6 +12,7 @@ common-obj-y += acpi_interface.o - common-obj-y += bios-linker-loader.o - common-obj-y += aml-build.o +@@ -13,6 +13,7 @@ common-obj-y += bios-linker-loader.o + common-obj-y += aml-build.o utils.o + common-obj-$(CONFIG_ACPI_PCI) += pci.o common-obj-$(CONFIG_TPM) += tpm.o +common-obj-$(CONFIG_CPUFREQ) += cpufreq.o @@ -89,10 +92,10 @@ index 555c24f2..73f97751 100644 int hi, lo; diff --git a/hw/acpi/cpufreq.c b/hw/acpi/cpufreq.c new file mode 100644 -index 00000000..c123a22b +index 00000000..d02a25a6 --- /dev/null +++ b/hw/acpi/cpufreq.c -@@ -0,0 +1,278 @@ +@@ -0,0 +1,287 @@ +/* + * ACPI CPPC register device + * @@ -124,6 +127,7 @@ index 00000000..c123a22b +#include "hw/acpi/acpi-defs.h" +#include "qemu/cutils.h" +#include "qemu/error-report.h" ++#include "hw/boards.h" + +#define TYPE_CPUFREQ "cpufreq" +#define CPUFREQ(obj) OBJECT_CHECK(CpuhzState, (obj), TYPE_CPUFREQ) @@ -189,6 +193,9 @@ index 00000000..c123a22b + uint64_t r; + uint64_t n; + ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ unsigned int smp_cpus = ms->smp.cpus; ++ + if (offset >= smp_cpus * CPPC_REG_PER_CPU_STRIDE) { + warn_report("cpufreq_read: offset 0x%lx out of range", offset); + return 0; @@ -258,6 +265,8 @@ index 00000000..c123a22b + uint64_t value, unsigned size) +{ + uint64_t n; ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ unsigned int smp_cpus = ms->smp.cpus; + + if (offset >= smp_cpus * CPPC_REG_PER_CPU_STRIDE) { + error_printf("cpufreq_write: offset 0x%lx out of range", offset); @@ -339,6 +348,9 @@ index 00000000..c123a22b + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + CpuhzState *s = CPUFREQ(obj); + ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ unsigned int smp_cpus = ms->smp.cpus; ++ + s->reg_size = smp_cpus * CPPC_REG_PER_CPU_STRIDE; + if (s->reg_size > MAX_SUPPORT_SPACE) { + error_report("Required space 0x%x excesses the max support 0x%x", @@ -372,7 +384,7 @@ index 00000000..c123a22b +type_init(cpufreq_register_types) + diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c -index bf9c0bc2..33a8e2e3 100644 +index 0afb3727..29494ebd 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -45,11 +45,73 @@ @@ -469,7 +481,7 @@ index bf9c0bc2..33a8e2e3 100644 aml_append(scope, dev); } } -@@ -740,7 +814,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) +@@ -718,7 +792,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) * the RTC ACPI device at all when using UEFI. */ scope = aml_scope("\\_SB"); @@ -479,10 +491,10 @@ index bf9c0bc2..33a8e2e3 100644 (irqmap[VIRT_UART] + ARM_SPI_BASE)); acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index ce2664a3..ec6f00ab 100644 +index d9496c93..0fa355ba 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -132,6 +132,7 @@ static const MemMapEntry base_memmap[] = { +@@ -135,6 +135,7 @@ static const MemMapEntry base_memmap[] = { [VIRT_SECURE_UART] = { 0x09040000, 0x00001000 }, [VIRT_SMMU] = { 0x09050000, 0x00020000 }, [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, @@ -490,7 +502,7 @@ index ce2664a3..ec6f00ab 100644 /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ [VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 }, [VIRT_SECURE_MEM] = { 0x0e000000, 0x01000000 }, -@@ -725,6 +726,16 @@ static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart, +@@ -731,6 +732,16 @@ static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart, g_free(nodename); } @@ -507,7 +519,7 @@ index ce2664a3..ec6f00ab 100644 static void create_rtc(const VirtMachineState *vms, qemu_irq *pic) { char *nodename; -@@ -1618,6 +1629,8 @@ static void machvirt_init(MachineState *machine) +@@ -1682,6 +1693,8 @@ static void machvirt_init(MachineState *machine) create_uart(vms, pic, VIRT_UART, sysmem, serial_hd(0)); @@ -517,10 +529,10 @@ index ce2664a3..ec6f00ab 100644 create_secure_ram(vms, secure_sysmem); create_uart(vms, pic, VIRT_SECURE_UART, secure_sysmem, serial_hd(1)); diff --git a/hw/char/Kconfig b/hw/char/Kconfig -index 6360c9ff..8cc3ae2a 100644 +index 40e7a8b8..2f61bf53 100644 --- a/hw/char/Kconfig +++ b/hw/char/Kconfig -@@ -40,3 +40,7 @@ config SCLPCONSOLE +@@ -46,3 +46,7 @@ config SCLPCONSOLE config TERMINAL3270 bool @@ -529,10 +541,10 @@ index 6360c9ff..8cc3ae2a 100644 + bool + default y diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h -index f9aa4bd3..b4899a32 100644 +index 57a3f58b..39ae91d3 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h -@@ -652,4 +652,42 @@ struct AcpiIortRC { +@@ -634,4 +634,42 @@ struct AcpiIortRC { } QEMU_PACKED; typedef struct AcpiIortRC AcpiIortRC; @@ -590,7 +602,7 @@ index 1a563ad7..375335ab 100644 /* Block AML object primitives */ Aml *aml_scope(const char *name_format, ...) GCC_FMT_ATTR(1, 2); diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h -index 507517c6..8465f9bd 100644 +index a7209420..43a6ce91 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -66,6 +66,7 @@ enum { @@ -602,5 +614,5 @@ index 507517c6..8465f9bd 100644 VIRT_RTC, VIRT_FW_CFG, -- -2.19.1 +2.23.0 diff --git a/hw-arm-virt-Add-memory-hotplug-framework.patch b/hw-arm-virt-Add-memory-hotplug-framework.patch new file mode 100644 index 0000000000000000000000000000000000000000..dcb0f21f5b63e10636d889f6cae99a4d738d1d0e --- /dev/null +++ b/hw-arm-virt-Add-memory-hotplug-framework.patch @@ -0,0 +1,130 @@ +From e14fadc66d488ad10a10a2076721b72cc239ded9 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Wed, 18 Sep 2019 14:06:26 +0100 +Subject: [PATCH] hw/arm/virt: Add memory hotplug framework + +This patch adds the memory hot-plug/hot-unplug infrastructure +in machvirt. The device memory is not yet exposed to the Guest +either through DT or ACPI and hence both cold/hot plug of memory +is explicitly disabled for now. + +Signed-off-by: Eric Auger +Signed-off-by: Kwangwoo Lee +Signed-off-by: Shameer Kolothum +Reviewed-by: Peter Maydell +Reviewed-by: Igor Mammedov +Message-Id: <20190918130633.4872-5-shameerali.kolothum.thodi@huawei.com> +Acked-by: Peter Maydell +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/arm/Kconfig | 2 ++ + hw/arm/virt.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 54 insertions(+), 1 deletion(-) + +diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig +index ab65ecd216..84961c17ab 100644 +--- a/hw/arm/Kconfig ++++ b/hw/arm/Kconfig +@@ -20,6 +20,8 @@ config ARM_VIRT + select SMBIOS + select VIRTIO_MMIO + select ACPI_PCI ++ select MEM_DEVICE ++ select DIMM + + config CHEETAH + bool +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 23d72aed97..c7c07fe3ac 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -65,6 +65,8 @@ + #include "hw/arm/smmuv3.h" + #include "hw/acpi/acpi.h" + #include "target/arm/internals.h" ++#include "hw/mem/pc-dimm.h" ++#include "hw/mem/nvdimm.h" + + #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ + static void virt_##major##_##minor##_class_init(ObjectClass *oc, \ +@@ -1998,6 +2000,42 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) + return ms->possible_cpus; + } + ++static void virt_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, ++ Error **errp) ++{ ++ ++ /* ++ * The device memory is not yet exposed to the Guest either through ++ * DT or ACPI and hence both cold/hot plug of memory is explicitly ++ * disabled for now. ++ */ ++ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { ++ error_setg(errp, "memory cold/hot plug is not yet supported"); ++ return; ++ } ++ ++ pc_dimm_pre_plug(PC_DIMM(dev), MACHINE(hotplug_dev), NULL, errp); ++} ++ ++static void virt_memory_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); ++ Error *local_err = NULL; ++ ++ pc_dimm_plug(PC_DIMM(dev), MACHINE(vms), &local_err); ++ ++ error_propagate(errp, local_err); ++} ++ ++static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { ++ virt_memory_pre_plug(hotplug_dev, dev, errp); ++ } ++} ++ + static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +@@ -2009,12 +2047,23 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev, + SYS_BUS_DEVICE(dev)); + } + } ++ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { ++ virt_memory_plug(hotplug_dev, dev, errp); ++ } ++} ++ ++static void virt_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ error_setg(errp, "device unplug request for unsupported device" ++ " type: %s", object_get_typename(OBJECT(dev))); + } + + static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine, + DeviceState *dev) + { +- if (object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE)) { ++ if (object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE) || ++ (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM))) { + return HOTPLUG_HANDLER(machine); + } + +@@ -2078,7 +2127,9 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) + mc->kvm_type = virt_kvm_type; + assert(!mc->get_hotplug_handler); + mc->get_hotplug_handler = virt_machine_get_hotplug_handler; ++ hc->pre_plug = virt_machine_device_pre_plug_cb; + hc->plug = virt_machine_device_plug_cb; ++ hc->unplug_request = virt_machine_device_unplug_request_cb; + mc->numa_mem_supported = true; + } + +-- +2.19.1 diff --git a/hw-arm-virt-Enable-device-memory-cold-hot-plug-with-.patch b/hw-arm-virt-Enable-device-memory-cold-hot-plug-with-.patch new file mode 100644 index 0000000000000000000000000000000000000000..b32b2a01929189ff6f89e94f011d4d9cc3811a3b --- /dev/null +++ b/hw-arm-virt-Enable-device-memory-cold-hot-plug-with-.patch @@ -0,0 +1,252 @@ +From ce813d8daa2e01df52509f4bb52b9ab774408706 Mon Sep 17 00:00:00 2001 +From: Shameer Kolothum +Date: Wed, 18 Sep 2019 14:06:27 +0100 +Subject: [PATCH] hw/arm/virt: Enable device memory cold/hot plug with ACPI + boot + +This initializes the GED device with base memory and irq, configures +ged memory hotplug event and builds the corresponding aml code. With +this, both hot and cold plug of device memory is enabled now for Guest +with ACPI boot. Memory cold plug support with Guest DT boot is not yet +supported. + +As DSDT table gets changed by this, update bios-tables-test-allowed-diff.h +to avoid "make check" failure. + +Signed-off-by: Shameer Kolothum +Message-Id: <20190918130633.4872-6-shameerali.kolothum.thodi@huawei.com> +Acked-by: Peter Maydell +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Igor Mammedov +--- + hw/arm/Kconfig | 2 ++ + hw/arm/virt-acpi-build.c | 21 ++++++++++++++ + hw/arm/virt.c | 59 +++++++++++++++++++++++++++++++++++----- + include/hw/arm/virt.h | 4 +++ + 4 files changed, 79 insertions(+), 7 deletions(-) + +diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig +index 84961c17ab..ad7f7c089b 100644 +--- a/hw/arm/Kconfig ++++ b/hw/arm/Kconfig +@@ -22,6 +22,8 @@ config ARM_VIRT + select ACPI_PCI + select MEM_DEVICE + select DIMM ++ select ACPI_MEMORY_HOTPLUG ++ select ACPI_HW_REDUCED + + config CHEETAH + bool +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index fe54411f6a..fca53ae01f 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -40,6 +40,8 @@ + #include "hw/acpi/aml-build.h" + #include "hw/acpi/utils.h" + #include "hw/acpi/pci.h" ++#include "hw/acpi/memory_hotplug.h" ++#include "hw/acpi/generic_event_device.h" + #include "hw/pci/pcie_host.h" + #include "hw/pci/pci.h" + #include "hw/arm/virt.h" +@@ -779,6 +781,7 @@ static void + build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + { + Aml *scope, *dsdt; ++ MachineState *ms = MACHINE(vms); + const MemMapEntry *memmap = vms->memmap; + const int *irqmap = vms->irqmap; + +@@ -803,6 +806,24 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + vms->highmem, vms->highmem_ecam); + acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO], + (irqmap[VIRT_GPIO] + ARM_SPI_BASE)); ++ if (vms->acpi_dev) { ++ build_ged_aml(scope, "\\_SB."GED_DEVICE, ++ HOTPLUG_HANDLER(vms->acpi_dev), ++ irqmap[VIRT_ACPI_GED] + ARM_SPI_BASE, AML_SYSTEM_MEMORY, ++ memmap[VIRT_ACPI_GED].base); ++ } ++ ++ if (vms->acpi_dev) { ++ uint32_t event = object_property_get_uint(OBJECT(vms->acpi_dev), ++ "ged-event", &error_abort); ++ ++ if (event & ACPI_GED_MEM_HOTPLUG_EVT) { ++ build_memory_hotplug_aml(scope, ms->ram_slots, "\\_SB", NULL, ++ AML_SYSTEM_MEMORY, ++ memmap[VIRT_PCDIMM_ACPI].base); ++ } ++ } ++ + acpi_dsdt_add_power_button(scope); + + aml_append(dsdt, scope); +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index c7c07fe3ac..8ccabd5159 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -67,6 +67,7 @@ + #include "target/arm/internals.h" + #include "hw/mem/pc-dimm.h" + #include "hw/mem/nvdimm.h" ++#include "hw/acpi/generic_event_device.h" + + #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ + static void virt_##major##_##minor##_class_init(ObjectClass *oc, \ +@@ -137,6 +138,8 @@ static const MemMapEntry base_memmap[] = { + [VIRT_GPIO] = { 0x09030000, 0x00001000 }, + [VIRT_SECURE_UART] = { 0x09040000, 0x00001000 }, + [VIRT_SMMU] = { 0x09050000, 0x00020000 }, ++ [VIRT_PCDIMM_ACPI] = { 0x09070000, MEMORY_HOTPLUG_IO_LEN }, ++ [VIRT_ACPI_GED] = { 0x09080000, ACPI_GED_EVT_SEL_LEN }, + [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, + [VIRT_CPUFREQ] = { 0x0b000000, 0x00010000 }, + /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ +@@ -173,6 +176,7 @@ static const int a15irqmap[] = { + [VIRT_PCIE] = 3, /* ... to 6 */ + [VIRT_GPIO] = 7, + [VIRT_SECURE_UART] = 8, ++ [VIRT_ACPI_GED] = 9, + [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 */ +@@ -630,6 +634,29 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms) + } + } + ++static inline DeviceState *create_acpi_ged(VirtMachineState *vms, qemu_irq *pic) ++{ ++ DeviceState *dev; ++ MachineState *ms = MACHINE(vms); ++ int irq = vms->irqmap[VIRT_ACPI_GED]; ++ uint32_t event = 0; ++ ++ if (ms->ram_slots) { ++ event = ACPI_GED_MEM_HOTPLUG_EVT; ++ } ++ ++ dev = qdev_create(NULL, TYPE_ACPI_GED); ++ qdev_prop_set_uint32(dev, "ged-event", event); ++ ++ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base); ++ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base); ++ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irq]); ++ ++ qdev_init_nofail(dev); ++ ++ return dev; ++} ++ + static void create_its(VirtMachineState *vms, DeviceState *gicdev) + { + const char *itsclass = its_class_name(); +@@ -1603,6 +1630,7 @@ static void machvirt_init(MachineState *machine) + MemoryRegion *ram = g_new(MemoryRegion, 1); + bool firmware_loaded; + bool aarch64 = true; ++ bool has_ged = !vmc->no_ged; + unsigned int smp_cpus = machine->smp.cpus; + unsigned int max_cpus = machine->smp.max_cpus; + +@@ -1824,6 +1852,10 @@ static void machvirt_init(MachineState *machine) + + create_gpio(vms, pic); + ++ if (has_ged && aarch64 && firmware_loaded && acpi_enabled) { ++ vms->acpi_dev = create_acpi_ged(vms, pic); ++ } ++ + /* Create mmio transports, so the user can create virtio backends + * (which will be automatically plugged in to the transports). If + * no backend is created the transport will just sit harmlessly idle. +@@ -2003,14 +2035,17 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) + static void virt_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) + { ++ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); ++ const bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM); + +- /* +- * The device memory is not yet exposed to the Guest either through +- * DT or ACPI and hence both cold/hot plug of memory is explicitly +- * disabled for now. +- */ +- if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { +- error_setg(errp, "memory cold/hot plug is not yet supported"); ++ if (is_nvdimm) { ++ error_setg(errp, "nvdimm is not yet supported"); ++ return; ++ } ++ ++ if (!vms->acpi_dev) { ++ error_setg(errp, ++ "memory hotplug is not enabled: missing acpi-ged device"); + return; + } + +@@ -2020,11 +2055,18 @@ static void virt_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + static void virt_memory_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { ++ HotplugHandlerClass *hhc; + VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); + Error *local_err = NULL; + + pc_dimm_plug(PC_DIMM(dev), MACHINE(vms), &local_err); ++ if (local_err) { ++ goto out; ++ } + ++ hhc = HOTPLUG_HANDLER_GET_CLASS(vms->acpi_dev); ++ hhc->plug(HOTPLUG_HANDLER(vms->acpi_dev), dev, &error_abort); ++out: + error_propagate(errp, local_err); + } + +@@ -2231,8 +2273,11 @@ DEFINE_VIRT_MACHINE_AS_LATEST(4, 1) + + static void virt_machine_4_0_options(MachineClass *mc) + { ++ VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc)); ++ + virt_machine_4_1_options(mc); + compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len); ++ vmc->no_ged = true; + } + DEFINE_VIRT_MACHINE(4, 0) + +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index a9d6977afc..0350285136 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -78,6 +78,8 @@ enum { + VIRT_GPIO, + VIRT_SECURE_UART, + VIRT_SECURE_MEM, ++ VIRT_PCDIMM_ACPI, ++ VIRT_ACPI_GED, + VIRT_LOWMEMMAP_LAST, + }; + +@@ -107,6 +109,7 @@ typedef struct { + bool claim_edge_triggered_timers; + bool smbios_old_sys_ver; + bool no_highmem_ecam; ++ bool no_ged; /* Machines < 4.1 has no support for ACPI GED device */ + bool kvm_no_adjvtime; + } VirtMachineClass; + +@@ -135,6 +138,7 @@ typedef struct { + uint32_t iommu_phandle; + int psci_conduit; + hwaddr highest_gpa; ++ DeviceState *acpi_dev; + } VirtMachineState; + + #define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM) +-- +2.19.1 diff --git a/hw-arm-virt-Factor-out-some-CPU-init-codes-to-pre_pl.patch b/hw-arm-virt-Factor-out-some-CPU-init-codes-to-pre_pl.patch new file mode 100644 index 0000000000000000000000000000000000000000..1e3befaf62920ca12cae4c8ead6d731800ef79a8 --- /dev/null +++ b/hw-arm-virt-Factor-out-some-CPU-init-codes-to-pre_pl.patch @@ -0,0 +1,170 @@ +From 3a0af1446395e74476a763ca12713b28c099a144 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Mon, 6 Apr 2020 12:50:54 +0800 +Subject: [PATCH] hw/arm/virt: Factor out some CPU init codes to pre_plug hook + +The init path of hotplugged CPU is pre_plug/realize/plug, so we +must move these init code in machvirt_init to pre_plug hook, to +let them be shared by all CPUs. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt.c | 108 +++++++++++++++++++++++++++----------------------- + 1 file changed, 58 insertions(+), 50 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 64532b61b2..83f4887e57 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -196,6 +196,8 @@ static const char *valid_cpus[] = { + ARM_CPU_TYPE_NAME("max"), + }; + ++static MemoryRegion *secure_sysmem; ++ + static bool cpu_type_valid(const char *cpu) + { + int i; +@@ -1629,7 +1631,6 @@ static void machvirt_init(MachineState *machine) + MachineClass *mc = MACHINE_GET_CLASS(machine); + const CPUArchIdList *possible_cpus; + MemoryRegion *sysmem = get_system_memory(); +- MemoryRegion *secure_sysmem = NULL; + int n, virt_max_cpus; + MemoryRegion *ram = g_new(MemoryRegion, 1); + bool firmware_loaded; +@@ -1752,57 +1753,10 @@ static void machvirt_init(MachineState *machine) + } + + cpuobj = object_new(possible_cpus->cpus[n].type); +- object_property_set_int(cpuobj, possible_cpus->cpus[n].arch_id, +- "mp-affinity", NULL); ++ aarch64 &= object_property_get_bool(cpuobj, "aarch64", NULL); + + cs = CPU(cpuobj); + cs->cpu_index = n; +- +- numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpuobj), +- &error_fatal); +- +- aarch64 &= object_property_get_bool(cpuobj, "aarch64", NULL); +- +- if (!vms->secure) { +- object_property_set_bool(cpuobj, false, "has_el3", NULL); +- } +- +- if (!vms->virt && object_property_find(cpuobj, "has_el2", NULL)) { +- object_property_set_bool(cpuobj, false, "has_el2", NULL); +- } +- +- if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) { +- object_property_set_int(cpuobj, vms->psci_conduit, +- "psci-conduit", NULL); +- +- /* Secondary CPUs start in PSCI powered-down state */ +- if (n > 0) { +- object_property_set_bool(cpuobj, true, +- "start-powered-off", NULL); +- } +- } +- +- if (vmc->kvm_no_adjvtime && +- object_property_find(cpuobj, "kvm-no-adjvtime", NULL)) { +- object_property_set_bool(cpuobj, true, "kvm-no-adjvtime", NULL); +- } +- +- if (vmc->no_pmu && object_property_find(cpuobj, "pmu", NULL)) { +- object_property_set_bool(cpuobj, false, "pmu", NULL); +- } +- +- if (object_property_find(cpuobj, "reset-cbar", NULL)) { +- object_property_set_int(cpuobj, vms->memmap[VIRT_CPUPERIPHS].base, +- "reset-cbar", &error_abort); +- } +- +- object_property_set_link(cpuobj, OBJECT(sysmem), "memory", +- &error_abort); +- if (vms->secure) { +- object_property_set_link(cpuobj, OBJECT(secure_sysmem), +- "secure-memory", &error_abort); +- } +- + object_property_set_bool(cpuobj, true, "realized", &error_fatal); + object_unref(cpuobj); + } +@@ -2089,10 +2043,16 @@ out: + static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- CPUState *cs = CPU(dev); + ARMCPUTopoInfo topo; ++ Object *cpuobj = OBJECT(dev); ++ CPUState *cs = CPU(dev); + ARMCPU *cpu = ARM_CPU(dev); + MachineState *ms = MACHINE(hotplug_dev); ++ MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev); ++ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); ++ VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(hotplug_dev); ++ const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); ++ MemoryRegion *sysmem = get_system_memory(); + int smp_cores = ms->smp.cores; + int smp_threads = ms->smp.threads; + +@@ -2145,6 +2105,54 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, + return; + } + cpu->thread_id = topo.smt_id; ++ ++ /* Init some properties */ ++ ++ object_property_set_int(cpuobj, possible_cpus->cpus[cs->cpu_index].arch_id, ++ "mp-affinity", NULL); ++ ++ numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpuobj), ++ &error_fatal); ++ ++ if (!vms->secure) { ++ object_property_set_bool(cpuobj, false, "has_el3", NULL); ++ } ++ ++ if (!vms->virt && object_property_find(cpuobj, "has_el2", NULL)) { ++ object_property_set_bool(cpuobj, false, "has_el2", NULL); ++ } ++ ++ if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) { ++ object_property_set_int(cpuobj, vms->psci_conduit, ++ "psci-conduit", NULL); ++ ++ /* Secondary CPUs start in PSCI powered-down state */ ++ if (cs->cpu_index > 0) { ++ object_property_set_bool(cpuobj, true, ++ "start-powered-off", NULL); ++ } ++ } ++ ++ if (vmc->kvm_no_adjvtime && ++ object_property_find(cpuobj, "kvm-no-adjvtime", NULL)) { ++ object_property_set_bool(cpuobj, true, "kvm-no-adjvtime", NULL); ++ } ++ ++ if (vmc->no_pmu && object_property_find(cpuobj, "pmu", NULL)) { ++ object_property_set_bool(cpuobj, false, "pmu", NULL); ++ } ++ ++ if (object_property_find(cpuobj, "reset-cbar", NULL)) { ++ object_property_set_int(cpuobj, vms->memmap[VIRT_CPUPERIPHS].base, ++ "reset-cbar", &error_abort); ++ } ++ ++ object_property_set_link(cpuobj, OBJECT(sysmem), "memory", ++ &error_abort); ++ if (vms->secure) { ++ object_property_set_link(cpuobj, OBJECT(secure_sysmem), ++ "secure-memory", &error_abort); ++ } + } + + static void virt_cpu_plug(HotplugHandler *hotplug_dev, +-- +2.19.1 diff --git a/hw-arm-virt-Introduce-cpu-topology-support.patch b/hw-arm-virt-Introduce-cpu-topology-support.patch index 027a5112effa77c9d37642f88cf9d00120bc6f47..932f467fe274453668edf80bac5d023817d6f95b 100644 --- a/hw-arm-virt-Introduce-cpu-topology-support.patch +++ b/hw-arm-virt-Introduce-cpu-topology-support.patch @@ -1,6 +1,6 @@ -From 123b4eb3cb7b9b4e3e0705a9b5f974b37d3b8431 Mon Sep 17 00:00:00 2001 -From: zhanghailiang -Date: Mon, 5 Aug 2019 15:04:31 +0800 +From 73fc4af05ebe12d77915e6b3c85c48f5e0c432f3 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 22 Apr 2020 19:23:27 +0800 Subject: [PATCH] hw/arm/virt: Introduce cpu topology support Add topology support for guest vcpu by cpu-map in dtb when the guest is booted @@ -11,13 +11,13 @@ Signed-off-by: zhanghailiang (picked-from https://patchwork.ozlabs.org/cover/939301/ which is pushed by Andrew Jones ) --- - device_tree.c | 32 +++++++++++++++++++++++ - hw/acpi/aml-build.c | 50 ++++++++++++++++++++++++++++++++++++ + device_tree.c | 32 ++++++++++++++++++++++ + hw/acpi/aml-build.c | 53 ++++++++++++++++++++++++++++++++++++ hw/arm/virt-acpi-build.c | 4 +++ - hw/arm/virt.c | 29 +++++++++++++++++++++ + hw/arm/virt.c | 32 +++++++++++++++++++++- include/hw/acpi/aml-build.h | 2 ++ include/sysemu/device_tree.h | 1 + - 6 files changed, 118 insertions(+) + 6 files changed, 123 insertions(+), 1 deletion(-) diff --git a/device_tree.c b/device_tree.c index f8b46b3c..03906a14 100644 @@ -26,7 +26,7 @@ index f8b46b3c..03906a14 100644 @@ -524,6 +524,38 @@ int qemu_fdt_add_subnode(void *fdt, const char *name) return retval; } - + +/** + * qemu_fdt_add_path + * @fdt: Flattened Device Tree @@ -63,7 +63,7 @@ index f8b46b3c..03906a14 100644 { const char *dumpdtb = qemu_opt_get(qemu_get_machine_opts(), "dumpdtb"); diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c -index 73f97751..9d39ad10 100644 +index 73f97751..f2c8c28f 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -25,6 +25,7 @@ @@ -71,13 +71,13 @@ index 73f97751..9d39ad10 100644 #include "qemu/bitops.h" #include "sysemu/numa.h" +#include "sysemu/cpus.h" - + static GArray *build_alloc_array(void) { -@@ -51,6 +52,55 @@ static void build_append_array(GArray *array, GArray *val) +@@ -51,6 +52,58 @@ static void build_append_array(GArray *array, GArray *val) g_array_append_vals(array, val->data, val->len); } - + +/* + * ACPI 6.2 Processor Properties Topology Table (PPTT) + */ @@ -97,6 +97,9 @@ index 73f97751..9d39ad10 100644 +{ + int pptt_start = table_data->len; + int uid = 0, cpus = 0, socket; ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ unsigned int smp_cores = ms->smp.cores; ++ unsigned int smp_threads = ms->smp.threads; + + acpi_data_push(table_data, sizeof(AcpiTableHeader)); + @@ -128,28 +131,28 @@ index 73f97751..9d39ad10 100644 +} + #define ACPI_NAMESEG_LEN 4 - + static void diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c -index 33a8e2e3..18653e6d 100644 +index 29494ebd..fe54411f 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c -@@ -870,6 +870,10 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) +@@ -848,6 +848,10 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_fadt_rev5(tables_blob, tables->linker, vms, dsdt); - + + acpi_add_table(table_offsets, tables_blob); + + build_pptt(tables_blob, tables->linker, vms->smp_cpus); + acpi_add_table(table_offsets, tables_blob); build_madt(tables_blob, tables->linker, vms); - + diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 57a78b16..16700a2e 100644 +index 0fa355ba..272455bc 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -42,6 +42,7 @@ +@@ -44,6 +44,7 @@ #include "net/net.h" #include "sysemu/device_tree.h" #include "sysemu/numa.h" @@ -157,10 +160,20 @@ index 57a78b16..16700a2e 100644 #include "sysemu/sysemu.h" #include "sysemu/kvm.h" #include "hw/loader.h" -@@ -364,8 +365,36 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) +@@ -312,7 +313,8 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) + int cpu; + int addr_cells = 1; + const MachineState *ms = MACHINE(vms); +- ++ unsigned int smp_cores = ms->smp.cores; ++ unsigned int smp_threads = ms->smp.threads; + /* + * From Documentation/devicetree/bindings/arm/cpus.txt + * On ARM v8 64-bit systems value should be set to 2, +@@ -368,8 +370,36 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) ms->possible_cpus->cpus[cs->cpu_index].props.node_id); } - + + qemu_fdt_setprop_cell(vms->fdt, nodename, "phandle", + qemu_fdt_alloc_phandle(vms->fdt)); + @@ -192,7 +205,7 @@ index 57a78b16..16700a2e 100644 + g_free(cpu_path); + } } - + static void fdt_add_its_gic_node(VirtMachineState *vms) diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index 375335ab..bfb0b100 100644 @@ -201,11 +214,11 @@ index 375335ab..bfb0b100 100644 @@ -417,6 +417,8 @@ build_append_gas_from_struct(GArray *table, const struct AcpiGenericAddress *s) void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base, uint64_t len, int node, MemoryAffinityFlags flags); - + +void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus); + void build_slit(GArray *table_data, BIOSLinker *linker); - + void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f, diff --git a/include/sysemu/device_tree.h b/include/sysemu/device_tree.h index c16fd69b..d62fc873 100644 @@ -216,9 +229,8 @@ index c16fd69b..d62fc873 100644 int qemu_fdt_nop_node(void *fdt, const char *node_path); int qemu_fdt_add_subnode(void *fdt, const char *name); +int qemu_fdt_add_path(void *fdt, const char *path); - + #define qemu_fdt_setprop_cells(fdt, node_path, property, ...) \ do { \ --- -2.19.1 - +-- +2.23.0 diff --git a/hw-arm-virt-Simplify-by-moving-the-gic-in-the-machin.patch b/hw-arm-virt-Simplify-by-moving-the-gic-in-the-machin.patch new file mode 100644 index 0000000000000000000000000000000000000000..262cb508bcb8ba48bf93a3875957f2c9ace7698d --- /dev/null +++ b/hw-arm-virt-Simplify-by-moving-the-gic-in-the-machin.patch @@ -0,0 +1,402 @@ +From 5d1be90750551f1debf5767d7a6e2b9c50054c05 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Mon, 9 Dec 2019 10:03:06 +0100 +Subject: [PATCH] hw/arm/virt: Simplify by moving the gic in the machine state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Make the gic a field in the machine state, and instead of filling +an array of qemu_irq and passing it around, directly call +qdev_get_gpio_in() on the gic field. + +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Luc Michel +Message-id: 20191209090306.20433-1-philmd@redhat.com +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +--- + hw/arm/virt.c | 109 +++++++++++++++++++++--------------------- + include/hw/arm/virt.h | 1 + + 2 files changed, 55 insertions(+), 55 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 18321e522b..8638aeedb7 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -634,7 +634,7 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms) + } + } + +-static inline DeviceState *create_acpi_ged(VirtMachineState *vms, qemu_irq *pic) ++static inline DeviceState *create_acpi_ged(VirtMachineState *vms) + { + DeviceState *dev; + MachineState *ms = MACHINE(vms); +@@ -650,14 +650,14 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms, qemu_irq *pic) + + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base); +- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irq]); ++ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic, irq)); + + qdev_init_nofail(dev); + + return dev; + } + +-static void create_its(VirtMachineState *vms, DeviceState *gicdev) ++static void create_its(VirtMachineState *vms) + { + const char *itsclass = its_class_name(); + DeviceState *dev; +@@ -669,7 +669,7 @@ static void create_its(VirtMachineState *vms, DeviceState *gicdev) + + dev = qdev_create(NULL, itsclass); + +- object_property_set_link(OBJECT(dev), OBJECT(gicdev), "parent-gicv3", ++ object_property_set_link(OBJECT(dev), OBJECT(vms->gic), "parent-gicv3", + &error_abort); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_ITS].base); +@@ -677,7 +677,7 @@ static void create_its(VirtMachineState *vms, DeviceState *gicdev) + fdt_add_its_gic_node(vms); + } + +-static void create_v2m(VirtMachineState *vms, qemu_irq *pic) ++static void create_v2m(VirtMachineState *vms) + { + int i; + int irq = vms->irqmap[VIRT_GIC_V2M]; +@@ -690,17 +690,17 @@ static void create_v2m(VirtMachineState *vms, qemu_irq *pic) + qdev_init_nofail(dev); + + for (i = 0; i < NUM_GICV2M_SPIS; i++) { +- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); ++ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, ++ qdev_get_gpio_in(vms->gic, irq + i)); + } + + fdt_add_v2m_gic_node(vms); + } + +-static void create_gic(VirtMachineState *vms, qemu_irq *pic) ++static void create_gic(VirtMachineState *vms) + { + MachineState *ms = MACHINE(vms); + /* We create a standalone GIC */ +- DeviceState *gicdev; + SysBusDevice *gicbusdev; + const char *gictype; + int type = vms->gic_version, i; +@@ -709,15 +709,15 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic) + + gictype = (type == 3) ? gicv3_class_name() : gic_class_name(); + +- gicdev = qdev_create(NULL, gictype); +- qdev_prop_set_uint32(gicdev, "revision", type); +- qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus); ++ vms->gic = qdev_create(NULL, gictype); ++ qdev_prop_set_uint32(vms->gic, "revision", type); ++ qdev_prop_set_uint32(vms->gic, "num-cpu", smp_cpus); + /* Note that the num-irq property counts both internal and external + * interrupts; there are always 32 of the former (mandated by GIC spec). + */ +- qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32); ++ qdev_prop_set_uint32(vms->gic, "num-irq", NUM_IRQS + 32); + if (!kvm_irqchip_in_kernel()) { +- qdev_prop_set_bit(gicdev, "has-security-extensions", vms->secure); ++ qdev_prop_set_bit(vms->gic, "has-security-extensions", vms->secure); + } + + if (type == 3) { +@@ -727,25 +727,25 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic) + + nb_redist_regions = virt_gicv3_redist_region_count(vms); + +- qdev_prop_set_uint32(gicdev, "len-redist-region-count", ++ qdev_prop_set_uint32(vms->gic, "len-redist-region-count", + nb_redist_regions); +- qdev_prop_set_uint32(gicdev, "redist-region-count[0]", redist0_count); ++ qdev_prop_set_uint32(vms->gic, "redist-region-count[0]", redist0_count); + + if (nb_redist_regions == 2) { + uint32_t redist1_capacity = + vms->memmap[VIRT_HIGH_GIC_REDIST2].size / GICV3_REDIST_SIZE; + +- qdev_prop_set_uint32(gicdev, "redist-region-count[1]", ++ qdev_prop_set_uint32(vms->gic, "redist-region-count[1]", + MIN(smp_cpus - redist0_count, redist1_capacity)); + } + } else { + if (!kvm_irqchip_in_kernel()) { +- qdev_prop_set_bit(gicdev, "has-virtualization-extensions", ++ qdev_prop_set_bit(vms->gic, "has-virtualization-extensions", + vms->virt); + } + } +- qdev_init_nofail(gicdev); +- gicbusdev = SYS_BUS_DEVICE(gicdev); ++ qdev_init_nofail(vms->gic); ++ gicbusdev = SYS_BUS_DEVICE(vms->gic); + sysbus_mmio_map(gicbusdev, 0, vms->memmap[VIRT_GIC_DIST].base); + if (type == 3) { + sysbus_mmio_map(gicbusdev, 1, vms->memmap[VIRT_GIC_REDIST].base); +@@ -781,23 +781,23 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic) + + for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { + qdev_connect_gpio_out(cpudev, irq, +- qdev_get_gpio_in(gicdev, ++ qdev_get_gpio_in(vms->gic, + ppibase + timer_irq[irq])); + } + + if (type == 3) { +- qemu_irq irq = qdev_get_gpio_in(gicdev, ++ qemu_irq irq = qdev_get_gpio_in(vms->gic, + ppibase + ARCH_GIC_MAINT_IRQ); + qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", + 0, irq); + } else if (vms->virt) { +- qemu_irq irq = qdev_get_gpio_in(gicdev, ++ qemu_irq irq = qdev_get_gpio_in(vms->gic, + ppibase + ARCH_GIC_MAINT_IRQ); + sysbus_connect_irq(gicbusdev, i + 4 * smp_cpus, irq); + } + + qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, +- qdev_get_gpio_in(gicdev, ppibase ++ qdev_get_gpio_in(vms->gic, ppibase + + VIRTUAL_PMU_IRQ)); + + sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); +@@ -809,20 +809,16 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic) + qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); + } + +- for (i = 0; i < NUM_IRQS; i++) { +- pic[i] = qdev_get_gpio_in(gicdev, i); +- } +- + fdt_add_gic_node(vms); + + if (type == 3 && vms->its) { +- create_its(vms, gicdev); ++ create_its(vms); + } else if (type == 2) { +- create_v2m(vms, pic); ++ create_v2m(vms); + } + } + +-static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart, ++static void create_uart(const VirtMachineState *vms, int uart, + MemoryRegion *mem, Chardev *chr) + { + char *nodename; +@@ -838,7 +834,7 @@ static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart, + qdev_init_nofail(dev); + memory_region_add_subregion(mem, base, + sysbus_mmio_get_region(s, 0)); +- sysbus_connect_irq(s, 0, pic[irq]); ++ sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq)); + + nodename = g_strdup_printf("/pl011@%" PRIx64, base); + qemu_fdt_add_subnode(vms->fdt, nodename); +@@ -880,7 +876,7 @@ static void create_cpufreq(const VirtMachineState *vms, MemoryRegion *mem) + memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0)); + } + +-static void create_rtc(const VirtMachineState *vms, qemu_irq *pic) ++static void create_rtc(const VirtMachineState *vms) + { + char *nodename; + hwaddr base = vms->memmap[VIRT_RTC].base; +@@ -888,7 +884,7 @@ static void create_rtc(const VirtMachineState *vms, qemu_irq *pic) + int irq = vms->irqmap[VIRT_RTC]; + const char compat[] = "arm,pl031\0arm,primecell"; + +- sysbus_create_simple("pl031", base, pic[irq]); ++ sysbus_create_simple("pl031", base, qdev_get_gpio_in(vms->gic, irq)); + + nodename = g_strdup_printf("/pl031@%" PRIx64, base); + qemu_fdt_add_subnode(vms->fdt, nodename); +@@ -916,7 +912,7 @@ static void virt_powerdown_req(Notifier *n, void *opaque) + } + } + +-static void create_gpio(const VirtMachineState *vms, qemu_irq *pic) ++static void create_gpio(const VirtMachineState *vms) + { + char *nodename; + DeviceState *pl061_dev; +@@ -925,7 +921,8 @@ static void create_gpio(const VirtMachineState *vms, qemu_irq *pic) + int irq = vms->irqmap[VIRT_GPIO]; + const char compat[] = "arm,pl061\0arm,primecell"; + +- pl061_dev = sysbus_create_simple("pl061", base, pic[irq]); ++ pl061_dev = sysbus_create_simple("pl061", base, ++ qdev_get_gpio_in(vms->gic, irq)); + + uint32_t phandle = qemu_fdt_alloc_phandle(vms->fdt); + nodename = g_strdup_printf("/pl061@%" PRIx64, base); +@@ -959,7 +956,7 @@ static void create_gpio(const VirtMachineState *vms, qemu_irq *pic) + g_free(nodename); + } + +-static void create_virtio_devices(const VirtMachineState *vms, qemu_irq *pic) ++static void create_virtio_devices(const VirtMachineState *vms) + { + int i; + hwaddr size = vms->memmap[VIRT_MMIO].size; +@@ -995,7 +992,8 @@ static void create_virtio_devices(const VirtMachineState *vms, qemu_irq *pic) + int irq = vms->irqmap[VIRT_MMIO] + i; + hwaddr base = vms->memmap[VIRT_MMIO].base + i * size; + +- sysbus_create_simple("virtio-mmio", base, pic[irq]); ++ sysbus_create_simple("virtio-mmio", base, ++ qdev_get_gpio_in(vms->gic, irq)); + } + + /* We add dtb nodes in reverse order so that they appear in the finished +@@ -1244,7 +1242,7 @@ static void create_pcie_irq_map(const VirtMachineState *vms, + 0x7 /* PCI irq */); + } + +-static void create_smmu(const VirtMachineState *vms, qemu_irq *pic, ++static void create_smmu(const VirtMachineState *vms, + PCIBus *bus) + { + char *node; +@@ -1267,7 +1265,8 @@ static void create_smmu(const VirtMachineState *vms, qemu_irq *pic, + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + for (i = 0; i < NUM_SMMU_IRQS; i++) { +- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); ++ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, ++ qdev_get_gpio_in(vms->gic, irq + i)); + } + + node = g_strdup_printf("/smmuv3@%" PRIx64, base); +@@ -1294,7 +1293,7 @@ static void create_smmu(const VirtMachineState *vms, qemu_irq *pic, + g_free(node); + } + +-static void create_pcie(VirtMachineState *vms, qemu_irq *pic) ++static void create_pcie(VirtMachineState *vms) + { + hwaddr base_mmio = vms->memmap[VIRT_PCIE_MMIO].base; + hwaddr size_mmio = vms->memmap[VIRT_PCIE_MMIO].size; +@@ -1354,7 +1353,8 @@ static void create_pcie(VirtMachineState *vms, qemu_irq *pic) + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio); + + for (i = 0; i < GPEX_NUM_IRQS; i++) { +- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); ++ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, ++ qdev_get_gpio_in(vms->gic, irq + i)); + gpex_set_irq_num(GPEX_HOST(dev), i, irq + i); + } + +@@ -1414,7 +1414,7 @@ static void create_pcie(VirtMachineState *vms, qemu_irq *pic) + if (vms->iommu) { + vms->iommu_phandle = qemu_fdt_alloc_phandle(vms->fdt); + +- create_smmu(vms, pic, pci->bus); ++ create_smmu(vms, pci->bus); + + qemu_fdt_setprop_cells(vms->fdt, nodename, "iommu-map", + 0x0, vms->iommu_phandle, 0x0, 0x10000); +@@ -1423,7 +1423,7 @@ static void create_pcie(VirtMachineState *vms, qemu_irq *pic) + g_free(nodename); + } + +-static void create_platform_bus(VirtMachineState *vms, qemu_irq *pic) ++static void create_platform_bus(VirtMachineState *vms) + { + DeviceState *dev; + SysBusDevice *s; +@@ -1439,8 +1439,8 @@ static void create_platform_bus(VirtMachineState *vms, qemu_irq *pic) + + s = SYS_BUS_DEVICE(dev); + for (i = 0; i < PLATFORM_BUS_NUM_IRQS; i++) { +- int irqn = vms->irqmap[VIRT_PLATFORM_BUS] + i; +- sysbus_connect_irq(s, i, pic[irqn]); ++ int irq = vms->irqmap[VIRT_PLATFORM_BUS] + i; ++ sysbus_connect_irq(s, i, qdev_get_gpio_in(vms->gic, irq)); + } + + memory_region_add_subregion(sysmem, +@@ -1621,7 +1621,6 @@ static void machvirt_init(MachineState *machine) + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(machine); + MachineClass *mc = MACHINE_GET_CLASS(machine); + const CPUArchIdList *possible_cpus; +- qemu_irq pic[NUM_IRQS]; + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *secure_sysmem = NULL; + int n, virt_max_cpus; +@@ -1829,29 +1828,29 @@ static void machvirt_init(MachineState *machine) + + virt_flash_fdt(vms, sysmem, secure_sysmem ?: sysmem); + +- create_gic(vms, pic); ++ create_gic(vms); + + fdt_add_pmu_nodes(vms); + +- create_uart(vms, pic, VIRT_UART, sysmem, serial_hd(0)); ++ create_uart(vms, VIRT_UART, sysmem, serial_hd(0)); + + create_cpufreq(vms, sysmem); + + if (vms->secure) { + create_secure_ram(vms, secure_sysmem); +- create_uart(vms, pic, VIRT_SECURE_UART, secure_sysmem, serial_hd(1)); ++ create_uart(vms, VIRT_SECURE_UART, secure_sysmem, serial_hd(1)); + } + + vms->highmem_ecam &= vms->highmem && (!firmware_loaded || aarch64); + +- create_rtc(vms, pic); ++ create_rtc(vms); + +- create_pcie(vms, pic); ++ create_pcie(vms); + + if (has_ged && aarch64 && firmware_loaded && acpi_enabled) { +- vms->acpi_dev = create_acpi_ged(vms, pic); ++ vms->acpi_dev = create_acpi_ged(vms); + } else { +- create_gpio(vms, pic); ++ create_gpio(vms); + } + + /* connect powerdown request */ +@@ -1862,12 +1861,12 @@ static void machvirt_init(MachineState *machine) + * (which will be automatically plugged in to the transports). If + * no backend is created the transport will just sit harmlessly idle. + */ +- create_virtio_devices(vms, pic); ++ create_virtio_devices(vms); + + vms->fw_cfg = create_fw_cfg(vms, &address_space_memory); + rom_set_fw(vms->fw_cfg); + +- create_platform_bus(vms, pic); ++ create_platform_bus(vms); + + vms->bootinfo.ram_size = machine->ram_size; + vms->bootinfo.kernel_filename = machine->kernel_filename; +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index dcceb9c615..3dfefca93b 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -138,6 +138,7 @@ typedef struct { + uint32_t iommu_phandle; + int psci_conduit; + hwaddr highest_gpa; ++ DeviceState *gic; + DeviceState *acpi_dev; + Notifier powerdown_notifier; + } VirtMachineState; +-- +2.19.1 diff --git a/hw-arm-virt-acpi-build-Add-PC-DIMM-in-SRAT.patch b/hw-arm-virt-acpi-build-Add-PC-DIMM-in-SRAT.patch new file mode 100644 index 0000000000000000000000000000000000000000..0602ab8d4d0d7af63f034c9b66c984e5aed627a7 --- /dev/null +++ b/hw-arm-virt-acpi-build-Add-PC-DIMM-in-SRAT.patch @@ -0,0 +1,75 @@ +From 8d287871fd4e1b4654fe9e5011b80614cb44f6d8 Mon Sep 17 00:00:00 2001 +From: Shameer Kolothum +Date: Wed, 18 Sep 2019 14:06:28 +0100 +Subject: [PATCH] hw/arm/virt-acpi-build: Add PC-DIMM in SRAT + +Generate Memory Affinity Structures for PC-DIMM ranges. + +Also, Linux and Windows need ACPI SRAT table to make memory hotplug +work properly, however currently QEMU doesn't create SRAT table if +numa options aren't present on CLI. Hence add support(>=4.2) to +create numa node automatically (auto_enable_numa_with_memhp) when +QEMU is started with memory hotplug enabled but without '-numa' +options on CLI. + +Signed-off-by: Shameer Kolothum +Signed-off-by: Eric Auger +Reviewed-by: Igor Mammedov +Message-Id: <20190918130633.4872-7-shameerali.kolothum.thodi@huawei.com> +Acked-by: Peter Maydell +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/arm/virt-acpi-build.c | 9 +++++++++ + hw/arm/virt.c | 2 ++ + 2 files changed, 11 insertions(+) + +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index fca53ae01f..9622994e50 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -592,6 +592,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + int i, srat_start; + uint64_t mem_base; + MachineClass *mc = MACHINE_GET_CLASS(vms); ++ MachineState *ms = MACHINE(vms); + const CPUArchIdList *cpu_list = mc->possible_cpu_arch_ids(MACHINE(vms)); + + srat_start = table_data->len; +@@ -617,6 +618,14 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + } + } + ++ if (ms->device_memory) { ++ numamem = acpi_data_push(table_data, sizeof *numamem); ++ build_srat_memory(numamem, ms->device_memory->base, ++ memory_region_size(&ms->device_memory->mr), ++ nb_numa_nodes - 1, ++ MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED); ++ } ++ + build_header(linker, table_data, (void *)(table_data->data + srat_start), + "SRAT", table_data->len - srat_start, 3, NULL, NULL); + } +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 8ccabd5159..ab33cce4b3 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2173,6 +2173,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) + hc->plug = virt_machine_device_plug_cb; + hc->unplug_request = virt_machine_device_unplug_request_cb; + mc->numa_mem_supported = true; ++ mc->auto_enable_numa_with_memhp = true; + } + + static void virt_instance_init(Object *obj) +@@ -2278,6 +2279,7 @@ static void virt_machine_4_0_options(MachineClass *mc) + virt_machine_4_1_options(mc); + compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len); + vmc->no_ged = true; ++ mc->auto_enable_numa_with_memhp = false; + } + DEFINE_VIRT_MACHINE(4, 0) + +-- +2.19.1 diff --git a/hw-arm-virt-add-missing-compat-for-kvm-no-adjvtime.patch b/hw-arm-virt-add-missing-compat-for-kvm-no-adjvtime.patch new file mode 100644 index 0000000000000000000000000000000000000000..3d711678a6bbd365da89b3039509259f9ffe3c2e --- /dev/null +++ b/hw-arm-virt-add-missing-compat-for-kvm-no-adjvtime.patch @@ -0,0 +1,25 @@ +From fbcb4ffa8648d0aa5be01c11816423a483f245ae Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Tue, 26 May 2020 22:39:23 +0800 +Subject: [PATCH] hw/arm/virt: add missing compat for kvm-no-adjvtime + +Machine compatibility for kvm-no-adjvtime is missed, +let's add it for virt machine 4.0 + +Signed-off-by: Ying Fang + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 4c727939..133d36a4 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2492,6 +2492,7 @@ static void virt_machine_4_0_options(MachineClass *mc) + compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len); + vmc->no_ged = true; + mc->auto_enable_numa_with_memhp = false; ++ vmc->kvm_no_adjvtime = true; + } + DEFINE_VIRT_MACHINE(4, 0) + +-- +2.23.0 + diff --git a/hw-arm-virt-vTPM-support.patch b/hw-arm-virt-vTPM-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..cbdc68e62f88981b10ebd459ce101caaf10dba6d --- /dev/null +++ b/hw-arm-virt-vTPM-support.patch @@ -0,0 +1,141 @@ +From 443ebab9c299b04f020a6873454facb078723141 Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Thu, 13 Aug 2020 20:01:10 +0800 +Subject: [PATCH 15/19] hw/arm/virt: vTPM support + +Let the TPM TIS SYSBUS device be dynamically instantiable +in ARM virt. A device tree node is dynamically created +(TPM via MMIO). + +The TPM Physical Presence interface (PPI) is not supported. + +To run with the swtmp TPM emulator, the qemu command line must +be augmented with: + + -chardev socket,id=chrtpm,path=swtpm-sock + -tpmdev emulator,id=tpm0,chardev=chrtpm + -device tpm-tis-device,tpmdev=tpm0 + +swtpm/libtpms command line example: + +swtpm socket --tpm2 -t -d --tpmstate dir=/tmp/tpm +--ctrl type=unixio,path=swtpm-sock + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Tested-by: Ard Biesheuvel +Acked-by: Ard Biesheuvel +Message-id: 20200305165149.618-7-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + hw/arm/Kconfig | 1 + + hw/arm/sysbus-fdt.c | 33 +++++++++++++++++++++++++++++++++ + hw/arm/virt.c | 7 +++++++ + 3 files changed, 41 insertions(+) + +diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig +index 15e18b0a..06e49f26 100644 +--- a/hw/arm/Kconfig ++++ b/hw/arm/Kconfig +@@ -5,6 +5,7 @@ config ARM_VIRT + imply VFIO_AMD_XGBE + imply VFIO_PLATFORM + imply VFIO_XGMAC ++ imply TPM_TIS_SYSBUS + select A15MPCORE + select ACPI + select ARM_SMMUV3 +diff --git a/hw/arm/sysbus-fdt.c b/hw/arm/sysbus-fdt.c +index 57f94e65..c725d325 100644 +--- a/hw/arm/sysbus-fdt.c ++++ b/hw/arm/sysbus-fdt.c +@@ -30,6 +30,7 @@ + #include "hw/arm/sysbus-fdt.h" + #include "qemu/error-report.h" + #include "sysemu/device_tree.h" ++#include "sysemu/tpm.h" + #include "hw/platform-bus.h" + #include "sysemu/sysemu.h" + #include "hw/vfio/vfio-platform.h" +@@ -437,6 +438,37 @@ static bool vfio_platform_match(SysBusDevice *sbdev, + + #endif /* CONFIG_LINUX */ + ++/* ++ * add_tpm_tis_fdt_node: Create a DT node for TPM TIS ++ * ++ * See kernel documentation: ++ * Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt ++ * Optional interrupt for command completion is not exposed ++ */ ++static int add_tpm_tis_fdt_node(SysBusDevice *sbdev, void *opaque) ++{ ++ PlatformBusFDTData *data = opaque; ++ PlatformBusDevice *pbus = data->pbus; ++ void *fdt = data->fdt; ++ const char *parent_node = data->pbus_node_name; ++ char *nodename; ++ uint32_t reg_attr[2]; ++ uint64_t mmio_base; ++ ++ mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0); ++ nodename = g_strdup_printf("%s/tpm_tis@%" PRIx64, parent_node, mmio_base); ++ qemu_fdt_add_subnode(fdt, nodename); ++ ++ qemu_fdt_setprop_string(fdt, nodename, "compatible", "tcg,tpm-tis-mmio"); ++ ++ reg_attr[0] = cpu_to_be32(mmio_base); ++ reg_attr[1] = cpu_to_be32(0x5000); ++ qemu_fdt_setprop(fdt, nodename, "reg", reg_attr, 2 * sizeof(uint32_t)); ++ ++ g_free(nodename); ++ return 0; ++} ++ + static int no_fdt_node(SysBusDevice *sbdev, void *opaque) + { + return 0; +@@ -457,6 +489,7 @@ static const BindingEntry bindings[] = { + TYPE_BINDING(TYPE_VFIO_AMD_XGBE, add_amd_xgbe_fdt_node), + VFIO_PLATFORM_BINDING("amd,xgbe-seattle-v1a", add_amd_xgbe_fdt_node), + #endif ++ TYPE_BINDING(TYPE_TPM_TIS_SYSBUS, add_tpm_tis_fdt_node), + TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node), + TYPE_BINDING("", NULL), /* last element */ + }; +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 133d36a4..7afc6c5e 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -47,6 +47,7 @@ + #include "sysemu/numa.h" + #include "sysemu/cpus.h" + #include "sysemu/sysemu.h" ++#include "sysemu/tpm.h" + #include "sysemu/kvm.h" + #include "sysemu/cpus.h" + #include "sysemu/hw_accel.h" +@@ -2368,6 +2369,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_AMD_XGBE); + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE); + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_PLATFORM); ++ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS); + mc->block_default_type = IF_VIRTIO; + mc->no_cdrom = 1; + mc->pci_allow_0_address = true; +@@ -2481,6 +2483,11 @@ type_init(machvirt_machine_init); + + static void virt_machine_4_1_options(MachineClass *mc) + { ++ static GlobalProperty compat[] = { ++ { TYPE_TPM_TIS_SYSBUS, "ppi", "false" }, ++ }; ++ ++ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); + } + DEFINE_VIRT_MACHINE_AS_LATEST(4, 1) + +-- +2.23.0 + diff --git a/hw-arm64-add-vcpu-cache-info-support.patch b/hw-arm64-add-vcpu-cache-info-support.patch index c9e843719b59a99112ee1867475846378c84264e..79e1dede39def063dc9d8a4f4b87339bcd39c435 100644 --- a/hw-arm64-add-vcpu-cache-info-support.patch +++ b/hw-arm64-add-vcpu-cache-info-support.patch @@ -1,6 +1,6 @@ -From 8db6d888e3eb131900111506b93f6101413df5b4 Mon Sep 17 00:00:00 2001 -From: zhanghailiang -Date: Mon, 5 Aug 2019 15:30:05 +0800 +From 5a0ed254f99ca37498bd81994b906b6984b5ffa9 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 22 Apr 2020 19:25:00 +0800 Subject: [PATCH] hw/arm64: add vcpu cache info support Support VCPU Cache info by dtb and PPTT table, including L1, L2 and L3 Cache. @@ -8,16 +8,16 @@ Support VCPU Cache info by dtb and PPTT table, including L1, L2 and L3 Cache. Signed-off-by: zhanghailiang Signed-off-by: Honghao --- - hw/acpi/aml-build.c | 124 ++++++++++++++++++++++++++++++++++++ - hw/arm/virt.c | 76 +++++++++++++++++++++- + hw/acpi/aml-build.c | 126 ++++++++++++++++++++++++++++++++++++ + hw/arm/virt.c | 80 ++++++++++++++++++++++- include/hw/acpi/aml-build.h | 46 +++++++++++++ - 3 files changed, 245 insertions(+), 1 deletion(-) + 3 files changed, 251 insertions(+), 1 deletion(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c -index 9d39ad10..99209c0a 100644 +index f2c8c28f..74e95005 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c -@@ -55,6 +55,129 @@ static void build_append_array(GArray *array, GArray *val) +@@ -55,6 +55,131 @@ static void build_append_array(GArray *array, GArray *val) /* * ACPI 6.2 Processor Properties Topology Table (PPTT) */ @@ -115,6 +115,8 @@ index 9d39ad10..99209c0a 100644 + int pptt_start = table_data->len; + int uid = 0, cpus = 0, socket; + struct offset_status offset; ++ const MachineState *ms = MACHINE(qdev_get_machine()); ++ unsigned int smp_cores = ms->smp.cores; + + acpi_data_push(table_data, sizeof(AcpiTableHeader)); + @@ -147,25 +149,27 @@ index 9d39ad10..99209c0a 100644 static void build_cpu_hierarchy(GArray *tbl, uint32_t flags, uint32_t parent, uint32_t id) { -@@ -100,6 +223,7 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus) +@@ -103,6 +228,7 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus) (void *)(table_data->data + pptt_start), "PPTT", table_data->len - pptt_start, 1, NULL, NULL); } +#endif - + #define ACPI_NAMESEG_LEN 4 - + diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 16700a2e..96f56e2e 100644 +index 272455bc..9669c70b 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c -@@ -304,6 +304,77 @@ static void fdt_add_timer_nodes(const VirtMachineState *vms) +@@ -308,6 +308,81 @@ static void fdt_add_timer_nodes(const VirtMachineState *vms) GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL2_IRQ, irqflags); } - + +static void fdt_add_l3cache_nodes(const VirtMachineState *vms) +{ + int i; ++ const MachineState *ms = MACHINE(qdev_get_machine()); ++ unsigned int smp_cores = ms->smp.cores; + unsigned int sockets = vms->smp_cpus / smp_cores; + + /* If current is not equal to max */ @@ -191,6 +195,8 @@ index 16700a2e..96f56e2e 100644 +static void fdt_add_l2cache_nodes(const VirtMachineState *vms) +{ + int i, j; ++ const MachineState *ms = MACHINE(qdev_get_machine()); ++ unsigned int smp_cores = ms->smp.cores; + signed int sockets = vms->smp_cpus / smp_cores; + + /* If current is not equal to max */ @@ -237,17 +243,17 @@ index 16700a2e..96f56e2e 100644 static void fdt_add_cpu_nodes(const VirtMachineState *vms) { int cpu; -@@ -336,6 +407,9 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) +@@ -341,6 +416,9 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) qemu_fdt_setprop_cell(vms->fdt, "/cpus", "#address-cells", addr_cells); qemu_fdt_setprop_cell(vms->fdt, "/cpus", "#size-cells", 0x0); - + + fdt_add_l3cache_nodes(vms); + fdt_add_l2cache_nodes(vms); + for (cpu = vms->smp_cpus - 1; cpu >= 0; cpu--) { char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu); ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu)); -@@ -364,7 +438,7 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) +@@ -369,7 +447,7 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) qemu_fdt_setprop_cell(vms->fdt, nodename, "numa-node-id", ms->possible_cpus->cpus[cs->cpu_index].props.node_id); } @@ -255,7 +261,7 @@ index 16700a2e..96f56e2e 100644 + fdt_add_l1cache_prop(vms, nodename, cpu); qemu_fdt_setprop_cell(vms->fdt, nodename, "phandle", qemu_fdt_alloc_phandle(vms->fdt)); - + diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index bfb0b100..0be3453a 100644 --- a/include/hw/acpi/aml-build.h @@ -263,7 +269,7 @@ index bfb0b100..0be3453a 100644 @@ -223,6 +223,52 @@ struct AcpiBuildTables { BIOSLinker *linker; } AcpiBuildTables; - + +#ifdef __aarch64__ +/* Definitions of the hardcoded cache info*/ + @@ -313,6 +319,5 @@ index bfb0b100..0be3453a 100644 /** * init_aml_allocator: * --- +-- 2.23.0 - diff --git a/hw-core-loader-Fix-possible-crash-in-rom_copy.patch b/hw-core-loader-Fix-possible-crash-in-rom_copy.patch new file mode 100644 index 0000000000000000000000000000000000000000..770f12b1acf9dfc3c4289e9a9bea7d5936df1968 --- /dev/null +++ b/hw-core-loader-Fix-possible-crash-in-rom_copy.patch @@ -0,0 +1,45 @@ +From aae0faa5d3bee91c66dc4c1543190f55a242771e Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Wed, 25 Sep 2019 14:16:43 +0200 +Subject: [PATCH] hw/core/loader: Fix possible crash in rom_copy() + +Both, "rom->addr" and "addr" are derived from the binary image +that can be loaded with the "-kernel" paramer. The code in +rom_copy() then calculates: + + d = dest + (rom->addr - addr); + +and uses "d" as destination in a memcpy() some lines later. Now with +bad kernel images, it is possible that rom->addr is smaller than addr, +thus "rom->addr - addr" gets negative and the memcpy() then tries to +copy contents from the image to a bad memory location. This could +maybe be used to inject code from a kernel image into the QEMU binary, +so we better fix it with an additional sanity check here. + +Cc: qemu-stable@nongnu.org +Reported-by: Guangming Liu +Buglink: https://bugs.launchpad.net/qemu/+bug/1844635 +Message-Id: <20190925130331.27825-1-thuth@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Thomas Huth +(cherry picked from commit e423455c4f23a1a828901c78fe6d03b7dde79319) +Signed-off-by: Michael Roth +--- + hw/core/loader.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/core/loader.c b/hw/core/loader.c +index 425bf69a99..838a34174a 100644 +--- a/hw/core/loader.c ++++ b/hw/core/loader.c +@@ -1242,7 +1242,7 @@ int rom_copy(uint8_t *dest, hwaddr addr, size_t size) + if (rom->addr + rom->romsize < addr) { + continue; + } +- if (rom->addr > end) { ++ if (rom->addr > end || rom->addr < addr) { + break; + } + +-- +2.23.0 diff --git a/hw-intc-gicv3-Add-CPU-hotplug-realize-hook.patch b/hw-intc-gicv3-Add-CPU-hotplug-realize-hook.patch new file mode 100644 index 0000000000000000000000000000000000000000..2b77e0b0ce8a678b0c13b7f9f852522617b90c71 --- /dev/null +++ b/hw-intc-gicv3-Add-CPU-hotplug-realize-hook.patch @@ -0,0 +1,170 @@ +From 6bbfb186c8d66b745aeb08143d3198fcedc52d6c Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Mon, 6 Apr 2020 11:26:35 +0800 +Subject: [PATCH] hw/intc/gicv3: Add CPU hotplug realize hook + +GICv3 exposes individual CPU realization capability through +this hook. It will be used for hotplugged CPU. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/intc/arm_gicv3.c | 17 ++++++++++++++++- + hw/intc/arm_gicv3_common.c | 8 ++++++++ + hw/intc/arm_gicv3_kvm.c | 11 +++++++++++ + include/hw/intc/arm_gicv3.h | 2 ++ + include/hw/intc/arm_gicv3_common.h | 4 ++++ + 5 files changed, 41 insertions(+), 1 deletion(-) + +diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c +index 2fe79f794d..cacef26546 100644 +--- a/hw/intc/arm_gicv3.c ++++ b/hw/intc/arm_gicv3.c +@@ -361,6 +361,19 @@ static const MemoryRegionOps gic_ops[] = { + } + }; + ++static void gicv3_cpu_realize(GICv3State *s, int i) ++{ ++ gicv3_init_one_cpuif(s, i); ++} ++ ++static void arm_gicv3_cpu_hotplug_realize(GICv3State *s, int ncpu) ++{ ++ ARMGICv3Class *agc = ARM_GICV3_GET_CLASS(s); ++ ++ agc->parent_cpu_hotplug_realize(s, ncpu); ++ gicv3_cpu_realize(s, ncpu); ++} ++ + static void arm_gic_realize(DeviceState *dev, Error **errp) + { + /* Device instance realize function for the GIC sysbus device */ +@@ -388,7 +401,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) + } + + for (i = 0; i < s->num_cpu; i++) { +- gicv3_init_one_cpuif(s, i); ++ gicv3_cpu_realize(s, i); + } + } + +@@ -398,6 +411,8 @@ static void arm_gicv3_class_init(ObjectClass *klass, void *data) + ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass); + ARMGICv3Class *agc = ARM_GICV3_CLASS(klass); + ++ agc->parent_cpu_hotplug_realize = agcc->cpu_hotplug_realize; ++ agcc->cpu_hotplug_realize = arm_gicv3_cpu_hotplug_realize; + agcc->post_load = arm_gicv3_post_load; + device_class_set_parent_realize(dc, arm_gic_realize, &agc->parent_realize); + } +diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c +index 798f295d7c..8740a52c9f 100644 +--- a/hw/intc/arm_gicv3_common.c ++++ b/hw/intc/arm_gicv3_common.c +@@ -313,6 +313,11 @@ static void arm_gicv3_common_cpu_realize(GICv3State *s, int ncpu) + gicv3_set_gicv3state(cpu, &s->cpu[ncpu]); + } + ++static void arm_gicv3_common_cpu_hotplug_realize(GICv3State *s, int ncpu) ++{ ++ arm_gicv3_common_cpu_realize(s, ncpu); ++} ++ + static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) + { + GICv3State *s = ARM_GICV3_COMMON(dev); +@@ -357,6 +362,7 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) + + for (i = 0; i < s->num_cpu; i++) { + CPUState *cpu = qemu_get_cpu(i); ++ + uint64_t cpu_affid; + int last; + +@@ -508,12 +514,14 @@ static Property arm_gicv3_common_properties[] = { + static void arm_gicv3_common_class_init(ObjectClass *klass, void *data) + { + DeviceClass *dc = DEVICE_CLASS(klass); ++ ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass); + ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_CLASS(klass); + + dc->reset = arm_gicv3_common_reset; + dc->realize = arm_gicv3_common_realize; + dc->props = arm_gicv3_common_properties; + dc->vmsd = &vmstate_gicv3; ++ agcc->cpu_hotplug_realize = arm_gicv3_common_cpu_hotplug_realize; + albifc->arm_linux_init = arm_gic_common_linux_init; + } + +diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c +index b2936938cb..f8d7be5479 100644 +--- a/hw/intc/arm_gicv3_kvm.c ++++ b/hw/intc/arm_gicv3_kvm.c +@@ -78,6 +78,7 @@ typedef struct KVMARMGICv3Class { + ARMGICv3CommonClass parent_class; + DeviceRealize parent_realize; + void (*parent_reset)(DeviceState *dev); ++ CPUHotplugRealize parent_cpu_hotplug_realize; + } KVMARMGICv3Class; + + static void kvm_arm_gicv3_set_irq(void *opaque, int irq, int level) +@@ -768,6 +769,14 @@ static void kvm_arm_gicv3_cpu_realize(GICv3State *s, int ncpu) + define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); + } + ++static void kvm_arm_gicv3_cpu_hotplug_realize(GICv3State *s, int ncpu) ++{ ++ KVMARMGICv3Class *kagcc = KVM_ARM_GICV3_GET_CLASS(s); ++ ++ kagcc->parent_cpu_hotplug_realize(s, ncpu); ++ kvm_arm_gicv3_cpu_realize(s, ncpu); ++} ++ + static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) + { + GICv3State *s = KVM_ARM_GICV3(dev); +@@ -884,6 +893,8 @@ static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) + ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass); + KVMARMGICv3Class *kgc = KVM_ARM_GICV3_CLASS(klass); + ++ kgc->parent_cpu_hotplug_realize = agcc->cpu_hotplug_realize; ++ agcc->cpu_hotplug_realize = kvm_arm_gicv3_cpu_hotplug_realize; + agcc->pre_save = kvm_arm_gicv3_get; + agcc->post_load = kvm_arm_gicv3_put; + device_class_set_parent_realize(dc, kvm_arm_gicv3_realize, +diff --git a/include/hw/intc/arm_gicv3.h b/include/hw/intc/arm_gicv3.h +index 4a6fd85e22..98f2bdb7e9 100644 +--- a/include/hw/intc/arm_gicv3.h ++++ b/include/hw/intc/arm_gicv3.h +@@ -26,6 +26,8 @@ typedef struct ARMGICv3Class { + ARMGICv3CommonClass parent_class; + /*< public >*/ + ++ CPUHotplugRealize parent_cpu_hotplug_realize; ++ + DeviceRealize parent_realize; + } ARMGICv3Class; + +diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h +index 31ec9a1ae4..45cc50ed3b 100644 +--- a/include/hw/intc/arm_gicv3_common.h ++++ b/include/hw/intc/arm_gicv3_common.h +@@ -286,11 +286,15 @@ GICV3_BITMAP_ACCESSORS(edge_trigger) + #define ARM_GICV3_COMMON_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ARMGICv3CommonClass, (obj), TYPE_ARM_GICV3_COMMON) + ++typedef void (*CPUHotplugRealize)(GICv3State *s, int ncpu); ++ + typedef struct ARMGICv3CommonClass { + /*< private >*/ + SysBusDeviceClass parent_class; + /*< public >*/ + ++ CPUHotplugRealize cpu_hotplug_realize; ++ + void (*pre_save)(GICv3State *s); + void (*post_load)(GICv3State *s); + } ARMGICv3CommonClass; +-- +2.19.1 diff --git a/hw-ppc-Kconfig-Enable-TPM_SPAPR-as-part-of-PSERIES-c.patch b/hw-ppc-Kconfig-Enable-TPM_SPAPR-as-part-of-PSERIES-c.patch new file mode 100644 index 0000000000000000000000000000000000000000..ad3fc3a8356d20d28805db548c12b2b3745e8054 --- /dev/null +++ b/hw-ppc-Kconfig-Enable-TPM_SPAPR-as-part-of-PSERIES-c.patch @@ -0,0 +1,36 @@ +From 95cbe18c649a20f98562a993537a67e0ad78bf36 Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 21 Jan 2020 10:29:34 -0500 +Subject: [PATCH 08/19] hw/ppc/Kconfig: Enable TPM_SPAPR as part of PSERIES + config +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Stefan Berger +Reviewed-by: Marc-André Lureau +Reviewed-by: David Gibson +Message-Id: <20200121152935.649898-6-stefanb@linux.ibm.com> +[dwg: Use default in Kconfig rather than select to avoid breaking + Windows host build] +Signed-off-by: David Gibson +Signed-off-by: jiangfangjie +--- + hw/tpm/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig +index 4d4ab085..9e67d990 100644 +--- a/hw/tpm/Kconfig ++++ b/hw/tpm/Kconfig +@@ -25,6 +25,6 @@ config TPM_EMULATOR + + config TPM_SPAPR + bool +- default n ++ default y + depends on TPM && PSERIES + select TPMDEV +-- +2.23.0 + diff --git a/hw-scsi-megasas-Fix-possible-out-of-bounds-array-acc.patch b/hw-scsi-megasas-Fix-possible-out-of-bounds-array-acc.patch new file mode 100644 index 0000000000000000000000000000000000000000..12c907453efdaa1141217b3adccf27d4099ee924 --- /dev/null +++ b/hw-scsi-megasas-Fix-possible-out-of-bounds-array-acc.patch @@ -0,0 +1,132 @@ +From 5ec15fabe78e385a81e44c7944cd05309de7f36e Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Mon, 15 Jun 2020 09:26:29 +0200 +Subject: [PATCH 7/9] hw/scsi/megasas: Fix possible out-of-bounds array access + in tracepoints +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some tracepoints in megasas.c use a guest-controlled value as an index +into the mfi_frame_desc[] array. Thus a malicious guest could cause an +out-of-bounds error here. Fortunately, the impact is very low since this +can only happen when the corresponding tracepoints have been enabled +before, but the problem should be fixed anyway with a proper check. + +Buglink: https://bugs.launchpad.net/qemu/+bug/1882065 +Signed-off-by: Thomas Huth +Message-Id: <20200615072629.32321-1-thuth@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Paolo Bonzini +--- + hw/scsi/megasas.c | 36 +++++++++++++++++++++++------------- + 1 file changed, 23 insertions(+), 13 deletions(-) + +diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c +index 94469e8169..9421f4d14e 100644 +--- a/hw/scsi/megasas.c ++++ b/hw/scsi/megasas.c +@@ -53,10 +53,6 @@ + #define MEGASAS_FLAG_USE_QUEUE64 1 + #define MEGASAS_MASK_USE_QUEUE64 (1 << MEGASAS_FLAG_USE_QUEUE64) + +-static const char *mfi_frame_desc[] = { +- "MFI init", "LD Read", "LD Write", "LD SCSI", "PD SCSI", +- "MFI Doorbell", "MFI Abort", "MFI SMP", "MFI Stop"}; +- + typedef struct MegasasCmd { + uint32_t index; + uint16_t flags; +@@ -182,6 +178,20 @@ static void megasas_frame_set_scsi_status(MegasasState *s, + stb_pci_dma(pci, frame + offsetof(struct mfi_frame_header, scsi_status), v); + } + ++static inline const char *mfi_frame_desc(unsigned int cmd) ++{ ++ static const char *mfi_frame_descs[] = { ++ "MFI init", "LD Read", "LD Write", "LD SCSI", "PD SCSI", ++ "MFI Doorbell", "MFI Abort", "MFI SMP", "MFI Stop" ++ }; ++ ++ if (cmd < ARRAY_SIZE(mfi_frame_descs)) { ++ return mfi_frame_descs[cmd]; ++ } ++ ++ return "Unknown"; ++} ++ + /* + * Context is considered opaque, but the HBA firmware is running + * in little endian mode. So convert it to little endian, too. +@@ -1669,25 +1679,25 @@ static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd, + if (is_logical) { + if (target_id >= MFI_MAX_LD || lun_id != 0) { + trace_megasas_scsi_target_not_present( +- mfi_frame_desc[frame_cmd], is_logical, target_id, lun_id); ++ mfi_frame_desc(frame_cmd), is_logical, target_id, lun_id); + return MFI_STAT_DEVICE_NOT_FOUND; + } + } + sdev = scsi_device_find(&s->bus, 0, target_id, lun_id); + + cmd->iov_size = le32_to_cpu(cmd->frame->header.data_len); +- trace_megasas_handle_scsi(mfi_frame_desc[frame_cmd], is_logical, ++ trace_megasas_handle_scsi(mfi_frame_desc(frame_cmd), is_logical, + target_id, lun_id, sdev, cmd->iov_size); + + if (!sdev || (megasas_is_jbod(s) && is_logical)) { + trace_megasas_scsi_target_not_present( +- mfi_frame_desc[frame_cmd], is_logical, target_id, lun_id); ++ mfi_frame_desc(frame_cmd), is_logical, target_id, lun_id); + return MFI_STAT_DEVICE_NOT_FOUND; + } + + if (cdb_len > 16) { + trace_megasas_scsi_invalid_cdb_len( +- mfi_frame_desc[frame_cmd], is_logical, ++ mfi_frame_desc(frame_cmd), is_logical, + target_id, lun_id, cdb_len); + megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE)); + cmd->frame->header.scsi_status = CHECK_CONDITION; +@@ -1705,7 +1715,7 @@ static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd, + cmd->req = scsi_req_new(sdev, cmd->index, lun_id, cdb, cmd); + if (!cmd->req) { + trace_megasas_scsi_req_alloc_failed( +- mfi_frame_desc[frame_cmd], target_id, lun_id); ++ mfi_frame_desc(frame_cmd), target_id, lun_id); + megasas_write_sense(cmd, SENSE_CODE(NO_SENSE)); + cmd->frame->header.scsi_status = BUSY; + s->event_count++; +@@ -1750,17 +1760,17 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd, int frame_cmd) + } + + trace_megasas_handle_io(cmd->index, +- mfi_frame_desc[frame_cmd], target_id, lun_id, ++ mfi_frame_desc(frame_cmd), target_id, lun_id, + (unsigned long)lba_start, (unsigned long)lba_count); + if (!sdev) { + trace_megasas_io_target_not_present(cmd->index, +- mfi_frame_desc[frame_cmd], target_id, lun_id); ++ mfi_frame_desc(frame_cmd), target_id, lun_id); + return MFI_STAT_DEVICE_NOT_FOUND; + } + + if (cdb_len > 16) { + trace_megasas_scsi_invalid_cdb_len( +- mfi_frame_desc[frame_cmd], 1, target_id, lun_id, cdb_len); ++ mfi_frame_desc(frame_cmd), 1, target_id, lun_id, cdb_len); + megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE)); + cmd->frame->header.scsi_status = CHECK_CONDITION; + s->event_count++; +@@ -1780,7 +1790,7 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd, int frame_cmd) + lun_id, cdb, cmd); + if (!cmd->req) { + trace_megasas_scsi_req_alloc_failed( +- mfi_frame_desc[frame_cmd], target_id, lun_id); ++ mfi_frame_desc(frame_cmd), target_id, lun_id); + megasas_write_sense(cmd, SENSE_CODE(NO_SENSE)); + cmd->frame->header.scsi_status = BUSY; + s->event_count++; +-- +2.25.1 + diff --git a/hw-tpm-rename-Error-parameter-to-more-common-errp.patch b/hw-tpm-rename-Error-parameter-to-more-common-errp.patch new file mode 100644 index 0000000000000000000000000000000000000000..a47a1ae68da792d7811b9d85cb5cbd5f5d5ac0cd --- /dev/null +++ b/hw-tpm-rename-Error-parameter-to-more-common-errp.patch @@ -0,0 +1,58 @@ +From f2dceb3cde537210896a2cadb8958cfd310113a3 Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Thu, 5 Dec 2019 20:46:30 +0300 +Subject: [PATCH 01/19] hw/tpm: rename Error ** parameter to more common errp +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Stefan Berger +Message-Id: <20191205174635.18758-17-vsementsov@virtuozzo.com> +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Markus Armbruster +Signed-off-by: jiangfangjie +--- + hw/tpm/tpm_emulator.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c +index fc0b512f..38bf5fd6 100644 +--- a/hw/tpm/tpm_emulator.c ++++ b/hw/tpm/tpm_emulator.c +@@ -155,7 +155,7 @@ static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu, + const uint8_t *in, uint32_t in_len, + uint8_t *out, uint32_t out_len, + bool *selftest_done, +- Error **err) ++ Error **errp) + { + ssize_t ret; + bool is_selftest = false; +@@ -165,20 +165,20 @@ static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu, + is_selftest = tpm_util_is_selftest(in, in_len); + } + +- ret = qio_channel_write_all(tpm_emu->data_ioc, (char *)in, in_len, err); ++ ret = qio_channel_write_all(tpm_emu->data_ioc, (char *)in, in_len, errp); + if (ret != 0) { + return -1; + } + + ret = qio_channel_read_all(tpm_emu->data_ioc, (char *)out, +- sizeof(struct tpm_resp_hdr), err); ++ sizeof(struct tpm_resp_hdr), errp); + if (ret != 0) { + return -1; + } + + ret = qio_channel_read_all(tpm_emu->data_ioc, + (char *)out + sizeof(struct tpm_resp_hdr), +- tpm_cmd_get_size(out) - sizeof(struct tpm_resp_hdr), err); ++ tpm_cmd_get_size(out) - sizeof(struct tpm_resp_hdr), errp); + if (ret != 0) { + return -1; + } +-- +2.23.0 + diff --git a/hw-usb-core-fix-buffer-overflow.patch b/hw-usb-core-fix-buffer-overflow.patch new file mode 100644 index 0000000000000000000000000000000000000000..494955788a2506fd2d28521ff234118025fbe674 --- /dev/null +++ b/hw-usb-core-fix-buffer-overflow.patch @@ -0,0 +1,46 @@ +hw-usb-core-fix-buffer-overflow + +From 18ad0451f113ffc3a2ff59c059d189cca1e42842 Mon Sep 17 00:00:00 2001 +From: root +Date: Wed, 19 Aug 2020 17:04:04 +0800 +Subject: [PATCH] hw/usb/core.c fix buffer overflow + +Store calculated setup_len in a local variable, verify it, + and only write it to the struct (USBDevice->setup_len) in case it passed the + sanity checks. + +This prevents other code (do_token_{in,out} function specifically) +from working with invalid USBDevice->setup_len values and overruning +the USBDevice->setup_buf[] buffer. +Store +Fixes: CVE-2020-14364 +Signed-off-by: Gred Hoffman +--- + hw/usb/core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/usb/core.c b/hw/usb/core.c +index 5abd128b..12342f13 100644 +--- a/hw/usb/core.c ++++ b/hw/usb/core.c +@@ -144,6 +144,8 @@ static void do_token_setup(USBDevice *s, USBPacket *p) + "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n", + s->setup_len, sizeof(s->data_buf)); + p->status = USB_RET_STALL; ++ s->setup_len = 0; ++ s->setup_state = SETUP_STATE_ACK; + return; + } + +@@ -277,6 +279,8 @@ static void do_parameter(USBDevice *s, USBPacket *p) + "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n", + s->setup_len, sizeof(s->data_buf)); + p->status = USB_RET_STALL; ++ s->setup_len = 0; ++ s->setup_state = SETUP_STATE_ACK; + return; + } + +-- +2.23.0 + diff --git a/ide-Fix-incorrect-handling-of-some-PRDTs-in-ide_dma_.patch b/ide-Fix-incorrect-handling-of-some-PRDTs-in-ide_dma_.patch new file mode 100644 index 0000000000000000000000000000000000000000..9570b46b755e06705212253195a6605d738db350 --- /dev/null +++ b/ide-Fix-incorrect-handling-of-some-PRDTs-in-ide_dma_.patch @@ -0,0 +1,89 @@ +From ed78352a59ea7acf7520d4d47a96b9911bae7fc3 Mon Sep 17 00:00:00 2001 +From: Alexander Popov +Date: Mon, 23 Dec 2019 20:51:16 +0300 +Subject: [PATCH] ide: Fix incorrect handling of some PRDTs in ide_dma_cb() + +The commit a718978ed58a from July 2015 introduced the assertion which +implies that the size of successful DMA transfers handled in ide_dma_cb() +should be multiple of 512 (the size of a sector). But guest systems can +initiate DMA transfers that don't fit this requirement. + +For fixing that let's check the number of bytes prepared for the transfer +by the prepare_buf() handler. The code in ide_dma_cb() must behave +according to the Programming Interface for Bus Master IDE Controller +(Revision 1.0 5/16/94): +1. If PRDs specified a smaller size than the IDE transfer + size, then the Interrupt and Active bits in the Controller + status register are not set (Error Condition). +2. If the size of the physical memory regions was equal to + the IDE device transfer size, the Interrupt bit in the + Controller status register is set to 1, Active bit is set to 0. +3. If PRDs specified a larger size than the IDE transfer size, + the Interrupt and Active bits in the Controller status register + are both set to 1. + +Signed-off-by: Alexander Popov +Reviewed-by: Kevin Wolf +Message-id: 20191223175117.508990-2-alex.popov@linux.com +Signed-off-by: John Snow + +diff --git a/hw/ide/core.c b/hw/ide/core.c +index 754ff4dc34..80000eb766 100644 +--- a/hw/ide/core.c ++++ b/hw/ide/core.c +@@ -849,6 +849,7 @@ static void ide_dma_cb(void *opaque, int ret) + int64_t sector_num; + uint64_t offset; + bool stay_active = false; ++ int32_t prep_size = 0; + + if (ret == -EINVAL) { + ide_dma_error(s); +@@ -863,13 +864,15 @@ static void ide_dma_cb(void *opaque, int ret) + } + } + +- n = s->io_buffer_size >> 9; +- if (n > s->nsector) { +- /* The PRDs were longer than needed for this request. Shorten them so +- * we don't get a negative remainder. The Active bit must remain set +- * after the request completes. */ ++ if (s->io_buffer_size > s->nsector * 512) { ++ /* ++ * The PRDs were longer than needed for this request. ++ * The Active bit must remain set after the request completes. ++ */ + n = s->nsector; + stay_active = true; ++ } else { ++ n = s->io_buffer_size >> 9; + } + + sector_num = ide_get_sector(s); +@@ -892,9 +895,20 @@ static void ide_dma_cb(void *opaque, int ret) + n = s->nsector; + s->io_buffer_index = 0; + s->io_buffer_size = n * 512; +- if (s->bus->dma->ops->prepare_buf(s->bus->dma, s->io_buffer_size) < 512) { +- /* The PRDs were too short. Reset the Active bit, but don't raise an +- * interrupt. */ ++ prep_size = s->bus->dma->ops->prepare_buf(s->bus->dma, s->io_buffer_size); ++ /* prepare_buf() must succeed and respect the limit */ ++ assert(prep_size >= 0 && prep_size <= n * 512); ++ ++ /* ++ * Now prep_size stores the number of bytes in the sglist, and ++ * s->io_buffer_size stores the number of bytes described by the PRDs. ++ */ ++ ++ if (prep_size < n * 512) { ++ /* ++ * The PRDs are too short for this request. Error condition! ++ * Reset the Active bit and don't raise the interrupt. ++ */ + s->status = READY_STAT | SEEK_STAT; + dma_buf_commit(s, 0); + goto eot; +-- +2.23.0 + diff --git a/intc-gicv3-Add-pre-sizing-capability-to-GICv3.patch b/intc-gicv3-Add-pre-sizing-capability-to-GICv3.patch new file mode 100644 index 0000000000000000000000000000000000000000..30175fb5126a8a9b7138c206365b61c96bcddaf0 --- /dev/null +++ b/intc-gicv3-Add-pre-sizing-capability-to-GICv3.patch @@ -0,0 +1,357 @@ +From 0a75312c069d89be94bcaa688429d8f60a0c528b Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Fri, 10 Apr 2020 13:15:35 +0800 +Subject: [PATCH] intc/gicv3: Add pre-sizing capability to GICv3 + +Currently GICv3 supports fixed smp_cpus CPUs, and all CPUs are +present always. Now we want to pre-sizing GICv3 to support max_cpus +CPUs and not all of them are present always, so some sizing codes +should be concerned. + +GIC irqs, GICR and GICC are pre-created for all possible CPUs at +start, but only smp_cpus CPUs are realize and irqs of smp_cpus CPUs +are connected. + +Other code changes are mainly for arm_gicv3, and we do little about +kvm_arm_gicv3 becasue KVM will deal with the sizing information properly. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt.c | 17 +++++++++++---- + hw/intc/arm_gicv3.c | 43 +++++++++++++++++++++++++------------- + hw/intc/arm_gicv3_common.c | 23 ++++++++++++++++++-- + hw/intc/arm_gicv3_cpuif.c | 4 ++++ + hw/intc/arm_gicv3_kvm.c | 28 ++++++++++++++++++++++++- + include/hw/arm/virt.h | 3 ++- + 6 files changed, 96 insertions(+), 22 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 55d403bad6..dda22194b5 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -761,14 +761,19 @@ static void create_gic(VirtMachineState *vms) + SysBusDevice *gicbusdev; + const char *gictype; + int type = vms->gic_version, i; ++ /* The max number of CPUs suppored by GIC */ ++ unsigned int num_cpus = ms->smp.cpus; ++ /* The number of CPUs present before boot */ + unsigned int smp_cpus = ms->smp.cpus; + uint32_t nb_redist_regions = 0; + ++ assert(num_cpus >= smp_cpus); ++ + gictype = (type == 3) ? gicv3_class_name() : gic_class_name(); + + vms->gic = qdev_create(NULL, gictype); + qdev_prop_set_uint32(vms->gic, "revision", type); +- qdev_prop_set_uint32(vms->gic, "num-cpu", smp_cpus); ++ qdev_prop_set_uint32(vms->gic, "num-cpu", num_cpus); + /* Note that the num-irq property counts both internal and external + * interrupts; there are always 32 of the former (mandated by GIC spec). + */ +@@ -780,7 +785,7 @@ static void create_gic(VirtMachineState *vms) + if (type == 3) { + uint32_t redist0_capacity = + vms->memmap[VIRT_GIC_REDIST].size / GICV3_REDIST_SIZE; +- uint32_t redist0_count = MIN(smp_cpus, redist0_capacity); ++ uint32_t redist0_count = MIN(num_cpus, redist0_capacity); + + nb_redist_regions = virt_gicv3_redist_region_count(vms); + +@@ -793,7 +798,7 @@ static void create_gic(VirtMachineState *vms) + vms->memmap[VIRT_HIGH_GIC_REDIST2].size / GICV3_REDIST_SIZE; + + qdev_prop_set_uint32(vms->gic, "redist-region-count[1]", +- MIN(smp_cpus - redist0_count, redist1_capacity)); ++ MIN(num_cpus - redist0_count, redist1_capacity)); + } + } else { + if (!kvm_irqchip_in_kernel()) { +@@ -820,7 +825,11 @@ static void create_gic(VirtMachineState *vms) + + /* Wire the outputs from each CPU's generic timer and the GICv3 + * maintenance interrupt signal to the appropriate GIC PPI inputs, +- * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs. ++ * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's ++ * inputs. ++ * ++ * The irqs of remaining CPUs (if we has) will be connected during ++ * hotplugging. + */ + for (i = 0; i < smp_cpus; i++) { + connect_gic_cpu_irqs(vms, i); +diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c +index cacef26546..a60185113f 100644 +--- a/hw/intc/arm_gicv3.c ++++ b/hw/intc/arm_gicv3.c +@@ -20,6 +20,7 @@ + #include "qemu/module.h" + #include "hw/sysbus.h" + #include "hw/intc/arm_gicv3.h" ++#include "qom/cpu.h" + #include "gicv3_internal.h" + + static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio) +@@ -206,7 +207,9 @@ static void gicv3_update_noirqset(GICv3State *s, int start, int len) + assert(len > 0); + + for (i = 0; i < s->num_cpu; i++) { +- s->cpu[i].seenbetter = false; ++ if (qemu_get_cpu(i)) { ++ s->cpu[i].seenbetter = false; ++ } + } + + /* Find the highest priority pending interrupt in this range. */ +@@ -248,16 +251,18 @@ static void gicv3_update_noirqset(GICv3State *s, int start, int len) + * now be the new best one). + */ + for (i = 0; i < s->num_cpu; i++) { +- GICv3CPUState *cs = &s->cpu[i]; ++ if (qemu_get_cpu(i)) { ++ GICv3CPUState *cs = &s->cpu[i]; + +- if (cs->seenbetter) { +- cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq); +- } ++ if (cs->seenbetter) { ++ cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq); ++ } + +- if (!cs->seenbetter && cs->hppi.prio != 0xff && +- cs->hppi.irq >= start && cs->hppi.irq < start + len) { +- gicv3_full_update_noirqset(s); +- break; ++ if (!cs->seenbetter && cs->hppi.prio != 0xff && ++ cs->hppi.irq >= start && cs->hppi.irq < start + len) { ++ gicv3_full_update_noirqset(s); ++ break; ++ } + } + } + } +@@ -268,7 +273,9 @@ void gicv3_update(GICv3State *s, int start, int len) + + gicv3_update_noirqset(s, start, len); + for (i = 0; i < s->num_cpu; i++) { +- gicv3_cpuif_update(&s->cpu[i]); ++ if (qemu_get_cpu(i)) { ++ gicv3_cpuif_update(&s->cpu[i]); ++ } + } + } + +@@ -280,7 +287,9 @@ void gicv3_full_update_noirqset(GICv3State *s) + int i; + + for (i = 0; i < s->num_cpu; i++) { +- s->cpu[i].hppi.prio = 0xff; ++ if (qemu_get_cpu(i)) { ++ s->cpu[i].hppi.prio = 0xff; ++ } + } + + /* Note that we can guarantee that these functions will not +@@ -291,7 +300,9 @@ void gicv3_full_update_noirqset(GICv3State *s) + gicv3_update_noirqset(s, GIC_INTERNAL, s->num_irq - GIC_INTERNAL); + + for (i = 0; i < s->num_cpu; i++) { +- gicv3_redist_update_noirqset(&s->cpu[i]); ++ if (qemu_get_cpu(i)) { ++ gicv3_redist_update_noirqset(&s->cpu[i]); ++ } + } + } + +@@ -304,7 +315,9 @@ void gicv3_full_update(GICv3State *s) + + gicv3_full_update_noirqset(s); + for (i = 0; i < s->num_cpu; i++) { +- gicv3_cpuif_update(&s->cpu[i]); ++ if (qemu_get_cpu(i)) { ++ gicv3_cpuif_update(&s->cpu[i]); ++ } + } + } + +@@ -401,7 +414,9 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) + } + + for (i = 0; i < s->num_cpu; i++) { +- gicv3_cpu_realize(s, i); ++ if (qemu_get_cpu(i)) { ++ gicv3_cpu_realize(s, i); ++ } + } + } + +diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c +index 8740a52c9f..913bf068be 100644 +--- a/hw/intc/arm_gicv3_common.c ++++ b/hw/intc/arm_gicv3_common.c +@@ -24,10 +24,12 @@ + #include "qemu/osdep.h" + #include "qapi/error.h" + #include "qemu/module.h" ++#include "qemu/error-report.h" + #include "qom/cpu.h" + #include "hw/intc/arm_gicv3_common.h" + #include "gicv3_internal.h" + #include "hw/arm/linux-boot-if.h" ++#include "hw/boards.h" + #include "sysemu/kvm.h" + + +@@ -363,10 +365,15 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) + for (i = 0; i < s->num_cpu; i++) { + CPUState *cpu = qemu_get_cpu(i); + ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ MachineClass *mc = MACHINE_GET_CLASS(ms); ++ const CPUArchIdList *possible_cpus = NULL; + uint64_t cpu_affid; + int last; + +- arm_gicv3_common_cpu_realize(s, i); ++ if (cpu) { ++ arm_gicv3_common_cpu_realize(s, i); ++ } + + /* Pre-construct the GICR_TYPER: + * For our implementation: +@@ -380,7 +387,19 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) + * VLPIS == 0 (virtual LPIs not supported) + * PLPIS == 0 (physical LPIs not supported) + */ +- cpu_affid = object_property_get_uint(OBJECT(cpu), "mp-affinity", NULL); ++ if (cpu) { ++ cpu_affid = object_property_get_uint(OBJECT(cpu), "mp-affinity", NULL); ++ } else { ++ if (!mc->possible_cpu_arch_ids) { ++ error_report("MachineClass must implement possible_cpu_arch_ids " ++ "hook to support pre-sizing GICv3"); ++ exit(1); ++ } ++ ++ possible_cpus = mc->possible_cpu_arch_ids(ms); ++ cpu_affid = possible_cpus->cpus[i].arch_id; ++ } ++ + last = (i == s->num_cpu - 1); + + /* The CPU mp-affinity property is in MPIDR register format; squash +diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c +index 56aa5efede..a20aa693ea 100644 +--- a/hw/intc/arm_gicv3_cpuif.c ++++ b/hw/intc/arm_gicv3_cpuif.c +@@ -1648,6 +1648,10 @@ static void icc_generate_sgi(CPUARMState *env, GICv3CPUState *cs, + aff, targetlist); + + for (i = 0; i < s->num_cpu; i++) { ++ if (!qemu_get_cpu(i)) { ++ continue; ++ } ++ + GICv3CPUState *ocs = &s->cpu[i]; + + if (irm) { +diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c +index f8d7be5479..8eea7c9dd9 100644 +--- a/hw/intc/arm_gicv3_kvm.c ++++ b/hw/intc/arm_gicv3_kvm.c +@@ -341,6 +341,10 @@ static void kvm_arm_gicv3_put(GICv3State *s) + for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { + GICv3CPUState *c = &s->cpu[ncpu]; + ++ if (!qemu_get_cpu(ncpu)) { ++ continue; ++ } ++ + reg64 = c->gicr_propbaser; + regl = (uint32_t)reg64; + kvm_gicr_access(s, GICR_PROPBASER, ncpu, ®l, true); +@@ -366,6 +370,10 @@ static void kvm_arm_gicv3_put(GICv3State *s) + for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { + GICv3CPUState *c = &s->cpu[ncpu]; + ++ if (!qemu_get_cpu(ncpu)) { ++ continue; ++ } ++ + reg = c->gicr_ctlr; + kvm_gicr_access(s, GICR_CTLR, ncpu, ®, true); + +@@ -462,6 +470,10 @@ static void kvm_arm_gicv3_put(GICv3State *s) + GICv3CPUState *c = &s->cpu[ncpu]; + int num_pri_bits; + ++ if (!qemu_get_cpu(ncpu)) { ++ continue; ++ } ++ + kvm_gicc_access(s, ICC_SRE_EL1, ncpu, &c->icc_sre_el1, true); + kvm_gicc_access(s, ICC_CTLR_EL1, ncpu, + &c->icc_ctlr_el1[GICV3_NS], true); +@@ -525,6 +537,10 @@ static void kvm_arm_gicv3_get(GICv3State *s) + /* Redistributor state (one per CPU) */ + + for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { ++ if (!qemu_get_cpu(ncpu)) { ++ continue; ++ } ++ + GICv3CPUState *c = &s->cpu[ncpu]; + + kvm_gicr_access(s, GICR_CTLR, ncpu, ®, false); +@@ -560,6 +576,10 @@ static void kvm_arm_gicv3_get(GICv3State *s) + + if (redist_typer & GICR_TYPER_PLPIS) { + for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { ++ if (!qemu_get_cpu(ncpu)) { ++ continue; ++ } ++ + GICv3CPUState *c = &s->cpu[ncpu]; + + kvm_gicr_access(s, GICR_PROPBASER, ncpu, ®l, false); +@@ -613,6 +633,10 @@ static void kvm_arm_gicv3_get(GICv3State *s) + */ + + for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { ++ if (!qemu_get_cpu(ncpu)) { ++ continue; ++ } ++ + GICv3CPUState *c = &s->cpu[ncpu]; + int num_pri_bits; + +@@ -806,7 +830,9 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) + } + + for (i = 0; i < s->num_cpu; i++) { +- kvm_arm_gicv3_cpu_realize(s, i); ++ if (qemu_get_cpu(i)) { ++ kvm_arm_gicv3_cpu_realize(s, i); ++ } + } + + /* Try to create the device via the device control API */ +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index 6880ebe07c..beef4c8002 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -168,8 +168,9 @@ static inline int virt_gicv3_redist_region_count(VirtMachineState *vms) + vms->memmap[VIRT_GIC_REDIST].size / GICV3_REDIST_SIZE; + + assert(vms->gic_version == 3); ++ GICv3State *s = ARM_GICV3_COMMON(vms->gic); + +- return vms->smp_cpus > redist0_capacity ? 2 : 1; ++ return s->num_cpu > redist0_capacity ? 2 : 1; + } + + #endif /* QEMU_ARM_VIRT_H */ +-- +2.19.1 diff --git a/intc-gicv3_common-Factor-out-arm_gicv3_common_cpu_re.patch b/intc-gicv3_common-Factor-out-arm_gicv3_common_cpu_re.patch new file mode 100644 index 0000000000000000000000000000000000000000..5232d3f2aeda4d3a8a83a725173eaff72d2af8d5 --- /dev/null +++ b/intc-gicv3_common-Factor-out-arm_gicv3_common_cpu_re.patch @@ -0,0 +1,50 @@ +From a7391f391336024986a5997e3beae8882c983ed0 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Fri, 10 Apr 2020 12:55:17 +0800 +Subject: [PATCH] intc/gicv3_common: Factor out arm_gicv3_common_cpu_realize + +The CPU object of hotplugged CPU will be defer-created (during +hotplug session), so we must factor out realization code to let +it can be applied to individual CPU. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/intc/arm_gicv3_common.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c +index 5edabb928f..798f295d7c 100644 +--- a/hw/intc/arm_gicv3_common.c ++++ b/hw/intc/arm_gicv3_common.c +@@ -303,6 +303,16 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler, + } + } + ++static void arm_gicv3_common_cpu_realize(GICv3State *s, int ncpu) ++{ ++ CPUState *cpu = qemu_get_cpu(ncpu); ++ ++ s->cpu[ncpu].cpu = cpu; ++ s->cpu[ncpu].gic = s; ++ /* Store GICv3CPUState in CPUARMState gicv3state pointer */ ++ gicv3_set_gicv3state(cpu, &s->cpu[ncpu]); ++} ++ + static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) + { + GICv3State *s = ARM_GICV3_COMMON(dev); +@@ -350,10 +360,7 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) + uint64_t cpu_affid; + int last; + +- s->cpu[i].cpu = cpu; +- s->cpu[i].gic = s; +- /* Store GICv3CPUState in CPUARMState gicv3state pointer */ +- gicv3_set_gicv3state(cpu, &s->cpu[i]); ++ arm_gicv3_common_cpu_realize(s, i); + + /* Pre-construct the GICR_TYPER: + * For our implementation: +-- +2.19.1 diff --git a/intc-gicv3_cpuif-Factor-out-gicv3_init_one_cpuif.patch b/intc-gicv3_cpuif-Factor-out-gicv3_init_one_cpuif.patch new file mode 100644 index 0000000000000000000000000000000000000000..95c60b02c66e48b2fbe6d64c5e139aa3ecdcfae9 --- /dev/null +++ b/intc-gicv3_cpuif-Factor-out-gicv3_init_one_cpuif.patch @@ -0,0 +1,197 @@ +From de97ff4a01008ad98f7d69adc4b84843fff3ce19 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Fri, 10 Apr 2020 10:59:55 +0800 +Subject: [PATCH] intc/gicv3_cpuif: Factor out gicv3_init_one_cpuif + +The CPU object of hotplugged CPU will be defer-created (during +hotplug session), so we must factor out some code to let it can +be applied to individual CPU. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/intc/arm_gicv3.c | 5 +- + hw/intc/arm_gicv3_cpuif.c | 122 ++++++++++++++++++-------------------- + hw/intc/gicv3_internal.h | 2 +- + 3 files changed, 64 insertions(+), 65 deletions(-) + +diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c +index 66eaa97198..2fe79f794d 100644 +--- a/hw/intc/arm_gicv3.c ++++ b/hw/intc/arm_gicv3.c +@@ -367,6 +367,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) + GICv3State *s = ARM_GICV3(dev); + ARMGICv3Class *agc = ARM_GICV3_GET_CLASS(s); + Error *local_err = NULL; ++ int i; + + agc->parent_realize(dev, &local_err); + if (local_err) { +@@ -386,7 +387,9 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) + return; + } + +- gicv3_init_cpuif(s); ++ for (i = 0; i < s->num_cpu; i++) { ++ gicv3_init_one_cpuif(s, i); ++ } + } + + static void arm_gicv3_class_init(ObjectClass *klass, void *data) +diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c +index 3b212d91c8..56aa5efede 100644 +--- a/hw/intc/arm_gicv3_cpuif.c ++++ b/hw/intc/arm_gicv3_cpuif.c +@@ -2597,78 +2597,74 @@ static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque) + gicv3_cpuif_update(cs); + } + +-void gicv3_init_cpuif(GICv3State *s) ++void gicv3_init_one_cpuif(GICv3State *s, int ncpu) + { + /* Called from the GICv3 realize function; register our system + * registers with the CPU + */ +- int i; +- +- for (i = 0; i < s->num_cpu; i++) { +- ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i)); +- GICv3CPUState *cs = &s->cpu[i]; +- +- /* Note that we can't just use the GICv3CPUState as an opaque pointer +- * in define_arm_cp_regs_with_opaque(), because when we're called back +- * it might be with code translated by CPU 0 but run by CPU 1, in +- * which case we'd get the wrong value. +- * So instead we define the regs with no ri->opaque info, and +- * get back to the GICv3CPUState from the CPUARMState. +- */ +- define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); +- if (arm_feature(&cpu->env, ARM_FEATURE_EL2) +- && cpu->gic_num_lrs) { +- int j; ++ ARMCPU *cpu = ARM_CPU(qemu_get_cpu(ncpu)); ++ GICv3CPUState *cs = &s->cpu[ncpu]; ++ ++ /* Note that we can't just use the GICv3CPUState as an opaque pointer ++ * in define_arm_cp_regs_with_opaque(), because when we're called back ++ * it might be with code translated by CPU 0 but run by CPU 1, in ++ * which case we'd get the wrong value. ++ * So instead we define the regs with no ri->opaque info, and ++ * get back to the GICv3CPUState from the CPUARMState. ++ */ ++ define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); ++ if (arm_feature(&cpu->env, ARM_FEATURE_EL2) ++ && cpu->gic_num_lrs) { ++ int j; + +- cs->maintenance_irq = cpu->gicv3_maintenance_interrupt; ++ cs->maintenance_irq = cpu->gicv3_maintenance_interrupt; + +- cs->num_list_regs = cpu->gic_num_lrs; +- cs->vpribits = cpu->gic_vpribits; +- cs->vprebits = cpu->gic_vprebits; ++ cs->num_list_regs = cpu->gic_num_lrs; ++ cs->vpribits = cpu->gic_vpribits; ++ cs->vprebits = cpu->gic_vprebits; + +- /* Check against architectural constraints: getting these +- * wrong would be a bug in the CPU code defining these, +- * and the implementation relies on them holding. +- */ +- g_assert(cs->vprebits <= cs->vpribits); +- g_assert(cs->vprebits >= 5 && cs->vprebits <= 7); +- g_assert(cs->vpribits >= 5 && cs->vpribits <= 8); ++ /* Check against architectural constraints: getting these ++ * wrong would be a bug in the CPU code defining these, ++ * and the implementation relies on them holding. ++ */ ++ g_assert(cs->vprebits <= cs->vpribits); ++ g_assert(cs->vprebits >= 5 && cs->vprebits <= 7); ++ g_assert(cs->vpribits >= 5 && cs->vpribits <= 8); + +- define_arm_cp_regs(cpu, gicv3_cpuif_hcr_reginfo); ++ define_arm_cp_regs(cpu, gicv3_cpuif_hcr_reginfo); + +- for (j = 0; j < cs->num_list_regs; j++) { +- /* Note that the AArch64 LRs are 64-bit; the AArch32 LRs +- * are split into two cp15 regs, LR (the low part, with the +- * same encoding as the AArch64 LR) and LRC (the high part). +- */ +- ARMCPRegInfo lr_regset[] = { +- { .name = "ICH_LRn_EL2", .state = ARM_CP_STATE_BOTH, +- .opc0 = 3, .opc1 = 4, .crn = 12, +- .crm = 12 + (j >> 3), .opc2 = j & 7, +- .type = ARM_CP_IO | ARM_CP_NO_RAW, +- .access = PL2_RW, +- .readfn = ich_lr_read, +- .writefn = ich_lr_write, +- }, +- { .name = "ICH_LRCn_EL2", .state = ARM_CP_STATE_AA32, +- .cp = 15, .opc1 = 4, .crn = 12, +- .crm = 14 + (j >> 3), .opc2 = j & 7, +- .type = ARM_CP_IO | ARM_CP_NO_RAW, +- .access = PL2_RW, +- .readfn = ich_lr_read, +- .writefn = ich_lr_write, +- }, +- REGINFO_SENTINEL +- }; +- define_arm_cp_regs(cpu, lr_regset); +- } +- if (cs->vprebits >= 6) { +- define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr1_reginfo); +- } +- if (cs->vprebits == 7) { +- define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr23_reginfo); +- } ++ for (j = 0; j < cs->num_list_regs; j++) { ++ /* Note that the AArch64 LRs are 64-bit; the AArch32 LRs ++ * are split into two cp15 regs, LR (the low part, with the ++ * same encoding as the AArch64 LR) and LRC (the high part). ++ */ ++ ARMCPRegInfo lr_regset[] = { ++ { .name = "ICH_LRn_EL2", .state = ARM_CP_STATE_BOTH, ++ .opc0 = 3, .opc1 = 4, .crn = 12, ++ .crm = 12 + (j >> 3), .opc2 = j & 7, ++ .type = ARM_CP_IO | ARM_CP_NO_RAW, ++ .access = PL2_RW, ++ .readfn = ich_lr_read, ++ .writefn = ich_lr_write, ++ }, ++ { .name = "ICH_LRCn_EL2", .state = ARM_CP_STATE_AA32, ++ .cp = 15, .opc1 = 4, .crn = 12, ++ .crm = 14 + (j >> 3), .opc2 = j & 7, ++ .type = ARM_CP_IO | ARM_CP_NO_RAW, ++ .access = PL2_RW, ++ .readfn = ich_lr_read, ++ .writefn = ich_lr_write, ++ }, ++ REGINFO_SENTINEL ++ }; ++ define_arm_cp_regs(cpu, lr_regset); ++ } ++ if (cs->vprebits >= 6) { ++ define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr1_reginfo); ++ } ++ if (cs->vprebits == 7) { ++ define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr23_reginfo); + } +- arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs); + } ++ arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs); + } +diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h +index 05303a55c8..cfbfe8a549 100644 +--- a/hw/intc/gicv3_internal.h ++++ b/hw/intc/gicv3_internal.h +@@ -297,7 +297,7 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data, + void gicv3_dist_set_irq(GICv3State *s, int irq, int level); + void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level); + void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns); +-void gicv3_init_cpuif(GICv3State *s); ++void gicv3_init_one_cpuif(GICv3State *s, int ncpu); + + /** + * gicv3_cpuif_update: +-- +2.19.1 diff --git a/intc-kvm_gicv3-Factor-out-kvm_arm_gicv3_cpu_realize.patch b/intc-kvm_gicv3-Factor-out-kvm_arm_gicv3_cpu_realize.patch new file mode 100644 index 0000000000000000000000000000000000000000..6af9a8f4f55fa4ce936c9d5898cd5c232abcaa9a --- /dev/null +++ b/intc-kvm_gicv3-Factor-out-kvm_arm_gicv3_cpu_realize.patch @@ -0,0 +1,45 @@ +From f45964c7e0df4ef17457a9ea92bfd255064139e1 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Fri, 10 Apr 2020 12:49:12 +0800 +Subject: [PATCH] intc/kvm_gicv3: Factor out kvm_arm_gicv3_cpu_realize + +The CPU object of hotplugged CPU will be defer-created (during +hotplug session), so we must factor out realization code to let +it can be applied to individual CPU. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/intc/arm_gicv3_kvm.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c +index b1e74147ba..b2936938cb 100644 +--- a/hw/intc/arm_gicv3_kvm.c ++++ b/hw/intc/arm_gicv3_kvm.c +@@ -761,6 +761,12 @@ static void vm_change_state_handler(void *opaque, int running, + } + } + ++static void kvm_arm_gicv3_cpu_realize(GICv3State *s, int ncpu) ++{ ++ ARMCPU *cpu = ARM_CPU(qemu_get_cpu(ncpu)); ++ ++ define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); ++} + + static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) + { +@@ -791,9 +797,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) + } + + for (i = 0; i < s->num_cpu; i++) { +- ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i)); +- +- define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); ++ kvm_arm_gicv3_cpu_realize(s, i); + } + + /* Try to create the device via the device control API */ +-- +2.19.1 diff --git a/ip_reass-Fix-use-after-free.patch b/ip_reass-Fix-use-after-free.patch new file mode 100644 index 0000000000000000000000000000000000000000..b26e8afb629d7d768608fdc471a9cf754be36f7e --- /dev/null +++ b/ip_reass-Fix-use-after-free.patch @@ -0,0 +1,40 @@ +From 63b07dfe20a0d4971b0929d27359f478ba2d816b Mon Sep 17 00:00:00 2001 +From: Samuel Thibault +Date: Fri, 22 May 2020 10:52:55 +0800 +Subject: [PATCH] ip_reass: Fix use after free + +Using ip_deq after m_free might read pointers from an allocation reuse. + +This would be difficult to exploit, but that is still related with +CVE-2019-14378 which generates fragmented IP packets that would trigger this +issue and at least produce a DoS. +Signed-off-by: Samuel Thibault's avatarSamuel Thibault + +diff --git a/slirp/src/ip_input.c b/slirp/src/ip_input.c +index 8c75d91..c07d7d4 100644 +--- a/slirp/src/ip_input.c ++++ b/slirp/src/ip_input.c +@@ -292,6 +292,7 @@ static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp) + */ + while (q != (struct ipasfrag *)&fp->frag_link && + ip->ip_off + ip->ip_len > q->ipf_off) { ++ struct ipasfrag *prev; + i = (ip->ip_off + ip->ip_len) - q->ipf_off; + if (i < q->ipf_len) { + q->ipf_len -= i; +@@ -299,9 +300,10 @@ static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp) + m_adj(dtom(slirp, q), i); + break; + } ++ prev = q; + q = q->ipf_next; +- m_free(dtom(slirp, q->ipf_prev)); +- ip_deq(q->ipf_prev); ++ ip_deq(prev); ++ m_free(dtom(slirp, prev)); + } + + insert: +-- +1.8.3.1 + diff --git a/libvhost-user-fix-SLAVE_SEND_FD-handling.patch b/libvhost-user-fix-SLAVE_SEND_FD-handling.patch new file mode 100644 index 0000000000000000000000000000000000000000..71cbf7baa7b59006c74a8eadb9b74b10079a9a9d --- /dev/null +++ b/libvhost-user-fix-SLAVE_SEND_FD-handling.patch @@ -0,0 +1,42 @@ +From 28a9a3558a427493049723fff390add7026653eb Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Tue, 3 Sep 2019 23:04:22 +0300 +Subject: [PATCH] libvhost-user: fix SLAVE_SEND_FD handling + +It doesn't look like this could possibly work properly since +VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD is defined to 10, but the +dev->protocol_features has a bitmap. I suppose the peer this +was tested with also supported VHOST_USER_PROTOCOL_F_LOG_SHMFD, +in which case the test would always be false, but nevertheless +the code seems wrong. + +Use has_feature() to fix this. + +Fixes: d84599f56c82 ("libvhost-user: support host notifier") +Signed-off-by: Johannes Berg +Message-Id: <20190903200422.11693-1-johannes@sipsolutions.net> +Reviewed-by: Tiwei Bie +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 8726b70b449896f1211f869ec4f608904f027207) +Signed-off-by: Michael Roth +--- + contrib/libvhost-user/libvhost-user.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c +index 4b36e35a82..cb5f5770e4 100644 +--- a/contrib/libvhost-user/libvhost-user.c ++++ b/contrib/libvhost-user/libvhost-user.c +@@ -1097,7 +1097,8 @@ bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq *vq, int fd, + + vmsg.fd_num = fd_num; + +- if ((dev->protocol_features & VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD) == 0) { ++ if (!has_feature(dev->protocol_features, ++ VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD)) { + return false; + } + +-- +2.23.0 diff --git a/linux-headers-update-against-KVM-ARM-Fix-256-vcpus.patch b/linux-headers-update-against-KVM-ARM-Fix-256-vcpus.patch index 3d4e4ad5bb7e833e97c2d51f9ab2cf5ae555e823..731d06a74024c81bcc1ececeb79da2b873c2546f 100644 --- a/linux-headers-update-against-KVM-ARM-Fix-256-vcpus.patch +++ b/linux-headers-update-against-KVM-ARM-Fix-256-vcpus.patch @@ -1,7 +1,7 @@ -From 896b9892d4df316b85836daa973e442c0c64cec6 Mon Sep 17 00:00:00 2001 +From 27a9f40b308efd8ddcb81e286441865b5a0cb541 Mon Sep 17 00:00:00 2001 From: Zenghui Yu -Date: Fri, 3 Jan 2020 17:16:55 +0800 -Subject: [PATCH 1/3] linux headers: update against "KVM/ARM: Fix >256 vcpus" +Date: Tue, 14 Apr 2020 21:52:42 +0800 +Subject: [PATCH] linux headers: update against "KVM/ARM: Fix >256 vcpus" This is part of upstream commit f363d039e883 ("linux headers: update against v5.4-rc1"), authored by Eric Auger . @@ -19,7 +19,7 @@ index e1f8b745..137a2730 100644 +++ b/linux-headers/asm-arm/kvm.h @@ -254,8 +254,10 @@ struct kvm_vcpu_events { #define KVM_DEV_ARM_ITS_CTRL_RESET 4 - + /* KVM_IRQ_LINE irq field index values */ +#define KVM_ARM_IRQ_VCPU2_SHIFT 28 +#define KVM_ARM_IRQ_VCPU2_MASK 0xf @@ -30,12 +30,12 @@ index e1f8b745..137a2730 100644 #define KVM_ARM_IRQ_VCPU_MASK 0xff #define KVM_ARM_IRQ_NUM_SHIFT 0 diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h -index e6a98c14..dfd3a028 100644 +index 2431ec35..cdfd5f33 100644 --- a/linux-headers/asm-arm64/kvm.h +++ b/linux-headers/asm-arm64/kvm.h -@@ -265,8 +265,10 @@ struct kvm_vcpu_events { +@@ -308,8 +308,10 @@ struct kvm_vcpu_events { #define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1 - + /* KVM_IRQ_LINE irq field index values */ +#define KVM_ARM_IRQ_VCPU2_SHIFT 28 +#define KVM_ARM_IRQ_VCPU2_MASK 0xf @@ -46,17 +46,16 @@ index e6a98c14..dfd3a028 100644 #define KVM_ARM_IRQ_VCPU_MASK 0xff #define KVM_ARM_IRQ_NUM_SHIFT 0 diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index b53ee597..086cea4d 100644 +index c8423e76..744e888e 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -988,6 +988,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_ARM_VM_IPA_SIZE 165 - #define KVM_CAP_MANUAL_DIRTY_LOG_PROTECT 166 + #define KVM_CAP_MANUAL_DIRTY_LOG_PROTECT 166 /* Obsolete */ #define KVM_CAP_HYPERV_CPUID 167 +#define KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 174 - - #ifdef KVM_CAP_IRQ_ROUTING - --- -2.19.1 - + #define KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 168 + #define KVM_CAP_PPC_IRQ_XIVE 169 + #define KVM_CAP_ARM_SVE 170 +-- +2.23.0 diff --git a/log-Add-some-logs-on-VM-runtime-path.patch b/log-Add-some-logs-on-VM-runtime-path.patch new file mode 100644 index 0000000000000000000000000000000000000000..80eb8c39b4bcc4884c5a8fbfa43f28b808efb912 --- /dev/null +++ b/log-Add-some-logs-on-VM-runtime-path.patch @@ -0,0 +1,181 @@ +From 0c83403e6e3ab21a01941be4ec57b02388eeb9c4 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Fri, 22 May 2020 18:56:09 +0800 +Subject: [PATCH] log: Add some logs on VM runtime path + +Add logs on VM runtime path, to make it easier to do trouble shooting. + +Signed-off-by: Ying Fang + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index f6d2223..b4b0ed2 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -32,6 +32,7 @@ + #include "qemu/range.h" + #include "hw/virtio/virtio-bus.h" + #include "qapi/visitor.h" ++#include "qemu/log.h" + + #define VIRTIO_PCI_REGION_SIZE(dev) VIRTIO_PCI_CONFIG_OFF(msix_present(dev)) + +@@ -1659,7 +1660,9 @@ static void virtio_pci_device_unplugged(DeviceState *d) + VirtIOPCIProxy *proxy = VIRTIO_PCI(d); + bool modern = virtio_pci_modern(proxy); + bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY; ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + ++ qemu_log("unplug device name: %s\n", !vdev ? "NULL" : vdev->name); + virtio_pci_stop_ioeventfd(proxy); + + if (modern) { +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 7c3822c..79c2dcf 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -1172,7 +1172,14 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val) + k->set_status(vdev, val); + } + vdev->status = val; +- ++ if (val) { ++ qemu_log("%s device status is %d that means %s\n", ++ vdev->name, val, ++ (val & VIRTIO_CONFIG_S_DRIVER_OK) ? "DRIVER OK" : ++ (val & VIRTIO_CONFIG_S_DRIVER) ? "DRIVER" : ++ (val & VIRTIO_CONFIG_S_ACKNOWLEDGE) ? "ACKNOWLEDGE" : ++ (val & VIRTIO_CONFIG_S_FAILED) ? "FAILED" : "UNKNOWN"); ++ } + return 0; + } + +@@ -1614,8 +1621,11 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, + break; + } + +- if (i == VIRTIO_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE) ++ if (i == VIRTIO_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE) { ++ qemu_log("unacceptable queue_size (%d) or num (%d)\n", ++ queue_size, i); + abort(); ++ } + + vdev->vq[i].vring.num = queue_size; + vdev->vq[i].vring.num_default = queue_size; +diff --git a/monitor/monitor.c b/monitor/monitor.c +index 3ef2817..6f726e8 100644 +--- a/monitor/monitor.c ++++ b/monitor/monitor.c +@@ -28,6 +28,7 @@ + #include "qapi/qapi-emit-events.h" + #include "qapi/qmp/qdict.h" + #include "qapi/qmp/qstring.h" ++#include "qapi/qmp/qjson.h" + #include "qemu/error-report.h" + #include "qemu/option.h" + #include "sysemu/qtest.h" +@@ -254,6 +255,7 @@ static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict) + { + Monitor *mon; + MonitorQMP *qmp_mon; ++ QString *json; + + trace_monitor_protocol_event_emit(event, qdict); + QTAILQ_FOREACH(mon, &mon_list, entry) { +@@ -264,6 +266,13 @@ static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict) + qmp_mon = container_of(mon, MonitorQMP, common); + if (qmp_mon->commands != &qmp_cap_negotiation_commands) { + qmp_send_response(qmp_mon, qdict); ++ json = qobject_to_json(QOBJECT(qdict)); ++ if (json) { ++ if (!strstr(json->string, "RTC_CHANGE")) { ++ qemu_log("%s\n", qstring_get_str(json)); ++ } ++ qobject_unref(json); ++ } + } + } + } +diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c +index e2c366e..6dfdad5 100644 +--- a/qapi/qmp-dispatch.c ++++ b/qapi/qmp-dispatch.c +@@ -17,7 +17,9 @@ + #include "qapi/qmp/qdict.h" + #include "qapi/qmp/qjson.h" + #include "qapi/qmp/qbool.h" ++#include "qapi/qmp/qstring.h" + #include "sysemu/sysemu.h" ++#include "qemu/log.h" + + static QDict *qmp_dispatch_check_obj(const QObject *request, bool allow_oob, + Error **errp) +@@ -83,6 +85,7 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request, + const char *command; + QDict *args, *dict; + QmpCommand *cmd; ++ QString *json; + QObject *ret = NULL; + + dict = qmp_dispatch_check_obj(request, allow_oob, errp); +@@ -128,6 +131,19 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request, + qobject_ref(args); + } + ++ json = qobject_to_json(QOBJECT(args)); ++ if (json) { ++ if ((strcmp(command, "query-block-jobs") != 0) ++ && (strcmp(command, "query-migrate") != 0) ++ && (strcmp(command, "query-blockstats") != 0) ++ && (strcmp(command, "query-balloon") != 0) ++ && (strcmp(command, "set_password") != 0)) { ++ qemu_log("qmp_cmd_name: %s, arguments: %s\n", ++ command, qstring_get_str(json)); ++ } ++ qobject_unref(json); ++ } ++ + cmd->fn(args, &ret, &local_err); + if (local_err) { + error_propagate(errp, local_err); +diff --git a/qdev-monitor.c b/qdev-monitor.c +index 58222c2..c6c1d3f 100644 +--- a/qdev-monitor.c ++++ b/qdev-monitor.c +@@ -34,6 +34,7 @@ + #include "qemu/qemu-print.h" + #include "sysemu/block-backend.h" + #include "migration/misc.h" ++#include "qemu/log.h" + + /* + * Aliases were a bad idea from the start. Let's keep them +@@ -586,6 +587,7 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) + if (path != NULL) { + bus = qbus_find(path, errp); + if (!bus) { ++ error_setg(errp, "can not find bus for %s", driver); + return NULL; + } + if (!object_dynamic_cast(OBJECT(bus), dc->bus_type)) { +@@ -627,6 +629,8 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) + + /* set properties */ + if (qemu_opt_foreach(opts, set_property, dev, &err)) { ++ error_setg(errp, "the bus %s -driver %s set property failed", ++ bus ? bus->name : "None", driver); + goto err_del_dev; + } + +@@ -636,6 +640,8 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) + dev->opts = NULL; + goto err_del_dev; + } ++ qemu_log("add qdev %s:%s success\n", driver, ++ qemu_opts_id(opts) ? qemu_opts_id(opts) : "none"); + return dev; + + err_del_dev: +-- +1.8.3.1 + diff --git a/make-release-pull-in-edk2-submodules-so-we-can-build.patch b/make-release-pull-in-edk2-submodules-so-we-can-build.patch new file mode 100644 index 0000000000000000000000000000000000000000..70bcc864d0fd976919e540165bc7167e5026c46e --- /dev/null +++ b/make-release-pull-in-edk2-submodules-so-we-can-build.patch @@ -0,0 +1,60 @@ +From c5c9b1362d1652a9d0f79f6d9ae2f80d4b5fe432 Mon Sep 17 00:00:00 2001 +From: Michael Roth +Date: Thu, 12 Sep 2019 18:12:01 -0500 +Subject: [PATCH] make-release: pull in edk2 submodules so we can build it from + tarballs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The `make efi` target added by 536d2173 is built from the roms/edk2 +submodule, which in turn relies on additional submodules nested under +roms/edk2. + +The make-release script currently only pulls in top-level submodules, +so these nested submodules are missing in the resulting tarball. + +We could try to address this situation more generally by recursively +pulling in all submodules, but this doesn't necessarily ensure the +end-result will build properly (this case also required other changes). + +Additionally, due to the nature of submodules, we may not always have +control over how these sorts of things are dealt with, so for now we +continue to handle it on a case-by-case in the make-release script. + +Cc: Laszlo Ersek +Cc: Bruce Rogers +Cc: qemu-stable@nongnu.org # v4.1.0 +Reported-by: Bruce Rogers +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Philippe Mathieu-Daudé +Signed-off-by: Michael Roth +Message-Id: <20190912231202.12327-2-mdroth@linux.vnet.ibm.com> +Signed-off-by: Philippe Mathieu-Daudé +(cherry picked from commit 45c61c6c23918e3b05ed9ecac5b2328ebae5f774) +Signed-off-by: Michael Roth +--- + scripts/make-release | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/scripts/make-release b/scripts/make-release +index b4af9c9e52..a2a8cda33c 100755 +--- a/scripts/make-release ++++ b/scripts/make-release +@@ -20,6 +20,14 @@ git checkout "v${version}" + git submodule update --init + (cd roms/seabios && git describe --tags --long --dirty > .version) + (cd roms/skiboot && ./make_version.sh > .version) ++# Fetch edk2 submodule's submodules, since it won't have access to them via ++# the tarball later. ++# ++# A more uniform way to handle this sort of situation would be nice, but we ++# don't necessarily have much control over how a submodule handles its ++# submodule dependencies, so we continue to handle these on a case-by-case ++# basis for now. ++(cd roms/edk2 && git submodule update --init) + popd + tar --exclude=.git -cjf ${destination}.tar.bz2 ${destination} + rm -rf ${destination} +-- +2.23.0 diff --git a/megasas-avoid-NULL-pointer-dereference.patch b/megasas-avoid-NULL-pointer-dereference.patch new file mode 100644 index 0000000000000000000000000000000000000000..c7bc95901d82110b49e65ccab6cd9a84dc562aa0 --- /dev/null +++ b/megasas-avoid-NULL-pointer-dereference.patch @@ -0,0 +1,36 @@ +From cf7f42b21aaa7694c6232a9a5027de9df341f299 Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit +Date: Thu, 14 May 2020 00:55:39 +0530 +Subject: [PATCH 5/9] megasas: avoid NULL pointer dereference + +While in megasas_handle_frame(), megasas_enqueue_frame() may +set a NULL frame into MegasasCmd object for a given 'frame_addr' +address. Add check to avoid a NULL pointer dereference issue. + +Reported-by: Alexander Bulekov +Fixes: https://bugs.launchpad.net/qemu/+bug/1878259 +Signed-off-by: Prasad J Pandit +Acked-by: Alexander Bulekov +Reviewed-by: Darren Kenny +Message-Id: <20200513192540.1583887-3-ppandit@redhat.com> +Signed-off-by: Paolo Bonzini +--- + hw/scsi/megasas.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c +index 7ee331d9da..5923ffbd22 100644 +--- a/hw/scsi/megasas.c ++++ b/hw/scsi/megasas.c +@@ -503,7 +503,7 @@ static MegasasCmd *megasas_enqueue_frame(MegasasState *s, + cmd->pa = frame; + /* Map all possible frames */ + cmd->frame = pci_dma_map(pcid, frame, &frame_size_p, 0); +- if (frame_size_p != frame_size) { ++ if (!cmd->frame || frame_size_p != frame_size) { + trace_megasas_qf_map_failed(cmd->index, (unsigned long)frame); + if (cmd->frame) { + megasas_unmap_frame(s, cmd); +-- +2.25.1 + diff --git a/megasas-use-unsigned-type-for-positive-numeric-field.patch b/megasas-use-unsigned-type-for-positive-numeric-field.patch new file mode 100644 index 0000000000000000000000000000000000000000..7e194395193623e061917b0a5e6315d6b8564a61 --- /dev/null +++ b/megasas-use-unsigned-type-for-positive-numeric-field.patch @@ -0,0 +1,97 @@ +From 7bad515189482d289d3efe4133c8af9f184662e4 Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit +Date: Thu, 14 May 2020 00:55:40 +0530 +Subject: [PATCH 6/9] megasas: use unsigned type for positive numeric fields + +Use unsigned type for the MegasasState fields which hold positive +numeric values. + +Signed-off-by: Prasad J Pandit +Reviewed-by: Darren Kenny +Message-Id: <20200513192540.1583887-4-ppandit@redhat.com> +Signed-off-by: Paolo Bonzini +--- + hw/scsi/megasas.c | 38 +++++++++++++++++++------------------- + 1 file changed, 19 insertions(+), 19 deletions(-) + +diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c +index 5923ffbd22..94469e8169 100644 +--- a/hw/scsi/megasas.c ++++ b/hw/scsi/megasas.c +@@ -85,34 +85,34 @@ typedef struct MegasasState { + MemoryRegion queue_io; + uint32_t frame_hi; + +- int fw_state; ++ uint32_t fw_state; + uint32_t fw_sge; + uint32_t fw_cmds; + uint32_t flags; +- int fw_luns; +- int intr_mask; +- int doorbell; +- int busy; +- int diag; +- int adp_reset; ++ uint32_t fw_luns; ++ uint32_t intr_mask; ++ uint32_t doorbell; ++ uint32_t busy; ++ uint32_t diag; ++ uint32_t adp_reset; + OnOffAuto msi; + OnOffAuto msix; + + MegasasCmd *event_cmd; +- int event_locale; ++ uint16_t event_locale; + int event_class; +- int event_count; +- int shutdown_event; +- int boot_event; ++ uint32_t event_count; ++ uint32_t shutdown_event; ++ uint32_t boot_event; + + uint64_t sas_addr; + char *hba_serial; + + uint64_t reply_queue_pa; + void *reply_queue; +- int reply_queue_len; ++ uint16_t reply_queue_len; + uint16_t reply_queue_head; +- int reply_queue_tail; ++ uint16_t reply_queue_tail; + uint64_t consumer_pa; + uint64_t producer_pa; + +@@ -2258,9 +2258,9 @@ static const VMStateDescription vmstate_megasas_gen1 = { + VMSTATE_PCI_DEVICE(parent_obj, MegasasState), + VMSTATE_MSIX(parent_obj, MegasasState), + +- VMSTATE_INT32(fw_state, MegasasState), +- VMSTATE_INT32(intr_mask, MegasasState), +- VMSTATE_INT32(doorbell, MegasasState), ++ VMSTATE_UINT32(fw_state, MegasasState), ++ VMSTATE_UINT32(intr_mask, MegasasState), ++ VMSTATE_UINT32(doorbell, MegasasState), + VMSTATE_UINT64(reply_queue_pa, MegasasState), + VMSTATE_UINT64(consumer_pa, MegasasState), + VMSTATE_UINT64(producer_pa, MegasasState), +@@ -2277,9 +2277,9 @@ static const VMStateDescription vmstate_megasas_gen2 = { + VMSTATE_PCI_DEVICE(parent_obj, MegasasState), + VMSTATE_MSIX(parent_obj, MegasasState), + +- VMSTATE_INT32(fw_state, MegasasState), +- VMSTATE_INT32(intr_mask, MegasasState), +- VMSTATE_INT32(doorbell, MegasasState), ++ VMSTATE_UINT32(fw_state, MegasasState), ++ VMSTATE_UINT32(intr_mask, MegasasState), ++ VMSTATE_UINT32(doorbell, MegasasState), + VMSTATE_UINT64(reply_queue_pa, MegasasState), + VMSTATE_UINT64(consumer_pa, MegasasState), + VMSTATE_UINT64(producer_pa, MegasasState), +-- +2.25.1 + diff --git a/megasas-use-unsigned-type-for-reply_queue_head-and-c.patch b/megasas-use-unsigned-type-for-reply_queue_head-and-c.patch new file mode 100644 index 0000000000000000000000000000000000000000..507aeafb6911562d542f06f91c75a3dd90f43478 --- /dev/null +++ b/megasas-use-unsigned-type-for-reply_queue_head-and-c.patch @@ -0,0 +1,51 @@ +From e081fb1058e357d4d7adc30201013a46123fe2ae Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit +Date: Thu, 14 May 2020 00:55:38 +0530 +Subject: [PATCH 4/9] megasas: use unsigned type for reply_queue_head and check + index + +A guest user may set 'reply_queue_head' field of MegasasState to +a negative value. Later in 'megasas_lookup_frame' it is used to +index into s->frames[] array. Use unsigned type to avoid OOB +access issue. + +Also check that 'index' value stays within s->frames[] bounds +through the while() loop in 'megasas_lookup_frame' to avoid OOB +access. + +Reported-by: Ren Ding +Reported-by: Hanqing Zhao +Reported-by: Alexander Bulekov +Signed-off-by: Prasad J Pandit +Acked-by: Alexander Bulekov +Message-Id: <20200513192540.1583887-2-ppandit@redhat.com> +Signed-off-by: Paolo Bonzini +--- + hw/scsi/megasas.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c +index 0c4399930a..7ee331d9da 100644 +--- a/hw/scsi/megasas.c ++++ b/hw/scsi/megasas.c +@@ -111,7 +111,7 @@ typedef struct MegasasState { + uint64_t reply_queue_pa; + void *reply_queue; + int reply_queue_len; +- int reply_queue_head; ++ uint16_t reply_queue_head; + int reply_queue_tail; + uint64_t consumer_pa; + uint64_t producer_pa; +@@ -444,7 +444,7 @@ static MegasasCmd *megasas_lookup_frame(MegasasState *s, + + index = s->reply_queue_head; + +- while (num < s->fw_cmds) { ++ while (num < s->fw_cmds && index < MEGASAS_MAX_FRAMES) { + if (s->frames[index].pa && s->frames[index].pa == frame) { + cmd = &s->frames[index]; + break; +-- +2.25.1 + diff --git a/memory-unref-the-memory-region-in-simplify-flatview.patch b/memory-unref-the-memory-region-in-simplify-flatview.patch deleted file mode 100644 index eb199646181ccf95dcfef2208a6b5592ff20b6d8..0000000000000000000000000000000000000000 --- a/memory-unref-the-memory-region-in-simplify-flatview.patch +++ /dev/null @@ -1,85 +0,0 @@ -From b9f43f0cca03586a31b53e47ade72e77db01cb4c Mon Sep 17 00:00:00 2001 -From: King Wang -Date: Fri, 12 Jul 2019 14:52:41 +0800 -Subject: [PATCH 2/5] memory: unref the memory region in simplify flatview - -The memory region reference is increased when insert a range -into flatview range array, then decreased by destroy flatview. -If some flat range merged by flatview_simplify, the memory region -reference can not be decreased by destroy flatview any more. - -In this case, start virtual machine by the command line: -qemu-system-x86_64 --name guest=ubuntu,debug-threads=on --machine pc,accel=kvm,usb=off,dump-guest-core=off --cpu host --m 16384 --realtime mlock=off --smp 8,sockets=2,cores=4,threads=1 --object memory-backend-file,id=ram-node0,prealloc=yes,mem-path=/dev/hugepages,share=yes,size=8589934592 --numa node,nodeid=0,cpus=0-3,memdev=ram-node0 --object memory-backend-file,id=ram-node1,prealloc=yes,mem-path=/dev/hugepages,share=yes,size=8589934592 --numa node,nodeid=1,cpus=4-7,memdev=ram-node1 --no-user-config --nodefaults --rtc base=utc --no-shutdown --boot strict=on --device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 --device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x2 --device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x3 --drive file=ubuntu.qcow2,format=qcow2,if=none,id=drive-virtio-disk0,cache=none,aio=native --device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 --chardev pty,id=charserial0 --device isa-serial,chardev=charserial0,id=serial0 --device usb-tablet,id=input0,bus=usb.0,port=1 --vnc 0.0.0.0:0 --device VGA,id=video0,vgamem_mb=16,bus=pci.0,addr=0x5 --device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x6 --msg timestamp=on - -And run the script in guest OS: -while true -do - setpci -s 00:06.0 04.b=03 - setpci -s 00:06.0 04.b=07 -done - -I found the reference of node0 HostMemoryBackendFile is a big one. -(gdb) p numa_info[0]->node_memdev->parent.ref -$6 = 1636278 -(gdb) - -Signed-off-by: King Wang -Message-Id: <20190712065241.11784-1-king.wang@huawei.com> -Signed-off-by: Paolo Bonzini ---- - memory.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/memory.c b/memory.c -index 9fbca52..0b49281 100644 ---- a/memory.c -+++ b/memory.c -@@ -320,7 +320,7 @@ static bool can_merge(FlatRange *r1, FlatRange *r2) - /* Attempt to simplify a view by merging adjacent ranges */ - static void flatview_simplify(FlatView *view) - { -- unsigned i, j; -+ unsigned i, j, k; - - i = 0; - while (i < view->nr) { -@@ -331,6 +331,9 @@ static void flatview_simplify(FlatView *view) - ++j; - } - ++i; -+ for (k = i; k < j; k++) { -+ memory_region_unref(view->ranges[k].mr); -+ } - memmove(&view->ranges[i], &view->ranges[j], - (view->nr - j) * sizeof(view->ranges[j])); - view->nr -= j - i; --- -1.8.3.1 - diff --git a/migration-Compat-virtual-timer-adjust-for-v4.0.1-and.patch b/migration-Compat-virtual-timer-adjust-for-v4.0.1-and.patch new file mode 100644 index 0000000000000000000000000000000000000000..79548949d7f449db1c57df2b747e347d7b220db5 --- /dev/null +++ b/migration-Compat-virtual-timer-adjust-for-v4.0.1-and.patch @@ -0,0 +1,80 @@ +From 79d722679731233ccb1aa775d896a4bf21e13d44 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 27 May 2020 10:02:06 +0800 +Subject: [PATCH] migration: Compat virtual timer adjust for v4.0.1 and v4.1.0 + +Vtimer adjust is used in openEuler qemu-4.0.1, however kvm_adjvtime +is introduced in openEuler qemu-4.1.0. To maintain the compatibility +and enable cross version migration, let's enable vtimer adjust only +if kvm_adjvtime is not enabled, otherwise there may be conflicts +between vtimer adjust and kvm_adjvtime. + +After this modification: +1: openEuler qemu-4.0.1 use vtimer as the default virtual timer +2: openEuler qemu-4.1.0 use kvm_adjvtime as the defaut virtual timer + +Migration from openEuler qemu-4.0.1 to openEuler qemu-4.1.0 will +be ok, but migration path from upstream qemu-4.0.1 to openEuler +qemu-4..0.1 will be broken. + +Since openEuler qemu-4.1.0, kvm_adjvtime is used as the default +virtual timer. So please upgrade to openEuler qemu-4.1.0 and +use the virt-4.1 machine. + +Signed-off-by: Ying Fang + +diff --git a/cpus.c b/cpus.c +index b9aa51f8..6a28bdef 100644 +--- a/cpus.c ++++ b/cpus.c +@@ -1067,6 +1067,12 @@ void cpu_synchronize_all_pre_loadvm(void) + } + + #ifdef __aarch64__ ++static bool kvm_adjvtime_enabled(CPUState *cs) ++{ ++ ARMCPU *cpu = ARM_CPU(cs); ++ return cpu->kvm_adjvtime == true; ++} ++ + static void get_vcpu_timer_tick(CPUState *cs) + { + CPUARMState *env = &ARM_CPU(cs)->env; +@@ -1096,7 +1102,13 @@ static int do_vm_stop(RunState state, bool send_stop) + cpu_disable_ticks(); + pause_all_vcpus(); + #ifdef __aarch64__ +- if (first_cpu) { ++ /* vtimer adjust is used in openEuler qemu-4.0.1, however kvm_adjvtime ++ * is introduced in openEuler qemu-4.1.0. To maintain the compatibility ++ * and enable cross version migration, let's enable vtimer adjust only ++ * if kvm_adjvtime is not enabled, otherwise there may be conflicts ++ * between vtimer adjust and kvm_adjvtime. ++ */ ++ if (first_cpu && !kvm_adjvtime_enabled(first_cpu)) { + get_vcpu_timer_tick(first_cpu); + } + #endif +@@ -1946,6 +1958,7 @@ void cpu_resume(CPUState *cpu) + } + + #ifdef __aarch64__ ++ + static void set_vcpu_timer_tick(CPUState *cs) + { + CPUARMState *env = &ARM_CPU(cs)->env; +@@ -1977,7 +1990,10 @@ void resume_all_vcpus(void) + + qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true); + #ifdef __aarch64__ +- if (first_cpu) { ++ /* Enable vtimer adjust only if kvm_adjvtime is not enabled, otherwise ++ * there may be conflicts between vtimer adjust and kvm_adjvtime. ++ */ ++ if (first_cpu && !kvm_adjvtime_enabled(first_cpu)) { + set_vcpu_timer_tick(first_cpu); + } + #endif +-- +2.23.0 + diff --git a/migration-Make-global-sem_sync-semaphore-by-channel.patch b/migration-Make-global-sem_sync-semaphore-by-channel.patch new file mode 100644 index 0000000000000000000000000000000000000000..d9dbab23e4f83d88595956668c61385618864fd7 --- /dev/null +++ b/migration-Make-global-sem_sync-semaphore-by-channel.patch @@ -0,0 +1,100 @@ +From 8c3794d709eefdae777477bef7ff3511d55bf418 Mon Sep 17 00:00:00 2001 +From: Juan Quintela +Date: Wed, 14 Aug 2019 04:02:14 +0200 +Subject: [PATCH 05/10] migration: Make global sem_sync semaphore by channel + +This makes easy to debug things because when you want for all threads +to arrive at that semaphore, you know which one your are waiting for. + +Change-Id: I533af8cdc68f619b68eff8e4e573c4de371a3954 +Signed-off-by: Juan Quintela +Message-Id: <20190814020218.1868-3-quintela@redhat.com> +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Dr. David Alan Gilbert +--- + migration/ram.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/migration/ram.c b/migration/ram.c +index c75716bb..51811c2d 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -661,6 +661,8 @@ typedef struct { + uint64_t num_packets; + /* pages sent through this channel */ + uint64_t num_pages; ++ /* syncs main thread and channels */ ++ QemuSemaphore sem_sync; + } MultiFDSendParams; + + typedef struct { +@@ -896,8 +898,6 @@ struct { + MultiFDSendParams *params; + /* array of pages to sent */ + MultiFDPages_t *pages; +- /* syncs main thread and channels */ +- QemuSemaphore sem_sync; + /* global number of generated multifd packets */ + uint64_t packet_num; + /* send channels ready */ +@@ -1037,6 +1037,7 @@ void multifd_save_cleanup(void) + p->c = NULL; + qemu_mutex_destroy(&p->mutex); + qemu_sem_destroy(&p->sem); ++ qemu_sem_destroy(&p->sem_sync); + g_free(p->name); + p->name = NULL; + multifd_pages_clear(p->pages); +@@ -1046,7 +1047,6 @@ void multifd_save_cleanup(void) + p->packet = NULL; + } + qemu_sem_destroy(&multifd_send_state->channels_ready); +- qemu_sem_destroy(&multifd_send_state->sem_sync); + g_free(multifd_send_state->params); + multifd_send_state->params = NULL; + multifd_pages_clear(multifd_send_state->pages); +@@ -1096,7 +1096,7 @@ static void multifd_send_sync_main(RAMState *rs) + MultiFDSendParams *p = &multifd_send_state->params[i]; + + trace_multifd_send_sync_main_wait(p->id); +- qemu_sem_wait(&multifd_send_state->sem_sync); ++ qemu_sem_wait(&p->sem_sync); + } + trace_multifd_send_sync_main(multifd_send_state->packet_num); + } +@@ -1156,7 +1156,7 @@ static void *multifd_send_thread(void *opaque) + qemu_mutex_unlock(&p->mutex); + + if (flags & MULTIFD_FLAG_SYNC) { +- qemu_sem_post(&multifd_send_state->sem_sync); ++ qemu_sem_post(&p->sem_sync); + } + qemu_sem_post(&multifd_send_state->channels_ready); + } else if (p->quit) { +@@ -1179,7 +1179,7 @@ out: + */ + if (ret != 0) { + if (flags & MULTIFD_FLAG_SYNC) { +- qemu_sem_post(&multifd_send_state->sem_sync); ++ qemu_sem_post(&p->sem_sync); + } + qemu_sem_post(&multifd_send_state->channels_ready); + } +@@ -1225,7 +1225,6 @@ int multifd_save_setup(void) + multifd_send_state = g_malloc0(sizeof(*multifd_send_state)); + multifd_send_state->params = g_new0(MultiFDSendParams, thread_count); + multifd_send_state->pages = multifd_pages_init(page_count); +- qemu_sem_init(&multifd_send_state->sem_sync, 0); + qemu_sem_init(&multifd_send_state->channels_ready, 0); + + for (i = 0; i < thread_count; i++) { +@@ -1233,6 +1232,7 @@ int multifd_save_setup(void) + + qemu_mutex_init(&p->mutex); + qemu_sem_init(&p->sem, 0); ++ qemu_sem_init(&p->sem_sync, 0); + p->quit = false; + p->pending_job = 0; + p->id = i; +-- +2.19.1 diff --git a/migration-Maybe-VM-is-paused-when-migration-is-cance.patch b/migration-Maybe-VM-is-paused-when-migration-is-cance.patch new file mode 100644 index 0000000000000000000000000000000000000000..6c918f3c17ca619dfb88e1856d3d26625419f465 --- /dev/null +++ b/migration-Maybe-VM-is-paused-when-migration-is-cance.patch @@ -0,0 +1,57 @@ +From 5e99e1329fa52dce8ab784a960e64a3e19b429aa Mon Sep 17 00:00:00 2001 +From: Zhimin Feng +Date: Tue, 14 Jan 2020 17:43:09 +0800 +Subject: [PATCH 07/10] migration: Maybe VM is paused when migration is + cancelled + +If the migration is cancelled when it is in the completion phase, +the migration state is set to MIGRATION_STATUS_CANCELLING. +The VM maybe wait for the 'pause_sem' semaphore in migration_maybe_pause +function, so that VM always is paused. + +Change-Id: Ib2f2f42ee1edbb14da269ee19ba1fe16dd363822 +Reported-by: Euler Robot +Signed-off-by: Zhimin Feng +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +--- + migration/migration.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/migration/migration.c b/migration/migration.c +index bea9b1d7..114c33a1 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -2731,14 +2731,22 @@ static int migration_maybe_pause(MigrationState *s, + /* This block intentionally left blank */ + } + +- qemu_mutex_unlock_iothread(); +- migrate_set_state(&s->state, *current_active_state, +- MIGRATION_STATUS_PRE_SWITCHOVER); +- qemu_sem_wait(&s->pause_sem); +- migrate_set_state(&s->state, MIGRATION_STATUS_PRE_SWITCHOVER, +- new_state); +- *current_active_state = new_state; +- qemu_mutex_lock_iothread(); ++ /* ++ * If the migration is cancelled when it is in the completion phase, ++ * the migration state is set to MIGRATION_STATUS_CANCELLING. ++ * So we don't need to wait a semaphore, otherwise we would always ++ * wait for the 'pause_sem' semaphore. ++ */ ++ if (s->state != MIGRATION_STATUS_CANCELLING) { ++ qemu_mutex_unlock_iothread(); ++ migrate_set_state(&s->state, *current_active_state, ++ MIGRATION_STATUS_PRE_SWITCHOVER); ++ qemu_sem_wait(&s->pause_sem); ++ migrate_set_state(&s->state, MIGRATION_STATUS_PRE_SWITCHOVER, ++ new_state); ++ *current_active_state = new_state; ++ qemu_mutex_lock_iothread(); ++ } + + return s->state == new_state ? 0 : -EINVAL; + } +-- +2.19.1 diff --git a/migration-add-qemu_file_update_transfer-interface.patch b/migration-add-qemu_file_update_transfer-interface.patch new file mode 100644 index 0000000000000000000000000000000000000000..4222fd0adb202051cd57a3f0cab01e5ad52f8248 --- /dev/null +++ b/migration-add-qemu_file_update_transfer-interface.patch @@ -0,0 +1,50 @@ +From 7572495245a437da717e6829a9ce852cc3f229c9 Mon Sep 17 00:00:00 2001 +From: Zheng Chuan +Date: Mon, 20 Apr 2020 15:13:47 +0800 +Subject: [PATCH 02/10] migration: add qemu_file_update_transfer interface + +Add qemu_file_update_transfer for just update bytes_xfer for speed +limitation. This will be used for further migration feature such as +multifd migration. + +Change-Id: I969aa15305c961254b6fb9805b0ed2d65826cc5d +Signed-off-by: Ivan Ren +Reviewed-by: Wei Yang +Reviewed-by: Juan Quintela +Message-Id: <1564464816-21804-2-git-send-email-ivanren@tencent.com> +Signed-off-by: Dr. David Alan Gilbert +--- + migration/qemu-file.c | 5 +++++ + migration/qemu-file.h | 1 + + 2 files changed, 6 insertions(+) + +diff --git a/migration/qemu-file.c b/migration/qemu-file.c +index 04315855..18f48052 100644 +--- a/migration/qemu-file.c ++++ b/migration/qemu-file.c +@@ -615,6 +615,11 @@ void qemu_file_reset_rate_limit(QEMUFile *f) + f->bytes_xfer = 0; + } + ++void qemu_file_update_transfer(QEMUFile *f, int64_t len) ++{ ++ f->bytes_xfer += len; ++} ++ + void qemu_put_be16(QEMUFile *f, unsigned int v) + { + qemu_put_byte(f, v >> 8); +diff --git a/migration/qemu-file.h b/migration/qemu-file.h +index 13baf896..5de9fa2e 100644 +--- a/migration/qemu-file.h ++++ b/migration/qemu-file.h +@@ -147,6 +147,7 @@ int qemu_peek_byte(QEMUFile *f, int offset); + void qemu_file_skip(QEMUFile *f, int size); + void qemu_update_position(QEMUFile *f, size_t size); + void qemu_file_reset_rate_limit(QEMUFile *f); ++void qemu_file_update_transfer(QEMUFile *f, int64_t len); + void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate); + int64_t qemu_file_get_rate_limit(QEMUFile *f); + void qemu_file_set_error(QEMUFile *f, int ret); +-- +2.19.1 diff --git a/migration-add-speed-limit-for-multifd-migration.patch b/migration-add-speed-limit-for-multifd-migration.patch new file mode 100644 index 0000000000000000000000000000000000000000..690d9c9cf095cafdb2ff18025d70ee57a2527de2 --- /dev/null +++ b/migration-add-speed-limit-for-multifd-migration.patch @@ -0,0 +1,127 @@ +From bc5780480db9e38699df0b4697e60a9f36258dc4 Mon Sep 17 00:00:00 2001 +From: Ivan Ren +Date: Tue, 30 Jul 2019 13:33:35 +0800 +Subject: [PATCH 03/10] migration: add speed limit for multifd migration + +Limit the speed of multifd migration through common speed limitation +qemu file. + +Change-Id: Id2abfc7ea85679bd53130a43043cc70179a52e87 +Signed-off-by: Ivan Ren +Message-Id: <1564464816-21804-3-git-send-email-ivanren@tencent.com> +Reviewed-by: Wei Yang +Reviewed-by: Juan Quintela +Signed-off-by: Dr. David Alan Gilbert +--- + migration/ram.c | 22 ++++++++++++---------- + 1 file changed, 12 insertions(+), 10 deletions(-) + +diff --git a/migration/ram.c b/migration/ram.c +index 889148dd..88ddd2bb 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -922,7 +922,7 @@ struct { + * false. + */ + +-static int multifd_send_pages(void) ++static int multifd_send_pages(RAMState *rs) + { + int i; + static int next_channel; +@@ -954,6 +954,7 @@ static int multifd_send_pages(void) + multifd_send_state->pages = p->pages; + p->pages = pages; + transferred = ((uint64_t) pages->used) * TARGET_PAGE_SIZE + p->packet_len; ++ qemu_file_update_transfer(rs->f, transferred); + ram_counters.multifd_bytes += transferred; + ram_counters.transferred += transferred;; + qemu_mutex_unlock(&p->mutex); +@@ -962,7 +963,7 @@ static int multifd_send_pages(void) + return 1; + } + +-static int multifd_queue_page(RAMBlock *block, ram_addr_t offset) ++static int multifd_queue_page(RAMState *rs, RAMBlock *block, ram_addr_t offset) + { + MultiFDPages_t *pages = multifd_send_state->pages; + +@@ -981,12 +982,12 @@ static int multifd_queue_page(RAMBlock *block, ram_addr_t offset) + } + } + +- if (multifd_send_pages() < 0) { ++ if (multifd_send_pages(rs) < 0) { + return -1; + } + + if (pages->block != block) { +- return multifd_queue_page(block, offset); ++ return multifd_queue_page(rs, block, offset); + } + + return 1; +@@ -1054,7 +1055,7 @@ void multifd_save_cleanup(void) + multifd_send_state = NULL; + } + +-static void multifd_send_sync_main(void) ++static void multifd_send_sync_main(RAMState *rs) + { + int i; + +@@ -1062,7 +1063,7 @@ static void multifd_send_sync_main(void) + return; + } + if (multifd_send_state->pages->used) { +- if (multifd_send_pages() < 0) { ++ if (multifd_send_pages(rs) < 0) { + error_report("%s: multifd_send_pages fail", __func__); + return; + } +@@ -1083,6 +1084,7 @@ static void multifd_send_sync_main(void) + p->packet_num = multifd_send_state->packet_num++; + p->flags |= MULTIFD_FLAG_SYNC; + p->pending_job++; ++ qemu_file_update_transfer(rs->f, p->packet_len); + qemu_mutex_unlock(&p->mutex); + qemu_sem_post(&p->sem); + } +@@ -2079,7 +2081,7 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage) + static int ram_save_multifd_page(RAMState *rs, RAMBlock *block, + ram_addr_t offset) + { +- if (multifd_queue_page(block, offset) < 0) { ++ if (multifd_queue_page(rs, block, offset) < 0) { + return -1; + } + ram_counters.normal++; +@@ -3482,7 +3484,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque) + ram_control_before_iterate(f, RAM_CONTROL_SETUP); + ram_control_after_iterate(f, RAM_CONTROL_SETUP); + +- multifd_send_sync_main(); ++ multifd_send_sync_main(*rsp); + qemu_put_be64(f, RAM_SAVE_FLAG_EOS); + qemu_fflush(f); + +@@ -3570,7 +3572,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) + ram_control_after_iterate(f, RAM_CONTROL_ROUND); + + out: +- multifd_send_sync_main(); ++ multifd_send_sync_main(rs); + qemu_put_be64(f, RAM_SAVE_FLAG_EOS); + qemu_fflush(f); + ram_counters.transferred += 8; +@@ -3629,7 +3631,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque) + + rcu_read_unlock(); + +- multifd_send_sync_main(); ++ multifd_send_sync_main(rs); + qemu_put_be64(f, RAM_SAVE_FLAG_EOS); + qemu_fflush(f); + +-- +2.19.1 diff --git a/migration-always-initialise-ram_counters-for-a-new-m.patch b/migration-always-initialise-ram_counters-for-a-new-m.patch new file mode 100644 index 0000000000000000000000000000000000000000..ccd0db9ab87204ca41e17c1120618748eb4383fe --- /dev/null +++ b/migration-always-initialise-ram_counters-for-a-new-m.patch @@ -0,0 +1,125 @@ +From af2aa4f553565ae6b2248204c154748f38ec4746 Mon Sep 17 00:00:00 2001 +From: Ivan Ren +Date: Fri, 2 Aug 2019 18:18:41 +0800 +Subject: [PATCH 01/10] migration: always initialise ram_counters for a new + migration + +This patch fix a multifd migration bug in migration speed calculation, this +problem can be reproduced as follows: +1. start a vm and give a heavy memory write stress to prevent the vm be + successfully migrated to destination +2. begin a migration with multifd +3. migrate for a long time [actually, this can be measured by transferred bytes] +4. migrate cancel +5. begin a new migration with multifd, the migration will directly run into + migration_completion phase + +Reason as follows: + +Migration update bandwidth and s->threshold_size in function +migration_update_counters after BUFFER_DELAY time: + + current_bytes = migration_total_bytes(s); + transferred = current_bytes - s->iteration_initial_bytes; + time_spent = current_time - s->iteration_start_time; + bandwidth = (double)transferred / time_spent; + s->threshold_size = bandwidth * s->parameters.downtime_limit; + +In multifd migration, migration_total_bytes function return +qemu_ftell(s->to_dst_file) + ram_counters.multifd_bytes. +s->iteration_initial_bytes will be initialized to 0 at every new migration, +but ram_counters is a global variable, and history migration data will be +accumulated. So if the ram_counters.multifd_bytes is big enough, it may lead +pending_size >= s->threshold_size become false in migration_iteration_run +after the first migration_update_counters. + +Change-Id: Ib153d8676a5b82650bfb1156060e09f0d29f3ac6 +Signed-off-by: Ivan Ren +Reviewed-by: Juan Quintela +Reviewed-by: Wei Yang +Suggested-by: Wei Yang +Message-Id: <1564741121-1840-1-git-send-email-ivanren@tencent.com> +Signed-off-by: Dr. David Alan Gilbert +--- + migration/migration.c | 25 +++++++++++++++++++------ + migration/savevm.c | 1 + + 2 files changed, 20 insertions(+), 6 deletions(-) + +diff --git a/migration/migration.c b/migration/migration.c +index 8a607fe1..bea9b1d7 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -1908,6 +1908,11 @@ static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc, + } + + migrate_init(s); ++ /* ++ * set ram_counters memory to zero for a ++ * new migration ++ */ ++ memset(&ram_counters, 0, sizeof(ram_counters)); + + return true; + } +@@ -3025,6 +3030,17 @@ static void migration_calculate_complete(MigrationState *s) + } + } + ++static void update_iteration_initial_status(MigrationState *s) ++{ ++ /* ++ * Update these three fields at the same time to avoid mismatch info lead ++ * wrong speed calculation. ++ */ ++ s->iteration_start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); ++ s->iteration_initial_bytes = migration_total_bytes(s); ++ s->iteration_initial_pages = ram_get_total_transferred_pages(); ++} ++ + static void migration_update_counters(MigrationState *s, + int64_t current_time) + { +@@ -3060,9 +3076,7 @@ static void migration_update_counters(MigrationState *s, + + qemu_file_reset_rate_limit(s->to_dst_file); + +- s->iteration_start_time = current_time; +- s->iteration_initial_bytes = current_bytes; +- s->iteration_initial_pages = ram_get_total_transferred_pages(); ++ update_iteration_initial_status(s); + + trace_migrate_transferred(transferred, time_spent, + bandwidth, s->threshold_size); +@@ -3186,7 +3200,7 @@ static void *migration_thread(void *opaque) + rcu_register_thread(); + + object_ref(OBJECT(s)); +- s->iteration_start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); ++ update_iteration_initial_status(s); + + qemu_savevm_state_header(s->to_dst_file); + +@@ -3251,8 +3265,7 @@ static void *migration_thread(void *opaque) + * the local variables. This is important to avoid + * breaking transferred_bytes and bandwidth calculation + */ +- s->iteration_start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); +- s->iteration_initial_bytes = 0; ++ update_iteration_initial_status(s); + } + + current_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); +diff --git a/migration/savevm.c b/migration/savevm.c +index 79ed44d4..480c511b 100644 +--- a/migration/savevm.c ++++ b/migration/savevm.c +@@ -1424,6 +1424,7 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp) + } + + migrate_init(ms); ++ memset(&ram_counters, 0, sizeof(ram_counters)); + ms->to_dst_file = f; + + qemu_mutex_unlock_iothread(); +-- +2.19.1 diff --git a/migration-multifd-fix-destroyed-mutex-access-in-term.patch b/migration-multifd-fix-destroyed-mutex-access-in-term.patch new file mode 100644 index 0000000000000000000000000000000000000000..a927ea533c253ff242c5867cde1055453668c1c5 --- /dev/null +++ b/migration-multifd-fix-destroyed-mutex-access-in-term.patch @@ -0,0 +1,64 @@ +From 34d797aa134a33c1d67ca85d9d9f996d58162276 Mon Sep 17 00:00:00 2001 +From: Jiahui Cen +Date: Wed, 23 Oct 2019 11:47:37 +0800 +Subject: [PATCH 09/10] migration/multifd: fix destroyed mutex access in + terminating multifd threads + +One multifd will lock all the other multifds' IOChannel mutex to inform them +to quit by setting p->quit or shutting down p->c. In this senario, if some +multifds had already been terminated and multifd_load_cleanup/multifd_save_cleanup +had destroyed their mutex, it could cause destroyed mutex access when trying +lock their mutex. + +Here is the coredump stack: + #0 0x00007f81a2794437 in raise () from /usr/lib64/libc.so.6 + #1 0x00007f81a2795b28 in abort () from /usr/lib64/libc.so.6 + #2 0x00007f81a278d1b6 in __assert_fail_base () from /usr/lib64/libc.so.6 + #3 0x00007f81a278d262 in __assert_fail () from /usr/lib64/libc.so.6 + #4 0x000055eb1bfadbd3 in qemu_mutex_lock_impl (mutex=0x55eb1e2d1988, file=, line=) at util/qemu-thread-posix.c:64 + #5 0x000055eb1bb4564a in multifd_send_terminate_threads (err=) at migration/ram.c:1015 + #6 0x000055eb1bb4bb7f in multifd_send_thread (opaque=0x55eb1e2d19f8) at migration/ram.c:1171 + #7 0x000055eb1bfad628 in qemu_thread_start (args=0x55eb1e170450) at util/qemu-thread-posix.c:502 + #8 0x00007f81a2b36df5 in start_thread () from /usr/lib64/libpthread.so.0 + #9 0x00007f81a286048d in clone () from /usr/lib64/libc.so.6 + +To fix it up, let's destroy the mutex after all the other multifd threads had +been terminated. + +Change-Id: I4124d43e8558ba302052bdc53fdae7cfcf9d8687 +Signed-off-by: Jiahui Cen +Signed-off-by: Ying Fang +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +--- + migration/ram.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/migration/ram.c b/migration/ram.c +index 029f1cdf..d7d2d5ec 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1033,6 +1033,10 @@ void multifd_save_cleanup(void) + if (p->running) { + qemu_thread_join(&p->thread); + } ++ } ++ for (i = 0; i < migrate_multifd_channels(); i++) { ++ MultiFDSendParams *p = &multifd_send_state->params[i]; ++ + socket_send_channel_destroy(p->c); + p->c = NULL; + qemu_mutex_destroy(&p->mutex); +@@ -1306,6 +1310,10 @@ int multifd_load_cleanup(Error **errp) + qemu_sem_post(&p->sem_sync); + qemu_thread_join(&p->thread); + } ++ } ++ for (i = 0; i < migrate_multifd_channels(); i++) { ++ MultiFDRecvParams *p = &multifd_recv_state->params[i]; ++ + object_unref(OBJECT(p->c)); + p->c = NULL; + qemu_mutex_destroy(&p->mutex); +-- +2.19.1 diff --git a/migration-multifd-fix-nullptr-access-in-multifd_send.patch b/migration-multifd-fix-nullptr-access-in-multifd_send.patch new file mode 100644 index 0000000000000000000000000000000000000000..f2d278a135434e3b0838be7876b1fe2a616816cd --- /dev/null +++ b/migration-multifd-fix-nullptr-access-in-multifd_send.patch @@ -0,0 +1,62 @@ +From 6a08ee257a95d9f2514bd995e90ddf46d3f78b41 Mon Sep 17 00:00:00 2001 +From: Zheng Chuan +Date: Tue, 21 Apr 2020 19:49:26 +0800 +Subject: [PATCH 10/10] migration/multifd: fix nullptr access in + multifd_send_terminate_threads + +If the multifd_send_threads is not created when migration is failed, +multifd_save_cleanup would be called twice. In this senario, the +multifd_send_state is accessed after it has been released, the result +is that the source VM is crashing down. + +Here is the coredump stack: + Program received signal SIGSEGV, Segmentation fault. + 0x00005629333a78ef in multifd_send_terminate_threads (err=err@entry=0x0) at migration/ram.c:1012 + 1012 MultiFDSendParams *p = &multifd_send_state->params[i]; + #0 0x00005629333a78ef in multifd_send_terminate_threads (err=err@entry=0x0) at migration/ram.c:1012 + #1 0x00005629333ab8a9 in multifd_save_cleanup () at migration/ram.c:1028 + #2 0x00005629333abaea in multifd_new_send_channel_async (task=0x562935450e70, opaque=) at migration/ram.c:1202 + #3 0x000056293373a562 in qio_task_complete (task=task@entry=0x562935450e70) at io/task.c:196 + #4 0x000056293373a6e0 in qio_task_thread_result (opaque=0x562935450e70) at io/task.c:111 + #5 0x00007f475d4d75a7 in g_idle_dispatch () from /usr/lib64/libglib-2.0.so.0 + #6 0x00007f475d4da9a9 in g_main_context_dispatch () from /usr/lib64/libglib-2.0.so.0 + #7 0x0000562933785b33 in glib_pollfds_poll () at util/main-loop.c:219 + #8 os_host_main_loop_wait (timeout=) at util/main-loop.c:242 + #9 main_loop_wait (nonblocking=nonblocking@entry=0) at util/main-loop.c:518 + #10 0x00005629334c5acf in main_loop () at vl.c:1810 + #11 0x000056293334d7bb in main (argc=, argv=, envp=) at vl.c:4471 + +If the multifd_send_threads is not created when migration is failed. +In this senario, we don't call multifd_save_cleanup in multifd_new_send_channel_async. + +Change-Id: I7441efe2ed542054ecd2a4da8146e2652824b452 +Signed-off-by: Zhimin Feng +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +--- + migration/ram.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/migration/ram.c b/migration/ram.c +index d7d2d5ec..1858d66c 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1205,7 +1205,15 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) + + if (qio_task_propagate_error(task, &local_err)) { + migrate_set_error(migrate_get_current(), local_err); +- multifd_save_cleanup(); ++ /* Error happen, we need to tell who pay attention to me */ ++ qemu_sem_post(&multifd_send_state->channels_ready); ++ qemu_sem_post(&p->sem_sync); ++ /* ++ * Although multifd_send_thread is not created, but main migration ++ * thread neet to judge whether it is running, so we need to mark ++ * its status. ++ */ ++ p->quit = true; + } else { + p->c = QIO_CHANNEL(sioc); + qio_channel_set_delay(p->c, false); +-- +2.19.1 diff --git a/migration-multifd-fix-nullptr-access-in-terminating-m.patch b/migration-multifd-fix-nullptr-access-in-terminating-m.patch new file mode 100644 index 0000000000000000000000000000000000000000..d403b28f28a708a94d7799618053e53c7d75b939 --- /dev/null +++ b/migration-multifd-fix-nullptr-access-in-terminating-m.patch @@ -0,0 +1,75 @@ +From d9a847f0982fcca6f63031215065c346fcc27bbc Mon Sep 17 00:00:00 2001 +From: Zheng Chuan +Date: Fri, 24 Apr 2020 11:58:33 +0800 +Subject: [PATCH 06/10] migration/multifd: fix nullptr access in terminating + multifd threads + +One multifd channel will shutdown all the other multifd's IOChannel when it +fails to receive an IOChannel. In this senario, if some multifds had not +received its IOChannel yet, it would try to shutdown its IOChannel which could +cause nullptr access at qio_channel_shutdown. + +Here is the coredump stack: + #0 object_get_class (obj=obj@entry=0x0) at qom/object.c:908 + #1 0x00005563fdbb8f4a in qio_channel_shutdown (ioc=0x0, how=QIO_CHANNEL_SHUTDOWN_BOTH, errp=0x0) at io/channel.c:355 + #2 0x00005563fd7b4c5f in multifd_recv_terminate_threads (err=) at migration/ram.c:1280 + #3 0x00005563fd7bc019 in multifd_recv_new_channel (ioc=ioc@entry=0x556400255610, errp=errp@entry=0x7ffec07dce00) at migration/ram.c:1478 + #4 0x00005563fda82177 in migration_ioc_process_incoming (ioc=ioc@entry=0x556400255610, errp=errp@entry=0x7ffec07dce30) at migration/migration.c:605 + #5 0x00005563fda8567d in migration_channel_process_incoming (ioc=0x556400255610) at migration/channel.c:44 + #6 0x00005563fda83ee0 in socket_accept_incoming_migration (listener=0x5563fff6b920, cioc=0x556400255610, opaque=) at migration/socket +.c:166 + #7 0x00005563fdbc25cd in qio_net_listener_channel_func (ioc=, condition=, opaque=) at io/net-listener.c:54 + #8 0x00007f895b6fe9a9 in g_main_context_dispatch () from /usr/lib64/libglib-2.0.so.0 + #9 0x00005563fdc18136 in glib_pollfds_poll () at util/main-loop.c:218 + #10 0x00005563fdc181b5 in os_host_main_loop_wait (timeout=1000000000) at util/main-loop.c:241 + #11 0x00005563fdc183a2 in main_loop_wait (nonblocking=nonblocking@entry=0) at util/main-loop.c:517 + #12 0x00005563fd8edb37 in main_loop () at vl.c:1791 + #13 0x00005563fd74fd45 in main (argc=, argv=, envp=) at vl.c:4473 + +To fix it up, let's check p->c before calling qio_channel_shutdown. + +Change-Id: Ib36c1b3d866a3ad92d1460512df840cfb8736ab6 +Signed-off-by: Jiahui Cen +Signed-off-by: Ying Fang +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +--- + migration/ram.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/migration/ram.c b/migration/ram.c +index 51811c2d..756a525f 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1112,6 +1112,7 @@ static void *multifd_send_thread(void *opaque) + rcu_register_thread(); + + if (multifd_send_initial_packet(p, &local_err) < 0) { ++ ret = -1; + goto out; + } + /* initial packet */ +@@ -1178,9 +1179,7 @@ out: + * who pay attention to me. + */ + if (ret != 0) { +- if (flags & MULTIFD_FLAG_SYNC) { +- qemu_sem_post(&p->sem_sync); +- } ++ qemu_sem_post(&p->sem_sync); + qemu_sem_post(&multifd_send_state->channels_ready); + } + +@@ -1279,7 +1278,9 @@ static void multifd_recv_terminate_threads(Error *err) + - normal quit, i.e. everything went fine, just finished + - error quit: We close the channels so the channel threads + finish the qio_channel_read_all_eof() */ +- qio_channel_shutdown(p->c, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); ++ if (p->c) { ++ qio_channel_shutdown(p->c, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); ++ } + qemu_mutex_unlock(&p->mutex); + } + } +-- +2.19.1 diff --git a/migration-multifd-fix-potential-wrong-acception-orde.patch b/migration-multifd-fix-potential-wrong-acception-orde.patch new file mode 100644 index 0000000000000000000000000000000000000000..6b8f18ce71abccf8987fb9261817654b3b10d631 --- /dev/null +++ b/migration-multifd-fix-potential-wrong-acception-orde.patch @@ -0,0 +1,302 @@ +From 71f3e496c128b46f803cc4776154b02a5e505cb2 Mon Sep 17 00:00:00 2001 +From: Zheng Chuan +Date: Wed, 22 Apr 2020 13:45:39 +0800 +Subject: [PATCH] migration/multifd: fix potential wrong acception order of + IOChannel + +Multifd assumes the migration thread IOChannel is always established before +the multifd IOChannels, but this assumption will be broken in many situations +like network packet loss. + +For example: +Step1: Source (migration thread IOChannel) --SYN--> Destination +Step2: Source (migration thread IOChannel) <--SYNACK Destination +Step3: Source (migration thread IOChannel, lost) --ACK-->X Destination +Step4: Source (multifd IOChannel) --SYN--> Destination +Step5: Source (multifd IOChannel) <--SYNACK Destination +Step6: Source (multifd IOChannel, ESTABLISHED) --ACK--> Destination +Step7: Destination accepts multifd IOChannel +Step8: Source (migration thread IOChannel, ESTABLISHED) -ACK,DATA-> Destination +Step9: Destination accepts migration thread IOChannel + +The above situation can be reproduced by creating a weak network environment, +such as "tc qdisc add dev eth0 root netem loss 50%". The wrong acception order +will cause magic check failure and thus lead to migration failure. + +This patch fixes this issue by sending a migration IOChannel initial packet with +a unique id when using multifd migration. Since the multifd IOChannels will also +send initial packets, the destination can judge whether the processing IOChannel +belongs to multifd by checking the id in the initial packet. This mechanism can +ensure that different IOChannels will go to correct branches in our test. + +Change-Id: I63d1c32c7b66063bd6a3c5e7d63500555bd148b9 +Signed-off-by: Jiahui Cen +Signed-off-by: Ying Fang + +diff --git a/migration/channel.c b/migration/channel.c +index 20e4c8e2..74621814 100644 +--- a/migration/channel.c ++++ b/migration/channel.c +@@ -82,6 +82,15 @@ void migration_channel_connect(MigrationState *s, + return; + } + } else { ++ if (migrate_use_multifd()) { ++ /* multifd migration cannot distinguish migration IOChannel ++ * from multifd IOChannels, so we need to send an initial packet ++ * to show it is migration IOChannel ++ */ ++ migration_send_initial_packet(ioc, ++ migrate_multifd_channels(), ++ &error); ++ } + QEMUFile *f = qemu_fopen_channel_output(ioc); + + qemu_mutex_lock(&s->qemu_file_lock); +diff --git a/migration/migration.c b/migration/migration.c +index 114c33a1..8f2fc2b4 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -517,12 +517,6 @@ static void migration_incoming_setup(QEMUFile *f) + { + MigrationIncomingState *mis = migration_incoming_get_current(); + +- if (multifd_load_setup() != 0) { +- /* We haven't been able to create multifd threads +- nothing better to do */ +- exit(EXIT_FAILURE); +- } +- + if (!mis->from_src_file) { + mis->from_src_file = f; + } +@@ -580,36 +574,41 @@ void migration_fd_process_incoming(QEMUFile *f) + void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp) + { + MigrationIncomingState *mis = migration_incoming_get_current(); +- bool start_migration; +- +- if (!mis->from_src_file) { +- /* The first connection (multifd may have multiple) */ +- QEMUFile *f = qemu_fopen_channel_input(ioc); ++ Error *local_err = NULL; ++ int id = 0; + +- /* If it's a recovery, we're done */ +- if (postcopy_try_recover(f)) { +- return; +- } ++ if (migrate_use_multifd()) { ++ id = migration_recv_initial_packet(ioc, &local_err); ++ } ++ if (!migrate_use_multifd() || id == migrate_multifd_channels()) { ++ if (!mis->from_src_file) { ++ /* The migration connection (multifd may have multiple) */ ++ QEMUFile *f = qemu_fopen_channel_input(ioc); + +- migration_incoming_setup(f); ++ /* If it's a recovery, we're done */ ++ if (postcopy_try_recover(f)) { ++ return; ++ } + +- /* +- * Common migration only needs one channel, so we can start +- * right now. Multifd needs more than one channel, we wait. +- */ +- start_migration = !migrate_use_multifd(); +- } else { +- Error *local_err = NULL; ++ migration_incoming_setup(f); ++ } ++ } else if (id >= 0) { + /* Multiple connections */ + assert(migrate_use_multifd()); +- start_migration = multifd_recv_new_channel(ioc, &local_err); ++ multifd_recv_new_channel(ioc, id, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } ++ } else { ++ /* Bad connections */ ++ multifd_recv_terminate_threads(local_err); ++ error_propagate(errp, local_err); ++ return; + } + +- if (start_migration) { ++ /* Once we have all the channels we need, we can start migration */ ++ if (migration_has_all_channels()) { + migration_incoming_process(); + } + } +diff --git a/migration/migration.h b/migration/migration.h +index 1fdd7b21..feb34430 100644 +--- a/migration/migration.h ++++ b/migration/migration.h +@@ -339,4 +339,7 @@ int foreach_not_ignored_block(RAMBlockIterFunc func, void *opaque); + void migration_make_urgent_request(void); + void migration_consume_urgent_request(void); + ++int migration_send_initial_packet(QIOChannel *c, uint8_t id, Error **errp); ++int migration_recv_initial_packet(QIOChannel *c, Error **errp); ++ + #endif +diff --git a/migration/ram.c b/migration/ram.c +index 756a525f..029f1cdf 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -593,7 +593,7 @@ typedef struct { + uint8_t id; + uint8_t unused1[7]; /* Reserved for future use */ + uint64_t unused2[4]; /* Reserved for future use */ +-} __attribute__((packed)) MultiFDInit_t; ++} __attribute__((packed)) MigrationInit_t; + + typedef struct { + uint32_t magic; +@@ -702,26 +702,26 @@ typedef struct { + QemuSemaphore sem_sync; + } MultiFDRecvParams; + +-static int multifd_send_initial_packet(MultiFDSendParams *p, Error **errp) ++int migration_send_initial_packet(QIOChannel *c, uint8_t id, Error **errp) + { +- MultiFDInit_t msg; ++ MigrationInit_t msg; + int ret; + + msg.magic = cpu_to_be32(MULTIFD_MAGIC); + msg.version = cpu_to_be32(MULTIFD_VERSION); +- msg.id = p->id; ++ msg.id = id; + memcpy(msg.uuid, &qemu_uuid.data, sizeof(msg.uuid)); + +- ret = qio_channel_write_all(p->c, (char *)&msg, sizeof(msg), errp); ++ ret = qio_channel_write_all(c, (char *)&msg, sizeof(msg), errp); + if (ret != 0) { + return -1; + } + return 0; + } + +-static int multifd_recv_initial_packet(QIOChannel *c, Error **errp) ++int migration_recv_initial_packet(QIOChannel *c, Error **errp) + { +- MultiFDInit_t msg; ++ MigrationInit_t msg; + int ret; + + ret = qio_channel_read_all(c, (char *)&msg, sizeof(msg), errp); +@@ -756,8 +756,8 @@ static int multifd_recv_initial_packet(QIOChannel *c, Error **errp) + } + + if (msg.id > migrate_multifd_channels()) { +- error_setg(errp, "multifd: received channel version %d " +- "expected %d", msg.version, MULTIFD_VERSION); ++ error_setg(errp, "multifd: received channel id %d " ++ "expected [0-%d]", msg.id, migrate_multifd_channels()); + return -1; + } + +@@ -1111,7 +1111,7 @@ static void *multifd_send_thread(void *opaque) + trace_multifd_send_thread_start(p->id); + rcu_register_thread(); + +- if (multifd_send_initial_packet(p, &local_err) < 0) { ++ if (migration_send_initial_packet(p->c, p->id, &local_err) < 0) { + ret = -1; + goto out; + } +@@ -1255,7 +1255,7 @@ struct { + uint64_t packet_num; + } *multifd_recv_state; + +-static void multifd_recv_terminate_threads(Error *err) ++void multifd_recv_terminate_threads(Error *err) + { + int i; + +@@ -1470,21 +1470,10 @@ bool multifd_recv_all_channels_created(void) + * - Return false and do not set @errp when correctly receiving the current one; + * - Return false and set @errp when failing to receive the current channel. + */ +-bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp) ++void multifd_recv_new_channel(QIOChannel *ioc, int id, Error **errp) + { + MultiFDRecvParams *p; + Error *local_err = NULL; +- int id; +- +- id = multifd_recv_initial_packet(ioc, &local_err); +- if (id < 0) { +- multifd_recv_terminate_threads(local_err); +- error_propagate_prepend(errp, local_err, +- "failed to receive packet" +- " via multifd channel %d: ", +- atomic_read(&multifd_recv_state->count)); +- return false; +- } + + p = &multifd_recv_state->params[id]; + if (p->c != NULL) { +@@ -1492,7 +1481,7 @@ bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp) + id); + multifd_recv_terminate_threads(local_err); + error_propagate(errp, local_err); +- return false; ++ return; + } + p->c = ioc; + object_ref(OBJECT(ioc)); +@@ -1503,8 +1492,6 @@ bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp) + qemu_thread_create(&p->thread, p->name, multifd_recv_thread, p, + QEMU_THREAD_JOINABLE); + atomic_inc(&multifd_recv_state->count); +- return atomic_read(&multifd_recv_state->count) == +- migrate_multifd_channels(); + } + + /** +diff --git a/migration/ram.h b/migration/ram.h +index bd0eee79..a788ff0e 100644 +--- a/migration/ram.h ++++ b/migration/ram.h +@@ -46,7 +46,8 @@ void multifd_save_cleanup(void); + int multifd_load_setup(void); + int multifd_load_cleanup(Error **errp); + bool multifd_recv_all_channels_created(void); +-bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp); ++void multifd_recv_new_channel(QIOChannel *ioc, int id, Error **errp); ++void multifd_recv_terminate_threads(Error *err); + + uint64_t ram_pagesize_summary(void); + int ram_save_queue_pages(const char *rbname, ram_addr_t start, ram_addr_t len); +diff --git a/migration/socket.c b/migration/socket.c +index 98efdc02..093b956b 100644 +--- a/migration/socket.c ++++ b/migration/socket.c +@@ -22,6 +22,7 @@ + #include "channel.h" + #include "socket.h" + #include "migration.h" ++#include "ram.h" + #include "qemu-file.h" + #include "io/channel-socket.h" + #include "io/net-listener.h" +@@ -181,6 +182,12 @@ static void socket_start_incoming_migration(SocketAddress *saddr, + + qio_net_listener_set_name(listener, "migration-socket-listener"); + ++ if (multifd_load_setup() != 0) { ++ /* We haven't been able to create multifd threads ++ nothing better to do */ ++ exit(EXIT_FAILURE); ++ } ++ + if (qio_net_listener_open_sync(listener, saddr, errp) < 0) { + object_unref(OBJECT(listener)); + return; +-- +2.23.0 diff --git a/migration-ram-Do-error_free-after-migrate_set_error-.patch b/migration-ram-Do-error_free-after-migrate_set_error-.patch new file mode 100644 index 0000000000000000000000000000000000000000..0039f43d86d5506bfca2953904a215d3f178526a --- /dev/null +++ b/migration-ram-Do-error_free-after-migrate_set_error-.patch @@ -0,0 +1,69 @@ +From 05d1fbd2390d441e5acb606dba3d308d506a8eb1 Mon Sep 17 00:00:00 2001 +From: Pan Nengyuan +Date: Tue, 5 May 2020 11:44:20 +0800 +Subject: [PATCH 1/3] migration/ram: Do error_free after migrate_set_error to + avoid memleaks + +If local_err is not NULL, it use error_copy to set migrate error in +multifd_send_terminate_threads. Thus, we should free it. + +Similarly, fix another leak in multifd_recv_thread. + +The leak stack: +Direct leak of 96 byte(s) in 2 object(s) allocated from: + #0 0xfffdd97fe938 in __interceptor_calloc (/lib64/libasan.so.4+0xee938) + #1 0xfffdd85a8bb0 in g_malloc0 (/lib64/libglib-2.0.so.0+0x58bb0) + #2 0xaaadfc6e41c4 in error_setv util/error.c:61 + #3 0xaaadfc6e4880 in error_setg_errno_internal util/error.c:109 + #4 0xaaadfc6192a8 in qio_channel_socket_writev io/channel-socket.c:552 + #5 0xaaadfc614604 in qio_channel_writev_all io/channel.c:171 + #6 0xaaadfc6147ec in qio_channel_write_all io/channel.c:257 + #7 0xaaadfbaec5fc in multifd_send_thread /usr/src/debug/qemu-4.1.0-4_asan.aarch64/migration/ram.c:1145 + #8 0xaaadfc6db768 in qemu_thread_start util/qemu-thread-posix.c:502 + #9 0xfffdd79a88c8 (/lib64/libpthread.so.0+0x88c8) + #10 0xfffdd78e9578 (/lib64/libc.so.6+0xd9578) + +Indirect leak of 104 byte(s) in 2 object(s) allocated from: + #0 0xfffdd97feb40 in realloc (/lib64/libasan.so.4+0xeeb40) + #1 0xfffdd78fa6e0 in __vasprintf_chk (/lib64/libc.so.6+0xea6e0) + #2 0xfffdd85ee710 in g_vasprintf (/lib64/libglib-2.0.so.0+0x9e710) + #3 0xfffdd85c45c4 in g_strdup_vprintf (/lib64/libglib-2.0.so.0+0x745c4) + #4 0xfffdd85c4674 in g_strdup_printf (/lib64/libglib-2.0.so.0+0x74674) + #5 0xaaadfc6e4214 in error_setv util/error.c:65 + #6 0xaaadfc6e4880 in error_setg_errno_internal util/error.c:109 + #7 0xaaadfc6192a8 in qio_channel_socket_writev io/channel-socket.c:552 + #8 0xaaadfc614604 in qio_channel_writev_all io/channel.c:171 + #9 0xaaadfc6147ec in qio_channel_write_all io/channel.c:257 + #10 0xaaadfbaec5fc in multifd_send_thread /usr/src/debug/qemu-4.1.0-4_asan.aarch64/migration/ram.c:1145 + #11 0xaaadfc6db768 in qemu_thread_start util/qemu-thread-posix.c:502 + #12 0xfffdd79a88c8 (/lib64/libpthread.so.0+0x88c8) + #13 0xfffdd78e9578 (/lib64/libc.so.6+0xd9578) + +Reported-by: Euler Robot +Signed-off-by: Pan Nengyuan +--- + migration/ram.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/migration/ram.c b/migration/ram.c +index 1858d66c..6baf1412 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1176,6 +1176,7 @@ static void *multifd_send_thread(void *opaque) + out: + if (local_err) { + multifd_send_terminate_threads(local_err); ++ error_free(local_err); + } + + /* +@@ -1427,6 +1428,7 @@ static void *multifd_recv_thread(void *opaque) + + if (local_err) { + multifd_recv_terminate_threads(local_err); ++ error_free(local_err); + } + qemu_mutex_lock(&p->mutex); + p->running = false; +-- +2.23.0 diff --git a/migration-ram-fix-memleaks-in-multifd_new_send_chann.patch b/migration-ram-fix-memleaks-in-multifd_new_send_chann.patch new file mode 100644 index 0000000000000000000000000000000000000000..f9cb2bf652b90968144c673fd6c59655acfd785f --- /dev/null +++ b/migration-ram-fix-memleaks-in-multifd_new_send_chann.patch @@ -0,0 +1,54 @@ +From 4d456b243a41a8e91535b2820fd6ed4f6fb4a194 Mon Sep 17 00:00:00 2001 +From: Pan Nengyuan +Date: Tue, 5 May 2020 15:50:54 +0800 +Subject: [PATCH 2/3] migration/ram: fix memleaks in + multifd_new_send_channel_async + +When error happen in multifd_new_send_channel_async, 'sioc' will not be used +to create the multifd_send_thread. Let's free it to avoid a memleak. And also +do error_free after migrate_set_error() to avoid another leak in the same place. + +The leak stack: +Direct leak of 2160 byte(s) in 6 object(s) allocated from: + #0 0xfffdd97fe754 in malloc (/lib64/libasan.so.4+0xee754) + #1 0xfffdd85a8b48 in g_malloc (/lib64/libglib-2.0.so.0+0x58b48) + #2 0xaaadfc4e2b10 in object_new_with_type qom/object.c:634 + #3 0xaaadfc619468 in qio_channel_socket_new io/channel-socket.c:56 + #4 0xaaadfc3d3e74 in socket_send_channel_create migration/socket.c:37 + #5 0xaaadfbaed6f4 in multifd_save_setup /usr/src/debug/qemu-4.1.0-4_asan.aarch64/migration/ram.c:1255 + #6 0xaaadfc3d2f78 in migrate_fd_connect migration/migration.c:3359 + #7 0xaaadfc3d6240 in migration_channel_connect migration/channel.c:101 + #8 0xaaadfc3d3590 in socket_outgoing_migration migration/socket.c:108 + #9 0xaaadfc625a64 in qio_task_complete io/task.c:195 + #10 0xaaadfc625ed0 in qio_task_thread_result io/task.c:111 + #11 0xfffdd859edec (/lib64/libglib-2.0.so.0+0x4edec) + #12 0xfffdd85a2a78 in g_main_context_dispatch (/lib64/libglib-2.0.so.0+0x52a78) + #13 0xaaadfc6d3b84 in glib_pollfds_poll util/main-loop.c:218 + #14 0xaaadfc6d3b84 in os_host_main_loop_wait util/main-loop.c:241 + #15 0xaaadfc6d3b84 in main_loop_wait util/main-loop.c:517 + #16 0xaaadfbf9206c in main_loop /usr/src/debug/qemu-4.1.0-4_asan.aarch64/vl.c:1791 + #17 0xaaadfba1b124 in main /usr/src/debug/qemu-4.1.0-4_asan.aarch64/vl.c:4473 + #18 0xfffdd7833f5c in __libc_start_main (/lib64/libc.so.6+0x23f5c) + #19 0xaaadfba26360 (/usr/libexec/qemu-kvm+0x886360) + +Reported-by: Euler Robot +Signed-off-by: Pan Nengyuan +--- + migration/ram.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/migration/ram.c b/migration/ram.c +index 6baf1412..840e3548 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1215,6 +1215,8 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) + * its status. + */ + p->quit = true; ++ object_unref(OBJECT(sioc)); ++ error_free(local_err); + } else { + p->c = QIO_CHANNEL(sioc); + qio_channel_set_delay(p->c, false); +-- +2.23.0 diff --git a/migration-rdma-fix-a-memleak-on-error-path-in-rdma_s.patch b/migration-rdma-fix-a-memleak-on-error-path-in-rdma_s.patch new file mode 100644 index 0000000000000000000000000000000000000000..5e0fb101d827377551a7858f225cf365367e12b7 --- /dev/null +++ b/migration-rdma-fix-a-memleak-on-error-path-in-rdma_s.patch @@ -0,0 +1,43 @@ +From 8ae2e3b8be812bcbdeb6151c685026bcaedd4a4b Mon Sep 17 00:00:00 2001 +From: Pan Nengyuan +Date: Sat, 9 May 2020 15:25:42 +0800 +Subject: [PATCH 3/3] migration/rdma: fix a memleak on error path in + rdma_start_incoming_migration + +'rdma->host' is malloced in qemu_rdma_data_init, but forgot to free on the error +path in rdma_start_incoming_migration(), this patch fix that. + +Direct leak of 2 byte(s) in 1 object(s) allocated from: + #0 0xfffce56d34fb in __interceptor_malloc (/lib64/libasan.so.4+0xd34fb) + #1 0xfffce5158aa3 in g_malloc (/lib64/libglib-2.0.so.0+0x58aa3) + #2 0xfffce5174213 in g_strdup (/lib64/libglib-2.0.so.0+0x74213) + #3 0xaaad7c569ddf in qemu_rdma_data_init /Images/qemu/migration/rdma.c:2647 + #4 0xaaad7c57c99f in rdma_start_incoming_migration /Images/qemu/migration/rdma.c:4020 + #5 0xaaad7c52b35f in qemu_start_incoming_migration /Images/qemu/migration/migration.c:371 + #6 0xaaad7be173bf in qemu_init /Images/qemu/softmmu/vl.c:4464 + #7 0xaaad7bb29843 in main /Images/qemu/softmmu/main.c:48 + #8 0xfffce3713f5f in __libc_start_main (/lib64/libc.so.6+0x23f5f) + #9 0xaaad7bb2bf73 (/Images/qemu/build/aarch64-softmmu/qemu-system-aarch64+0x8fbf73) + +Reported-by: Euler Robot +Signed-off-by: Pan Nengyuan +--- + migration/rdma.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/migration/rdma.c b/migration/rdma.c +index 3036221e..b5fdb6a7 100644 +--- a/migration/rdma.c ++++ b/migration/rdma.c +@@ -4068,6 +4068,9 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp) + return; + err: + error_propagate(errp, local_err); ++ if (rdma) { ++ g_free(rdma->host); ++ } + g_free(rdma); + g_free(rdma_return_path); + } +-- +2.23.0 diff --git a/migration-update-ram_counters-for-multifd-sync-packe.patch b/migration-update-ram_counters-for-multifd-sync-packe.patch new file mode 100644 index 0000000000000000000000000000000000000000..838380403f1ac31df0f2befd62a14711cee71e58 --- /dev/null +++ b/migration-update-ram_counters-for-multifd-sync-packe.patch @@ -0,0 +1,35 @@ +From e93040851d683f1f7750acfa0e862b4405678f24 Mon Sep 17 00:00:00 2001 +From: Zheng Chuan +Date: Fri, 24 Apr 2020 11:50:41 +0800 +Subject: [PATCH 04/10] migration: update ram_counters for multifd sync packet + +Multifd sync will send MULTIFD_FLAG_SYNC flag info to destination, add +these bytes to ram_counters record. + +Change-Id: I885166f412f58e74de40ea6ffec1c35e82ae4619 +Signed-off-by: Ivan Ren +Suggested-by: Wei Yang +Message-Id: <1564464816-21804-4-git-send-email-ivanren@tencent.com> +Reviewed-by: Juan Quintela +Signed-off-by: Dr. David Alan Gilbert +--- + migration/ram.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/migration/ram.c b/migration/ram.c +index 88ddd2bb..c75716bb 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1085,6 +1085,10 @@ static void multifd_send_sync_main(RAMState *rs) + p->flags |= MULTIFD_FLAG_SYNC; + p->pending_job++; + qemu_file_update_transfer(rs->f, p->packet_len); ++ ram_counters.multifd_bytes += p->packet_len; ++ ram_counters.transferred += p->packet_len; ++ ram_counters.multifd_bytes += p->packet_len; ++ ram_counters.transferred += p->packet_len; + qemu_mutex_unlock(&p->mutex); + qemu_sem_post(&p->sem); + } +-- +2.19.1 diff --git a/mirror-Keep-mirror_top_bs-drained-after-dropping-per.patch b/mirror-Keep-mirror_top_bs-drained-after-dropping-per.patch new file mode 100644 index 0000000000000000000000000000000000000000..52f07f951aef929e9fe58740955f97af25e5ba85 --- /dev/null +++ b/mirror-Keep-mirror_top_bs-drained-after-dropping-per.patch @@ -0,0 +1,52 @@ +From e092a17d3825a8f2c93cb429aaa5d857b579b64c Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Mon, 22 Jul 2019 17:44:27 +0200 +Subject: [PATCH] mirror: Keep mirror_top_bs drained after dropping permissions + +mirror_top_bs is currently implicitly drained through its connection to +the source or the target node. However, the drain section for target_bs +ends early after moving mirror_top_bs from src to target_bs, so that +requests can already be restarted while mirror_top_bs is still present +in the chain, but has dropped all permissions and therefore runs into an +assertion failure like this: + + qemu-system-x86_64: block/io.c:1634: bdrv_co_write_req_prepare: + Assertion `child->perm & BLK_PERM_WRITE' failed. + +Keep mirror_top_bs drained until all graph changes have completed. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit d2da5e288a2e71e82866c8fdefd41b5727300124) +Signed-off-by: Michael Roth +--- + block/mirror.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/block/mirror.c b/block/mirror.c +index 0e3f7923cf..681b305de6 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -661,7 +661,10 @@ static int mirror_exit_common(Job *job) + s->target = NULL; + + /* We don't access the source any more. Dropping any WRITE/RESIZE is +- * required before it could become a backing file of target_bs. */ ++ * required before it could become a backing file of target_bs. Not having ++ * these permissions any more means that we can't allow any new requests on ++ * mirror_top_bs from now on, so keep it drained. */ ++ bdrv_drained_begin(mirror_top_bs); + bs_opaque->stop = true; + bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing, + &error_abort); +@@ -729,6 +732,7 @@ static int mirror_exit_common(Job *job) + bs_opaque->job = NULL; + + bdrv_drained_end(src); ++ bdrv_drained_end(mirror_top_bs); + s->in_drain = false; + bdrv_unref(mirror_top_bs); + bdrv_unref(src); +-- +2.23.0 diff --git a/monitor-fix-memory-leak-in-monitor_fdset_dup_fd_find.patch b/monitor-fix-memory-leak-in-monitor_fdset_dup_fd_find.patch index 51f4113b4a67e8c9dfd67d5f21011ee998e04d13..791449b59540fd0d66cac0c367af8436abb55741 100644 --- a/monitor-fix-memory-leak-in-monitor_fdset_dup_fd_find.patch +++ b/monitor-fix-memory-leak-in-monitor_fdset_dup_fd_find.patch @@ -1,6 +1,6 @@ -From 6f7a7f18f4460b0891eabbe1ca69e599216427b7 Mon Sep 17 00:00:00 2001 +From 117082ef493e62e6e2cd972b309e0cd72682ab02 Mon Sep 17 00:00:00 2001 From: Chen Qun -Date: Mon, 16 Mar 2020 14:26:06 +0800 +Date: Tue, 14 Apr 2020 19:50:59 +0800 Subject: [PATCH] moniter: fix memleak in monitor_fdset_dup_fd_find_remove When remove dup_fd in monitor_fdset_dup_fd_find_remove function, @@ -25,14 +25,14 @@ Reported-by: Euler Robot Signed-off-by: Chen Qun (cherry picked from commit a661614de18c89f58cad3fc1bb8aab44e820183a) --- - monitor.c | 1 + + monitor/misc.c | 1 + 1 file changed, 1 insertion(+) -diff --git a/monitor.c b/monitor.c -index 4807bbe..b5b15b5 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -2596,6 +2596,7 @@ static int monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove) +diff --git a/monitor/misc.c b/monitor/misc.c +index 00338c00..0d6369ba 100644 +--- a/monitor/misc.c ++++ b/monitor/misc.c +@@ -1746,6 +1746,7 @@ static int64_t monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove) if (mon_fdset_fd_dup->fd == dup_fd) { if (remove) { QLIST_REMOVE(mon_fdset_fd_dup, next); @@ -40,6 +40,5 @@ index 4807bbe..b5b15b5 100644 if (QLIST_EMPTY(&mon_fdset->dup_fds)) { monitor_fdset_cleanup(mon_fdset); } --- -1.8.3.1 - +-- +2.23.0 diff --git a/pc-Don-t-make-die-id-mandatory-unless-necessary.patch b/pc-Don-t-make-die-id-mandatory-unless-necessary.patch new file mode 100644 index 0000000000000000000000000000000000000000..c51b40f33020e36547f44b895b040acc07bf741c --- /dev/null +++ b/pc-Don-t-make-die-id-mandatory-unless-necessary.patch @@ -0,0 +1,102 @@ +From 7ebcd375ade505358c1c45542de22f188c599bdd Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Fri, 16 Aug 2019 14:07:50 -0300 +Subject: [PATCH] pc: Don't make die-id mandatory unless necessary + +We have this issue reported when using libvirt to hotplug CPUs: +https://bugzilla.redhat.com/show_bug.cgi?id=1741451 + +Basically, libvirt is not copying die-id from +query-hotpluggable-cpus, but die-id is now mandatory. + +We could blame libvirt and say it is not following the documented +interface, because we have this buried in the QAPI schema +documentation: + +> Note: currently there are 5 properties that could be present +> but management should be prepared to pass through other +> properties with device_add command to allow for future +> interface extension. This also requires the filed names to be kept in +> sync with the properties passed to -device/device_add. + +But I don't think this would be reasonable from us. We can just +make QEMU more flexible and let die-id to be omitted when there's +no ambiguity. This will allow us to keep compatibility with +existing libvirt versions. + +Test case included to ensure we don't break this again. + +Fixes: commit 176d2cda0dee ("i386/cpu: Consolidate die-id validity in smp context") +Signed-off-by: Eduardo Habkost +Message-Id: <20190816170750.23910-1-ehabkost@redhat.com> +Signed-off-by: Eduardo Habkost +(cherry picked from commit fea374e7c8079563bca7c8fac895c6a880f76adc) +Signed-off-by: Michael Roth +--- + hw/i386/pc.c | 8 ++++++ + tests/acceptance/pc_cpu_hotplug_props.py | 35 ++++++++++++++++++++++++ + 2 files changed, 43 insertions(+) + create mode 100644 tests/acceptance/pc_cpu_hotplug_props.py + +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index 549c437050..947f81070f 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -2403,6 +2403,14 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev, + int max_socket = (ms->smp.max_cpus - 1) / + smp_threads / smp_cores / pcms->smp_dies; + ++ /* ++ * die-id was optional in QEMU 4.0 and older, so keep it optional ++ * if there's only one die per socket. ++ */ ++ if (cpu->die_id < 0 && pcms->smp_dies == 1) { ++ cpu->die_id = 0; ++ } ++ + if (cpu->socket_id < 0) { + error_setg(errp, "CPU socket-id is not set"); + return; +diff --git a/tests/acceptance/pc_cpu_hotplug_props.py b/tests/acceptance/pc_cpu_hotplug_props.py +new file mode 100644 +index 0000000000..08b7e632c6 +--- /dev/null ++++ b/tests/acceptance/pc_cpu_hotplug_props.py +@@ -0,0 +1,35 @@ ++# ++# Ensure CPU die-id can be omitted on -device ++# ++# Copyright (c) 2019 Red Hat Inc ++# ++# Author: ++# Eduardo Habkost ++# ++# This library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU Lesser General Public ++# License as published by the Free Software Foundation; either ++# version 2 of the License, or (at your option) any later version. ++# ++# This library is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# Lesser General Public License for more details. ++# ++# You should have received a copy of the GNU Lesser General Public ++# License along with this library; if not, see . ++# ++ ++from avocado_qemu import Test ++ ++class OmittedCPUProps(Test): ++ """ ++ :avocado: tags=arch:x86_64 ++ """ ++ def test_no_die_id(self): ++ self.vm.add_args('-nodefaults', '-S') ++ self.vm.add_args('-smp', '1,sockets=2,cores=2,threads=2,maxcpus=8') ++ self.vm.add_args('-cpu', 'qemu64') ++ self.vm.add_args('-device', 'qemu64-x86_64-cpu,socket-id=1,core-id=0,thread-id=0') ++ self.vm.launch() ++ self.assertEquals(len(self.vm.command('query-cpus')), 2) +-- +2.23.0 diff --git a/pr-manager-Fix-invalid-g_free-crash-bug.patch b/pr-manager-Fix-invalid-g_free-crash-bug.patch new file mode 100644 index 0000000000000000000000000000000000000000..b171cdb5ae34dab7135926c2250541814d543a02 --- /dev/null +++ b/pr-manager-Fix-invalid-g_free-crash-bug.patch @@ -0,0 +1,39 @@ +From 57fdf4a13ff16d9d48a43f02a5e7b42e3d264f83 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Thu, 22 Aug 2019 15:38:46 +0200 +Subject: [PATCH] pr-manager: Fix invalid g_free() crash bug +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +pr_manager_worker() passes its @opaque argument to g_free(). Wrong; +it points to pr_manager_worker()'s automatic @data. Broken when +commit 2f3a7ab39be converted @data from heap- to stack-allocated. Fix +by deleting the g_free(). + +Fixes: 2f3a7ab39bec4ba8022dc4d42ea641165b004e3e +Cc: qemu-stable@nongnu.org +Signed-off-by: Markus Armbruster +Reviewed-by: Philippe Mathieu-Daudé +Acked-by: Paolo Bonzini +Signed-off-by: Kevin Wolf +(cherry picked from commit 6b9d62c2a9e83bbad73fb61406f0ff69b46ff6f3) +Signed-off-by: Michael Roth +--- + scsi/pr-manager.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/scsi/pr-manager.c b/scsi/pr-manager.c +index ee43663576..0c866e8698 100644 +--- a/scsi/pr-manager.c ++++ b/scsi/pr-manager.c +@@ -39,7 +39,6 @@ static int pr_manager_worker(void *opaque) + int fd = data->fd; + int r; + +- g_free(data); + trace_pr_manager_run(fd, hdr->cmdp[0], hdr->cmdp[1]); + + /* The reference was taken in pr_manager_execute. */ +-- +2.23.0 diff --git a/qcow2-Fix-QCOW2_COMPRESSED_SECTOR_MASK.patch b/qcow2-Fix-QCOW2_COMPRESSED_SECTOR_MASK.patch new file mode 100644 index 0000000000000000000000000000000000000000..f2a4e5c26f50c820eb9122e8a8449b76713a8db7 --- /dev/null +++ b/qcow2-Fix-QCOW2_COMPRESSED_SECTOR_MASK.patch @@ -0,0 +1,35 @@ +From 405deba14f6b61b9c557484b46e863308c8cf373 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 28 Oct 2019 17:18:40 +0100 +Subject: [PATCH] qcow2: Fix QCOW2_COMPRESSED_SECTOR_MASK + +Masks for L2 table entries should have 64 bit. + +Fixes: b6c246942b14d3e0dec46a6c5868ed84e7dbea19 +Buglink: https://bugs.launchpad.net/qemu/+bug/1850000 +Cc: qemu-stable@nongnu.org +Signed-off-by: Max Reitz +Message-id: 20191028161841.1198-2-mreitz@redhat.com +Reviewed-by: Alberto Garcia +Signed-off-by: Max Reitz +(cherry picked from commit 24552feb6ae2f615b76c2b95394af43901f75046) +Signed-off-by: Michael Roth +--- + block/qcow2.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/qcow2.h b/block/qcow2.h +index fc1b0d3c1e..359197f89f 100644 +--- a/block/qcow2.h ++++ b/block/qcow2.h +@@ -77,7 +77,7 @@ + + /* Defined in the qcow2 spec (compressed cluster descriptor) */ + #define QCOW2_COMPRESSED_SECTOR_SIZE 512U +-#define QCOW2_COMPRESSED_SECTOR_MASK (~(QCOW2_COMPRESSED_SECTOR_SIZE - 1)) ++#define QCOW2_COMPRESSED_SECTOR_MASK (~(QCOW2_COMPRESSED_SECTOR_SIZE - 1ULL)) + + /* Must be at least 2 to cover COW */ + #define MIN_L2_CACHE_SIZE 2 /* cache entries */ +-- +2.23.0 diff --git a/qcow2-Fix-corruption-bug-in-qcow2_detect_metadata_pr.patch b/qcow2-Fix-corruption-bug-in-qcow2_detect_metadata_pr.patch new file mode 100644 index 0000000000000000000000000000000000000000..b4c25806d7f7b99408a0419987c22c2175f4fee3 --- /dev/null +++ b/qcow2-Fix-corruption-bug-in-qcow2_detect_metadata_pr.patch @@ -0,0 +1,71 @@ +From 416a692e51b8b582407e30046ddcffbbe52ecf77 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Thu, 24 Oct 2019 16:26:58 +0200 +Subject: [PATCH] qcow2: Fix corruption bug in + qcow2_detect_metadata_preallocation() + +qcow2_detect_metadata_preallocation() calls qcow2_get_refcount() which +requires s->lock to be taken to protect its accesses to the refcount +table and refcount blocks. However, nothing in this code path actually +took the lock. This could cause the same cache entry to be used by two +requests at the same time, for different tables at different offsets, +resulting in image corruption. + +As it would be preferable to base the detection on consistent data (even +though it's just heuristics), let's take the lock not only around the +qcow2_get_refcount() calls, but around the whole function. + +This patch takes the lock in qcow2_co_block_status() earlier and asserts +in qcow2_detect_metadata_preallocation() that we hold the lock. + +Fixes: 69f47505ee66afaa513305de0c1895a224e52c45 +Cc: qemu-stable@nongnu.org +Reported-by: Michael Weiser +Signed-off-by: Kevin Wolf +Tested-by: Michael Weiser +Reviewed-by: Michael Weiser +Reviewed-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Max Reitz +(cherry picked from commit 5e9785505210e2477e590e61b1ab100d0ec22b01) +Signed-off-by: Michael Roth +--- + block/qcow2-refcount.c | 2 ++ + block/qcow2.c | 3 ++- + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c +index ef965d7895..0d64bf5a5e 100644 +--- a/block/qcow2-refcount.c ++++ b/block/qcow2-refcount.c +@@ -3455,6 +3455,8 @@ int qcow2_detect_metadata_preallocation(BlockDriverState *bs) + int64_t i, end_cluster, cluster_count = 0, threshold; + int64_t file_length, real_allocation, real_clusters; + ++ qemu_co_mutex_assert_locked(&s->lock); ++ + file_length = bdrv_getlength(bs->file->bs); + if (file_length < 0) { + return file_length; +diff --git a/block/qcow2.c b/block/qcow2.c +index 865839682c..c0f5439dc8 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -1899,6 +1899,8 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs, + unsigned int bytes; + int status = 0; + ++ qemu_co_mutex_lock(&s->lock); ++ + if (!s->metadata_preallocation_checked) { + ret = qcow2_detect_metadata_preallocation(bs); + s->metadata_preallocation = (ret == 1); +@@ -1906,7 +1908,6 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs, + } + + bytes = MIN(INT_MAX, count); +- qemu_co_mutex_lock(&s->lock); + ret = qcow2_get_cluster_offset(bs, offset, &bytes, &cluster_offset); + qemu_co_mutex_unlock(&s->lock); + if (ret < 0) { +-- +2.23.0 diff --git a/qcow2-Fix-the-calculation-of-the-maximum-L2-cache-si.patch b/qcow2-Fix-the-calculation-of-the-maximum-L2-cache-si.patch new file mode 100644 index 0000000000000000000000000000000000000000..be2c3c72ced8b33f569fabef0c1f01dd382993ef --- /dev/null +++ b/qcow2-Fix-the-calculation-of-the-maximum-L2-cache-si.patch @@ -0,0 +1,58 @@ +From c9ffb12754b1575babfef45168b6e1b1af80a95f Mon Sep 17 00:00:00 2001 +From: Alberto Garcia +Date: Fri, 16 Aug 2019 15:17:42 +0300 +Subject: [PATCH] qcow2: Fix the calculation of the maximum L2 cache size + +The size of the qcow2 L2 cache defaults to 32 MB, which can be easily +larger than the maximum amount of L2 metadata that the image can have. +For example: with 64 KB clusters the user would need a qcow2 image +with a virtual size of 256 GB in order to have 32 MB of L2 metadata. + +Because of that, since commit b749562d9822d14ef69c9eaa5f85903010b86c30 +we forbid the L2 cache to become larger than the maximum amount of L2 +metadata for the image, calculated using this formula: + + uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8); + +The problem with this formula is that the result should be rounded up +to the cluster size because an L2 table on disk always takes one full +cluster. + +For example, a 1280 MB qcow2 image with 64 KB clusters needs exactly +160 KB of L2 metadata, but we need 192 KB on disk (3 clusters) even if +the last 32 KB of those are not going to be used. + +However QEMU rounds the numbers down and only creates 2 cache tables +(128 KB), which is not enough for the image. + +A quick test doing 4KB random writes on a 1280 MB image gives me +around 500 IOPS, while with the correct cache size I get 16K IOPS. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Alberto Garcia +Signed-off-by: Kevin Wolf +(cherry picked from commit b70d08205b2e4044c529eefc21df2c8ab61b473b) +Signed-off-by: Michael Roth +--- + block/qcow2.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/block/qcow2.c b/block/qcow2.c +index 039bdc2f7e..865839682c 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -826,7 +826,11 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, + bool l2_cache_entry_size_set; + int min_refcount_cache = MIN_REFCOUNT_CACHE_SIZE * s->cluster_size; + uint64_t virtual_disk_size = bs->total_sectors * BDRV_SECTOR_SIZE; +- uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8); ++ uint64_t max_l2_entries = DIV_ROUND_UP(virtual_disk_size, s->cluster_size); ++ /* An L2 table is always one cluster in size so the max cache size ++ * should be a multiple of the cluster size. */ ++ uint64_t max_l2_cache = ROUND_UP(max_l2_entries * sizeof(uint64_t), ++ s->cluster_size); + + combined_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_CACHE_SIZE); + l2_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_L2_CACHE_SIZE); +-- +2.23.0 diff --git a/qemu-4.0.1.tar.xz b/qemu-4.1.0.tar.xz similarity index 79% rename from qemu-4.0.1.tar.xz rename to qemu-4.1.0.tar.xz index 703a6c2ff7a99ef107bc55570fc0d52b5e79f0a9..79ad0661eda38092de13a677ef70eeaece3ad848 100644 Binary files a/qemu-4.0.1.tar.xz and b/qemu-4.1.0.tar.xz differ diff --git a/qemu-bridge-helper-move-repeating-code-in-parse_acl.patch b/qemu-bridge-helper-move-repeating-code-in-parse_acl.patch deleted file mode 100644 index 8cd599a13bf7a4e4e2b45ab014cd05809051e4f7..0000000000000000000000000000000000000000 --- a/qemu-bridge-helper-move-repeating-code-in-parse_acl.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 3283dde4b5b5cce0f96f48d536bebff66d97ce0b Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Tue, 23 Jul 2019 16:17:53 +0530 -Subject: [PATCH 2/2] qemu-bridge-helper: move repeating code in parse_acl_file -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Move repeating error handling sequence in parse_acl_file routine -to an 'err' label. - -This patch fixes CVE-2019-13164. - -Signed-off-by: Prasad J Pandit -Reviewed-by: Stefan Hajnoczi -Reviewed-by: Daniel P. Berrangé -Reviewed-by: Li Qiang -Signed-off-by: Jason Wang -(cherry-picked from commit 3283dde4b5b5cce0f96f48d536bebff66d97ce0b) ---- - qemu-bridge-helper.c | 19 +++++++++---------- - 1 file changed, 9 insertions(+), 10 deletions(-) - -diff --git a/qemu-bridge-helper.c b/qemu-bridge-helper.c -index 2058e10454..3d50ec094c 100644 ---- a/qemu-bridge-helper.c -+++ b/qemu-bridge-helper.c -@@ -102,9 +102,7 @@ static int parse_acl_file(const char *filename, ACLList *acl_list) - - if (arg == NULL) { - fprintf(stderr, "Invalid config line:\n %s\n", line); -- fclose(f); -- errno = EINVAL; -- return -1; -+ goto err; - } - - *arg = 0; -@@ -121,9 +119,7 @@ static int parse_acl_file(const char *filename, ACLList *acl_list) - - if (!g_str_equal(cmd, "include") && strlen(arg) >= IFNAMSIZ) { - fprintf(stderr, "name `%s' too long: %zu\n", arg, strlen(arg)); -- fclose(f); -- errno = EINVAL; -- return -1; -+ goto err; - } - - if (strcmp(cmd, "deny") == 0) { -@@ -149,15 +145,18 @@ static int parse_acl_file(const char *filename, ACLList *acl_list) - parse_acl_file(arg, acl_list); - } else { - fprintf(stderr, "Unknown command `%s'\n", cmd); -- fclose(f); -- errno = EINVAL; -- return -1; -+ goto err; - } - } - - fclose(f); -- - return 0; -+ -+err: -+ fclose(f); -+ errno = EINVAL; -+ return -1; -+ - } - - static bool has_vnet_hdr(int fd) --- -2.19.1 - diff --git a/qemu-bridge-helper-restrict-interface-name-to-IFNAMS.patch b/qemu-bridge-helper-restrict-interface-name-to-IFNAMS.patch deleted file mode 100644 index b6dc25e4dfdc9e204c78c545ad5582c52c07dc26..0000000000000000000000000000000000000000 --- a/qemu-bridge-helper-restrict-interface-name-to-IFNAMS.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 6f5d8671225dc77190647f18a27a0d156d4ca97a Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Tue, 23 Jul 2019 16:17:52 +0530 -Subject: [PATCH 1/2] qemu-bridge-helper: restrict interface name to IFNAMSIZ -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The network interface name in Linux is defined to be of size -IFNAMSIZ(=16), including the terminating null('\0') byte. -The same is applied to interface names read from 'bridge.conf' -file to form ACL rules. If user supplied '--br=bridge' name -is not restricted to the same length, it could lead to ACL bypass -issue. Restrict interface name to IFNAMSIZ, including null byte. - -This patch fixes CVE-2019-13164. - -Reported-by: Riccardo Schirone -Signed-off-by: Prasad J Pandit -Reviewed-by: Stefan Hajnoczi -Reviewed-by: Daniel P. Berrangé -Reviewed-by: Li Qiang -Signed-off-by: Jason Wang -(cherry-picked from commit 6f5d8671225dc77190647f18a27a0d156d4ca97a) ---- - qemu-bridge-helper.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/qemu-bridge-helper.c b/qemu-bridge-helper.c -index 95624bc300..2058e10454 100644 ---- a/qemu-bridge-helper.c -+++ b/qemu-bridge-helper.c -@@ -119,6 +119,13 @@ static int parse_acl_file(const char *filename, ACLList *acl_list) - } - *argend = 0; - -+ if (!g_str_equal(cmd, "include") && strlen(arg) >= IFNAMSIZ) { -+ fprintf(stderr, "name `%s' too long: %zu\n", arg, strlen(arg)); -+ fclose(f); -+ errno = EINVAL; -+ return -1; -+ } -+ - if (strcmp(cmd, "deny") == 0) { - acl_rule = g_malloc(sizeof(*acl_rule)); - if (strcmp(arg, "all") == 0) { -@@ -269,6 +276,10 @@ int main(int argc, char **argv) - usage(); - return EXIT_FAILURE; - } -+ if (strlen(bridge) >= IFNAMSIZ) { -+ fprintf(stderr, "name `%s' too long: %zu\n", bridge, strlen(bridge)); -+ return EXIT_FAILURE; -+ } - - /* parse default acl file */ - QSIMPLEQ_INIT(&acl_list); --- -2.19.1 - diff --git a/qemu.spec b/qemu.spec index eb3cc8989b070c63b09c4a33f53e6f507c59dc65..f89933abab68e32fbd2cd34246c2c6fba4d4b781 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,6 +1,6 @@ Name: qemu -Version: 4.0.1 -Release: 11 +Version: 4.1.0 +Release: 19 Epoch: 2 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY @@ -10,57 +10,201 @@ Source1: 80-kvm.rules Source2: 99-qemu-guest-agent.rules Source3: bridge.conf -Patch0001: qxl-check-release-info-object.patch -Patch0002: ARM64-record-vtimer-tick-when-cpu-is-stopped.patch -Patch0003: pl011-reset-read-FIFO-when-UARTTIMSC-0-UARTICR-0xfff.patch -Patch0004: pl031-support-rtc-timer-property-for-pl031.patch -Patch0005: vhost-cancel-migration-when-vhost-user-restarted.patch -Patch0006: qcow2-fix-memory-leak-in-qcow2_read_extensions.patch -Patch0007: hw-arm-expose-host-CPU-frequency-info-to-guest.patch -Patch0008: qemu-bridge-helper-restrict-interface-name-to-IFNAMS.patch -Patch0009: qemu-bridge-helper-move-repeating-code-in-parse_acl.patch -Patch0010: smbios-Add-missing-member-of-type-4-for-smbios-3.0.patch -Patch0011: hw-arm-virt-Introduce-cpu-topology-support.patch -Patch0012: hw-arm64-add-vcpu-cache-info-support.patch -Patch0013: xhci-Fix-memory-leak-in-xhci_address_slot.patch -Patch0014: xhci-Fix-memory-leak-in-xhci_kick_epctx.patch -Patch0015: ehci-fix-queue-dev-null-ptr-dereference.patch -Patch0016: memory-unref-the-memory-region-in-simplify-flatview.patch -Patch0017: util-async-hold-AioContext-ref-to-prevent-use-after-free.patch -Patch0018: vhost-user-scsi-prevent-using-uninitialized-vqs.patch -Patch0019: cpu-add-Kunpeng-920-cpu-support.patch -Patch0020: cpu-parse-feature-to-avoid-failure.patch -Patch0021: cpu-add-Cortex-A72-processor-kvm-target-support.patch -Patch0022: vnc-fix-memory-leak-when-vnc-disconnect.patch -Patch0023: pcie-disable-the-PCI_EXP_LINKSTA_DLLA-cap.patch -Patch0024: linux-headers-update-against-KVM-ARM-Fix-256-vcpus.patch -Patch0025: intc-arm_gic-Support-IRQ-injection-for-more-than-256.patch -Patch0026: ARM-KVM-Check-KVM_CAP_ARM_IRQ_LINE_LAYOUT_2-for-smp_.patch -Patch0027: 9pfs-local-Fix-possible-memory-leak-in-local_link.patch -Patch0028: scsi-disk-define-props-in-scsi_block_disk-to-avoid-memleaks.patch -Patch0029: arm-translate-a64-fix-uninitialized-variable-warning.patch -Patch0030: nbd-fix-uninitialized-variable-warning.patch -Patch0031: xhci-Fix-memory-leak-in-xhci_kick_epctx-when-poweroff.patch -Patch0032: block-fix-memleaks-in-bdrv_refresh_filename.patch -Patch0033: iscsi-Cap-block-count-from-GET-LBA-STATUS-CVE-2020-1.patch -Patch0034: tcp_emu-Fix-oob-access.patch -Patch0035: slirp-use-correct-size-while-emulating-IRC-commands.patch -Patch0036: slirp-use-correct-size-while-emulating-commands.patch -Patch0037: tcp_emu-fix-unsafe-snprintf-usages.patch -Patch0038: block-iscsi-use-MIN-between-mx_sb_len-and-sb_len_wr.patch -Patch0039: monitor-fix-memory-leak-in-monitor_fdset_dup_fd_find.patch +Patch0001: pl011-reset-read-FIFO-when-UARTTIMSC-0-UARTICR-0xfff.patch +Patch0002: pl031-support-rtc-timer-property-for-pl031.patch +Patch0003: vhost-cancel-migration-when-vhost-user-restarted.patch +Patch0004: qcow2-fix-memory-leak-in-qcow2_read_extensions.patch +Patch0005: bios-tables-test-prepare-to-change-ARM-virt-ACPI-DSDT.patch +Patch0006: hw-arm-expose-host-CPU-frequency-info-to-guest.patch +Patch0007: smbios-Add-missing-member-of-type-4-for-smbios-3.0.patch +Patch0008: tests-bios-tables-test-disable-this-testcase.patch +Patch0009: hw-arm-virt-Introduce-cpu-topology-support.patch +Patch0010: hw-arm64-add-vcpu-cache-info-support.patch +Patch0011: xhci-Fix-memory-leak-in-xhci_address_slot.patch +Patch0012: xhci-Fix-memory-leak-in-xhci_kick_epctx.patch +Patch0013: ehci-fix-queue-dev-null-ptr-dereference.patch +Patch0014: util-async-hold-AioContext-ref-to-prevent-use-after-free.patch +Patch0015: vhost-user-scsi-prevent-using-uninitialized-vqs.patch +Patch0016: cpu-add-Kunpeng-920-cpu-support.patch +Patch0017: cpu-parse-feature-to-avoid-failure.patch +Patch0018: cpu-add-Cortex-A72-processor-kvm-target-support.patch +Patch0019: pcie-disable-the-PCI_EXP_LINKSTA_DLLA-cap.patch +Patch0020: vnc-fix-memory-leak-when-vnc-disconnect.patch +Patch0021: linux-headers-update-against-KVM-ARM-Fix-256-vcpus.patch +Patch0022: intc-arm_gic-Support-IRQ-injection-for-more-than-256.patch +Patch0023: ARM-KVM-Check-KVM_CAP_ARM_IRQ_LINE_LAYOUT_2-for-smp.patch +Patch0024: 9pfs-local-Fix-possible-memory-leak-in-local_link.patch +Patch0025: scsi-disk-define-props-in-scsi_block_disk-to-avoid-memleaks.patch +Patch0026: arm-translate-a64-fix-uninitialized-variable-warning.patch +Patch0027: nbd-fix-uninitialized-variable-warning.patch +Patch0028: xhci-Fix-memory-leak-in-xhci_kick_epctx-when-poweroff.patch +Patch0029: block-fix-memleaks-in-bdrv_refresh_filename.patch +Patch0030: iscsi-Cap-block-count-from-GET-LBA-STATUS-CVE-2020-1.patch +Patch0031: tcp_emu-Fix-oob-access.patch +Patch0032: slirp-use-correct-size-while-emulating-IRC-commands.patch +Patch0033: slirp-use-correct-size-while-emulating-commands.patch +Patch0034: util-add-slirp_fmt-helpers.patch +Patch0035: tcp_emu-fix-unsafe-snprintf-usages.patch +Patch0036: block-iscsi-use-MIN-between-mx_sb_len-and-sb_len_wr.patch +Patch0037: monitor-fix-memory-leak-in-monitor_fdset_dup_fd_find.patch +Patch0038: memory-Align-MemoryRegionSections-fields.patch +Patch0039: memory-Provide-an-equality-function-for-MemoryRegion.patch Patch0040: vhost-Fix-memory-region-section-comparison.patch -Patch0041: memory-Align-MemoryRegionSections-fields.patch -Patch0042: memory-Provide-an-equality-function-for-MemoryRegion.patch -Patch0043: file-posix-Handle-undetectable-alignment.patch -Patch0044: block-backup-fix-max_transfer-handling-for-copy_rang.patch -Patch0045: block-backup-fix-backup_cow_with_offload-for-last-cl.patch -Patch0046: qcow2-Limit-total-allocation-range-to-INT_MAX.patch -Patch0047: mirror-Do-not-dereference-invalid-pointers.patch -Patch0048: COLO-compare-Fix-incorrect-if-logic.patch -Patch0049: qcow2-bitmap-Fix-uint64_t-left-shift-overflow.patch -Patch0050: pcie-Add-pcie-root-port-fast-plug-unplug-feature.patch -Patch0051: pcie-Compat-with-devices-which-do-not-support-Link-W.patch +Patch0041: file-posix-Handle-undetectable-alignment.patch +Patch0042: block-backup-fix-max_transfer-handling-for-copy_rang.patch +Patch0043: block-backup-fix-backup_cow_with_offload-for-last-cl.patch +Patch0044: qcow2-Limit-total-allocation-range-to-INT_MAX.patch +Patch0045: mirror-Do-not-dereference-invalid-pointers.patch +Patch0046: COLO-compare-Fix-incorrect-if-logic.patch +Patch0047: qcow2-bitmap-Fix-uint64_t-left-shift-overflow.patch +Patch0048: pcie-Add-pcie-root-port-fast-plug-unplug-feature.patch +Patch0049: pcie-Compat-with-devices-which-do-not-support-Link-W.patch +Patch0050: aio-wait-delegate-polling-of-main-AioContext-if-BQL-not-held.patch +Patch0051: async-use-explicit-memory-barriers.patch +Patch0052: dma-helpers-ensure-AIO-callback-is-invoked-after-can.patch +Patch0053: Revert-ide-ahci-Check-for-ECANCELED-in-aio-callbacks.patch +Patch0054: pc-Don-t-make-die-id-mandatory-unless-necessary.patch +Patch0055: block-file-posix-Reduce-xfsctl-use.patch +Patch0056: pr-manager-Fix-invalid-g_free-crash-bug.patch +Patch0057: x86-do-not-advertise-die-id-in-query-hotpluggbale-cp.patch +Patch0058: vpc-Return-0-from-vpc_co_create-on-success.patch +Patch0059: target-arm-Free-TCG-temps-in-trans_VMOV_64_sp.patch +Patch0060: target-arm-Don-t-abort-on-M-profile-exception-return.patch +Patch0061: libvhost-user-fix-SLAVE_SEND_FD-handling.patch +Patch0062: qcow2-Fix-the-calculation-of-the-maximum-L2-cache-si.patch +Patch0063: block-nfs-tear-down-aio-before-nfs_close.patch +Patch0064: blockjob-update-nodes-head-while-removing-all-bdrv.patch +Patch0065: block-qcow2-Fix-corruption-introduced-by-commit-8ac0.patch +Patch0066: coroutine-Add-qemu_co_mutex_assert_locked.patch +Patch0067: qcow2-Fix-corruption-bug-in-qcow2_detect_metadata_pr.patch +Patch0068: hw-arm-boot.c-Set-NSACR.-CP11-CP10-for-NS-kernel-boo.patch +Patch0069: make-release-pull-in-edk2-submodules-so-we-can-build.patch +Patch0070: roms-Makefile.edk2-don-t-pull-in-submodules-when-bui.patch +Patch0071: block-snapshot-Restrict-set-of-snapshot-nodes.patch +Patch0072: vhost-user-save-features-if-the-char-dev-is-closed.patch +Patch0073: hw-core-loader-Fix-possible-crash-in-rom_copy.patch +Patch0074: ui-Fix-hanging-up-Cocoa-display-on-macOS-10.15-Catal.patch +Patch0075: virtio-new-post_load-hook.patch +Patch0076: virtio-net-prevent-offloads-reset-on-migration.patch +Patch0077: util-hbitmap-strict-hbitmap_reset.patch +Patch0078: hbitmap-handle-set-reset-with-zero-length.patch +Patch0079: target-arm-Allow-reading-flags-from-FPSCR-for-M-prof.patch +Patch0080: scsi-lsi-exit-infinite-loop-while-executing-script-C.patch +Patch0081: virtio-blk-Cancel-the-pending-BH-when-the-dataplane-.patch +Patch0082: qcow2-Fix-QCOW2_COMPRESSED_SECTOR_MASK.patch +Patch0083: util-iov-introduce-qemu_iovec_init_extended.patch +Patch0084: util-iov-improve-qemu_iovec_is_zero.patch +Patch0085: block-io-refactor-padding.patch +Patch0086: block-Make-wait-mark-serialising-requests-public.patch +Patch0087: block-Add-bdrv_co_get_self_request.patch +Patch0088: block-file-posix-Let-post-EOF-fallocate-serialize.patch +Patch0089: block-posix-Always-allocate-the-first-block.patch +Patch0090: block-create-Do-not-abort-if-a-block-driver-is-not-a.patch +Patch0091: mirror-Keep-mirror_top_bs-drained-after-dropping-per.patch +Patch0092: target-arm-kvm-trivial-Clean-up-header-documentation.patch +Patch0093: target-arm-kvm64-kvm64-cpus-have-timer-registers.patch +Patch0094: target-arm-kvm-Implement-virtual-time-adjustment.patch +Patch0095: target-arm-cpu-Add-the-kvm-no-adjvtime-CPU-property.patch +Patch0096: hw-acpi-Make-ACPI-IO-address-space-configurable.patch +Patch0097: hw-acpi-Do-not-create-memory-hotplug-method-when-han.patch +Patch0098: hw-acpi-Add-ACPI-Generic-Event-Device-Support.patch +Patch0099: hw-arm-virt-Add-memory-hotplug-framework.patch +Patch0100: hw-arm-virt-Enable-device-memory-cold-hot-plug-with-.patch +Patch0101: hw-arm-virt-acpi-build-Add-PC-DIMM-in-SRAT.patch +Patch0102: hw-arm-Factor-out-powerdown-notifier-from-GPIO.patch +Patch0103: hw-arm-Use-GED-for-system_powerdown-event.patch +Patch0104: docs-specs-Add-ACPI-GED-documentation.patch +Patch0105: tests-Update-ACPI-tables-list-for-upcoming-arm-virt-.patch +Patch0106: tests-acpi-add-empty-files.patch +Patch0107: tests-allow-empty-expected-files.patch +Patch0108: tests-Add-bios-tests-to-arm-virt.patch +Patch0109: tests-document-how-to-update-acpi-tables.patch +Patch0110: hw-arm-virt-Simplify-by-moving-the-gic-in-the-machin.patch +Patch0111: bugfix-Use-gicr_typer-in-arm_gicv3_icc_reset.patch +Patch0112: Typo-Correct-the-name-of-CPU-hotplug-memory-region.patch +Patch0113: acpi-madt-Factor-out-the-building-of-MADT-GICC-struc.patch +Patch0114: acpi-ged-Add-virt_madt_cpu_entry-to-madt_cpu-hook.patch +Patch0115: arm-virt-acpi-Factor-out-CPPC-building-from-DSDT-CPU.patch +Patch0116: acpi-cpu-Prepare-build_cpus_aml-for-arm-virt.patch +Patch0117: acpi-ged-Extend-ACPI-GED-to-support-CPU-hotplug.patch +Patch0118: arm-cpu-assign-arm_get_arch_id-handler-to-get_arch_i.patch +Patch0119: arm-virt-Attach-ACPI-CPU-hotplug-support-to-virt.patch +Patch0120: arm-virt-Add-CPU-hotplug-framework.patch +Patch0121: arm-virt-Add-CPU-topology-support.patch +Patch0122: test-numa-Adjust-aarch64-numa-test.patch +Patch0123: hw-arm-virt-Factor-out-some-CPU-init-codes-to-pre_pl.patch +Patch0124: hw-arm-boot-Add-manually-register-and-trigger-of-CPU.patch +Patch0125: arm-virt-gic-Construct-irqs-connection-from-create_g.patch +Patch0126: intc-gicv3_common-Factor-out-arm_gicv3_common_cpu_re.patch +Patch0127: intc-gicv3_cpuif-Factor-out-gicv3_init_one_cpuif.patch +Patch0128: intc-kvm_gicv3-Factor-out-kvm_arm_gicv3_cpu_realize.patch +Patch0129: hw-intc-gicv3-Add-CPU-hotplug-realize-hook.patch +Patch0130: accel-kvm-Add-pre-park-vCPU-support.patch +Patch0131: intc-gicv3-Add-pre-sizing-capability-to-GICv3.patch +Patch0132: acpi-madt-Add-pre-sizing-capability-to-MADT-GICC-str.patch +Patch0133: arm-virt-Add-cpu_hotplug_enabled-field.patch +Patch0134: arm-virt-acpi-Extend-cpufreq-to-support-max_cpus.patch +Patch0135: arm-virt-Pre-sizing-MADT-GICC-PPTT-GICv3-and-Pre-par.patch +Patch0136: arm-virt-Add-some-sanity-checks-in-cpu_pre_plug-hook.patch +Patch0137: arm-virt-Start-up-CPU-hot-plug.patch +Patch0138: migration-always-initialise-ram_counters-for-a-new-m.patch +Patch0139: migration-add-qemu_file_update_transfer-interface.patch +Patch0140: migration-add-speed-limit-for-multifd-migration.patch +Patch0141: migration-update-ram_counters-for-multifd-sync-packe.patch +Patch0142: migration-Make-global-sem_sync-semaphore-by-channel.patch +Patch0143: migration-multifd-fix-nullptr-access-in-terminating-m.patch +Patch0144: migration-Maybe-VM-is-paused-when-migration-is-cance.patch +Patch0145: migration-multifd-fix-potential-wrong-acception-orde.patch +Patch0146: migration-multifd-fix-destroyed-mutex-access-in-term.patch +Patch0147: migration-multifd-fix-nullptr-access-in-multifd_send.patch +Patch0148: vtimer-compat-cross-version-migration-from-v4.0.1.patch +Patch0149: migration-ram-Do-error_free-after-migrate_set_error-.patch +Patch0150: migration-ram-fix-memleaks-in-multifd_new_send_chann.patch +Patch0151: migration-rdma-fix-a-memleak-on-error-path-in-rdma_s.patch +Patch0152: arm-virt-Support-CPU-cold-plug.patch +Patch0153: ide-Fix-incorrect-handling-of-some-PRDTs-in-ide_dma_.patch +Patch0154: ati-vga-Fix-checks-in-ati_2d_blt-to-avoid-crash.patch +Patch0155: slirp-tftp-restrict-relative-path-access.patch +Patch0156: ip_reass-Fix-use-after-free.patch +Patch0157: bt-use-size_t-type-for-length-parameters-instead-of-.patch +Patch0158: log-Add-some-logs-on-VM-runtime-path.patch +Patch0159: Revert-vtimer-compat-cross-version-migration-from-v4.patch +Patch0160: ARM64-record-vtimer-tick-when-cpu-is-stopped.patch +Patch0161: hw-arm-virt-add-missing-compat-for-kvm-no-adjvtime.patch +Patch0162: migration-Compat-virtual-timer-adjust-for-v4.0.1-and.patch +Patch0163: vtimer-Drop-vtimer-virtual-timer-adjust.patch +Patch0164: target-arm-Add-the-kvm_adjvtime-vcpu-property-for-Co.patch +Patch0165: target-arm-Fix-PAuth-sbox-functions.patch +Patch0166: tests-Disalbe-filemonitor-testcase.patch +Patch0167: es1370-check-total-frame-count-against-current-frame.patch +Patch0168: exec-set-map-length-to-zero-when-returning-NULL.patch +Patch0169: ati-vga-check-mm_index-before-recursive-call-CVE-202.patch +Patch0170: megasas-use-unsigned-type-for-reply_queue_head-and-c.patch +Patch0171: megasas-avoid-NULL-pointer-dereference.patch +Patch0172: megasas-use-unsigned-type-for-positive-numeric-field.patch +Patch0173: hw-scsi-megasas-Fix-possible-out-of-bounds-array-acc.patch +Patch0174: hw-arm-acpi-enable-SHPC-native-hot-plug.patch +Patch0175: hw-tpm-rename-Error-parameter-to-more-common-errp.patch +Patch0176: tpm-ppi-page-align-PPI-RAM.patch +Patch0177: tpm-Move-tpm_tis_show_buffer-to-tpm_util.c.patch +Patch0178: spapr-Implement-get_dt_compatible-callback.patch +Patch0179: delete-the-in-tpm.txt.patch +Patch0180: tpm_spapr-Support-TPM-for-ppc64-using-CRQ-based-inte.patch +Patch0181: tpm_spapr-Support-suspend-and-resume.patch +Patch0182: hw-ppc-Kconfig-Enable-TPM_SPAPR-as-part-of-PSERIES-c.patch +Patch0183: docs-specs-tpm-reST-ify-TPM-documentation.patch +Patch0184: tpm-rename-TPM_TIS-into-TPM_TIS_ISA.patch +Patch0185: tpm-Use-TPMState-as-a-common-struct.patch +Patch0186: tpm-Separate-tpm_tis-common-functions-from-isa-code.patch +Patch0187: tpm-Separate-TPM_TIS-and-TPM_TIS_ISA-configs.patch +Patch0188: tpm-Add-the-SysBus-TPM-TIS-device.patch +Patch0189: hw-arm-virt-vTPM-support.patch +Patch0190: docs-specs-tpm-Document-TPM_TIS-sysbus-device-for-AR.patch +Patch0191: test-tpm-pass-optional-machine-options-to-swtpm-test.patch +Patch0192: test-tpm-tis-Get-prepared-to-share-tests-between-ISA.patch +Patch0193: test-tpm-tis-Add-Sysbus-TPM-TIS-device-test.patch +Patch0194: build-smt-processor-structure-to-support-smt-topolog.patch +Patch0195: hw-usb-core-fix-buffer-overflow.patch BuildRequires: flex BuildRequires: bison @@ -103,6 +247,7 @@ BuildRequires: libudev-devel BuildRequires: pam-devel BuildRequires: perl-Test-Harness BuildRequires: python3-devel +BuildRequires: librbd-devel %ifarch aarch64 BuildRequires: libfdt-devel BuildRequires: virglrenderer-devel @@ -187,7 +332,6 @@ buildldflags="VL_LDFLAGS=-Wl,--build-id" --with-pkgversion=%{name}-%{version}-%{release} \ --python=/usr/bin/python3 \ --disable-strip \ - --disable-werror \ --disable-slirp \ --enable-gtk \ --enable-docs \ @@ -203,6 +347,7 @@ buildldflags="VL_LDFLAGS=-Wl,--build-id" --enable-linux-aio \ --enable-cap-ng \ --enable-vhost-user \ + --enable-tpm \ %ifarch aarch64 --enable-fdt \ --enable-virglrenderer \ @@ -247,7 +392,9 @@ install -D -m 0644 %{_sourcedir}/99-qemu-guest-agent.rules %{buildroot}%{_udevdi mkdir -p %{buildroot}%{_localstatedir}/log touch %{buildroot}%{_localstatedir}/log/qga-fsfreeze-hook.log +# For qemu docs package %global qemudocdir %{_docdir}/%{name} +rm -rf %{buildroot}%{qemudocdir}/specs install -D -p -m 0644 -t %{buildroot}%{qemudocdir} Changelog README COPYING COPYING.LIB LICENSE chmod -x %{buildroot}%{_mandir}/man1/* @@ -262,6 +409,9 @@ rm -rf %{buildroot}%{_datadir}/%{name}/multiboot.bin rm -rf %{buildroot}%{_datadir}/%{name}/linuxboot_dma.bin rm -rf %{buildroot}%{_datadir}/%{name}/pvh.bin %endif +%ifarch x86_64 +rm -rf %{buildroot}%{_datadir}/%{name}/vgabios-ati.bin +%endif rm -rf %{buildroot}%{_datadir}/%{name}/openbios-* rm -rf %{buildroot}%{_datadir}/%{name}/slof.bin rm -rf %{buildroot}%{_datadir}/%{name}/QEMU,*.bin @@ -277,6 +427,11 @@ rm -rf %{buildroot}%{_datadir}/%{name}/skiboot.lid rm -rf %{buildroot}%{_datadir}/%{name}/spapr-* rm -rf %{buildroot}%{_datadir}/%{name}/u-boot* rm -rf %{buildroot}%{_bindir}/ivshmem* +rm -f %{buildroot}%{_datadir}/%{name}/edk2* +rm -rf %{buildroot}%{_datadir}/%{name}/firmware +rm -rf %{buildroot}%{_datadir}/%{name}/opensbi* +rm -rf %{buildroot}%{_datadir}/%{name}/qemu-nsis.bmp + for f in %{buildroot}%{_bindir}/* %{buildroot}%{_libdir}/* \ %{buildroot}%{_libexecdir}/*; do @@ -396,89 +551,174 @@ getent passwd qemu >/dev/null || \ %endif %changelog -* Wed Mar 18 2020 Huawei Technologies Co., Ltd. +* Fri Aug 21 2020 Huawei Technologies Co., Ltd +- hw/usb/core.c: fix buffer overflow in do_token_setup function + +* Tue Aug 18 2020 Huawei Technologies Co., Ltd +- hw/acpi/aml-build.c: build smt processor structure to support smt topology + +* Thu Aug 13 2020 Huawei Technologies Co., Ltd +-target/arm: Aarch64 support vtpm + +* Wed Aug 12 2020 Huawei Technologies Co., Ltd +- backport upstream patch to support SHPCHotplug in arm + +* Thu Aug 6 2020 Huawei Technologies Co., Ltd +- es1370: check total frame count against current frame +- exec: set map length to zero when returning NULL +- ati-vga: check mm_index before recursive call (CVE-2020-13800) +- megasas: use unsigned type for reply_queue_head and check index +- megasas: avoid NULL pointer dereference +- megasas: use unsigned type for positive numeric fields +- hw/scsi/megasas: Fix possible out-of-bounds array access in tracepoints + +* Thu Aug 6 2020 Huawei Technologies Co., Ltd +- tests: Disalbe filemonitor testcase + +* Sat Jun 20 2020 Huawei Technologies Co., Ltd +- target/arm: Fix PAuth sbox functions +- fix two patches' format which can cause git am failed + +* Fri May 29 2020 Huawei Technologies Co., Ltd +- target/arm: Add the kvm_adjvtime vcpu property for Cortex-A72 + +* Wed May 27 2020 Huawei Technologies Co., Ltd. +- Revert: "vtimer: compat cross version migration from v4.0.1" +- ARM64: record vtimer tick when cpu is stopped +- hw/arm/virt: add missing compat for kvm-no-adjvtime +- migration: Compat virtual timer adjust for v4.0.1 and v4.1.0 +- vtimer: Drop vtimer virtual timer adjust + +* Fri May 22 2020 Huawei Technologies Co., Ltd. +- ip_reass: Fix use after free +- bt: use size_t type for length parameters instead of int +- log: Add some logs on VM runtime path + +* Fri May 15 2020 Huawei Technologies Co., Ltd. +- ide: Fix incorrect handling of some PRDTs in ide_dma_cb() +- ati-vga: Fix checks in ati_2d_blt() to avoid crash +- slirp: tftp: restrict relative path access + +* Tue May 12 2020 Huawei Technologies Co., Ltd. +- arm/virt: Support CPU cold plug + +* Sat May 9 2020 Huawei Technologies Co., Ltd. +- migration/ram: do error_free after migrate_set_error to avoid memleaks. +- migration/ram: fix memleaks in multifd_new_send_channel_async. +- migration/rdma: fix a memleak on error path in rdma_start_incoming_migration. + +* Fri May 8 2020 Huawei Technologies Co., Ltd. +- vtimer: compat cross version migration from v4.0.1 + +* Fri Apr 24 2020 Huawei Technologies Co., Ltd. +- migration: backport migration patches from upstream + +* Fri Apr 24 2020 Huawei Technologies Co., Ltd. +- arm/virt: Add CPU hotplug support + +* Wed Apr 22 2020 Huawei Technologies Co., Ltd. +- backport patch to enable arm/virt memory hotplug + +* Wed Apr 22 2020 Huawei Technologies Co., Ltd. +- backport patch to enable target/arm/kvm Adjust virtual time + +* Fri Apr 17 2020 Huawei Technologies Co., Ltd. +- backport patch bundles from qemu stable v4.1.1 + +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- aio-wait: delegate polling of main AioContext if BQL not held +- async: use explicit memory barriers + +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. - pcie: Add pcie-root-port fast plug/unplug feature -- pcie: Compat with devices which do not support Link Width +- pcie: Compat with devices which do not support Link Width, such as ioh3420 -* Tue Mar 17 2020 Huawei Technologies Co., Ltd. -- Put linuxboot_dma.bin and pvh.bin in x86 package +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- qcow2-bitmap: Fix uint64_t left-shift overflow -* Mon Mar 16 2020 backport some bug fix patches from upstream -- Patch from number 0040 to 0049 are picked from stable-4.1.1 +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- COLO-compare: Fix incorrect `if` logic -* Mon Mar 16 2020 Huawei Technologies Co., Ltd. -- moniter: fix memleak in monitor_fdset_dup_fd_find_remove +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- block/backup: fix max_transfer handling for copy_range +- block/backup: fix backup_cow_with_offload for last cluster +- qcow2: Limit total allocation range to INT_MAX +- mirror: Do not dereference invalid pointers + +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- file-posix: Handle undetectable alignment + +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- vhost: Fix memory region section comparison +- memory: Provide an equality function for MemoryRegionSections +- memory: Align MemoryRegionSections fields + +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. - block/iscsi: use MIN() between mx_sb_len and sb_len_wr +- moniter: fix memleak in monitor_fdset_dup_fd_find_remove -* Wed Mar 11 2020 backport from qemu upstream -- tcp_emu: Fix oob access -- slirp: use correct size while emulating IRC commands -- slirp: use correct size while emulating commands +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. - tcp_emu: fix unsafe snprintf() usages - -* Mon Mar 9 2020 backport from qemu upstream +- util: add slirp_fmt() helpers +- slirp: use correct size while emulating commands +- slirp: use correct size while emulating IRC commands +- tcp_emu: Fix oob access - iscsi: Cap block count from GET LBA STATUS (CVE-2020-1711) -* Thu Feb 6 2020 Huawei Technologies Co., Ltd. -- spec: remove fno-inline option for configure - -* Thu Jan 16 2020 Huawei Technologies Co., Ltd. +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- 9pfs: local: Fix possible memory leak in local_link() +- scsi-disk: define props in scsi_block_disk to avoid memleaks +- arm/translate-a64: fix uninitialized variable warning +- block: fix memleaks in bdrv_refresh_filename +- vnc: fix memory leak when vnc disconnect - block: fix memleaks in bdrv_refresh_filename -* Mon Jan 13 2020 Huawei Technologies Co., Ltd. -- 9pfs: Fix a possible memory leak in local_link -- scsi-disk: disk define props in scsi_block to avoid memleaks -- arm/translate-a64: fix uninitialized variable warning -- nbd: fix uninitialized variable warning -- xhci: Fix memory leak in xhci_kick_epctx when poweroff +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- linux headers: update against "KVM/ARM: Fix >256 vcpus" +- intc/arm_gic: Support IRQ injection for more than 256 vcpus +- ARM: KVM: Check KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 for smp_cpus > + +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- vnc: fix memory leak when vnc disconnect -* Mon Jan 6 2020 backport from qemu upstream -- linux headers: update against "KVM/ARM: Fix >256 vcp -- intc/arm_gic: Support IRQ injection for more than 256 vpus -- ARM: KVM: Check KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 for smp_cpus > 256 +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- pcie: disable the PCI_EXP_LINKSTA_DLLA cap for pcie-root-port by default -* Thu Dec 12 2019 backport from qemu upstream v4.0.1 release -- tpm: Exit in reset when backend indicates failure -- tpm_emulator: Translate TPM error codes to strings +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- cpu: add Kunpeng-920 cpu support +- cpu: parse +/- feature to avoid failure +- cpu: add Cortex-A72 processor kvm target support -* Thu Oct 17 2019 backport from qemu upstream -- vnc-fix-memory-leak-when-vnc-disconnect.patch +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- vhost-user-scsi: prevent using uninitialized vqs -* Mon Sep 9 2019 backport from qemu upstream -- ehci-fix-queue-dev-null-ptr-dereference.patch -- memory-unref-the-memory-region-in-simplify-flatview.patch -- util-async-hold-AioContext-ref-to-prevent-use-after-.patch -- vhost-user-scsi-prevent-using-uninitialized-vqs.patch +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- util/async: hold AioContext ref to prevent use-after-free -* Fri Aug 30 2019 Huawei Technologies Co., Ltd. +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. - xhci: Fix memory leak in xhci_address_slot - xhci: Fix memory leak in xhci_kick_epctx +- ehci: fix queue->dev null ptr dereference -* Wed Aug 7 2019 Huawei Technologies Co., Ltd. +* Thu Apr 16 2020 Huawei Technologies Co., Ltd. +- tests/bios-tables-test: disable this testcase - hw/arm/virt: Introduce cpu topology support - hw/arm64: add vcpu cache info support -* Tue Aug 6 2019 Huawei Technologies Co., Ltd. -- Update release version to 4.0.0-2 - -* Mon Aug 5 2019 Huawei Technologies Co., Ltd. -- enable make check +* Wed Apr 15 2020 Huawei Technologies Co., Ltd. - smbios: Add missing member of type 4 for smbios 3.0 -* Mon Aug 5 2019 fix CVE-2019-13164 -- qemu-bridge-helper: restrict interface name to IFNAMSIZ -- qemu-bridge-helper: move repeating code in parse_acl_file +* Wed Apr 15 2020 Huawei Technologies Co., Ltd. +- bios-tables-test: prepare to change ARM virt ACPI DSDT +- arm64: Add the cpufreq device to show cpufreq info to guest -* Tue Jul 30 2019 Huawei Technologies Co., Ltd. - qcow2: fix memory leak in qcow2_read_extensions -- hw/arm: expose host CPU frequency info to guest -* Fri Jul 26 2019 Huawei Technologies Co., Ltd. -- vhost: cancel migration when vhost-user restarted +* Wed Apr 15 2020 Huawei Technologies Co., Ltd. +- pl011: reset read FIFIO when UARTTIMSC=0 & UARTICR=0xff - pl031: support rtc-timer property for pl031 -- pl011: reset read FIFO when UARTTIMSC=0 & UARTICR=0xffff -- ARM64: record vtimer tick when cpu is stopped +- vhost: cancel migration when vhost-user restarted -* Tue Jul 23 2019 openEuler Buildteam - version-release +* Mon Apr 13 2020 openEuler Buildteam - version-release - Package init - diff --git a/qxl-check-release-info-object.patch b/qxl-check-release-info-object.patch deleted file mode 100644 index aeddbe467c34aa83a3c7b8bca6b98b44abf546a6..0000000000000000000000000000000000000000 --- a/qxl-check-release-info-object.patch +++ /dev/null @@ -1,36 +0,0 @@ -From cbed4e0108ca1403f1f47cde292330b87a0d8bf2 Mon Sep 17 00:00:00 2001 -From: Prasad J Pandit -Date: Thu, 25 Apr 2019 12:05:34 +0530 -Subject: [PATCH] qxl: check release info object - -When releasing spice resources in release_resource() routine, -if release info object 'ext.info' is null, it leads to null -pointer dereference. Add check to avoid it. - -(This is cherry-pick d52680fc932efb8a2f334cc6993e705ed1e31e99) - -Reported-by: Bugs SysSec -Signed-off-by: Prasad J Pandit -Message-id: 20190425063534.32747-1-ppandit@redhat.com -Signed-off-by: Gerd Hoffmann ---- - hw/display/qxl.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/hw/display/qxl.c b/hw/display/qxl.c -index c8ce578..632923a 100644 ---- a/hw/display/qxl.c -+++ b/hw/display/qxl.c -@@ -777,6 +777,9 @@ static void interface_release_resource(QXLInstance *sin, - QXLReleaseRing *ring; - uint64_t *item, id; - -+ if (!ext.info) { -+ return; -+ } - if (ext.group_id == MEMSLOT_GROUP_HOST) { - /* host group -> vga mode update request */ - QXLCommandExt *cmdext = (void *)(intptr_t)(ext.info->id); --- -1.8.3.1 - diff --git a/roms-Makefile.edk2-don-t-pull-in-submodules-when-bui.patch b/roms-Makefile.edk2-don-t-pull-in-submodules-when-bui.patch new file mode 100644 index 0000000000000000000000000000000000000000..00e672662ddd5d848fc031967a0efdcf9dc4432b --- /dev/null +++ b/roms-Makefile.edk2-don-t-pull-in-submodules-when-bui.patch @@ -0,0 +1,54 @@ +From fc5afb1a9230fe21d76bcef527b0d3cee90a2cd3 Mon Sep 17 00:00:00 2001 +From: Michael Roth +Date: Thu, 12 Sep 2019 18:12:02 -0500 +Subject: [PATCH] roms/Makefile.edk2: don't pull in submodules when building + from tarball +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently the `make efi` target pulls submodules nested under the +roms/edk2 submodule as dependencies. However, when we attempt to build +from a tarball this fails since we are no longer in a git tree. + +A preceding patch will pre-populate these submodules in the tarball, +so assume this build dependency is only needed when building from a +git tree. + +Cc: Laszlo Ersek +Cc: Bruce Rogers +Cc: qemu-stable@nongnu.org # v4.1.0 +Reported-by: Bruce Rogers +Reviewed-by: Laszlo Ersek +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Philippe Mathieu-Daudé +Signed-off-by: Michael Roth +Message-Id: <20190912231202.12327-3-mdroth@linux.vnet.ibm.com> +Signed-off-by: Philippe Mathieu-Daudé +(cherry picked from commit f3e330e3c319160ac04954399b5a10afc965098c) +Signed-off-by: Michael Roth +--- + roms/Makefile.edk2 | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/roms/Makefile.edk2 b/roms/Makefile.edk2 +index c2f2ff59d5..33a074d3a4 100644 +--- a/roms/Makefile.edk2 ++++ b/roms/Makefile.edk2 +@@ -46,8 +46,13 @@ all: $(foreach flashdev,$(flashdevs),../pc-bios/edk2-$(flashdev).fd.bz2) \ + # files. + .INTERMEDIATE: $(foreach flashdev,$(flashdevs),../pc-bios/edk2-$(flashdev).fd) + ++# Fetch edk2 submodule's submodules. If it is not in a git tree, assume ++# we're building from a tarball and that they've already been fetched by ++# make-release/tarball scripts. + submodules: +- cd edk2 && git submodule update --init --force ++ if test -d edk2/.git; then \ ++ cd edk2 && git submodule update --init --force; \ ++ fi + + # See notes on the ".NOTPARALLEL" target and the "+" indicator in + # "tests/uefi-test-tools/Makefile". +-- +2.23.0 diff --git a/scsi-lsi-exit-infinite-loop-while-executing-script-C.patch b/scsi-lsi-exit-infinite-loop-while-executing-script-C.patch new file mode 100644 index 0000000000000000000000000000000000000000..5d20a9f009c9bd52f9eef578344c5b0012ee8942 --- /dev/null +++ b/scsi-lsi-exit-infinite-loop-while-executing-script-C.patch @@ -0,0 +1,104 @@ +From 051c9b3cbcb4beb42a6ed017c2146ec3e7a754fb Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 14 Aug 2019 17:35:21 +0530 +Subject: [PATCH] scsi: lsi: exit infinite loop while executing script + (CVE-2019-12068) + +When executing script in lsi_execute_script(), the LSI scsi adapter +emulator advances 's->dsp' index to read next opcode. This can lead +to an infinite loop if the next opcode is empty. Move the existing +loop exit after 10k iterations so that it covers no-op opcodes as +well. + +Reported-by: Bugs SysSec +Signed-off-by: Paolo Bonzini +Signed-off-by: Prasad J Pandit +Signed-off-by: Paolo Bonzini +(cherry picked from commit de594e47659029316bbf9391efb79da0a1a08e08) +Signed-off-by: Michael Roth +--- + hw/scsi/lsi53c895a.c | 41 +++++++++++++++++++++++++++-------------- + 1 file changed, 27 insertions(+), 14 deletions(-) + +diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c +index 10468c1ec1..72f7b59ab5 100644 +--- a/hw/scsi/lsi53c895a.c ++++ b/hw/scsi/lsi53c895a.c +@@ -185,6 +185,9 @@ static const char *names[] = { + /* Flag set if this is a tagged command. */ + #define LSI_TAG_VALID (1 << 16) + ++/* Maximum instructions to process. */ ++#define LSI_MAX_INSN 10000 ++ + typedef struct lsi_request { + SCSIRequest *req; + uint32_t tag; +@@ -1132,7 +1135,21 @@ static void lsi_execute_script(LSIState *s) + + s->istat1 |= LSI_ISTAT1_SRUN; + again: +- insn_processed++; ++ if (++insn_processed > LSI_MAX_INSN) { ++ /* Some windows drivers make the device spin waiting for a memory ++ location to change. If we have been executed a lot of code then ++ assume this is the case and force an unexpected device disconnect. ++ This is apparently sufficient to beat the drivers into submission. ++ */ ++ if (!(s->sien0 & LSI_SIST0_UDC)) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "lsi_scsi: inf. loop with UDC masked"); ++ } ++ lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0); ++ lsi_disconnect(s); ++ trace_lsi_execute_script_stop(); ++ return; ++ } + insn = read_dword(s, s->dsp); + if (!insn) { + /* If we receive an empty opcode increment the DSP by 4 bytes +@@ -1569,19 +1586,7 @@ again: + } + } + } +- if (insn_processed > 10000 && s->waiting == LSI_NOWAIT) { +- /* Some windows drivers make the device spin waiting for a memory +- location to change. If we have been executed a lot of code then +- assume this is the case and force an unexpected device disconnect. +- This is apparently sufficient to beat the drivers into submission. +- */ +- if (!(s->sien0 & LSI_SIST0_UDC)) { +- qemu_log_mask(LOG_GUEST_ERROR, +- "lsi_scsi: inf. loop with UDC masked"); +- } +- lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0); +- lsi_disconnect(s); +- } else if (s->istat1 & LSI_ISTAT1_SRUN && s->waiting == LSI_NOWAIT) { ++ if (s->istat1 & LSI_ISTAT1_SRUN && s->waiting == LSI_NOWAIT) { + if (s->dcntl & LSI_DCNTL_SSM) { + lsi_script_dma_interrupt(s, LSI_DSTAT_SSI); + } else { +@@ -1969,6 +1974,10 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) + case 0x2f: /* DSP[24:31] */ + s->dsp &= 0x00ffffff; + s->dsp |= val << 24; ++ /* ++ * FIXME: if s->waiting != LSI_NOWAIT, this will only execute one ++ * instruction. Is this correct? ++ */ + if ((s->dmode & LSI_DMODE_MAN) == 0 + && (s->istat1 & LSI_ISTAT1_SRUN) == 0) + lsi_execute_script(s); +@@ -1987,6 +1996,10 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) + break; + case 0x3b: /* DCNTL */ + s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD); ++ /* ++ * FIXME: if s->waiting != LSI_NOWAIT, this will only execute one ++ * instruction. Is this correct? ++ */ + if ((val & LSI_DCNTL_STD) && (s->istat1 & LSI_ISTAT1_SRUN) == 0) + lsi_execute_script(s); + break; +-- +2.23.0 diff --git a/slirp-tftp-restrict-relative-path-access.patch b/slirp-tftp-restrict-relative-path-access.patch new file mode 100644 index 0000000000000000000000000000000000000000..b7f09462525437c9048b4ab249b6e4208adda4ef --- /dev/null +++ b/slirp-tftp-restrict-relative-path-access.patch @@ -0,0 +1,37 @@ +From 2fc07f4ce31a2cc9973cfb1c20897c6a4babd8b8 Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit +Date: Fri, 15 May 2020 16:45:28 +0800 +Subject: [PATCH] slirp: tftp: restrict relative path access + +tftp restricts relative or directory path access on Linux systems. +Apply same restrictions on Windows systems too. It helps to avoid +directory traversal issue. + +Fixes: https://bugs.launchpad.net/qemu/+bug/1812451Reported-by: default avatarPeter Maydell +Signed-off-by: default avatarPrasad J Pandit +Reviewed-by: Samuel Thibault's avatarSamuel Thibault +Message-Id: <20200113121431.156708-1-ppandit@redhat.com> + +diff --git a/slirp/src/tftp.c b/slirp/src/tftp.c +index 093c2e06..2b4176cc 100644 +--- a/slirp/src/tftp.c ++++ b/slirp/src/tftp.c +@@ -344,8 +344,13 @@ static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas, + k += 6; /* skipping octet */ + + /* do sanity checks on the filename */ +- if (!strncmp(req_fname, "../", 3) || +- req_fname[strlen(req_fname) - 1] == '/' || strstr(req_fname, "/../")) { ++ if ( ++#ifdef G_OS_WIN32 ++ strstr(req_fname, "..\\") || ++ req_fname[strlen(req_fname) - 1] == '\\' || ++#endif ++ strstr(req_fname, "../") || ++ req_fname[strlen(req_fname) -1] == '/') { + tftp_send_error(spt, 2, "Access violation", tp); + return; + } +-- +2.23.0 + diff --git a/slirp-use-correct-size-while-emulating-IRC-commands.patch b/slirp-use-correct-size-while-emulating-IRC-commands.patch index 4503688dd1502c85f7a8e0fee1e5a36bcca838b2..1b4039e1da3c0bcd08b97f4c61983ef3adac3823 100644 --- a/slirp-use-correct-size-while-emulating-IRC-commands.patch +++ b/slirp-use-correct-size-while-emulating-IRC-commands.patch @@ -1,6 +1,6 @@ -From 882149fd8401f8ff667ea384bb68008354fd110f Mon Sep 17 00:00:00 2001 +From 011880f527ff317a40769ea8673a6353e5db53ac Mon Sep 17 00:00:00 2001 From: Prasad J Pandit -Date: Wed, 11 Mar 2020 18:19:36 +0800 +Date: Tue, 14 Apr 2020 18:23:23 +0800 Subject: [PATCH] slirp: use correct size while emulating IRC commands While emulating IRC DCC commands, tcp_emu() uses 'mbuf' size @@ -13,40 +13,42 @@ Signed-off-by: default avatarPrasad J Pandit Reviewed-by: Samuel Thibault's avatarSamuel Thibault Message-Id: <20200109094228.79764-2-ppandit@redhat.com> --- - slirp/src/tcp_subr.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) + slirp/src/tcp_subr.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/slirp/src/tcp_subr.c b/slirp/src/tcp_subr.c -index 4608942f..2053b11b 100644 +index 9c94c03a..2a15b16a 100644 --- a/slirp/src/tcp_subr.c +++ b/slirp/src/tcp_subr.c -@@ -786,7 +786,7 @@ tcp_emu(struct socket *so, struct mbuf *m) - return 1; - } - m->m_len = bptr - m->m_data; /* Adjust length */ -- m->m_len += snprintf(bptr, m->m_size, -+ m->m_len += snprintf(bptr, M_FREEROOM(m), - "DCC CHAT chat %lu %u%c\n", - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), 1); -@@ -797,7 +797,7 @@ tcp_emu(struct socket *so, struct mbuf *m) - return 1; - } - m->m_len = bptr - m->m_data; /* Adjust length */ -- m->m_len += snprintf(bptr, m->m_size, -+ m->m_len += snprintf(bptr, M_FREEROOM(m), - "DCC SEND %s %lu %u %u%c\n", buff, - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), n1, 1); -@@ -808,7 +808,7 @@ tcp_emu(struct socket *so, struct mbuf *m) - return 1; - } - m->m_len = bptr - m->m_data; /* Adjust length */ -- m->m_len += snprintf(bptr, m->m_size, -+ m->m_len += snprintf(bptr, M_FREEROOM(m), - "DCC MOVE %s %lu %u %u%c\n", buff, - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), n1, 1); --- -2.21.1 (Apple Git-122.3) - +@@ -778,7 +778,8 @@ int tcp_emu(struct socket *so, struct mbuf *m) + return 1; + } + m->m_len = bptr - m->m_data; /* Adjust length */ +- m->m_len += snprintf(bptr, m->m_size, "DCC CHAT chat %lu %u%c\n", ++ m->m_len += snprintf(bptr, M_FREEROOM(m), ++ "DCC CHAT chat %lu %u%c\n", + (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), 1); + } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, +@@ -789,7 +790,8 @@ int tcp_emu(struct socket *so, struct mbuf *m) + } + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += +- snprintf(bptr, m->m_size, "DCC SEND %s %lu %u %u%c\n", buff, ++ snprintf(bptr, M_FREEROOM(m), ++ "DCC SEND %s %lu %u %u%c\n", buff, + (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), n1, 1); + } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, +@@ -800,7 +802,8 @@ int tcp_emu(struct socket *so, struct mbuf *m) + } + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += +- snprintf(bptr, m->m_size, "DCC MOVE %s %lu %u %u%c\n", buff, ++ snprintf(bptr, M_FREEROOM(m), ++ "DCC MOVE %s %lu %u %u%c\n", buff, + (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), n1, 1); + } +-- +2.23.0 diff --git a/slirp-use-correct-size-while-emulating-commands.patch b/slirp-use-correct-size-while-emulating-commands.patch index 76507a4d82f3c769540cf34294d855242ac0737f..25f64e2738e2ae3cbff541719b726dff963007d2 100644 --- a/slirp-use-correct-size-while-emulating-commands.patch +++ b/slirp-use-correct-size-while-emulating-commands.patch @@ -1,6 +1,6 @@ -From 66e2f47a01ffcaafe11acae0a191efd1805f86c6 Mon Sep 17 00:00:00 2001 +From 662aa4f1d168b32335a4dc40782e816329afcac0 Mon Sep 17 00:00:00 2001 From: Prasad J Pandit -Date: Wed, 11 Mar 2020 18:27:22 +0800 +Date: Tue, 14 Apr 2020 18:36:12 +0800 Subject: [PATCH] slirp: use correct size while emulating commands While emulating services in tcp_emu(), it uses 'mbuf' size @@ -10,42 +10,40 @@ Signed-off-by: default avatarPrasad J Pandit Signed-off-by: Samuel Thibault's avatarSamuel Thibault Message-Id: <20200109094228.79764-3-ppandit@redhat.com> --- - slirp/src/tcp_subr.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) + slirp/src/tcp_subr.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/slirp/src/tcp_subr.c b/slirp/src/tcp_subr.c -index 2053b11b..e898fd03 100644 +index 2a15b16a..019b637a 100644 --- a/slirp/src/tcp_subr.c +++ b/slirp/src/tcp_subr.c -@@ -707,7 +707,7 @@ tcp_emu(struct socket *so, struct mbuf *m) - n4 = (laddr & 0xff); - - m->m_len = bptr - m->m_data; /* Adjust length */ -- m->m_len += snprintf(bptr, m->m_size - m->m_len, -+ m->m_len += snprintf(bptr, M_FREEROOM(m), - "ORT %d,%d,%d,%d,%d,%d\r\n%s", - n1, n2, n3, n4, n5, n6, x==7?buff:""); - return 1; -@@ -740,7 +740,7 @@ tcp_emu(struct socket *so, struct mbuf *m) - n4 = (laddr & 0xff); - - m->m_len = bptr - m->m_data; /* Adjust length */ -- m->m_len += snprintf(bptr, m->m_size - m->m_len, -+ m->m_len += snprintf(bptr, M_FREEROOM(m), - "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", - n1, n2, n3, n4, n5, n6, x==7?buff:""); - -@@ -766,8 +766,8 @@ tcp_emu(struct socket *so, struct mbuf *m) - if (m->m_data[m->m_len-1] == '\0' && lport != 0 && - (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr, - htons(lport), SS_FACCEPTONCE)) != NULL) -- m->m_len = snprintf(m->m_data, m->m_size, "%d", -- ntohs(so->so_fport)) + 1; -+ m->m_len = snprintf(m->m_data, M_ROOM(m), -+ "%d", ntohs(so->so_fport)) + 1; - return 1; - - case EMU_IRC: --- -2.21.1 (Apple Git-122.3) +@@ -696,7 +696,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) + n4 = (laddr & 0xff); + m->m_len = bptr - m->m_data; /* Adjust length */ +- m->m_len += snprintf(bptr, m->m_size - m->m_len, ++ m->m_len += snprintf(bptr, M_FREEROOM(m), + "ORT %d,%d,%d,%d,%d,%d\r\n%s", n1, n2, n3, n4, + n5, n6, x == 7 ? buff : ""); + return 1; +@@ -732,7 +732,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += +- snprintf(bptr, m->m_size - m->m_len, ++ snprintf(bptr, M_FREEROOM(m), + "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", + n1, n2, n3, n4, n5, n6, x == 7 ? buff : ""); + +@@ -759,7 +759,8 @@ int tcp_emu(struct socket *so, struct mbuf *m) + (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr, + htons(lport), SS_FACCEPTONCE)) != NULL) + m->m_len = +- snprintf(m->m_data, m->m_size, "%d", ntohs(so->so_fport)) + 1; ++ snprintf(m->m_data, M_ROOM(m), ++ "%d", ntohs(so->so_fport)) + 1; + return 1; + + case EMU_IRC: +-- +2.23.0 diff --git a/smbios-Add-missing-member-of-type-4-for-smbios-3.0.patch b/smbios-Add-missing-member-of-type-4-for-smbios-3.0.patch index c45af3e6aa3ba4b5c58583f5605c7a6b9f90e508..cfd1842d3f199ec1db6e324e448df37b4553ea2a 100644 --- a/smbios-Add-missing-member-of-type-4-for-smbios-3.0.patch +++ b/smbios-Add-missing-member-of-type-4-for-smbios-3.0.patch @@ -1,21 +1,19 @@ -From e52fdbd850b49304c5bbd5f19c9f518b80efef42 Mon Sep 17 00:00:00 2001 -From: zhanghailiang -Date: Wed, 31 Jul 2019 15:40:55 +0800 +From 2b8ad77678da175cb92c902955cb85827e661de3 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Tue, 14 Apr 2020 14:53:44 +0800 Subject: [PATCH] smbios: Add missing member of type 4 for smbios 3.0 According to smbios 3.0 spec, for processor information (type 4), -it adds three new members (Core Count 2, Core enabled 2, thread count 2) for 3.0, - -Without this three members, we can not get correct cpu frequency from dmi, +it adds three new members (Core Count 2, Core enabled 2, thread count 2) for 3.0, Without this three members, we can not get correct cpu frequency from dmi, Because it will failed to check the length of Processor Infomation in DMI. The corresponding codes in kernel is like: - if (dm->type == DMI_ENTRY_PROCESSOR && - dm->length >= DMI_ENTRY_PROCESSOR_MIN_LENGTH) { - u16 val = (u16)get_unaligned((const u16 *) - (dmi_data + DMI_PROCESSOR_MAX_SPEED)); - *mhz = val > *mhz ? val : *mhz; - } + if (dm->type == DMI_ENTRY_PROCESSOR && + dm->length >= DMI_ENTRY_PROCESSOR_MIN_LENGTH) { + u16 val = (u16)get_unaligned((const u16 *) + (dmi_data + DMI_PROCESSOR_MAX_SPEED)); + *mhz = val > *mhz ? val : *mhz; + } Signed-off-by: zhanghailiang --- @@ -24,11 +22,11 @@ Signed-off-by: zhanghailiang 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c -index 47be9071..b11ec6e3 100644 +index 7bcd67b0..51b00d44 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c -@@ -600,7 +600,9 @@ static void smbios_build_type_4_table(unsigned instance) - t->thread_count = smp_threads; +@@ -603,7 +603,9 @@ static void smbios_build_type_4_table(MachineState *ms, unsigned instance) + t->thread_count = ms->smp.threads; t->processor_characteristics = cpu_to_le16(0x02); /* Unknown */ t->processor_family2 = cpu_to_le16(0x01); /* Other */ - @@ -39,7 +37,7 @@ index 47be9071..b11ec6e3 100644 smbios_type4_count++; } diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h -index 6fef32a3..70eb7304 100644 +index 02a0ced0..6887bca4 100644 --- a/include/hw/firmware/smbios.h +++ b/include/hw/firmware/smbios.h @@ -193,6 +193,9 @@ struct smbios_type_4 { @@ -50,8 +48,7 @@ index 6fef32a3..70eb7304 100644 + uint16_t enabledcorecount2; + uint16_t threadcount2; } QEMU_PACKED; - - /* SMBIOS type 11 - OEM strings */ --- -2.19.1 + /* SMBIOS type 11 - OEM strings */ +-- +2.23.0 diff --git a/spapr-Implement-get_dt_compatible-callback.patch b/spapr-Implement-get_dt_compatible-callback.patch new file mode 100644 index 0000000000000000000000000000000000000000..e64a8746f498a68085824f6cace1bb2e958ce7c7 --- /dev/null +++ b/spapr-Implement-get_dt_compatible-callback.patch @@ -0,0 +1,68 @@ +From c520d8e823431be94268daa2a911e224cab81521 Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 21 Jan 2020 10:29:31 -0500 +Subject: [PATCH 04/19] spapr: Implement get_dt_compatible() callback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +For devices that cannot be statically initialized, implement a +get_dt_compatible() callback that allows us to ask the device for +the 'compatible' value. + +Signed-off-by: Stefan Berger +Reviewed-by: Marc-André Lureau +Reviewed-by: David Gibson +Message-Id: <20200121152935.649898-3-stefanb@linux.ibm.com> +Signed-off-by: David Gibson +Signed-off-by: jiangfangjie +--- + hw/ppc/spapr_vio.c | 11 +++++++++-- + include/hw/ppc/spapr_vio.h | 1 + + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c +index 583c13de..4e50916f 100644 +--- a/hw/ppc/spapr_vio.c ++++ b/hw/ppc/spapr_vio.c +@@ -89,6 +89,7 @@ static int vio_make_devnode(SpaprVioDevice *dev, + SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); + int vdevice_off, node_off, ret; + char *dt_name; ++ const char *dt_compatible; + + vdevice_off = fdt_path_offset(fdt, "/vdevice"); + if (vdevice_off < 0) { +@@ -115,9 +116,15 @@ static int vio_make_devnode(SpaprVioDevice *dev, + } + } + +- if (pc->dt_compatible) { ++ if (pc->get_dt_compatible) { ++ dt_compatible = pc->get_dt_compatible(dev); ++ } else { ++ dt_compatible = pc->dt_compatible; ++ } ++ ++ if (dt_compatible) { + ret = fdt_setprop_string(fdt, node_off, "compatible", +- pc->dt_compatible); ++ dt_compatible); + if (ret < 0) { + return ret; + } +diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h +index 04609f21..97951fc6 100644 +--- a/include/hw/ppc/spapr_vio.h ++++ b/include/hw/ppc/spapr_vio.h +@@ -56,6 +56,7 @@ typedef struct SpaprVioDeviceClass { + void (*realize)(SpaprVioDevice *dev, Error **errp); + void (*reset)(SpaprVioDevice *dev); + int (*devnode)(SpaprVioDevice *dev, void *fdt, int node_off); ++ const char *(*get_dt_compatible)(SpaprVioDevice *dev); + } SpaprVioDeviceClass; + + struct SpaprVioDevice { +-- +2.23.0 + diff --git a/target-arm-Add-the-kvm_adjvtime-vcpu-property-for-Co.patch b/target-arm-Add-the-kvm_adjvtime-vcpu-property-for-Co.patch new file mode 100644 index 0000000000000000000000000000000000000000..49c7dc63022ec1196b8c225b1c5291fbbe10e1ad --- /dev/null +++ b/target-arm-Add-the-kvm_adjvtime-vcpu-property-for-Co.patch @@ -0,0 +1,27 @@ +From 427975fbc87c3d999ee4d13b65a95ba496c148d6 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Fri, 29 May 2020 11:02:44 +0800 +Subject: [PATCH] target/arm: Add the kvm_adjvtime vcpu property for Cortex-A72 + +Add the kvm_adjvtime vcpu property for ARM Cortex-A72 cpu model, +so that virtual time adjust will be enabled for it. + +Signed-off-by: Ying Fang + +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index b30ca7c9..15f4ee92 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -257,6 +257,9 @@ static void aarch64_a72_initfn(Object *obj) + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); ++ if(kvm_enabled()) { ++ kvm_arm_add_vcpu_properties(obj); ++ } + } + + static void aarch64_kunpeng_920_initfn(Object *obj) +-- +2.23.0 + diff --git a/target-arm-Allow-reading-flags-from-FPSCR-for-M-prof.patch b/target-arm-Allow-reading-flags-from-FPSCR-for-M-prof.patch new file mode 100644 index 0000000000000000000000000000000000000000..ca4b796b58600aa35771d26a247690dfca413cc9 --- /dev/null +++ b/target-arm-Allow-reading-flags-from-FPSCR-for-M-prof.patch @@ -0,0 +1,41 @@ +From cdc6896659b85f7ed8f7552850312e55170de0c5 Mon Sep 17 00:00:00 2001 +From: Christophe Lyon +Date: Fri, 25 Oct 2019 11:57:11 +0200 +Subject: [PATCH] target/arm: Allow reading flags from FPSCR for M-profile + +rt==15 is a special case when reading the flags: it means the +destination is APSR. This patch avoids rejecting +vmrs apsr_nzcv, fpscr +as illegal instruction. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Christophe Lyon +Message-id: 20191025095711.10853-1-christophe.lyon@linaro.org +[PMM: updated the comment] +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +(cherry picked from commit 2529ab43b8a05534494704e803e0332d111d8b91) +Signed-off-by: Michael Roth +--- + target/arm/translate-vfp.inc.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c +index ef45cecbea..75406fd9db 100644 +--- a/target/arm/translate-vfp.inc.c ++++ b/target/arm/translate-vfp.inc.c +@@ -704,9 +704,10 @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a) + if (arm_dc_feature(s, ARM_FEATURE_M)) { + /* + * The only M-profile VFP vmrs/vmsr sysreg is FPSCR. +- * Writes to R15 are UNPREDICTABLE; we choose to undef. ++ * Accesses to R15 are UNPREDICTABLE; we choose to undef. ++ * (FPSCR -> r15 is a special case which writes to the PSR flags.) + */ +- if (a->rt == 15 || a->reg != ARM_VFP_FPSCR) { ++ if (a->rt == 15 && (!a->l || a->reg != ARM_VFP_FPSCR)) { + return false; + } + } +-- +2.23.0 diff --git a/target-arm-Don-t-abort-on-M-profile-exception-return.patch b/target-arm-Don-t-abort-on-M-profile-exception-return.patch new file mode 100644 index 0000000000000000000000000000000000000000..b6796e25b8b04c76a117ad129cb807a0da93da45 --- /dev/null +++ b/target-arm-Don-t-abort-on-M-profile-exception-return.patch @@ -0,0 +1,103 @@ +From 9027d3fba605d8f6093342ebe4a1da450d374630 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Thu, 22 Aug 2019 14:15:34 +0100 +Subject: [PATCH] target/arm: Don't abort on M-profile exception return in + linux-user mode + +An attempt to do an exception-return (branch to one of the magic +addresses) in linux-user mode for M-profile should behave like +a normal branch, because linux-user mode is always going to be +in 'handler' mode. This used to work, but we broke it when we added +support for the M-profile security extension in commit d02a8698d7ae2bfed. + +In that commit we allowed even handler-mode calls to magic return +values to be checked for and dealt with by causing an +EXCP_EXCEPTION_EXIT exception to be taken, because this is +needed for the FNC_RETURN return-from-non-secure-function-call +handling. For system mode we added a check in do_v7m_exception_exit() +to make any spurious calls from Handler mode behave correctly, but +forgot that linux-user mode would also be affected. + +How an attempted return-from-non-secure-function-call in linux-user +mode should be handled is not clear -- on real hardware it would +result in return to secure code (not to the Linux kernel) which +could then handle the error in any way it chose. For QEMU we take +the simple approach of treating this erroneous return the same way +it would be handled on a CPU without the security extensions -- +treat it as a normal branch. + +The upshot of all this is that for linux-user mode we should never +do any of the bx_excret magic, so the code change is simple. + +This ought to be a weird corner case that only affects broken guest +code (because Linux user processes should never be attempting to do +exception returns or NS function returns), except that the code that +assigns addresses in RAM for the process and stack in our linux-user +code does not attempt to avoid this magic address range, so +legitimate code attempting to return to a trampoline routine on the +stack can fall into this case. This change fixes those programs, +but we should also look at restricting the range of memory we +use for M-profile linux-user guests to the area that would be +real RAM in hardware. + +Cc: qemu-stable@nongnu.org +Reported-by: Christophe Lyon +Reviewed-by: Richard Henderson +Signed-off-by: Peter Maydell +Message-id: 20190822131534.16602-1-peter.maydell@linaro.org +Fixes: https://bugs.launchpad.net/qemu/+bug/1840922 +Signed-off-by: Peter Maydell +(cherry picked from commit 5e5584c89f36b302c666bc6db535fd3f7ff35ad2) +Signed-off-by: Michael Roth +--- + target/arm/translate.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/target/arm/translate.c b/target/arm/translate.c +index 7853462b21..24cb4ba075 100644 +--- a/target/arm/translate.c ++++ b/target/arm/translate.c +@@ -952,10 +952,27 @@ static inline void gen_bx(DisasContext *s, TCGv_i32 var) + store_cpu_field(var, thumb); + } + +-/* Set PC and Thumb state from var. var is marked as dead. ++/* ++ * Set PC and Thumb state from var. var is marked as dead. + * For M-profile CPUs, include logic to detect exception-return + * branches and handle them. This is needed for Thumb POP/LDM to PC, LDR to PC, + * and BX reg, and no others, and happens only for code in Handler mode. ++ * The Security Extension also requires us to check for the FNC_RETURN ++ * which signals a function return from non-secure state; this can happen ++ * in both Handler and Thread mode. ++ * To avoid having to do multiple comparisons in inline generated code, ++ * we make the check we do here loose, so it will match for EXC_RETURN ++ * in Thread mode. For system emulation do_v7m_exception_exit() checks ++ * for these spurious cases and returns without doing anything (giving ++ * the same behaviour as for a branch to a non-magic address). ++ * ++ * In linux-user mode it is unclear what the right behaviour for an ++ * attempted FNC_RETURN should be, because in real hardware this will go ++ * directly to Secure code (ie not the Linux kernel) which will then treat ++ * the error in any way it chooses. For QEMU we opt to make the FNC_RETURN ++ * attempt behave the way it would on a CPU without the security extension, ++ * which is to say "like a normal branch". That means we can simply treat ++ * all branches as normal with no magic address behaviour. + */ + static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var) + { +@@ -963,10 +980,12 @@ static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var) + * s->base.is_jmp that we need to do the rest of the work later. + */ + gen_bx(s, var); ++#ifndef CONFIG_USER_ONLY + if (arm_dc_feature(s, ARM_FEATURE_M_SECURITY) || + (s->v7m_handler_mode && arm_dc_feature(s, ARM_FEATURE_M))) { + s->base.is_jmp = DISAS_BX_EXCRET; + } ++#endif + } + + static inline void gen_bx_excret_final_code(DisasContext *s) +-- +2.23.0 diff --git a/target-arm-Fix-PAuth-sbox-functions.patch b/target-arm-Fix-PAuth-sbox-functions.patch new file mode 100644 index 0000000000000000000000000000000000000000..ac8d05065f766eb8ca90cd00de6a60350c2306c3 --- /dev/null +++ b/target-arm-Fix-PAuth-sbox-functions.patch @@ -0,0 +1,49 @@ +From a7149fc18020c3d432c31838069dcfcb745299bf Mon Sep 17 00:00:00 2001 +From: zhanghailiang +Date: Sat, 20 Jun 2020 12:01:30 +0800 +Subject: [PATCH] target/arm: Fix PAuth sbox functions + +In the PAC computation, sbox was applied over wrong bits. +As this is a 4-bit sbox, bit index should be incremented by 4 instead of 16. + +Test vector from QARMA paper (https://eprint.iacr.org/2016/444.pdf) was +used to verify one computation of the pauth_computepac() function which +uses sbox2. + +Launchpad: https://bugs.launchpad.net/bugs/1859713 +Reviewed-by: Richard Henderson +Signed-off-by: Vincent DEHORS +Signed-off-by: Adrien GRASSEIN +Message-id: 20200116230809.19078-2-richard.henderson@linaro.org +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +Signed-off-by: zhanghailiang +--- + target/arm/pauth_helper.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/target/arm/pauth_helper.c b/target/arm/pauth_helper.c +index d3194f20..0a5f41e1 100644 +--- a/target/arm/pauth_helper.c ++++ b/target/arm/pauth_helper.c +@@ -89,7 +89,7 @@ static uint64_t pac_sub(uint64_t i) + uint64_t o = 0; + int b; + +- for (b = 0; b < 64; b += 16) { ++ for (b = 0; b < 64; b += 4) { + o |= (uint64_t)sub[(i >> b) & 0xf] << b; + } + return o; +@@ -104,7 +104,7 @@ static uint64_t pac_inv_sub(uint64_t i) + uint64_t o = 0; + int b; + +- for (b = 0; b < 64; b += 16) { ++ for (b = 0; b < 64; b += 4) { + o |= (uint64_t)inv_sub[(i >> b) & 0xf] << b; + } + return o; +-- +2.23.0 + diff --git a/target-arm-Free-TCG-temps-in-trans_VMOV_64_sp.patch b/target-arm-Free-TCG-temps-in-trans_VMOV_64_sp.patch new file mode 100644 index 0000000000000000000000000000000000000000..a46232f8ba04e1e2a956d8493dc1515fcf1f272a --- /dev/null +++ b/target-arm-Free-TCG-temps-in-trans_VMOV_64_sp.patch @@ -0,0 +1,40 @@ +From 38fb634853ac6547326d9f88b9a068d9fc6b4ad4 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Tue, 27 Aug 2019 13:19:31 +0100 +Subject: [PATCH] target/arm: Free TCG temps in trans_VMOV_64_sp() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The function neon_store_reg32() doesn't free the TCG temp that it +is passed, so the caller must do that. We got this right in most +places but forgot to free the TCG temps in trans_VMOV_64_sp(). + +Cc: qemu-stable@nongnu.org +Signed-off-by: Peter Maydell +Reviewed-by: Richard Henderson +Reviewed-by: Philippe Mathieu-Daudé +Message-id: 20190827121931.26836-1-peter.maydell@linaro.org +(cherry picked from commit 342d27581bd3ecdb995e4fc55fcd383cf3242888) +Signed-off-by: Michael Roth +--- + target/arm/translate-vfp.inc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c +index 092eb5ec53..ef45cecbea 100644 +--- a/target/arm/translate-vfp.inc.c ++++ b/target/arm/translate-vfp.inc.c +@@ -881,8 +881,10 @@ static bool trans_VMOV_64_sp(DisasContext *s, arg_VMOV_64_sp *a) + /* gpreg to fpreg */ + tmp = load_reg(s, a->rt); + neon_store_reg32(tmp, a->vm); ++ tcg_temp_free_i32(tmp); + tmp = load_reg(s, a->rt2); + neon_store_reg32(tmp, a->vm + 1); ++ tcg_temp_free_i32(tmp); + } + + return true; +-- +2.23.0 diff --git a/target-arm-cpu-Add-the-kvm-no-adjvtime-CPU-property.patch b/target-arm-cpu-Add-the-kvm-no-adjvtime-CPU-property.patch new file mode 100644 index 0000000000000000000000000000000000000000..41c67cf1b8024af9f48888ecd782e9927a2f166e --- /dev/null +++ b/target-arm-cpu-Add-the-kvm-no-adjvtime-CPU-property.patch @@ -0,0 +1,152 @@ +From 860035652c7866b033762f6d90f81d5ddedf855c Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 22 Apr 2020 17:08:43 +0800 +Subject: [PATCH] target/arm/cpu: Add the kvm-no-adjvtime CPU property + +kvm-no-adjvtime is a KVM specific CPU property and a first of its +kind. To accommodate it we also add kvm_arm_add_vcpu_properties() +and a KVM specific CPU properties description to the CPU features +document. + +Signed-off-by: Andrew Jones +Message-id: 20200120101023.16030-7-drjones@redhat.com +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index e9a2a959..cfda6cc5 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -1748,6 +1748,11 @@ static void machvirt_init(MachineState *machine) + } + } + ++ if (vmc->kvm_no_adjvtime && ++ object_property_find(cpuobj, "kvm-no-adjvtime", NULL)) { ++ object_property_set_bool(cpuobj, true, "kvm-no-adjvtime", NULL); ++ } ++ + if (vmc->no_pmu && object_property_find(cpuobj, "pmu", NULL)) { + object_property_set_bool(cpuobj, false, "pmu", NULL); + } +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index 43a6ce91..a9d6977a 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -107,6 +107,7 @@ typedef struct { + bool claim_edge_triggered_timers; + bool smbios_old_sys_ver; + bool no_highmem_ecam; ++ bool kvm_no_adjvtime; + } VirtMachineClass; + + typedef struct { +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index bc3da9a3..39bbe7e2 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -2441,6 +2441,7 @@ static void arm_max_initfn(Object *obj) + + if (kvm_enabled()) { + kvm_arm_set_cpu_features_from_host(cpu); ++ kvm_arm_add_vcpu_properties(obj); + } else { + cortex_a15_initfn(obj); + +@@ -2629,6 +2630,7 @@ static void arm_host_initfn(Object *obj) + ARMCPU *cpu = ARM_CPU(obj); + + kvm_arm_set_cpu_features_from_host(cpu); ++ kvm_arm_add_vcpu_properties(obj); + arm_cpu_post_init(obj); + } + +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index dbf44b92..b30ca7c9 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -312,6 +312,7 @@ static void aarch64_max_initfn(Object *obj) + + if (kvm_enabled()) { + kvm_arm_set_cpu_features_from_host(cpu); ++ kvm_arm_add_vcpu_properties(obj); + } else { + uint64_t t; + uint32_t u; +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index 21fb7ecd..327b3bc3 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -16,6 +16,8 @@ + #include "qemu-common.h" + #include "qemu/timer.h" + #include "qemu/error-report.h" ++#include "qom/object.h" ++#include "qapi/error.h" + #include "sysemu/sysemu.h" + #include "sysemu/kvm.h" + #include "sysemu/kvm_int.h" +@@ -162,6 +164,32 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu) + env->features = arm_host_cpu_features.features; + } + ++static bool kvm_no_adjvtime_get(Object *obj, Error **errp) ++{ ++ return !ARM_CPU(obj)->kvm_adjvtime; ++} ++ ++static void kvm_no_adjvtime_set(Object *obj, bool value, Error **errp) ++{ ++ ARM_CPU(obj)->kvm_adjvtime = !value; ++} ++ ++/* KVM VCPU properties should be prefixed with "kvm-". */ ++void kvm_arm_add_vcpu_properties(Object *obj) ++{ ++ if (!kvm_enabled()) { ++ return; ++ } ++ ++ ARM_CPU(obj)->kvm_adjvtime = true; ++ object_property_add_bool(obj, "kvm-no-adjvtime", kvm_no_adjvtime_get, ++ kvm_no_adjvtime_set, &error_abort); ++ object_property_set_description(obj, "kvm-no-adjvtime", ++ "Set on to disable the adjustment of " ++ "the virtual counter. VM stopped time " ++ "will be counted.", &error_abort); ++} ++ + int kvm_arm_get_max_vm_ipa_size(MachineState *ms) + { + KVMState *s = KVM_STATE(ms->accelerator); +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index 97560d4e..0de5f83e 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -230,6 +230,15 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf); + */ + void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu); + ++/** ++ * kvm_arm_add_vcpu_properties: ++ * @obj: The CPU object to add the properties to ++ * ++ * Add all KVM specific CPU properties to the CPU object. These ++ * are the CPU properties with "kvm-" prefixed names. ++ */ ++void kvm_arm_add_vcpu_properties(Object *obj); ++ + /** + * kvm_arm_get_max_vm_ipa_size: + * @ms: Machine state handle +@@ -294,6 +303,8 @@ static inline void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu) + cpu->host_cpu_probe_failed = true; + } + ++static inline void kvm_arm_add_vcpu_properties(Object *obj) {} ++ + static inline int kvm_arm_get_max_vm_ipa_size(MachineState *ms) + { + return -ENOENT; +-- +2.23.0 diff --git a/target-arm-kvm-Implement-virtual-time-adjustment.patch b/target-arm-kvm-Implement-virtual-time-adjustment.patch new file mode 100644 index 0000000000000000000000000000000000000000..86450c4d8f1739527a7065ec9242706605487b0e --- /dev/null +++ b/target-arm-kvm-Implement-virtual-time-adjustment.patch @@ -0,0 +1,290 @@ +From 77ee224418fac859acecd9aca4d18555ced42db6 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Tue, 21 Apr 2020 17:32:31 +0800 +Subject: [PATCH 3/4] target/arm/kvm: Implement virtual time adjustment + +When a VM is stopped (such as when it's paused) guest virtual time +should stop counting. Otherwise, when the VM is resumed it will +experience time jumps and its kernel may report soft lockups. Not +counting virtual time while the VM is stopped has the side effect +of making the guest's time appear to lag when compared with real +time, and even with time derived from the physical counter. For +this reason, this change, which is enabled by default, comes with +a KVM CPU feature allowing it to be disabled, restoring legacy +behavior. + +This patch only provides the implementation of the virtual time +adjustment. A subsequent patch will provide the CPU property +allowing the change to be enabled and disabled. + +Reported-by: Bijan Mottahedeh +Signed-off-by: Andrew Jones +Message-id: 20200120101023.16030-6-drjones@redhat.com +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +--- + target/arm/cpu.h | 7 ++++ + target/arm/kvm.c | 92 ++++++++++++++++++++++++++++++++++++++++++++ + target/arm/kvm32.c | 2 + + target/arm/kvm64.c | 2 + + target/arm/kvm_arm.h | 37 ++++++++++++++++++ + target/arm/machine.c | 7 ++++ + 6 files changed, 147 insertions(+) + +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 94c990cd..e19531a7 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -816,6 +816,13 @@ struct ARMCPU { + /* KVM init features for this CPU */ + uint32_t kvm_init_features[7]; + ++ /* KVM CPU state */ ++ ++ /* KVM virtual time adjustment */ ++ bool kvm_adjvtime; ++ bool kvm_vtime_dirty; ++ uint64_t kvm_vtime; ++ + /* Uniprocessor system with MP extensions */ + bool mp_is_up; + +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index cc7a46df..21fb7ecd 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -336,6 +336,22 @@ static int compare_u64(const void *a, const void *b) + return 0; + } + ++/* ++ * cpreg_values are sorted in ascending order by KVM register ID ++ * (see kvm_arm_init_cpreg_list). This allows us to cheaply find ++ * the storage for a KVM register by ID with a binary search. ++ */ ++static uint64_t *kvm_arm_get_cpreg_ptr(ARMCPU *cpu, uint64_t regidx) ++{ ++ uint64_t *res; ++ ++ res = bsearch(®idx, cpu->cpreg_indexes, cpu->cpreg_array_len, ++ sizeof(uint64_t), compare_u64); ++ assert(res); ++ ++ return &cpu->cpreg_values[res - cpu->cpreg_indexes]; ++} ++ + /* Initialize the ARMCPU cpreg list according to the kernel's + * definition of what CPU registers it knows about (and throw away + * the previous TCG-created cpreg list). +@@ -489,6 +505,23 @@ bool write_list_to_kvmstate(ARMCPU *cpu, int level) + return ok; + } + ++void kvm_arm_cpu_pre_save(ARMCPU *cpu) ++{ ++ /* KVM virtual time adjustment */ ++ if (cpu->kvm_vtime_dirty) { ++ *kvm_arm_get_cpreg_ptr(cpu, KVM_REG_ARM_TIMER_CNT) = cpu->kvm_vtime; ++ } ++} ++ ++void kvm_arm_cpu_post_load(ARMCPU *cpu) ++{ ++ /* KVM virtual time adjustment */ ++ if (cpu->kvm_adjvtime) { ++ cpu->kvm_vtime = *kvm_arm_get_cpreg_ptr(cpu, KVM_REG_ARM_TIMER_CNT); ++ cpu->kvm_vtime_dirty = true; ++ } ++} ++ + void kvm_arm_reset_vcpu(ARMCPU *cpu) + { + int ret; +@@ -556,6 +589,50 @@ int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu) + return 0; + } + ++void kvm_arm_get_virtual_time(CPUState *cs) ++{ ++ ARMCPU *cpu = ARM_CPU(cs); ++ struct kvm_one_reg reg = { ++ .id = KVM_REG_ARM_TIMER_CNT, ++ .addr = (uintptr_t)&cpu->kvm_vtime, ++ }; ++ int ret; ++ ++ if (cpu->kvm_vtime_dirty) { ++ return; ++ } ++ ++ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); ++ if (ret) { ++ error_report("Failed to get KVM_REG_ARM_TIMER_CNT"); ++ abort(); ++ } ++ ++ cpu->kvm_vtime_dirty = true; ++} ++ ++void kvm_arm_put_virtual_time(CPUState *cs) ++{ ++ ARMCPU *cpu = ARM_CPU(cs); ++ struct kvm_one_reg reg = { ++ .id = KVM_REG_ARM_TIMER_CNT, ++ .addr = (uintptr_t)&cpu->kvm_vtime, ++ }; ++ int ret; ++ ++ if (!cpu->kvm_vtime_dirty) { ++ return; ++ } ++ ++ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); ++ if (ret) { ++ error_report("Failed to set KVM_REG_ARM_TIMER_CNT"); ++ abort(); ++ } ++ ++ cpu->kvm_vtime_dirty = false; ++} ++ + int kvm_put_vcpu_events(ARMCPU *cpu) + { + CPUARMState *env = &cpu->env; +@@ -667,6 +744,21 @@ MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) + return MEMTXATTRS_UNSPECIFIED; + } + ++void kvm_arm_vm_state_change(void *opaque, int running, RunState state) ++{ ++ CPUState *cs = opaque; ++ ARMCPU *cpu = ARM_CPU(cs); ++ ++ if (running) { ++ if (cpu->kvm_adjvtime) { ++ kvm_arm_put_virtual_time(cs); ++ } ++ } else { ++ if (cpu->kvm_adjvtime) { ++ kvm_arm_get_virtual_time(cs); ++ } ++ } ++} + + int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) + { +diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c +index 51f78f72..ee158830 100644 +--- a/target/arm/kvm32.c ++++ b/target/arm/kvm32.c +@@ -195,6 +195,8 @@ int kvm_arch_init_vcpu(CPUState *cs) + return -EINVAL; + } + ++ qemu_add_vm_change_state_handler(kvm_arm_vm_state_change, cs); ++ + /* Determine init features for this CPU */ + memset(cpu->kvm_init_features, 0, sizeof(cpu->kvm_init_features)); + if (cpu->start_powered_off) { +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index f2f0a92e..4f0bf000 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -609,6 +609,8 @@ int kvm_arch_init_vcpu(CPUState *cs) + return -EINVAL; + } + ++ qemu_add_vm_change_state_handler(kvm_arm_vm_state_change, cs); ++ + /* Determine init features for this CPU */ + memset(cpu->kvm_init_features, 0, sizeof(cpu->kvm_init_features)); + if (cpu->start_powered_off) { +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index 32d97ce5..97560d4e 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -113,6 +113,23 @@ bool write_list_to_kvmstate(ARMCPU *cpu, int level); + */ + bool write_kvmstate_to_list(ARMCPU *cpu); + ++/** ++ * kvm_arm_cpu_pre_save: ++ * @cpu: ARMCPU ++ * ++ * Called after write_kvmstate_to_list() from cpu_pre_save() to update ++ * the cpreg list with KVM CPU state. ++ */ ++void kvm_arm_cpu_pre_save(ARMCPU *cpu); ++ ++/** ++ * kvm_arm_cpu_post_load: ++ * @cpu: ARMCPU ++ * ++ * Called from cpu_post_load() to update KVM CPU state from the cpreg list. ++ */ ++void kvm_arm_cpu_post_load(ARMCPU *cpu); ++ + /** + * kvm_arm_reset_vcpu: + * @cpu: ARMCPU +@@ -241,6 +258,24 @@ int kvm_arm_sync_mpstate_to_kvm(ARMCPU *cpu); + */ + int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu); + ++/** ++ * kvm_arm_get_virtual_time: ++ * @cs: CPUState ++ * ++ * Gets the VCPU's virtual counter and stores it in the KVM CPU state. ++ */ ++void kvm_arm_get_virtual_time(CPUState *cs); ++ ++/** ++ * kvm_arm_put_virtual_time: ++ * @cs: CPUState ++ * ++ * Sets the VCPU's virtual counter to the value stored in the KVM CPU state. ++ */ ++void kvm_arm_put_virtual_time(CPUState *cs); ++ ++void kvm_arm_vm_state_change(void *opaque, int running, RunState state); ++ + int kvm_arm_vgic_probe(void); + + void kvm_arm_pmu_set_irq(CPUState *cs, int irq); +@@ -272,6 +307,8 @@ static inline int kvm_arm_vgic_probe(void) + static inline void kvm_arm_pmu_set_irq(CPUState *cs, int irq) {} + static inline void kvm_arm_pmu_init(CPUState *cs) {} + ++static inline void kvm_arm_get_virtual_time(CPUState *cs) {} ++static inline void kvm_arm_put_virtual_time(CPUState *cs) {} + #endif + + static inline const char *gic_class_name(void) +diff --git a/target/arm/machine.c b/target/arm/machine.c +index 3fd319a3..ee3c59a6 100644 +--- a/target/arm/machine.c ++++ b/target/arm/machine.c +@@ -644,6 +644,12 @@ static int cpu_pre_save(void *opaque) + /* This should never fail */ + abort(); + } ++ ++ /* ++ * kvm_arm_cpu_pre_save() must be called after ++ * write_kvmstate_to_list() ++ */ ++ kvm_arm_cpu_pre_save(cpu); + } else { + if (!write_cpustate_to_list(cpu, false)) { + /* This should never fail. */ +@@ -746,6 +752,7 @@ static int cpu_post_load(void *opaque, int version_id) + * we're using it. + */ + write_list_to_cpustate(cpu); ++ kvm_arm_cpu_post_load(cpu); + } else { + if (!write_list_to_cpustate(cpu)) { + return -1; +-- +2.23.0 diff --git a/target-arm-kvm-trivial-Clean-up-header-documentation.patch b/target-arm-kvm-trivial-Clean-up-header-documentation.patch new file mode 100644 index 0000000000000000000000000000000000000000..8c28c63b1e9fa89ace5860f635f07e2d9b221bbe --- /dev/null +++ b/target-arm-kvm-trivial-Clean-up-header-documentation.patch @@ -0,0 +1,144 @@ +From c057499f90af4be8b26f57f8755aca0ddfcf9467 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Tue, 21 Apr 2020 16:52:07 +0800 +Subject: [PATCH 1/4] target/arm/kvm: trivial: Clean up header documentation + +Signed-off-by: Andrew Jones +Message-id: 20200120101023.16030-2-drjones@redhat.com +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +--- + target/arm/kvm_arm.h | 38 +++++++++++++++++++++++--------------- + 1 file changed, 23 insertions(+), 15 deletions(-) + +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index a9f3ccab..32d97ce5 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -61,8 +61,8 @@ void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid, uint64_t group, + int kvm_arm_init_cpreg_list(ARMCPU *cpu); + + /** +- * kvm_arm_reg_syncs_via_cpreg_list +- * regidx: KVM register index ++ * kvm_arm_reg_syncs_via_cpreg_list: ++ * @regidx: KVM register index + * + * Return true if this KVM register should be synchronized via the + * cpreg list of arbitrary system registers, false if it is synchronized +@@ -71,8 +71,8 @@ int kvm_arm_init_cpreg_list(ARMCPU *cpu); + bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx); + + /** +- * kvm_arm_cpreg_level +- * regidx: KVM register index ++ * kvm_arm_cpreg_level: ++ * @regidx: KVM register index + * + * Return the level of this coprocessor/system register. Return value is + * either KVM_PUT_RUNTIME_STATE, KVM_PUT_RESET_STATE, or KVM_PUT_FULL_STATE. +@@ -134,6 +134,8 @@ void kvm_arm_init_serror_injection(CPUState *cs); + * @cpu: ARMCPU + * + * Get VCPU related state from kvm. ++ * ++ * Returns: 0 if success else < 0 error code + */ + int kvm_get_vcpu_events(ARMCPU *cpu); + +@@ -142,6 +144,8 @@ int kvm_get_vcpu_events(ARMCPU *cpu); + * @cpu: ARMCPU + * + * Put VCPU related state to kvm. ++ * ++ * Returns: 0 if success else < 0 error code + */ + int kvm_put_vcpu_events(ARMCPU *cpu); + +@@ -191,10 +195,12 @@ typedef struct ARMHostCPUFeatures { + + /** + * kvm_arm_get_host_cpu_features: +- * @ahcc: ARMHostCPUClass to fill in ++ * @ahcf: ARMHostCPUClass to fill in + * + * Probe the capabilities of the host kernel's preferred CPU and fill + * in the ARMHostCPUClass struct accordingly. ++ * ++ * Returns true on success and false otherwise. + */ + bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf); + +@@ -208,26 +214,30 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf); + void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu); + + /** +- * kvm_arm_get_max_vm_ipa_size - Returns the number of bits in the +- * IPA address space supported by KVM +- * ++ * kvm_arm_get_max_vm_ipa_size: + * @ms: Machine state handle ++ * ++ * Returns the number of bits in the IPA address space supported by KVM + */ + int kvm_arm_get_max_vm_ipa_size(MachineState *ms); + + /** +- * kvm_arm_sync_mpstate_to_kvm ++ * kvm_arm_sync_mpstate_to_kvm: + * @cpu: ARMCPU + * + * If supported set the KVM MP_STATE based on QEMU's model. ++ * ++ * Returns 0 on success and -1 on failure. + */ + int kvm_arm_sync_mpstate_to_kvm(ARMCPU *cpu); + + /** +- * kvm_arm_sync_mpstate_to_qemu ++ * kvm_arm_sync_mpstate_to_qemu: + * @cpu: ARMCPU + * + * If supported get the MP_STATE from KVM and store in QEMU's model. ++ * ++ * Returns 0 on success and aborts on failure. + */ + int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu); + +@@ -241,7 +251,8 @@ int kvm_arm_set_irq(int cpu, int irqtype, int irq, int level); + + static inline void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu) + { +- /* This should never actually be called in the "not KVM" case, ++ /* ++ * This should never actually be called in the "not KVM" case, + * but set up the fields to indicate an error anyway. + */ + cpu->kvm_target = QEMU_KVM_ARM_TARGET_NONE; +@@ -310,23 +321,20 @@ bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit); + * + * Return: TRUE if any hardware breakpoints in use. + */ +- + bool kvm_arm_hw_debug_active(CPUState *cs); + + /** + * kvm_arm_copy_hw_debug_data: +- * + * @ptr: kvm_guest_debug_arch structure + * + * Copy the architecture specific debug registers into the + * kvm_guest_debug ioctl structure. + */ + struct kvm_guest_debug_arch; +- + void kvm_arm_copy_hw_debug_data(struct kvm_guest_debug_arch *ptr); + + /** +- * its_class_name ++ * its_class_name: + * + * Return the ITS class name to use depending on whether KVM acceleration + * and KVM CAP_SIGNAL_MSI are supported +-- +2.23.0 diff --git a/target-arm-kvm64-kvm64-cpus-have-timer-registers.patch b/target-arm-kvm64-kvm64-cpus-have-timer-registers.patch new file mode 100644 index 0000000000000000000000000000000000000000..b8cec1bd36e2da9526a643229252ac6760eebecf --- /dev/null +++ b/target-arm-kvm64-kvm64-cpus-have-timer-registers.patch @@ -0,0 +1,37 @@ +From 07bd62920f968da7d1d8962cc7fd3d29652d25f4 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Tue, 21 Apr 2020 17:04:13 +0800 +Subject: [PATCH 2/4] target/arm/kvm64: kvm64 cpus have timer registers + +Add the missing GENERIC_TIMER feature to kvm64 cpus. + +We don't currently use these registers when KVM is enabled, but it's +probably best we add the feature flag for consistency and potential +future use. There's also precedent, as we add the PMU feature flag to +KVM enabled guests, even though we don't use those registers either. + +This change was originally posted as a hunk of a different, never +merged patch from Bijan Mottahedeh. + +Signed-off-by: Andrew Jones +Reviewed-by: Richard Henderson +Message-id: 20200120101023.16030-4-drjones@redhat.com +Signed-off-by: Peter Maydell +--- + target/arm/kvm64.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 22d19c9a..f2f0a92e 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -587,6 +587,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + set_feature(&features, ARM_FEATURE_NEON); + set_feature(&features, ARM_FEATURE_AARCH64); + set_feature(&features, ARM_FEATURE_PMU); ++ set_feature(&features, ARM_FEATURE_GENERIC_TIMER); + + ahcf->features = features; + +-- +2.23.0 diff --git a/tcp_emu-Fix-oob-access.patch b/tcp_emu-Fix-oob-access.patch index 5182f54363d585efd23f0a5c236d0e9c5153215e..807dfef08e28fe33a65fede676bbb076f5d9e393 100644 --- a/tcp_emu-Fix-oob-access.patch +++ b/tcp_emu-Fix-oob-access.patch @@ -1,6 +1,6 @@ -From 0f7224535cdfec549cd43a5ae4ccde936f50ee95 Mon Sep 17 00:00:00 2001 +From 585634894f511bc1821cef54494bf2d9abc109c9 Mon Sep 17 00:00:00 2001 From: Samuel Thibault -Date: Wed, 11 Mar 2020 17:33:46 +0800 +Date: Tue, 14 Apr 2020 18:04:33 +0800 Subject: [PATCH] tcp_emu: Fix oob access The main loop only checks for one available byte, while we sometimes @@ -10,29 +10,28 @@ need two bytes. 1 file changed, 6 insertions(+) diff --git a/slirp/src/tcp_subr.c b/slirp/src/tcp_subr.c -index fde9207b..4608942f 100644 +index d6dd133a..9c94c03a 100644 --- a/slirp/src/tcp_subr.c +++ b/slirp/src/tcp_subr.c -@@ -895,6 +895,9 @@ tcp_emu(struct socket *so, struct mbuf *m) - break; - - case 5: -+ if (bptr == m->m_data + m->m_len - 1) -+ return 1; /* We need two bytes */ +@@ -886,6 +886,9 @@ int tcp_emu(struct socket *so, struct mbuf *m) + break; + + case 5: ++ if (bptr == m->m_data + m->m_len - 1) ++ return 1; /* We need two bytes */ + - /* - * The difference between versions 1.0 and - * 2.0 is here. For future versions of -@@ -910,6 +913,9 @@ tcp_emu(struct socket *so, struct mbuf *m) - /* This is the field containing the port - * number that RA-player is listening to. - */ -+ if (bptr == m->m_data + m->m_len - 1) -+ return 1; /* We need two bytes */ + /* + * The difference between versions 1.0 and + * 2.0 is here. For future versions of +@@ -901,6 +904,9 @@ int tcp_emu(struct socket *so, struct mbuf *m) + /* This is the field containing the port + * number that RA-player is listening to. + */ ++ if (bptr == m->m_data + m->m_len - 1) ++ return 1; /* We need two bytes */ + - lport = (((uint8_t*)bptr)[0] << 8) - + ((uint8_t *)bptr)[1]; - if (lport < 6970) --- -2.21.1 (Apple Git-122.3) - + lport = (((uint8_t *)bptr)[0] << 8) + ((uint8_t *)bptr)[1]; + if (lport < 6970) + lport += 256; /* don't know why */ +-- +2.23.0 diff --git a/tcp_emu-fix-unsafe-snprintf-usages.patch b/tcp_emu-fix-unsafe-snprintf-usages.patch index cc13154ca1449831d6a91dbacc27234af4caf0e5..2f6850a60c2fb942ecc7ef15030686d3dd94aa9c 100644 --- a/tcp_emu-fix-unsafe-snprintf-usages.patch +++ b/tcp_emu-fix-unsafe-snprintf-usages.patch @@ -1,6 +1,6 @@ -From 1db8bcc0ec91bb4374b3ffdd03da3c4ede381fb5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Wed, 11 Mar 2020 18:52:07 +0800 +From 220a52fda279038d46c25d39a372154ff9b024d2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureauls?= +Date: Tue, 14 Apr 2020 19:06:35 +0800 Subject: [PATCH] tcp_emu: fix unsafe snprintf() usages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -28,67 +28,76 @@ Signed-off-by: default avatarMarc-André Lureau Reviewed-by: Samuel Thibault's avatarSamuel Thibault Message-Id: <20200127092414.169796-7-marcandre.lureau@redhat.com> --- - slirp/src/tcp_subr.c | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) + slirp/src/tcp_subr.c | 15 +++++++-------- + 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/slirp/src/tcp_subr.c b/slirp/src/tcp_subr.c -index e898fd03..88dadc76 100644 +index 019b637a..6c1b17bd 100644 --- a/slirp/src/tcp_subr.c +++ b/slirp/src/tcp_subr.c -@@ -707,7 +707,7 @@ tcp_emu(struct socket *so, struct mbuf *m) - n4 = (laddr & 0xff); - - m->m_len = bptr - m->m_data; /* Adjust length */ -- m->m_len += snprintf(bptr, M_FREEROOM(m), -+ m->m_len += slirp_fmt(bptr, M_FREEROOM(m), - "ORT %d,%d,%d,%d,%d,%d\r\n%s", - n1, n2, n3, n4, n5, n6, x==7?buff:""); - return 1; -@@ -740,7 +740,7 @@ tcp_emu(struct socket *so, struct mbuf *m) - n4 = (laddr & 0xff); - - m->m_len = bptr - m->m_data; /* Adjust length */ -- m->m_len += snprintf(bptr, M_FREEROOM(m), -+ m->m_len += slirp_fmt(bptr, M_FREEROOM(m), - "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", - n1, n2, n3, n4, n5, n6, x==7?buff:""); - -@@ -766,7 +766,7 @@ tcp_emu(struct socket *so, struct mbuf *m) - if (m->m_data[m->m_len-1] == '\0' && lport != 0 && - (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr, - htons(lport), SS_FACCEPTONCE)) != NULL) -- m->m_len = snprintf(m->m_data, M_ROOM(m), -+ m->m_len = slirp_fmt0(m->m_data, M_ROOM(m), - "%d", ntohs(so->so_fport)) + 1; - return 1; - -@@ -786,7 +786,7 @@ tcp_emu(struct socket *so, struct mbuf *m) - return 1; - } - m->m_len = bptr - m->m_data; /* Adjust length */ -- m->m_len += snprintf(bptr, M_FREEROOM(m), -+ m->m_len += slirp_fmt(bptr, M_FREEROOM(m), - "DCC CHAT chat %lu %u%c\n", - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), 1); -@@ -797,7 +797,7 @@ tcp_emu(struct socket *so, struct mbuf *m) - return 1; - } - m->m_len = bptr - m->m_data; /* Adjust length */ -- m->m_len += snprintf(bptr, M_FREEROOM(m), -+ m->m_len += slirp_fmt(bptr, M_FREEROOM(m), - "DCC SEND %s %lu %u %u%c\n", buff, - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), n1, 1); -@@ -808,7 +808,7 @@ tcp_emu(struct socket *so, struct mbuf *m) - return 1; - } - m->m_len = bptr - m->m_data; /* Adjust length */ -- m->m_len += snprintf(bptr, M_FREEROOM(m), -+ m->m_len += slirp_fmt(bptr, M_FREEROOM(m), - "DCC MOVE %s %lu %u %u%c\n", buff, - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), n1, 1); --- -2.21.1 (Apple Git-122.3) +@@ -655,8 +655,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) + NTOHS(n1); + NTOHS(n2); + m_inc(m, snprintf(NULL, 0, "%d,%d\r\n", n1, n2) + 1); +- m->m_len = snprintf(m->m_data, M_ROOM(m), "%d,%d\r\n", n1, n2); +- assert(m->m_len < M_ROOM(m)); ++ m->m_len = slirp_fmt(m->m_data, M_ROOM(m), "%d,%d\r\n", n1, n2); + } else { + *eol = '\r'; + } +@@ -696,7 +695,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) + n4 = (laddr & 0xff); + m->m_len = bptr - m->m_data; /* Adjust length */ +- m->m_len += snprintf(bptr, M_FREEROOM(m), ++ m->m_len += slirp_fmt(bptr, M_FREEROOM(m), + "ORT %d,%d,%d,%d,%d,%d\r\n%s", n1, n2, n3, n4, + n5, n6, x == 7 ? buff : ""); + return 1; +@@ -732,7 +731,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += +- snprintf(bptr, M_FREEROOM(m), ++ slirp_fmt(bptr, M_FREEROOM(m), + "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", + n1, n2, n3, n4, n5, n6, x == 7 ? buff : ""); + +@@ -759,7 +758,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) + (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr, + htons(lport), SS_FACCEPTONCE)) != NULL) + m->m_len = +- snprintf(m->m_data, M_ROOM(m), ++ slirp_fmt0(m->m_data, M_ROOM(m), + "%d", ntohs(so->so_fport)) + 1; + return 1; + +@@ -779,7 +778,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) + return 1; + } + m->m_len = bptr - m->m_data; /* Adjust length */ +- m->m_len += snprintf(bptr, M_FREEROOM(m), ++ m->m_len += slirp_fmt(bptr, M_FREEROOM(m), + "DCC CHAT chat %lu %u%c\n", + (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), 1); +@@ -791,7 +790,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) + } + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += +- snprintf(bptr, M_FREEROOM(m), ++ slirp_fmt(bptr, M_FREEROOM(m), + "DCC SEND %s %lu %u %u%c\n", buff, + (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), n1, 1); +@@ -803,7 +802,7 @@ int tcp_emu(struct socket *so, struct mbuf *m) + } + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += +- snprintf(bptr, M_FREEROOM(m), ++ slirp_fmt(bptr, M_FREEROOM(m), + "DCC MOVE %s %lu %u %u%c\n", buff, + (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), n1, 1); +-- +2.23.0 diff --git a/test-numa-Adjust-aarch64-numa-test.patch b/test-numa-Adjust-aarch64-numa-test.patch new file mode 100644 index 0000000000000000000000000000000000000000..24145937724385b1ff8dd0bd280e5e62341ad659 --- /dev/null +++ b/test-numa-Adjust-aarch64-numa-test.patch @@ -0,0 +1,58 @@ +From 3ef97cc418d1061fc0ec70098270ce2d76005cc1 Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Thu, 23 Apr 2020 20:54:18 +0800 +Subject: [PATCH] test/numa: Adjust aarch64 numa test + +We have supported topology for arm/virt in previous patch, which +changes the meaning of "thread-id", so we must modify test case. + +Signed-off-by: Keqian Zhu +--- + tests/numa-test.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/tests/numa-test.c b/tests/numa-test.c +index 8de8581231..71cdd7b4f7 100644 +--- a/tests/numa-test.c ++++ b/tests/numa-test.c +@@ -231,17 +231,17 @@ static void aarch64_numa_cpu(const void *data) + QObject *e; + QTestState *qts; + +- cli = make_cli(data, "-smp 2 " ++ cli = make_cli(data, "-smp 2,cores=2 " + "-numa node,nodeid=0 -numa node,nodeid=1 " +- "-numa cpu,node-id=1,thread-id=0 " +- "-numa cpu,node-id=0,thread-id=1"); ++ "-numa cpu,node-id=1,core-id=0 " ++ "-numa cpu,node-id=0,core-id=1"); + qts = qtest_init(cli); + cpus = get_cpus(qts, &resp); + g_assert(cpus); + + while ((e = qlist_pop(cpus))) { + QDict *cpu, *props; +- int64_t thread, node; ++ int64_t core, node; + + cpu = qobject_to(QDict, e); + g_assert(qdict_haskey(cpu, "props")); +@@ -249,12 +249,12 @@ static void aarch64_numa_cpu(const void *data) + + g_assert(qdict_haskey(props, "node-id")); + node = qdict_get_int(props, "node-id"); +- g_assert(qdict_haskey(props, "thread-id")); +- thread = qdict_get_int(props, "thread-id"); ++ g_assert(qdict_haskey(props, "core-id")); ++ core = qdict_get_int(props, "core-id"); + +- if (thread == 0) { ++ if (core == 0) { + g_assert_cmpint(node, ==, 1); +- } else if (thread == 1) { ++ } else if (core == 1) { + g_assert_cmpint(node, ==, 0); + } else { + g_assert(false); +-- +2.19.1 diff --git a/test-tpm-pass-optional-machine-options-to-swtpm-test.patch b/test-tpm-pass-optional-machine-options-to-swtpm-test.patch new file mode 100644 index 0000000000000000000000000000000000000000..fe7fd4ac907813d676cdf0c2a713e31279c29685 --- /dev/null +++ b/test-tpm-pass-optional-machine-options-to-swtpm-test.patch @@ -0,0 +1,187 @@ +From c06a3ceacc1793bc1cfe5c2a6ed510c9aea8253d Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Thu, 13 Aug 2020 20:28:25 +0800 +Subject: [PATCH 17/19] test: tpm: pass optional machine options to swtpm test + functions + +We plan to use swtpm test functions on ARM for testing the +sysbus TPM-TIS device. However on ARM there is no default machine +type. So we need to explictly pass some machine options on startup. +Let's allow this by adding a new parameter to both swtpm test +functions and update all call sites. + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Message-id: 20200305165149.618-9-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + tests/tpm-crb-swtpm-test.c | 5 +++-- + tests/tpm-tests.c | 10 ++++++---- + tests/tpm-tests.h | 5 +++-- + tests/tpm-tis-swtpm-test.c | 5 +++-- + tests/tpm-util.c | 8 ++++++-- + tests/tpm-util.h | 3 ++- + 6 files changed, 23 insertions(+), 13 deletions(-) + +diff --git a/tests/tpm-crb-swtpm-test.c b/tests/tpm-crb-swtpm-test.c +index 2c4fb8ae..5228cb7a 100644 +--- a/tests/tpm-crb-swtpm-test.c ++++ b/tests/tpm-crb-swtpm-test.c +@@ -29,7 +29,8 @@ static void tpm_crb_swtpm_test(const void *data) + { + const TestState *ts = data; + +- tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_crb_transfer, "tpm-crb"); ++ tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_crb_transfer, ++ "tpm-crb", NULL); + } + + static void tpm_crb_swtpm_migration_test(const void *data) +@@ -37,7 +38,7 @@ static void tpm_crb_swtpm_migration_test(const void *data) + const TestState *ts = data; + + tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri, +- tpm_util_crb_transfer, "tpm-crb"); ++ tpm_util_crb_transfer, "tpm-crb", NULL); + } + + int main(int argc, char **argv) +diff --git a/tests/tpm-tests.c b/tests/tpm-tests.c +index e640777a..d823bda8 100644 +--- a/tests/tpm-tests.c ++++ b/tests/tpm-tests.c +@@ -30,7 +30,7 @@ tpm_test_swtpm_skip(void) + } + + void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx, +- const char *ifmodel) ++ const char *ifmodel, const char *machine_options) + { + char *args = NULL; + QTestState *s; +@@ -47,10 +47,11 @@ void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx, + g_assert_true(succ); + + args = g_strdup_printf( ++ "%s " + "-chardev socket,id=chr,path=%s " + "-tpmdev emulator,id=dev,chardev=chr " + "-device %s,tpmdev=dev", +- addr->u.q_unix.path, ifmodel); ++ machine_options ? : "", addr->u.q_unix.path, ifmodel); + + s = qtest_start(args); + g_free(args); +@@ -78,7 +79,8 @@ void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx, + void tpm_test_swtpm_migration_test(const char *src_tpm_path, + const char *dst_tpm_path, + const char *uri, tx_func *tx, +- const char *ifmodel) ++ const char *ifmodel, ++ const char *machine_options) + { + gboolean succ; + GPid src_tpm_pid, dst_tpm_pid; +@@ -100,7 +102,7 @@ void tpm_test_swtpm_migration_test(const char *src_tpm_path, + + tpm_util_migration_start_qemu(&src_qemu, &dst_qemu, + src_tpm_addr, dst_tpm_addr, uri, +- ifmodel); ++ ifmodel, machine_options); + + tpm_util_startup(src_qemu, tx); + tpm_util_pcrextend(src_qemu, tx); +diff --git a/tests/tpm-tests.h b/tests/tpm-tests.h +index b97688fe..a5df35ab 100644 +--- a/tests/tpm-tests.h ++++ b/tests/tpm-tests.h +@@ -16,11 +16,12 @@ + #include "tpm-util.h" + + void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx, +- const char *ifmodel); ++ const char *ifmodel, const char *machine_options); + + void tpm_test_swtpm_migration_test(const char *src_tpm_path, + const char *dst_tpm_path, + const char *uri, tx_func *tx, +- const char *ifmodel); ++ const char *ifmodel, ++ const char *machine_options); + + #endif /* TESTS_TPM_TESTS_H */ +diff --git a/tests/tpm-tis-swtpm-test.c b/tests/tpm-tis-swtpm-test.c +index 9f58a3a9..9470f157 100644 +--- a/tests/tpm-tis-swtpm-test.c ++++ b/tests/tpm-tis-swtpm-test.c +@@ -29,7 +29,8 @@ static void tpm_tis_swtpm_test(const void *data) + { + const TestState *ts = data; + +- tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer, "tpm-tis"); ++ tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer, ++ "tpm-tis", NULL); + } + + static void tpm_tis_swtpm_migration_test(const void *data) +@@ -37,7 +38,7 @@ static void tpm_tis_swtpm_migration_test(const void *data) + const TestState *ts = data; + + tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri, +- tpm_util_tis_transfer, "tpm-tis"); ++ tpm_util_tis_transfer, "tpm-tis", NULL); + } + + int main(int argc, char **argv) +diff --git a/tests/tpm-util.c b/tests/tpm-util.c +index e08b1376..7ecdae2f 100644 +--- a/tests/tpm-util.c ++++ b/tests/tpm-util.c +@@ -258,23 +258,27 @@ void tpm_util_migration_start_qemu(QTestState **src_qemu, + SocketAddress *src_tpm_addr, + SocketAddress *dst_tpm_addr, + const char *miguri, +- const char *ifmodel) ++ const char *ifmodel, ++ const char *machine_options) + { + char *src_qemu_args, *dst_qemu_args; + + src_qemu_args = g_strdup_printf( ++ "%s " + "-chardev socket,id=chr,path=%s " + "-tpmdev emulator,id=dev,chardev=chr " + "-device %s,tpmdev=dev ", +- src_tpm_addr->u.q_unix.path, ifmodel); ++ machine_options ? : "", src_tpm_addr->u.q_unix.path, ifmodel); + + *src_qemu = qtest_init(src_qemu_args); + + dst_qemu_args = g_strdup_printf( ++ "%s " + "-chardev socket,id=chr,path=%s " + "-tpmdev emulator,id=dev,chardev=chr " + "-device %s,tpmdev=dev " + "-incoming %s", ++ machine_options ? : "", + dst_tpm_addr->u.q_unix.path, + ifmodel, miguri); + +diff --git a/tests/tpm-util.h b/tests/tpm-util.h +index 5755698a..15e39249 100644 +--- a/tests/tpm-util.h ++++ b/tests/tpm-util.h +@@ -44,7 +44,8 @@ void tpm_util_migration_start_qemu(QTestState **src_qemu, + SocketAddress *src_tpm_addr, + SocketAddress *dst_tpm_addr, + const char *miguri, +- const char *ifmodel); ++ const char *ifmodel, ++ const char *machine_options); + + void tpm_util_wait_for_migration_complete(QTestState *who); + +-- +2.23.0 + diff --git a/test-tpm-tis-Add-Sysbus-TPM-TIS-device-test.patch b/test-tpm-tis-Add-Sysbus-TPM-TIS-device-test.patch new file mode 100644 index 0000000000000000000000000000000000000000..fe33c8f4bd99eba304dc696d70a5126c559cd052 --- /dev/null +++ b/test-tpm-tis-Add-Sysbus-TPM-TIS-device-test.patch @@ -0,0 +1,226 @@ +From 2d28c0edddeaee5e4aa6e8c6b109776cddc1c4e4 Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Thu, 13 Aug 2020 21:37:23 +0800 +Subject: [PATCH 19/19] test: tpm-tis: Add Sysbus TPM-TIS device test + +The tests themselves are the same as the ISA device ones. +Only the main() changes as the tpm-tis-device device gets +instantiated. Also the base address of the device is not +0xFED40000 anymore but matches the base address of the +ARM virt platform bus. + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Message-id: 20200305165149.618-11-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + tests/Makefile.include | 5 ++ + tests/tpm-tis-device-swtpm-test.c | 76 +++++++++++++++++++++++++++ + tests/tpm-tis-device-test.c | 87 +++++++++++++++++++++++++++++++ + 3 files changed, 168 insertions(+) + create mode 100644 tests/tpm-tis-device-swtpm-test.c + create mode 100644 tests/tpm-tis-device-test.c + +diff --git a/tests/Makefile.include b/tests/Makefile.include +index 950b32a2..d6de4e10 100644 +--- a/tests/Makefile.include ++++ b/tests/Makefile.include +@@ -263,6 +263,8 @@ check-qtest-arm-y += tests/boot-serial-test$(EXESUF) + check-qtest-arm-y += tests/hexloader-test$(EXESUF) + check-qtest-arm-$(CONFIG_PFLASH_CFI02) += tests/pflash-cfi02-test$(EXESUF) + ++check-qtest-aarch64-$(CONFIG_TPM_TIS_SYSBUS) += tpm-tis-device-test ++check-qtest-aarch64-$(CONFIG_TPM_TIS_SYSBUS) += tpm-tis-device-swtpm-test + check-qtest-aarch64-y = tests/numa-test$(EXESUF) + check-qtest-aarch64-y += tests/boot-serial-test$(EXESUF) + check-qtest-aarch64-y += tests/migration-test$(EXESUF) +@@ -667,7 +669,10 @@ tests/tpm-crb-swtpm-test$(EXESUF): tests/tpm-crb-swtpm-test.o tests/tpm-emu.o \ + tests/tpm-crb-test$(EXESUF): tests/tpm-crb-test.o tests/tpm-emu.o $(test-io-obj-y) + tests/tpm-tis-swtpm-test$(EXESUF): tests/tpm-tis-swtpm-test.o tests/tpm-emu.o \ + tests/tpm-util.o tests/tpm-tests.o $(test-io-obj-y) ++tests/tpm-tis-device-swtpm-test$(EXESUF): tests/tpm-tis-device-swtpm-test.o tests/tpm-emu.o \ ++ tests/tpm-util.o tests/tpm-tests.o $(test-io-obj-y) + tests/tpm-tis-test$(EXESUF): tests/tpm-tis-test.o tests/tpm-tis-util.o tests/tpm-emu.o $(test-io-obj-y) ++tests/tpm-tis-device-test$(EXESUF): tests/tpm-tis-device-test.o tests/tpm-tis-util.o tests/tpm-emu.o $(test-io-obj-y) + tests/test-io-channel-file$(EXESUF): tests/test-io-channel-file.o \ + tests/io-channel-helpers.o $(test-io-obj-y) + tests/test-io-channel-tls$(EXESUF): tests/test-io-channel-tls.o \ +diff --git a/tests/tpm-tis-device-swtpm-test.c b/tests/tpm-tis-device-swtpm-test.c +new file mode 100644 +index 00000000..7b200351 +--- /dev/null ++++ b/tests/tpm-tis-device-swtpm-test.c +@@ -0,0 +1,76 @@ ++/* ++ * QTest testcase for Sysbus TPM TIS talking to external swtpm and swtpm ++ * migration ++ * ++ * Copyright (c) 2018 IBM Corporation ++ * with parts borrowed from migration-test.c that is: ++ * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates ++ * ++ * Authors: ++ * Stefan Berger ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#include "qemu/osdep.h" ++#include ++ ++#include "libqtest.h" ++#include "qemu/module.h" ++#include "tpm-tests.h" ++#include "hw/acpi/tpm.h" ++ ++uint64_t tpm_tis_base_addr = 0xc000000; ++#define MACHINE_OPTIONS "-machine virt,gic-version=max -accel tcg" ++ ++typedef struct TestState { ++ char *src_tpm_path; ++ char *dst_tpm_path; ++ char *uri; ++} TestState; ++ ++static void tpm_tis_swtpm_test(const void *data) ++{ ++ const TestState *ts = data; ++ ++ tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer, ++ "tpm-tis-device", MACHINE_OPTIONS); ++} ++ ++static void tpm_tis_swtpm_migration_test(const void *data) ++{ ++ const TestState *ts = data; ++ ++ tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri, ++ tpm_util_tis_transfer, "tpm-tis-device", ++ MACHINE_OPTIONS); ++} ++ ++int main(int argc, char **argv) ++{ ++ int ret; ++ TestState ts = { 0 }; ++ ++ ts.src_tpm_path = g_dir_make_tmp("qemu-tpm-tis-device-swtpm-test.XXXXXX", ++ NULL); ++ ts.dst_tpm_path = g_dir_make_tmp("qemu-tpm-tis-device-swtpm-test.XXXXXX", ++ NULL); ++ ts.uri = g_strdup_printf("unix:%s/migsocket", ts.src_tpm_path); ++ ++ module_call_init(MODULE_INIT_QOM); ++ g_test_init(&argc, &argv, NULL); ++ ++ qtest_add_data_func("/tpm/tis-swtpm/test", &ts, tpm_tis_swtpm_test); ++ qtest_add_data_func("/tpm/tis-swtpm-migration/test", &ts, ++ tpm_tis_swtpm_migration_test); ++ ret = g_test_run(); ++ ++ g_rmdir(ts.dst_tpm_path); ++ g_free(ts.dst_tpm_path); ++ g_rmdir(ts.src_tpm_path); ++ g_free(ts.src_tpm_path); ++ g_free(ts.uri); ++ ++ return ret; ++} +diff --git a/tests/tpm-tis-device-test.c b/tests/tpm-tis-device-test.c +new file mode 100644 +index 00000000..63ed3644 +--- /dev/null ++++ b/tests/tpm-tis-device-test.c +@@ -0,0 +1,87 @@ ++/* ++ * QTest testcase for SYSBUS TPM TIS ++ * ++ * Copyright (c) 2018 Red Hat, Inc. ++ * Copyright (c) 2018 IBM Corporation ++ * ++ * Authors: ++ * Marc-André Lureau ++ * Stefan Berger ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#include "qemu/osdep.h" ++#include ++ ++#include "io/channel-socket.h" ++#include "libqtest-single.h" ++#include "qemu/module.h" ++#include "tpm-emu.h" ++#include "tpm-util.h" ++#include "tpm-tis-util.h" ++ ++/* ++ * As the Sysbus tpm-tis-device is instantiated on the ARM virt ++ * platform bus and it is the only sysbus device dynamically ++ * instantiated, it gets plugged at its base address ++ */ ++uint64_t tpm_tis_base_addr = 0xc000000; ++ ++int main(int argc, char **argv) ++{ ++ char *tmp_path = g_dir_make_tmp("qemu-tpm-tis-device-test.XXXXXX", NULL); ++ GThread *thread; ++ TestState test; ++ char *args; ++ int ret; ++ ++ module_call_init(MODULE_INIT_QOM); ++ g_test_init(&argc, &argv, NULL); ++ ++ test.addr = g_new0(SocketAddress, 1); ++ test.addr->type = SOCKET_ADDRESS_TYPE_UNIX; ++ test.addr->u.q_unix.path = g_build_filename(tmp_path, "sock", NULL); ++ g_mutex_init(&test.data_mutex); ++ g_cond_init(&test.data_cond); ++ test.data_cond_signal = false; ++ ++ thread = g_thread_new(NULL, tpm_emu_ctrl_thread, &test); ++ tpm_emu_test_wait_cond(&test); ++ ++ args = g_strdup_printf( ++ "-machine virt,gic-version=max -accel tcg " ++ "-chardev socket,id=chr,path=%s " ++ "-tpmdev emulator,id=dev,chardev=chr " ++ "-device tpm-tis-device,tpmdev=dev", ++ test.addr->u.q_unix.path); ++ qtest_start(args); ++ ++ qtest_add_data_func("/tpm-tis/test_check_localities", &test, ++ tpm_tis_test_check_localities); ++ ++ qtest_add_data_func("/tpm-tis/test_check_access_reg", &test, ++ tpm_tis_test_check_access_reg); ++ ++ qtest_add_data_func("/tpm-tis/test_check_access_reg_seize", &test, ++ tpm_tis_test_check_access_reg_seize); ++ ++ qtest_add_data_func("/tpm-tis/test_check_access_reg_release", &test, ++ tpm_tis_test_check_access_reg_release); ++ ++ qtest_add_data_func("/tpm-tis/test_check_transmit", &test, ++ tpm_tis_test_check_transmit); ++ ++ ret = g_test_run(); ++ ++ qtest_end(); ++ ++ g_thread_join(thread); ++ g_unlink(test.addr->u.q_unix.path); ++ qapi_free_SocketAddress(test.addr); ++ g_rmdir(tmp_path); ++ g_free(tmp_path); ++ g_free(args); ++ return ret; ++} +-- +2.23.0 + diff --git a/test-tpm-tis-Get-prepared-to-share-tests-between-ISA.patch b/test-tpm-tis-Get-prepared-to-share-tests-between-ISA.patch new file mode 100644 index 0000000000000000000000000000000000000000..4c7be00a5f1d015d5da4fcf4791e6a175f0ff9c7 --- /dev/null +++ b/test-tpm-tis-Get-prepared-to-share-tests-between-ISA.patch @@ -0,0 +1,1044 @@ +From c8ed2a1fbe306ecbfb5c7d4156ae81c029829d95 Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Thu, 13 Aug 2020 20:56:54 +0800 +Subject: [PATCH 18/19] test: tpm-tis: Get prepared to share tests between ISA + and sysbus devices + +ISA and sysbus TPM-TIS devices will share their tests. Only +the main() will change (instantiation option is different). +Also the base address of the TPM-TIS device is going to be +different. on x86 it is located at 0xFED40000 while on ARM +it can be located at any location, discovered through the +device tree description. + +So we put shared test functions in a new object module. +Each test needs to set tpm_tis_base_addr global variable. + +Also take benefit of this move to fix "block comments using +a leading */ on a separate line" checkpatch warnings. + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Message-id: 20200305165149.618-10-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + tests/Makefile.include | 2 +- + tests/tpm-crb-swtpm-test.c | 4 + + tests/tpm-crb-test.c | 3 + + tests/tpm-tis-swtpm-test.c | 3 + + tests/tpm-tis-test.c | 414 +--------------------------------- + tests/tpm-tis-util.c | 451 +++++++++++++++++++++++++++++++++++++ + tests/tpm-tis-util.h | 23 ++ + tests/tpm-util.c | 3 - + tests/tpm-util.h | 5 + + 9 files changed, 493 insertions(+), 415 deletions(-) + create mode 100644 tests/tpm-tis-util.c + create mode 100644 tests/tpm-tis-util.h + +diff --git a/tests/Makefile.include b/tests/Makefile.include +index c151de64..950b32a2 100644 +--- a/tests/Makefile.include ++++ b/tests/Makefile.include +@@ -667,7 +667,7 @@ tests/tpm-crb-swtpm-test$(EXESUF): tests/tpm-crb-swtpm-test.o tests/tpm-emu.o \ + tests/tpm-crb-test$(EXESUF): tests/tpm-crb-test.o tests/tpm-emu.o $(test-io-obj-y) + tests/tpm-tis-swtpm-test$(EXESUF): tests/tpm-tis-swtpm-test.o tests/tpm-emu.o \ + tests/tpm-util.o tests/tpm-tests.o $(test-io-obj-y) +-tests/tpm-tis-test$(EXESUF): tests/tpm-tis-test.o tests/tpm-emu.o $(test-io-obj-y) ++tests/tpm-tis-test$(EXESUF): tests/tpm-tis-test.o tests/tpm-tis-util.o tests/tpm-emu.o $(test-io-obj-y) + tests/test-io-channel-file$(EXESUF): tests/test-io-channel-file.o \ + tests/io-channel-helpers.o $(test-io-obj-y) + tests/test-io-channel-tls$(EXESUF): tests/test-io-channel-tls.o \ +diff --git a/tests/tpm-crb-swtpm-test.c b/tests/tpm-crb-swtpm-test.c +index 5228cb7a..55fdb565 100644 +--- a/tests/tpm-crb-swtpm-test.c ++++ b/tests/tpm-crb-swtpm-test.c +@@ -18,6 +18,10 @@ + #include "libqtest.h" + #include "qemu/module.h" + #include "tpm-tests.h" ++#include "hw/acpi/tpm.h" ++ ++/* Not used but needed for linking */ ++uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE; + + typedef struct TestState { + char *src_tpm_path; +diff --git a/tests/tpm-crb-test.c b/tests/tpm-crb-test.c +index a139caa5..32695810 100644 +--- a/tests/tpm-crb-test.c ++++ b/tests/tpm-crb-test.c +@@ -19,6 +19,9 @@ + #include "qemu/module.h" + #include "tpm-emu.h" + ++/* Not used but needed for linking */ ++uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE; ++ + #define TPM_CMD "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00" + + static void tpm_crb_test(const void *data) +diff --git a/tests/tpm-tis-swtpm-test.c b/tests/tpm-tis-swtpm-test.c +index 9470f157..90131cb3 100644 +--- a/tests/tpm-tis-swtpm-test.c ++++ b/tests/tpm-tis-swtpm-test.c +@@ -18,6 +18,9 @@ + #include "libqtest.h" + #include "qemu/module.h" + #include "tpm-tests.h" ++#include "hw/acpi/tpm.h" ++ ++uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE; + + typedef struct TestState { + char *src_tpm_path; +diff --git a/tests/tpm-tis-test.c b/tests/tpm-tis-test.c +index 92a7e95a..8042de13 100644 +--- a/tests/tpm-tis-test.c ++++ b/tests/tpm-tis-test.c +@@ -1,5 +1,5 @@ + /* +- * QTest testcase for TPM TIS ++ * QTest testcase for ISA TPM TIS + * + * Copyright (c) 2018 Red Hat, Inc. + * Copyright (c) 2018 IBM Corporation +@@ -20,417 +20,9 @@ + #include "libqtest.h" + #include "qemu/module.h" + #include "tpm-emu.h" ++#include "tpm-tis-util.h" + +-#define TIS_REG(LOCTY, REG) \ +- (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG) +- +-#define DEBUG_TIS_TEST 0 +- +-#define DPRINTF(fmt, ...) do { \ +- if (DEBUG_TIS_TEST) { \ +- printf(fmt, ## __VA_ARGS__); \ +- } \ +-} while (0) +- +-#define DPRINTF_ACCESS \ +- DPRINTF("%s: %d: locty=%d l=%d access=0x%02x pending_request_flag=0x%x\n", \ +- __func__, __LINE__, locty, l, access, pending_request_flag) +- +-#define DPRINTF_STS \ +- DPRINTF("%s: %d: sts = 0x%08x\n", __func__, __LINE__, sts) +- +-static const uint8_t TPM_CMD[12] = +- "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00"; +- +-static void tpm_tis_test_check_localities(const void *data) +-{ +- uint8_t locty; +- uint8_t access; +- uint32_t ifaceid; +- uint32_t capability; +- uint32_t didvid; +- uint32_t rid; +- +- for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES; locty++) { +- access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- capability = readl(TIS_REG(locty, TPM_TIS_REG_INTF_CAPABILITY)); +- g_assert_cmpint(capability, ==, TPM_TIS_CAPABILITIES_SUPPORTED2_0); +- +- ifaceid = readl(TIS_REG(locty, TPM_TIS_REG_INTERFACE_ID)); +- g_assert_cmpint(ifaceid, ==, TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0); +- +- didvid = readl(TIS_REG(locty, TPM_TIS_REG_DID_VID)); +- g_assert_cmpint(didvid, !=, 0); +- g_assert_cmpint(didvid, !=, 0xffffffff); +- +- rid = readl(TIS_REG(locty, TPM_TIS_REG_RID)); +- g_assert_cmpint(rid, !=, 0); +- g_assert_cmpint(rid, !=, 0xffffffff); +- } +-} +- +-static void tpm_tis_test_check_access_reg(const void *data) +-{ +- uint8_t locty; +- uint8_t access; +- +- /* do not test locality 4 (hw only) */ +- for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* request use of locality */ +- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* release access */ +- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- } +-} +- +-/* +- * Test case for seizing access by a higher number locality +- */ +-static void tpm_tis_test_check_access_reg_seize(const void *data) +-{ +- int locty, l; +- uint8_t access; +- uint8_t pending_request_flag; +- +- /* do not test locality 4 (hw only) */ +- for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { +- pending_request_flag = 0; +- +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* request use of locality */ +- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* lower localities cannot seize access */ +- for (l = 0; l < locty; l++) { +- /* lower locality is not active */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* try to request use from 'l' */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- +- /* requesting use from 'l' was not possible; +- we must see REQUEST_USE and possibly PENDING_REQUEST */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_REQUEST_USE | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* locality 'locty' must be unchanged; +- we must see PENDING_REQUEST */ +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_PENDING_REQUEST | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* try to seize from 'l' */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); +- /* seize from 'l' was not possible */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_REQUEST_USE | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* locality 'locty' must be unchanged */ +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_PENDING_REQUEST | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* on the next loop we will have a PENDING_REQUEST flag +- set for locality 'l' */ +- pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; +- } +- +- /* higher localities can 'seize' access but not 'request use'; +- note: this will activate first l+1, then l+2 etc. */ +- for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { +- /* try to 'request use' from 'l' */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- +- /* requesting use from 'l' was not possible; we should see +- REQUEST_USE and may see PENDING_REQUEST */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_REQUEST_USE | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* locality 'l-1' must be unchanged; we should always +- see PENDING_REQUEST from 'l' requesting access */ +- access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_PENDING_REQUEST | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* try to seize from 'l' */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); +- +- /* seize from 'l' was possible */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* l - 1 should show that it has BEEN_SEIZED */ +- access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_BEEN_SEIZED | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* clear the BEEN_SEIZED flag and make sure it's gone */ +- writeb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_BEEN_SEIZED); +- +- access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- } +- +- /* PENDING_REQUEST will not be set if locty = 0 since all localities +- were active; in case of locty = 1, locality 0 will be active +- but no PENDING_REQUEST anywhere */ +- if (locty <= 1) { +- pending_request_flag = 0; +- } +- +- /* release access from l - 1; this activates locty - 1 */ +- l--; +- +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- +- DPRINTF("%s: %d: relinquishing control on l = %d\n", +- __func__, __LINE__, l); +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- for (l = locty - 1; l >= 0; l--) { +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* release this locality */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- +- if (l == 1) { +- pending_request_flag = 0; +- } +- } +- +- /* no locality may be active now */ +- for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- } +- } +-} +- +-/* +- * Test case for getting access when higher number locality relinquishes access +- */ +-static void tpm_tis_test_check_access_reg_release(const void *data) +-{ +- int locty, l; +- uint8_t access; +- uint8_t pending_request_flag; +- +- /* do not test locality 4 (hw only) */ +- for (locty = TPM_TIS_NUM_LOCALITIES - 2; locty >= 0; locty--) { +- pending_request_flag = 0; +- +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* request use of locality */ +- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* request use of all other localities */ +- for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { +- if (l == locty) { +- continue; +- } +- /* request use of locality 'l' -- we MUST see REQUEST USE and +- may see PENDING_REQUEST */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_REQUEST_USE | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; +- } +- /* release locality 'locty' */ +- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- /* highest locality should now be active; release it and make sure the +- next higest locality is active afterwards */ +- for (l = TPM_TIS_NUM_LOCALITIES - 2; l >= 0; l--) { +- if (l == locty) { +- continue; +- } +- /* 'l' should be active now */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- /* 'l' relinquishes access */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- if (l == 1 || (locty <= 1 && l == 2)) { +- pending_request_flag = 0; +- } +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- } +- } +-} +- +-/* +- * Test case for transmitting packets +- */ +-static void tpm_tis_test_check_transmit(const void *data) +-{ +- const TestState *s = data; +- uint8_t access; +- uint32_t sts; +- uint16_t bcount; +- size_t i; +- +- /* request use of locality 0 */ +- writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- DPRINTF_STS; +- +- g_assert_cmpint(sts & 0xff, ==, 0); +- g_assert_cmpint(sts & TPM_TIS_STS_TPM_FAMILY_MASK, ==, +- TPM_TIS_STS_TPM_FAMILY2_0); +- +- bcount = (sts >> 8) & 0xffff; +- g_assert_cmpint(bcount, >=, 128); +- +- writel(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY); +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- DPRINTF_STS; +- g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_COMMAND_READY); +- +- /* transmit command */ +- for (i = 0; i < sizeof(TPM_CMD); i++) { +- writeb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO), TPM_CMD[i]); +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- DPRINTF_STS; +- if (i < sizeof(TPM_CMD) - 1) { +- g_assert_cmpint(sts & 0xff, ==, +- TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); +- } else { +- g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_VALID); +- } +- g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); +- } +- /* start processing */ +- writeb(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO); +- +- uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND; +- do { +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) { +- break; +- } +- } while (g_get_monotonic_time() < end_time); +- +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- DPRINTF_STS; +- g_assert_cmpint(sts & 0xff, == , +- TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); +- bcount = (sts >> 8) & 0xffff; +- +- /* read response */ +- uint8_t tpm_msg[sizeof(struct tpm_hdr)]; +- g_assert_cmpint(sizeof(tpm_msg), ==, bcount); +- +- for (i = 0; i < sizeof(tpm_msg); i++) { +- tpm_msg[i] = readb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO)); +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- DPRINTF_STS; +- if (sts & TPM_TIS_STS_DATA_AVAILABLE) { +- g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); +- } +- } +- g_assert_cmpmem(tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg)); +- +- /* relinquish use of locality 0 */ +- writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); +-} ++uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE; + + int main(int argc, char **argv) + { +diff --git a/tests/tpm-tis-util.c b/tests/tpm-tis-util.c +new file mode 100644 +index 00000000..9aff503f +--- /dev/null ++++ b/tests/tpm-tis-util.c +@@ -0,0 +1,451 @@ ++/* ++ * QTest testcase for TPM TIS: common test functions used for both ++ * the ISA and SYSBUS devices ++ * ++ * Copyright (c) 2018 Red Hat, Inc. ++ * Copyright (c) 2018 IBM Corporation ++ * ++ * Authors: ++ * Marc-André Lureau ++ * Stefan Berger ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#include "qemu/osdep.h" ++#include ++ ++#include "hw/acpi/tpm.h" ++#include "io/channel-socket.h" ++#include "libqtest.h" ++#include "qemu/module.h" ++#include "tpm-emu.h" ++#include "tpm-util.h" ++#include "tpm-tis-util.h" ++ ++#define DEBUG_TIS_TEST 0 ++ ++#define DPRINTF(fmt, ...) do { \ ++ if (DEBUG_TIS_TEST) { \ ++ printf(fmt, ## __VA_ARGS__); \ ++ } \ ++} while (0) ++ ++#define DPRINTF_ACCESS \ ++ DPRINTF("%s: %d: locty=%d l=%d access=0x%02x pending_request_flag=0x%x\n", \ ++ __func__, __LINE__, locty, l, access, pending_request_flag) ++ ++#define DPRINTF_STS \ ++ DPRINTF("%s: %d: sts = 0x%08x\n", __func__, __LINE__, sts) ++ ++static const uint8_t TPM_CMD[12] = ++ "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00"; ++ ++void tpm_tis_test_check_localities(const void *data) ++{ ++ uint8_t locty; ++ uint8_t access; ++ uint32_t ifaceid; ++ uint32_t capability; ++ uint32_t didvid; ++ uint32_t rid; ++ ++ for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES; locty++) { ++ access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ capability = readl(TIS_REG(locty, TPM_TIS_REG_INTF_CAPABILITY)); ++ g_assert_cmpint(capability, ==, TPM_TIS_CAPABILITIES_SUPPORTED2_0); ++ ++ ifaceid = readl(TIS_REG(locty, TPM_TIS_REG_INTERFACE_ID)); ++ g_assert_cmpint(ifaceid, ==, TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0); ++ ++ didvid = readl(TIS_REG(locty, TPM_TIS_REG_DID_VID)); ++ g_assert_cmpint(didvid, !=, 0); ++ g_assert_cmpint(didvid, !=, 0xffffffff); ++ ++ rid = readl(TIS_REG(locty, TPM_TIS_REG_RID)); ++ g_assert_cmpint(rid, !=, 0); ++ g_assert_cmpint(rid, !=, 0xffffffff); ++ } ++} ++ ++void tpm_tis_test_check_access_reg(const void *data) ++{ ++ uint8_t locty; ++ uint8_t access; ++ ++ /* do not test locality 4 (hw only) */ ++ for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* request use of locality */ ++ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* release access */ ++ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ } ++} ++ ++/* ++ * Test case for seizing access by a higher number locality ++ */ ++void tpm_tis_test_check_access_reg_seize(const void *data) ++{ ++ int locty, l; ++ uint8_t access; ++ uint8_t pending_request_flag; ++ ++ /* do not test locality 4 (hw only) */ ++ for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { ++ pending_request_flag = 0; ++ ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* request use of locality */ ++ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* lower localities cannot seize access */ ++ for (l = 0; l < locty; l++) { ++ /* lower locality is not active */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* try to request use from 'l' */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ ++ /* ++ * requesting use from 'l' was not possible; ++ * we must see REQUEST_USE and possibly PENDING_REQUEST ++ */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_REQUEST_USE | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* ++ * locality 'locty' must be unchanged; ++ * we must see PENDING_REQUEST ++ */ ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_PENDING_REQUEST | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* try to seize from 'l' */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); ++ /* seize from 'l' was not possible */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_REQUEST_USE | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* locality 'locty' must be unchanged */ ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_PENDING_REQUEST | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* ++ * on the next loop we will have a PENDING_REQUEST flag ++ * set for locality 'l' ++ */ ++ pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; ++ } ++ ++ /* ++ * higher localities can 'seize' access but not 'request use'; ++ * note: this will activate first l+1, then l+2 etc. ++ */ ++ for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { ++ /* try to 'request use' from 'l' */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ ++ /* ++ * requesting use from 'l' was not possible; we should see ++ * REQUEST_USE and may see PENDING_REQUEST ++ */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_REQUEST_USE | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* ++ * locality 'l-1' must be unchanged; we should always ++ * see PENDING_REQUEST from 'l' requesting access ++ */ ++ access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_PENDING_REQUEST | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* try to seize from 'l' */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); ++ ++ /* seize from 'l' was possible */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* l - 1 should show that it has BEEN_SEIZED */ ++ access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_BEEN_SEIZED | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* clear the BEEN_SEIZED flag and make sure it's gone */ ++ writeb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_BEEN_SEIZED); ++ ++ access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ } ++ ++ /* ++ * PENDING_REQUEST will not be set if locty = 0 since all localities ++ * were active; in case of locty = 1, locality 0 will be active ++ * but no PENDING_REQUEST anywhere ++ */ ++ if (locty <= 1) { ++ pending_request_flag = 0; ++ } ++ ++ /* release access from l - 1; this activates locty - 1 */ ++ l--; ++ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ ++ DPRINTF("%s: %d: relinquishing control on l = %d\n", ++ __func__, __LINE__, l); ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ for (l = locty - 1; l >= 0; l--) { ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* release this locality */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ ++ if (l == 1) { ++ pending_request_flag = 0; ++ } ++ } ++ ++ /* no locality may be active now */ ++ for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ } ++ } ++} ++ ++/* ++ * Test case for getting access when higher number locality relinquishes access ++ */ ++void tpm_tis_test_check_access_reg_release(const void *data) ++{ ++ int locty, l; ++ uint8_t access; ++ uint8_t pending_request_flag; ++ ++ /* do not test locality 4 (hw only) */ ++ for (locty = TPM_TIS_NUM_LOCALITIES - 2; locty >= 0; locty--) { ++ pending_request_flag = 0; ++ ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* request use of locality */ ++ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* request use of all other localities */ ++ for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { ++ if (l == locty) { ++ continue; ++ } ++ /* ++ * request use of locality 'l' -- we MUST see REQUEST USE and ++ * may see PENDING_REQUEST ++ */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_REQUEST_USE | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; ++ } ++ /* release locality 'locty' */ ++ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ /* ++ * highest locality should now be active; release it and make sure the ++ * next higest locality is active afterwards ++ */ ++ for (l = TPM_TIS_NUM_LOCALITIES - 2; l >= 0; l--) { ++ if (l == locty) { ++ continue; ++ } ++ /* 'l' should be active now */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ /* 'l' relinquishes access */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ if (l == 1 || (locty <= 1 && l == 2)) { ++ pending_request_flag = 0; ++ } ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ } ++ } ++} ++ ++/* ++ * Test case for transmitting packets ++ */ ++void tpm_tis_test_check_transmit(const void *data) ++{ ++ const TestState *s = data; ++ uint8_t access; ++ uint32_t sts; ++ uint16_t bcount; ++ size_t i; ++ ++ /* request use of locality 0 */ ++ writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ DPRINTF_STS; ++ ++ g_assert_cmpint(sts & 0xff, ==, 0); ++ g_assert_cmpint(sts & TPM_TIS_STS_TPM_FAMILY_MASK, ==, ++ TPM_TIS_STS_TPM_FAMILY2_0); ++ ++ bcount = (sts >> 8) & 0xffff; ++ g_assert_cmpint(bcount, >=, 128); ++ ++ writel(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY); ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ DPRINTF_STS; ++ g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_COMMAND_READY); ++ ++ /* transmit command */ ++ for (i = 0; i < sizeof(TPM_CMD); i++) { ++ writeb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO), TPM_CMD[i]); ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ DPRINTF_STS; ++ if (i < sizeof(TPM_CMD) - 1) { ++ g_assert_cmpint(sts & 0xff, ==, ++ TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); ++ } else { ++ g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_VALID); ++ } ++ g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); ++ } ++ /* start processing */ ++ writeb(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO); ++ ++ uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND; ++ do { ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) { ++ break; ++ } ++ } while (g_get_monotonic_time() < end_time); ++ ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ DPRINTF_STS; ++ g_assert_cmpint(sts & 0xff, == , ++ TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); ++ bcount = (sts >> 8) & 0xffff; ++ ++ /* read response */ ++ uint8_t tpm_msg[sizeof(struct tpm_hdr)]; ++ g_assert_cmpint(sizeof(tpm_msg), ==, bcount); ++ ++ for (i = 0; i < sizeof(tpm_msg); i++) { ++ tpm_msg[i] = readb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO)); ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ DPRINTF_STS; ++ if (sts & TPM_TIS_STS_DATA_AVAILABLE) { ++ g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); ++ } ++ } ++ g_assert_cmpmem(tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg)); ++ ++ /* relinquish use of locality 0 */ ++ writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); ++} +diff --git a/tests/tpm-tis-util.h b/tests/tpm-tis-util.h +new file mode 100644 +index 00000000..d10efe86 +--- /dev/null ++++ b/tests/tpm-tis-util.h +@@ -0,0 +1,23 @@ ++/* ++ * QTest TPM TIS: Common test functions used for both the ++ * ISA and SYSBUS devices ++ * ++ * Copyright (c) 2018 IBM Corporation ++ * ++ * Authors: ++ * Stefan Berger ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#ifndef TESTS_TPM_TIS_UTIL_H ++#define TESTS_TPM_TIS_UTIL_H ++ ++void tpm_tis_test_check_localities(const void *data); ++void tpm_tis_test_check_access_reg(const void *data); ++void tpm_tis_test_check_access_reg_seize(const void *data); ++void tpm_tis_test_check_access_reg_release(const void *data); ++void tpm_tis_test_check_transmit(const void *data); ++ ++#endif /* TESTS_TPM_TIS_UTIL_H */ +diff --git a/tests/tpm-util.c b/tests/tpm-util.c +index 7ecdae2f..34efae8f 100644 +--- a/tests/tpm-util.c ++++ b/tests/tpm-util.c +@@ -19,9 +19,6 @@ + #include "tpm-util.h" + #include "qapi/qmp/qdict.h" + +-#define TIS_REG(LOCTY, REG) \ +- (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG) +- + void tpm_util_crb_transfer(QTestState *s, + const unsigned char *req, size_t req_size, + unsigned char *rsp, size_t rsp_size) +diff --git a/tests/tpm-util.h b/tests/tpm-util.h +index 15e39249..3b97d690 100644 +--- a/tests/tpm-util.h ++++ b/tests/tpm-util.h +@@ -15,6 +15,11 @@ + + #include "io/channel-socket.h" + ++extern uint64_t tpm_tis_base_addr; ++ ++#define TIS_REG(LOCTY, REG) \ ++ (tpm_tis_base_addr + ((LOCTY) << 12) + REG) ++ + typedef void (tx_func)(QTestState *s, + const unsigned char *req, size_t req_size, + unsigned char *rsp, size_t rsp_size); +-- +2.23.0 + diff --git a/tests-Add-bios-tests-to-arm-virt.patch b/tests-Add-bios-tests-to-arm-virt.patch new file mode 100644 index 0000000000000000000000000000000000000000..025afb506017f9bc1c6fdb26df35c9534a8f3672 --- /dev/null +++ b/tests-Add-bios-tests-to-arm-virt.patch @@ -0,0 +1,86 @@ +From abbcc35ccb22d81d69a28dc66b5f5d94e673a25e Mon Sep 17 00:00:00 2001 +From: Shameer Kolothum +Date: Wed, 18 Sep 2019 14:06:33 +0100 +Subject: [PATCH] tests: Add bios tests to arm/virt + +This adds numamem and memhp tests for arm/virt platform. + +Signed-off-by: Shameer Kolothum +Reviewed-by: Igor Mammedov +Message-Id: <20190918130633.4872-12-shameerali.kolothum.thodi@huawei.com> +Acked-by: Peter Maydell +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + tests/bios-tables-test.c | 49 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 49 insertions(+) + +diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c +index 53a91a8067..5e177b7155 100644 +--- a/tests/bios-tables-test.c ++++ b/tests/bios-tables-test.c +@@ -874,6 +874,53 @@ static void test_acpi_piix4_tcg_dimm_pxm(void) + test_acpi_tcg_dimm_pxm(MACHINE_PC); + } + ++static void test_acpi_virt_tcg_memhp(void) ++{ ++ test_data data = { ++ .machine = "virt", ++ .accel = "tcg", ++ .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd", ++ .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", ++ .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2", ++ .ram_start = 0x40000000ULL, ++ .scan_len = 256ULL * 1024 * 1024, ++ }; ++ ++ data.variant = ".memhp"; ++ test_acpi_one(" -cpu cortex-a57" ++ " -m 256M,slots=3,maxmem=1G" ++ " -object memory-backend-ram,id=ram0,size=128M" ++ " -object memory-backend-ram,id=ram1,size=128M" ++ " -numa node,memdev=ram0 -numa node,memdev=ram1" ++ " -numa dist,src=0,dst=1,val=21", ++ &data); ++ ++ free_test_data(&data); ++ ++} ++ ++static void test_acpi_virt_tcg_numamem(void) ++{ ++ test_data data = { ++ .machine = "virt", ++ .accel = "tcg", ++ .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd", ++ .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", ++ .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2", ++ .ram_start = 0x40000000ULL, ++ .scan_len = 128ULL * 1024 * 1024, ++ }; ++ ++ data.variant = ".numamem"; ++ test_acpi_one(" -cpu cortex-a57" ++ " -object memory-backend-ram,id=ram0,size=128M" ++ " -numa node,memdev=ram0", ++ &data); ++ ++ free_test_data(&data); ++ ++} ++ + static void test_acpi_virt_tcg(void) + { + test_data data = { +@@ -920,6 +967,8 @@ int main(int argc, char *argv[]) + qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm); + } else if (strcmp(arch, "aarch64") == 0) { + qtest_add_func("acpi/virt", test_acpi_virt_tcg); ++ qtest_add_func("acpi/virt/numamem", test_acpi_virt_tcg_numamem); ++ qtest_add_func("acpi/virt/memhp", test_acpi_virt_tcg_memhp); + } + ret = g_test_run(); + boot_sector_cleanup(disk); +-- +2.19.1 diff --git a/tests-Disalbe-filemonitor-testcase.patch b/tests-Disalbe-filemonitor-testcase.patch new file mode 100644 index 0000000000000000000000000000000000000000..b389299e35dd49154f6e660ee3d66237b15ec58b --- /dev/null +++ b/tests-Disalbe-filemonitor-testcase.patch @@ -0,0 +1,34 @@ +From 4f1eaa63065594276c11958e963377a09668d44b Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Thu, 6 Aug 2020 10:05:00 +0800 +Subject: [PATCH] tests: Disalbe filemonitor testcase + +Since filemonitor testcase requires that host kernel being a LTS version, +we cannot guarantee that on OBS system. Let's disable it by default. + +Signed-of-by: Ying Fang + +diff --git a/tests/Makefile.include b/tests/Makefile.include +index d8cf00c1..f3273ad3 100644 +--- a/tests/Makefile.include ++++ b/tests/Makefile.include +@@ -117,7 +117,6 @@ ifneq (,$(findstring qemu-ga,$(TOOLS))) + check-unit-$(call land,$(CONFIG_LINUX),$(CONFIG_VIRTIO_SERIAL)) += tests/test-qga$(EXESUF) + endif + check-unit-y += tests/test-timed-average$(EXESUF) +-check-unit-$(CONFIG_INOTIFY1) += tests/test-util-filemonitor$(EXESUF) + check-unit-y += tests/test-util-sockets$(EXESUF) + check-unit-$(CONFIG_BLOCK) += tests/test-authz-simple$(EXESUF) + check-unit-$(CONFIG_BLOCK) += tests/test-authz-list$(EXESUF) +@@ -654,8 +653,6 @@ tests/test-crypto-tlssession$(EXESUF): tests/test-crypto-tlssession.o \ + tests/crypto-tls-x509-helpers.o tests/pkix_asn1_tab.o \ + tests/crypto-tls-psk-helpers.o \ + $(test-crypto-obj-y) +-tests/test-util-filemonitor$(EXESUF): tests/test-util-filemonitor.o \ +- $(test-util-obj-y) + tests/test-util-sockets$(EXESUF): tests/test-util-sockets.o \ + tests/socket-helpers.o $(test-util-obj-y) + tests/test-authz-simple$(EXESUF): tests/test-authz-simple.o $(test-authz-obj-y) +-- +2.23.0 + diff --git a/tests-Update-ACPI-tables-list-for-upcoming-arm-virt-.patch b/tests-Update-ACPI-tables-list-for-upcoming-arm-virt-.patch new file mode 100644 index 0000000000000000000000000000000000000000..e739883feb04d14f33a97a2a0b6690ac6c5ccc24 --- /dev/null +++ b/tests-Update-ACPI-tables-list-for-upcoming-arm-virt-.patch @@ -0,0 +1,44 @@ +From 27e2533e43f0ab2b8a60f1902f58f8752581ea9f Mon Sep 17 00:00:00 2001 +From: Shameer Kolothum +Date: Wed, 18 Sep 2019 14:06:32 +0100 +Subject: [PATCH] tests: Update ACPI tables list for upcoming arm/virt tests + +This is in preparation to add numamem and memhp tests to +arm/virt platform. The bios-tables-test-allowed-diff.h +is updated with a list of expected ACPI tables that needs to be +present in tests/data/acpi/virt folder. + +Signed-off-by: Shameer Kolothum +Message-Id: <20190918130633.4872-11-shameerali.kolothum.thodi@huawei.com> +Acked-by: Peter Maydell +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Igor Mammedov +--- + tests/bios-tables-test-allowed-diff.h | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/tests/bios-tables-test-allowed-diff.h b/tests/bios-tables-test-allowed-diff.h +index 32a401ae35..3776dd2f3d 100644 +--- a/tests/bios-tables-test-allowed-diff.h ++++ b/tests/bios-tables-test-allowed-diff.h +@@ -1,4 +1,17 @@ + /* List of comma-separated changed AML files to ignore */ + "tests/data/acpi/virt/DSDT", ++"tests/data/acpi/virt/APIC.memhp", ++"tests/data/acpi/virt/APIC.numamem", + "tests/data/acpi/virt/DSDT.memhp", + "tests/data/acpi/virt/DSDT.numamem", ++"tests/data/acpi/virt/FACP.memhp", ++"tests/data/acpi/virt/FACP.numamem", ++"tests/data/acpi/virt/GTDT.memhp", ++"tests/data/acpi/virt/GTDT.numamem", ++"tests/data/acpi/virt/MCFG.memhp", ++"tests/data/acpi/virt/MCFG.numamem", ++"tests/data/acpi/virt/SLIT.memhp", ++"tests/data/acpi/virt/SPCR.memhp", ++"tests/data/acpi/virt/SPCR.numamem", ++"tests/data/acpi/virt/SRAT.memhp", ++"tests/data/acpi/virt/SRAT.numamem", +-- +2.19.1 diff --git a/tests-acpi-add-empty-files.patch b/tests-acpi-add-empty-files.patch new file mode 100644 index 0000000000000000000000000000000000000000..46e51c0de0e0ba84b6edf01fb62e3005acd37697 --- /dev/null +++ b/tests-acpi-add-empty-files.patch @@ -0,0 +1,88 @@ +From c943416df54931cea8b19183fd7c4f2dbd86ec72 Mon Sep 17 00:00:00 2001 +From: "Michael S. Tsirkin" +Date: Sun, 29 Sep 2019 10:54:12 -0400 +Subject: [PATCH] tests/acpi: add empty files + +Needed to make tests pass. Will replace with actual files. + +Signed-off-by: Michael S. Tsirkin +--- + tests/data/acpi/virt/APIC.memhp | 0 + tests/data/acpi/virt/APIC.numamem | 0 + tests/data/acpi/virt/DSDT.memhp | 0 + tests/data/acpi/virt/DSDT.numamem | 0 + tests/data/acpi/virt/FACP.memhp | 0 + tests/data/acpi/virt/FACP.numamem | 0 + tests/data/acpi/virt/GTDT.memhp | 0 + tests/data/acpi/virt/GTDT.numamem | 0 + tests/data/acpi/virt/MCFG.memhp | 0 + tests/data/acpi/virt/MCFG.numamem | 0 + tests/data/acpi/virt/SLIT.memhp | 0 + tests/data/acpi/virt/SPCR.memhp | 0 + tests/data/acpi/virt/SPCR.numamem | 0 + tests/data/acpi/virt/SRAT.memhp | 0 + tests/data/acpi/virt/SRAT.numamem | 0 + 15 files changed, 0 insertions(+), 0 deletions(-) + create mode 100644 tests/data/acpi/virt/APIC.memhp + create mode 100644 tests/data/acpi/virt/APIC.numamem + create mode 100644 tests/data/acpi/virt/DSDT.memhp + create mode 100644 tests/data/acpi/virt/DSDT.numamem + create mode 100644 tests/data/acpi/virt/FACP.memhp + create mode 100644 tests/data/acpi/virt/FACP.numamem + create mode 100644 tests/data/acpi/virt/GTDT.memhp + create mode 100644 tests/data/acpi/virt/GTDT.numamem + create mode 100644 tests/data/acpi/virt/MCFG.memhp + create mode 100644 tests/data/acpi/virt/MCFG.numamem + create mode 100644 tests/data/acpi/virt/SLIT.memhp + create mode 100644 tests/data/acpi/virt/SPCR.memhp + create mode 100644 tests/data/acpi/virt/SPCR.numamem + create mode 100644 tests/data/acpi/virt/SRAT.memhp + create mode 100644 tests/data/acpi/virt/SRAT.numamem + +diff --git a/tests/data/acpi/virt/APIC.memhp b/tests/data/acpi/virt/APIC.memhp +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/tests/data/acpi/virt/APIC.numamem b/tests/data/acpi/virt/APIC.numamem +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/tests/data/acpi/virt/DSDT.memhp b/tests/data/acpi/virt/DSDT.memhp +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/tests/data/acpi/virt/DSDT.numamem b/tests/data/acpi/virt/DSDT.numamem +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/tests/data/acpi/virt/FACP.memhp b/tests/data/acpi/virt/FACP.memhp +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/tests/data/acpi/virt/FACP.numamem b/tests/data/acpi/virt/FACP.numamem +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/tests/data/acpi/virt/GTDT.memhp b/tests/data/acpi/virt/GTDT.memhp +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/tests/data/acpi/virt/GTDT.numamem b/tests/data/acpi/virt/GTDT.numamem +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/tests/data/acpi/virt/MCFG.memhp b/tests/data/acpi/virt/MCFG.memhp +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/tests/data/acpi/virt/MCFG.numamem b/tests/data/acpi/virt/MCFG.numamem +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/tests/data/acpi/virt/SLIT.memhp b/tests/data/acpi/virt/SLIT.memhp +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/tests/data/acpi/virt/SPCR.memhp b/tests/data/acpi/virt/SPCR.memhp +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/tests/data/acpi/virt/SPCR.numamem b/tests/data/acpi/virt/SPCR.numamem +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/tests/data/acpi/virt/SRAT.memhp b/tests/data/acpi/virt/SRAT.memhp +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/tests/data/acpi/virt/SRAT.numamem b/tests/data/acpi/virt/SRAT.numamem +new file mode 100644 +index 0000000000..e69de29bb2 +-- +2.19.1 diff --git a/tests-allow-empty-expected-files.patch b/tests-allow-empty-expected-files.patch new file mode 100644 index 0000000000000000000000000000000000000000..615fb2121d3ffd93d926fe4f3e9623ffce16eb88 --- /dev/null +++ b/tests-allow-empty-expected-files.patch @@ -0,0 +1,31 @@ +From 2ab0636e0c8fcb8b5b1b222f0d5ae7f4dfc663c5 Mon Sep 17 00:00:00 2001 +From: "Michael S. Tsirkin" +Date: Sat, 5 Oct 2019 17:09:17 -0400 +Subject: [PATCH] tests: allow empty expected files + +An empty expected file is a handy way to seed the files +without creating merge conflicts. + +Signed-off-by: Michael S. Tsirkin +--- + tests/bios-tables-test.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c +index a356ac3489..53a91a8067 100644 +--- a/tests/bios-tables-test.c ++++ b/tests/bios-tables-test.c +@@ -334,7 +334,10 @@ try_again: + g_assert(ret); + g_assert_no_error(error); + g_assert(exp_sdt.aml); +- g_assert(exp_sdt.aml_len); ++ if (!exp_sdt.aml_len) { ++ fprintf(stderr, "Warning! zero length expected file '%s'\n", ++ aml_file); ++ } + + g_array_append_val(exp_tables, exp_sdt); + } +-- +2.19.1 diff --git a/tests-bios-tables-test-disable-this-testcase.patch b/tests-bios-tables-test-disable-this-testcase.patch new file mode 100644 index 0000000000000000000000000000000000000000..993fee935546735c16bfe9a30ff856ac135f4d53 --- /dev/null +++ b/tests-bios-tables-test-disable-this-testcase.patch @@ -0,0 +1,48 @@ +From 0814ef80cdf212c68b73fc1fbad4eeece3560ef9 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 15 Apr 2020 19:52:09 +0800 +Subject: [PATCH] tests/bios-tables-test: disable this testcase + +We will change ARM virt ACPI FACP and PPTT table in order to +support CPU topology information presentation. However our +change make this testcase fail since we changed the table +totally and we cannot apply patch with rpmbuild system. + +Signed-off-by: Ying Fang +--- + tests/Makefile.include | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/tests/Makefile.include b/tests/Makefile.include +index fd7fdb86..d8cf00c1 100644 +--- a/tests/Makefile.include ++++ b/tests/Makefile.include +@@ -164,7 +164,7 @@ check-qtest-i386-y += tests/ide-test$(EXESUF) + check-qtest-i386-y += tests/ahci-test$(EXESUF) + check-qtest-i386-y += tests/hd-geo-test$(EXESUF) + check-qtest-i386-y += tests/boot-order-test$(EXESUF) +-check-qtest-i386-y += tests/bios-tables-test$(EXESUF) ++# check-qtest-i386-y += tests/bios-tables-test$(EXESUF) + check-qtest-i386-$(CONFIG_SGA) += tests/boot-serial-test$(EXESUF) + check-qtest-i386-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF) + check-qtest-i386-y += tests/rtc-test$(EXESUF) +@@ -269,7 +269,7 @@ check-qtest-aarch64-y += tests/boot-serial-test$(EXESUF) + check-qtest-aarch64-y += tests/migration-test$(EXESUF) + # TODO: once aarch64 TCG is fixed on ARM 32 bit host, make test unconditional + ifneq ($(ARCH),arm) +-check-qtest-aarch64-y += tests/bios-tables-test$(EXESUF) ++#check-qtest-aarch64-y += tests/bios-tables-test$(EXESUF) + endif + + check-qtest-microblazeel-y += $(check-qtest-microblaze-y) +@@ -783,7 +783,7 @@ tests/ipmi-bt-test$(EXESUF): tests/ipmi-bt-test.o + tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o + tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y) + tests/boot-serial-test$(EXESUF): tests/boot-serial-test.o $(libqos-obj-y) +-tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \ ++#tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \ + tests/boot-sector.o tests/acpi-utils.o $(libqos-obj-y) + tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y) + tests/microbit-test$(EXESUF): tests/microbit-test.o +-- +2.23.0 diff --git a/tests-document-how-to-update-acpi-tables.patch b/tests-document-how-to-update-acpi-tables.patch new file mode 100644 index 0000000000000000000000000000000000000000..c961069b6e77c2a193b34d606466f04c7b059611 --- /dev/null +++ b/tests-document-how-to-update-acpi-tables.patch @@ -0,0 +1,53 @@ +From d9642ad522d34f0d803a87654a2c258baf1070dd Mon Sep 17 00:00:00 2001 +From: "Michael S. Tsirkin" +Date: Sat, 5 Oct 2019 17:25:55 -0400 +Subject: [PATCH] tests: document how to update acpi tables + +Looks like no one understands how to do it. +Document the process. + +Signed-off-by: Michael S. Tsirkin +--- + tests/bios-tables-test.c | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c +index 5e177b7155..d47ee9be99 100644 +--- a/tests/bios-tables-test.c ++++ b/tests/bios-tables-test.c +@@ -10,6 +10,33 @@ + * See the COPYING file in the top-level directory. + */ + ++/* ++ * How to add or update the tests: ++ * Contributor: ++ * 1. add empty files for new tables, if any, under tests/data/acpi ++ * 2. list any changed files in tests/bios-tables-test-allowed-diff.h ++ * 3. commit the above *before* making changes that affect the tables ++ * Maintainer: ++ * After 1-3 above tests will pass but ignore differences with the expected files. ++ * You will also notice that tests/bios-tables-test-allowed-diff.h lists ++ * a bunch of files. This is your hint that you need to do the below: ++ * 4. Run ++ * make check V=1 ++ * this will produce a bunch of warnings about differences ++ * beween actual and expected ACPI tables. If you have IASL installed, ++ * they will also be disassembled so you can look at the disassembled ++ * output. If not - disassemble them yourself in any way you like. ++ * Look at the differences - make sure they make sense and match what the ++ * changes you are merging are supposed to do. ++ * ++ * 5. From build directory, run: ++ * $(SRC_PATH)/tests/data/acpi/rebuild-expected-aml.sh ++ * 6. Now commit any changes. ++ * 7. Before doing a pull request, make sure tests/bios-tables-test-allowed-diff.h ++ * is empty - this will ensure following changes to ACPI tables will ++ * be noticed. ++ */ ++ + #include "qemu/osdep.h" + #include + #include "qemu-common.h" +-- +2.19.1 diff --git a/tpm-Add-the-SysBus-TPM-TIS-device.patch b/tpm-Add-the-SysBus-TPM-TIS-device.patch new file mode 100644 index 0000000000000000000000000000000000000000..e0a6254025932eb942b3a15d16b66d4808a33f42 --- /dev/null +++ b/tpm-Add-the-SysBus-TPM-TIS-device.patch @@ -0,0 +1,231 @@ +From 4fe655326eeae322b621dcc25c53af722d2e1afa Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Tue, 11 Aug 2020 11:23:34 +0800 +Subject: [PATCH 14/19] tpm: Add the SysBus TPM TIS device + +Introduce the tpm-tis-device which is a sysbus device +and is bound to be used on ARM. + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Tested-by: Ard Biesheuvel +Acked-by: Ard Biesheuvel +Message-id: 20200305165149.618-6-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + hw/tpm/Kconfig | 5 ++ + hw/tpm/Makefile.objs | 1 + + hw/tpm/tpm_tis_sysbus.c | 159 ++++++++++++++++++++++++++++++++++++++++ + include/sysemu/tpm.h | 1 + + 4 files changed, 166 insertions(+) + create mode 100644 hw/tpm/tpm_tis_sysbus.c + +diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig +index 686f8206..4794e7fe 100644 +--- a/hw/tpm/Kconfig ++++ b/hw/tpm/Kconfig +@@ -7,6 +7,11 @@ config TPM_TIS_ISA + depends on TPM && ISA_BUS + select TPM_TIS + ++config TPM_TIS_SYSBUS ++ bool ++ depends on TPM ++ select TPM_TIS ++ + config TPM_TIS + bool + depends on TPM +diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs +index 3ef2036c..f1ec4beb 100644 +--- a/hw/tpm/Makefile.objs ++++ b/hw/tpm/Makefile.objs +@@ -1,6 +1,7 @@ + common-obj-$(CONFIG_TPM) += tpm_util.o + obj-$(call lor,$(CONFIG_TPM_TIS),$(CONFIG_TPM_CRB)) += tpm_ppi.o + common-obj-$(CONFIG_TPM_TIS_ISA) += tpm_tis_isa.o ++common-obj-$(CONFIG_TPM_TIS_SYSBUS) += tpm_tis_sysbus.o + common-obj-$(CONFIG_TPM_TIS) += tpm_tis_common.o + common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o + common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o +diff --git a/hw/tpm/tpm_tis_sysbus.c b/hw/tpm/tpm_tis_sysbus.c +new file mode 100644 +index 00000000..18c02aed +--- /dev/null ++++ b/hw/tpm/tpm_tis_sysbus.c +@@ -0,0 +1,159 @@ ++/* ++ * tpm_tis_sysbus.c - QEMU's TPM TIS SYSBUS Device ++ * ++ * Copyright (C) 2006,2010-2013 IBM Corporation ++ * ++ * Authors: ++ * Stefan Berger ++ * David Safford ++ * ++ * Xen 4 support: Andrease Niederl ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ * Implementation of the TIS interface according to specs found at ++ * http://www.trustedcomputinggroup.org. This implementation currently ++ * supports version 1.3, 21 March 2013 ++ * In the developers menu choose the PC Client section then find the TIS ++ * specification. ++ * ++ * TPM TIS for TPM 2 implementation following TCG PC Client Platform ++ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/qdev-properties.h" ++#include "migration/vmstate.h" ++#include "tpm_util.h" ++#include "hw/sysbus.h" ++#include "tpm_tis.h" ++ ++typedef struct TPMStateSysBus { ++ /*< private >*/ ++ SysBusDevice parent_obj; ++ ++ /*< public >*/ ++ TPMState state; /* not a QOM object */ ++} TPMStateSysBus; ++ ++#define TPM_TIS_SYSBUS(obj) OBJECT_CHECK(TPMStateSysBus, (obj), TYPE_TPM_TIS_SYSBUS) ++ ++static int tpm_tis_pre_save_sysbus(void *opaque) ++{ ++ TPMStateSysBus *sbdev = opaque; ++ ++ return tpm_tis_pre_save(&sbdev->state); ++} ++ ++static const VMStateDescription vmstate_tpm_tis_sysbus = { ++ .name = "tpm-tis", ++ .version_id = 0, ++ .pre_save = tpm_tis_pre_save_sysbus, ++ .fields = (VMStateField[]) { ++ VMSTATE_BUFFER(state.buffer, TPMStateSysBus), ++ VMSTATE_UINT16(state.rw_offset, TPMStateSysBus), ++ VMSTATE_UINT8(state.active_locty, TPMStateSysBus), ++ VMSTATE_UINT8(state.aborting_locty, TPMStateSysBus), ++ VMSTATE_UINT8(state.next_locty, TPMStateSysBus), ++ ++ VMSTATE_STRUCT_ARRAY(state.loc, TPMStateSysBus, TPM_TIS_NUM_LOCALITIES, ++ 0, vmstate_locty, TPMLocality), ++ ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++static void tpm_tis_sysbus_request_completed(TPMIf *ti, int ret) ++{ ++ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(ti); ++ TPMState *s = &sbdev->state; ++ ++ tpm_tis_request_completed(s, ret); ++} ++ ++static enum TPMVersion tpm_tis_sysbus_get_tpm_version(TPMIf *ti) ++{ ++ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(ti); ++ TPMState *s = &sbdev->state; ++ ++ return tpm_tis_get_tpm_version(s); ++} ++ ++static void tpm_tis_sysbus_reset(DeviceState *dev) ++{ ++ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(dev); ++ TPMState *s = &sbdev->state; ++ ++ return tpm_tis_reset(s); ++} ++ ++static Property tpm_tis_sysbus_properties[] = { ++ DEFINE_PROP_UINT32("irq", TPMStateSysBus, state.irq_num, TPM_TIS_IRQ), ++ DEFINE_PROP_TPMBE("tpmdev", TPMStateSysBus, state.be_driver), ++ DEFINE_PROP_BOOL("ppi", TPMStateSysBus, state.ppi_enabled, true), ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ ++static void tpm_tis_sysbus_initfn(Object *obj) ++{ ++ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(obj); ++ TPMState *s = &sbdev->state; ++ ++ memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops, ++ s, "tpm-tis-mmio", ++ TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); ++ ++ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); ++ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); ++} ++ ++static void tpm_tis_sysbus_realizefn(DeviceState *dev, Error **errp) ++{ ++ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(dev); ++ TPMState *s = &sbdev->state; ++ ++ if (!tpm_find()) { ++ error_setg(errp, "at most one TPM device is permitted"); ++ return; ++ } ++ ++ if (!s->be_driver) { ++ error_setg(errp, "'tpmdev' property is required"); ++ return; ++ } ++} ++ ++static void tpm_tis_sysbus_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ TPMIfClass *tc = TPM_IF_CLASS(klass); ++ ++ dc->props = tpm_tis_sysbus_properties; ++ dc->vmsd = &vmstate_tpm_tis_sysbus; ++ tc->model = TPM_MODEL_TPM_TIS; ++ dc->realize = tpm_tis_sysbus_realizefn; ++ dc->user_creatable = true; ++ dc->reset = tpm_tis_sysbus_reset; ++ tc->request_completed = tpm_tis_sysbus_request_completed; ++ tc->get_version = tpm_tis_sysbus_get_tpm_version; ++} ++ ++static const TypeInfo tpm_tis_sysbus_info = { ++ .name = TYPE_TPM_TIS_SYSBUS, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(TPMStateSysBus), ++ .instance_init = tpm_tis_sysbus_initfn, ++ .class_init = tpm_tis_sysbus_class_init, ++ .interfaces = (InterfaceInfo[]) { ++ { TYPE_TPM_IF }, ++ { } ++ } ++}; ++ ++static void tpm_tis_sysbus_register(void) ++{ ++ type_register_static(&tpm_tis_sysbus_info); ++} ++ ++type_init(tpm_tis_sysbus_register) +diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h +index 1691b92c..f37851b1 100644 +--- a/include/sysemu/tpm.h ++++ b/include/sysemu/tpm.h +@@ -44,6 +44,7 @@ typedef struct TPMIfClass { + } TPMIfClass; + + #define TYPE_TPM_TIS_ISA "tpm-tis" ++#define TYPE_TPM_TIS_SYSBUS "tpm-tis-device" + #define TYPE_TPM_CRB "tpm-crb" + #define TYPE_TPM_SPAPR "tpm-spapr" + +-- +2.23.0 + diff --git a/tpm-Move-tpm_tis_show_buffer-to-tpm_util.c.patch b/tpm-Move-tpm_tis_show_buffer-to-tpm_util.c.patch new file mode 100644 index 0000000000000000000000000000000000000000..93139b5e7f8284cecf6faa9930eaa8e802db13d9 --- /dev/null +++ b/tpm-Move-tpm_tis_show_buffer-to-tpm_util.c.patch @@ -0,0 +1,146 @@ +From c6cf45f38cb6e28cf4db42296fedcd5f26ca610b Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 21 Jan 2020 10:29:30 -0500 +Subject: [PATCH 03/19] tpm: Move tpm_tis_show_buffer to tpm_util.c +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Stefan Berger +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: David Gibson +Message-Id: <20200121152935.649898-2-stefanb@linux.ibm.com> +Signed-off-by: David Gibson +Signed-off-by: jiangfangjie +--- + hw/tpm/tpm_tis.c | 32 ++++---------------------------- + hw/tpm/tpm_util.c | 25 +++++++++++++++++++++++++ + hw/tpm/tpm_util.h | 3 +++ + hw/tpm/trace-events | 2 +- + 4 files changed, 33 insertions(+), 29 deletions(-) + +diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c +index d6b32128..96a9ac48 100644 +--- a/hw/tpm/tpm_tis.c ++++ b/hw/tpm/tpm_tis.c +@@ -104,30 +104,6 @@ static uint8_t tpm_tis_locality_from_addr(hwaddr addr) + return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7); + } + +-static void tpm_tis_show_buffer(const unsigned char *buffer, +- size_t buffer_size, const char *string) +-{ +- size_t len, i; +- char *line_buffer, *p; +- +- len = MIN(tpm_cmd_get_size(buffer), buffer_size); +- +- /* +- * allocate enough room for 3 chars per buffer entry plus a +- * newline after every 16 chars and a final null terminator. +- */ +- line_buffer = g_malloc(len * 3 + (len / 16) + 1); +- +- for (i = 0, p = line_buffer; i < len; i++) { +- if (i && !(i % 16)) { +- p += sprintf(p, "\n"); +- } +- p += sprintf(p, "%.2X ", buffer[i]); +- } +- trace_tpm_tis_show_buffer(string, len, line_buffer); +- +- g_free(line_buffer); +-} + + /* + * Set the given flags in the STS register by clearing the register but +@@ -153,8 +129,8 @@ static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags) + */ + static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) + { +- if (trace_event_get_state_backends(TRACE_TPM_TIS_SHOW_BUFFER)) { +- tpm_tis_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); ++ if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); + } + + /* +@@ -322,8 +298,8 @@ static void tpm_tis_request_completed(TPMIf *ti, int ret) + s->loc[locty].state = TPM_TIS_STATE_COMPLETION; + s->rw_offset = 0; + +- if (trace_event_get_state_backends(TRACE_TPM_TIS_SHOW_BUFFER)) { +- tpm_tis_show_buffer(s->buffer, s->be_buffer_size, "From TPM"); ++ if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "From TPM"); + } + + if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) { +diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c +index ee41757e..8643eb50 100644 +--- a/hw/tpm/tpm_util.c ++++ b/hw/tpm/tpm_util.c +@@ -350,3 +350,28 @@ void tpm_sized_buffer_reset(TPMSizedBuffer *tsb) + tsb->buffer = NULL; + tsb->size = 0; + } ++ ++void tpm_util_show_buffer(const unsigned char *buffer, ++ size_t buffer_size, const char *string) ++{ ++ size_t len, i; ++ char *line_buffer, *p; ++ ++ len = MIN(tpm_cmd_get_size(buffer), buffer_size); ++ ++ /* ++ * allocate enough room for 3 chars per buffer entry plus a ++ * newline after every 16 chars and a final null terminator. ++ */ ++ line_buffer = g_malloc(len * 3 + (len / 16) + 1); ++ ++ for (i = 0, p = line_buffer; i < len; i++) { ++ if (i && !(i % 16)) { ++ p += sprintf(p, "\n"); ++ } ++ p += sprintf(p, "%.2X ", buffer[i]); ++ } ++ trace_tpm_util_show_buffer(string, len, line_buffer); ++ ++ g_free(line_buffer); ++} +diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h +index f397ac21..7889081f 100644 +--- a/hw/tpm/tpm_util.h ++++ b/hw/tpm/tpm_util.h +@@ -79,4 +79,7 @@ typedef struct TPMSizedBuffer { + + void tpm_sized_buffer_reset(TPMSizedBuffer *tsb); + ++void tpm_util_show_buffer(const unsigned char *buffer, ++ size_t buffer_size, const char *string); ++ + #endif /* TPM_TPM_UTIL_H */ +diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events +index 0b94aa15..82c45ee5 100644 +--- a/hw/tpm/trace-events ++++ b/hw/tpm/trace-events +@@ -14,6 +14,7 @@ tpm_util_get_buffer_size_len(uint32_t len, size_t expected) "tpm_resp->len = %u, + tpm_util_get_buffer_size_hdr_len2(uint32_t len, size_t expected) "tpm2_resp->hdr.len = %u, expected = %zu" + tpm_util_get_buffer_size_len2(uint32_t len, size_t expected) "tpm2_resp->len = %u, expected = %zu" + tpm_util_get_buffer_size(size_t len) "buffersize of device: %zu" ++tpm_util_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s" + + # tpm_emulator.c + tpm_emulator_set_locality(uint8_t locty) "setting locality to %d" +@@ -36,7 +37,6 @@ tpm_emulator_pre_save(void) "" + tpm_emulator_inst_init(void) "" + + # tpm_tis.c +-tpm_tis_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\nbuf: %s" + tpm_tis_raise_irq(uint32_t irqmask) "Raising IRQ for flag 0x%08x" + tpm_tis_new_active_locality(uint8_t locty) "Active locality is now %d" + tpm_tis_abort(uint8_t locty) "New active locality is %d" +-- +2.23.0 + diff --git a/tpm-Separate-TPM_TIS-and-TPM_TIS_ISA-configs.patch b/tpm-Separate-TPM_TIS-and-TPM_TIS_ISA-configs.patch new file mode 100644 index 0000000000000000000000000000000000000000..97dcaa000b251bd8a4390a5c68e75011aef9401f --- /dev/null +++ b/tpm-Separate-TPM_TIS-and-TPM_TIS_ISA-configs.patch @@ -0,0 +1,108 @@ +From 1eca7dbacabbc8ccc737f320839e7800fef5dfa1 Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Tue, 11 Aug 2020 12:42:31 +0800 +Subject: [PATCH 13/19] tpm: Separate TPM_TIS and TPM_TIS_ISA configs + MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 + Content-Transfer-Encoding: 8bit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let's separate the compilation of tpm_tis_common.c from +the compilation of tpm_tis_isa.c + +The common part will be also compiled along with the +tpm_tis_sysbus device. + +Signed-off-by: Eric Auger +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Ard Biesheuvel +Acked-by: Ard Biesheuvel +Message-id: 20200305165149.618-5-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + default-configs/i386-softmmu.mak | 2 +- + hw/i386/Kconfig | 2 +- + hw/tpm/Kconfig | 7 ++++++- + hw/tpm/Makefile.objs | 3 ++- + tests/Makefile.include | 4 ++-- + 5 files changed, 12 insertions(+), 6 deletions(-) + +diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak +index cd5ea391..bdeef670 100644 +--- a/default-configs/i386-softmmu.mak ++++ b/default-configs/i386-softmmu.mak +@@ -17,7 +17,7 @@ + #CONFIG_SGA=n + #CONFIG_TEST_DEVICES=n + #CONFIG_TPM_CRB=n +-#CONFIG_TPM_TIS=n ++#CONFIG_TPM_TIS_ISA=n + #CONFIG_VTD=n + + # Boards: +diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig +index 63504380..60334504 100644 +--- a/hw/i386/Kconfig ++++ b/hw/i386/Kconfig +@@ -17,7 +17,7 @@ config PC + imply SGA + imply TEST_DEVICES + imply TPM_CRB +- imply TPM_TIS ++ imply TPM_TIS_ISA + imply VGA_PCI + imply VIRTIO_VGA + select FDC +diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig +index 9e67d990..686f8206 100644 +--- a/hw/tpm/Kconfig ++++ b/hw/tpm/Kconfig +@@ -2,9 +2,14 @@ config TPMDEV + bool + depends on TPM + +-config TPM_TIS ++config TPM_TIS_ISA + bool + depends on TPM && ISA_BUS ++ select TPM_TIS ++ ++config TPM_TIS ++ bool ++ depends on TPM + select TPMDEV + + config TPM_CRB +diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs +index fcc4c2f2..3ef2036c 100644 +--- a/hw/tpm/Makefile.objs ++++ b/hw/tpm/Makefile.objs +@@ -1,6 +1,7 @@ + common-obj-$(CONFIG_TPM) += tpm_util.o + obj-$(call lor,$(CONFIG_TPM_TIS),$(CONFIG_TPM_CRB)) += tpm_ppi.o +-common-obj-$(CONFIG_TPM_TIS) += tpm_tis_isa.o tpm_tis_common.o ++common-obj-$(CONFIG_TPM_TIS_ISA) += tpm_tis_isa.o ++common-obj-$(CONFIG_TPM_TIS) += tpm_tis_common.o + common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o + common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o + common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o +diff --git a/tests/Makefile.include b/tests/Makefile.include +index f3273ad3..c151de64 100644 +--- a/tests/Makefile.include ++++ b/tests/Makefile.include +@@ -190,8 +190,8 @@ check-qtest-i386-y += tests/q35-test$(EXESUF) + check-qtest-i386-y += tests/vmgenid-test$(EXESUF) + check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-swtpm-test$(EXESUF) + check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-test$(EXESUF) +-check-qtest-i386-$(CONFIG_TPM_TIS) += tests/tpm-tis-swtpm-test$(EXESUF) +-check-qtest-i386-$(CONFIG_TPM_TIS) += tests/tpm-tis-test$(EXESUF) ++check-qtest-i386-$(CONFIG_TPM_TIS_ISA) += tests/tpm-tis-swtpm-test$(EXESUF) ++check-qtest-i386-$(CONFIG_TPM_TIS_ISA) += tests/tpm-tis-test$(EXESUF) + check-qtest-i386-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF) + check-qtest-i386-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF) + check-qtest-i386-$(CONFIG_RTL8139_PCI) += tests/test-filter-redirector$(EXESUF) +-- +2.23.0 + diff --git a/tpm-Separate-tpm_tis-common-functions-from-isa-code.patch b/tpm-Separate-tpm_tis-common-functions-from-isa-code.patch new file mode 100644 index 0000000000000000000000000000000000000000..32f180c98d784b1478268a768b4caed6c8a3fa23 --- /dev/null +++ b/tpm-Separate-tpm_tis-common-functions-from-isa-code.patch @@ -0,0 +1,1194 @@ +From 425f6bc8392c71d2f29b572d19232785d0ab0b73 Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Tue, 11 Aug 2020 02:55:35 +0000 +Subject: [PATCH 12/19] tpm: Separate tpm_tis common functions from isa code + +Move the device agnostic code into tpm_tis_common.c and +put the ISA device specific code into tpm_tis_isa.c + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Tested-by: Ard Biesheuvel +Acked-by: Ard Biesheuvel +Message-id: 20200305165149.618-4-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + hw/tpm/Makefile.objs | 2 +- + hw/tpm/{tpm_tis.c => tpm_tis.c.orig} | 0 + hw/tpm/tpm_tis.h | 91 +++ + hw/tpm/tpm_tis_common.c | 869 +++++++++++++++++++++++++++ + hw/tpm/tpm_tis_isa.c | 170 ++++++ + 5 files changed, 1131 insertions(+), 1 deletion(-) + rename hw/tpm/{tpm_tis.c => tpm_tis.c.orig} (100%) + create mode 100644 hw/tpm/tpm_tis.h + create mode 100644 hw/tpm/tpm_tis_common.c + create mode 100644 hw/tpm/tpm_tis_isa.c + +diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs +index 85eb99ae..fcc4c2f2 100644 +--- a/hw/tpm/Makefile.objs ++++ b/hw/tpm/Makefile.objs +@@ -1,6 +1,6 @@ + common-obj-$(CONFIG_TPM) += tpm_util.o + obj-$(call lor,$(CONFIG_TPM_TIS),$(CONFIG_TPM_CRB)) += tpm_ppi.o +-common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o ++common-obj-$(CONFIG_TPM_TIS) += tpm_tis_isa.o tpm_tis_common.o + common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o + common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o + common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o +diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c.orig +similarity index 100% +rename from hw/tpm/tpm_tis.c +rename to hw/tpm/tpm_tis.c.orig +diff --git a/hw/tpm/tpm_tis.h b/hw/tpm/tpm_tis.h +new file mode 100644 +index 00000000..55549893 +--- /dev/null ++++ b/hw/tpm/tpm_tis.h +@@ -0,0 +1,91 @@ ++/* ++ * tpm_tis.h - QEMU's TPM TIS common header ++ * ++ * Copyright (C) 2006,2010-2013 IBM Corporation ++ * ++ * Authors: ++ * Stefan Berger ++ * David Safford ++ * ++ * Xen 4 support: Andrease Niederl ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ * Implementation of the TIS interface according to specs found at ++ * http://www.trustedcomputinggroup.org. This implementation currently ++ * supports version 1.3, 21 March 2013 ++ * In the developers menu choose the PC Client section then find the TIS ++ * specification. ++ * ++ * TPM TIS for TPM 2 implementation following TCG PC Client Platform ++ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 ++ */ ++#ifndef TPM_TPM_TIS_H ++#define TPM_TPM_TIS_H ++ ++#include "qemu/osdep.h" ++#include "sysemu/tpm_backend.h" ++#include "tpm_ppi.h" ++ ++#define TPM_TIS_NUM_LOCALITIES 5 /* per spec */ ++#define TPM_TIS_LOCALITY_SHIFT 12 ++#define TPM_TIS_NO_LOCALITY 0xff ++ ++#define TPM_TIS_IS_VALID_LOCTY(x) ((x) < TPM_TIS_NUM_LOCALITIES) ++ ++#define TPM_TIS_BUFFER_MAX 4096 ++ ++typedef enum { ++ TPM_TIS_STATE_IDLE = 0, ++ TPM_TIS_STATE_READY, ++ TPM_TIS_STATE_COMPLETION, ++ TPM_TIS_STATE_EXECUTION, ++ TPM_TIS_STATE_RECEPTION, ++} TPMTISState; ++ ++/* locality data -- all fields are persisted */ ++typedef struct TPMLocality { ++ TPMTISState state; ++ uint8_t access; ++ uint32_t sts; ++ uint32_t iface_id; ++ uint32_t inte; ++ uint32_t ints; ++} TPMLocality; ++ ++typedef struct TPMState { ++ MemoryRegion mmio; ++ ++ unsigned char buffer[TPM_TIS_BUFFER_MAX]; ++ uint16_t rw_offset; ++ ++ uint8_t active_locty; ++ uint8_t aborting_locty; ++ uint8_t next_locty; ++ ++ TPMLocality loc[TPM_TIS_NUM_LOCALITIES]; ++ ++ qemu_irq irq; ++ uint32_t irq_num; ++ ++ TPMBackendCmd cmd; ++ ++ TPMBackend *be_driver; ++ TPMVersion be_tpm_version; ++ ++ size_t be_buffer_size; ++ ++ bool ppi_enabled; ++ TPMPPI ppi; ++} TPMState; ++ ++extern const VMStateDescription vmstate_locty; ++extern const MemoryRegionOps tpm_tis_memory_ops; ++ ++int tpm_tis_pre_save(TPMState *s); ++void tpm_tis_reset(TPMState *s); ++enum TPMVersion tpm_tis_get_tpm_version(TPMState *s); ++void tpm_tis_request_completed(TPMState *s, int ret); ++ ++#endif /* TPM_TPM_TIS_H */ +diff --git a/hw/tpm/tpm_tis_common.c b/hw/tpm/tpm_tis_common.c +new file mode 100644 +index 00000000..9a51c71e +--- /dev/null ++++ b/hw/tpm/tpm_tis_common.c +@@ -0,0 +1,869 @@ ++/* ++ * tpm_tis_common.c - QEMU's TPM TIS interface emulator ++ * device agnostic functions ++ * ++ * Copyright (C) 2006,2010-2013 IBM Corporation ++ * ++ * Authors: ++ * Stefan Berger ++ * David Safford ++ * ++ * Xen 4 support: Andrease Niederl ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ * Implementation of the TIS interface according to specs found at ++ * http://www.trustedcomputinggroup.org. This implementation currently ++ * supports version 1.3, 21 March 2013 ++ * In the developers menu choose the PC Client section then find the TIS ++ * specification. ++ * ++ * TPM TIS for TPM 2 implementation following TCG PC Client Platform ++ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 ++ */ ++#include "qemu/osdep.h" ++#include "hw/isa/isa.h" ++#include "qapi/error.h" ++#include "qemu/module.h" ++ ++#include "hw/acpi/tpm.h" ++#include "hw/pci/pci_ids.h" ++#include "sysemu/tpm_backend.h" ++#include "tpm_int.h" ++#include "tpm_util.h" ++#include "tpm_ppi.h" ++#include "trace.h" ++ ++#include "tpm_tis.h" ++ ++#define DEBUG_TIS 0 ++ ++/* local prototypes */ ++ ++static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, ++ unsigned size); ++ ++/* utility functions */ ++ ++static uint8_t tpm_tis_locality_from_addr(hwaddr addr) ++{ ++ return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7); ++} ++ ++ ++/* ++ * Set the given flags in the STS register by clearing the register but ++ * preserving the SELFTEST_DONE and TPM_FAMILY_MASK flags and then setting ++ * the new flags. ++ * ++ * The SELFTEST_DONE flag is acquired from the backend that determines it by ++ * peeking into TPM commands. ++ * ++ * A VM suspend/resume will preserve the flag by storing it into the VM ++ * device state, but the backend will not remember it when QEMU is started ++ * again. Therefore, we cache the flag here. Once set, it will not be unset ++ * except by a reset. ++ */ ++static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags) ++{ ++ l->sts &= TPM_TIS_STS_SELFTEST_DONE | TPM_TIS_STS_TPM_FAMILY_MASK; ++ l->sts |= flags; ++} ++ ++/* ++ * Send a request to the TPM. ++ */ ++static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) ++{ ++ if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); ++ } ++ ++ /* ++ * rw_offset serves as length indicator for length of data; ++ * it's reset when the response comes back ++ */ ++ s->loc[locty].state = TPM_TIS_STATE_EXECUTION; ++ ++ s->cmd = (TPMBackendCmd) { ++ .locty = locty, ++ .in = s->buffer, ++ .in_len = s->rw_offset, ++ .out = s->buffer, ++ .out_len = s->be_buffer_size, ++ }; ++ ++ tpm_backend_deliver_request(s->be_driver, &s->cmd); ++} ++ ++/* raise an interrupt if allowed */ ++static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask) ++{ ++ if (!TPM_TIS_IS_VALID_LOCTY(locty)) { ++ return; ++ } ++ ++ if ((s->loc[locty].inte & TPM_TIS_INT_ENABLED) && ++ (s->loc[locty].inte & irqmask)) { ++ trace_tpm_tis_raise_irq(irqmask); ++ qemu_irq_raise(s->irq); ++ s->loc[locty].ints |= irqmask; ++ } ++} ++ ++static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty) ++{ ++ uint8_t l; ++ ++ for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { ++ if (l == locty) { ++ continue; ++ } ++ if ((s->loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) { ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty) ++{ ++ bool change = (s->active_locty != new_active_locty); ++ bool is_seize; ++ uint8_t mask; ++ ++ if (change && TPM_TIS_IS_VALID_LOCTY(s->active_locty)) { ++ is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) && ++ s->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE; ++ ++ if (is_seize) { ++ mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ } else { ++ mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY| ++ TPM_TIS_ACCESS_REQUEST_USE); ++ } ++ /* reset flags on the old active locality */ ++ s->loc[s->active_locty].access &= mask; ++ ++ if (is_seize) { ++ s->loc[s->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED; ++ } ++ } ++ ++ s->active_locty = new_active_locty; ++ ++ trace_tpm_tis_new_active_locality(s->active_locty); ++ ++ if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) { ++ /* set flags on the new active locality */ ++ s->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY; ++ s->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE | ++ TPM_TIS_ACCESS_SEIZE); ++ } ++ ++ if (change) { ++ tpm_tis_raise_irq(s, s->active_locty, TPM_TIS_INT_LOCALITY_CHANGED); ++ } ++} ++ ++/* abort -- this function switches the locality */ ++static void tpm_tis_abort(TPMState *s) ++{ ++ s->rw_offset = 0; ++ ++ trace_tpm_tis_abort(s->next_locty); ++ ++ /* ++ * Need to react differently depending on who's aborting now and ++ * which locality will become active afterwards. ++ */ ++ if (s->aborting_locty == s->next_locty) { ++ s->loc[s->aborting_locty].state = TPM_TIS_STATE_READY; ++ tpm_tis_sts_set(&s->loc[s->aborting_locty], ++ TPM_TIS_STS_COMMAND_READY); ++ tpm_tis_raise_irq(s, s->aborting_locty, TPM_TIS_INT_COMMAND_READY); ++ } ++ ++ /* locality after abort is another one than the current one */ ++ tpm_tis_new_active_locality(s, s->next_locty); ++ ++ s->next_locty = TPM_TIS_NO_LOCALITY; ++ /* nobody's aborting a command anymore */ ++ s->aborting_locty = TPM_TIS_NO_LOCALITY; ++} ++ ++/* prepare aborting current command */ ++static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty) ++{ ++ uint8_t busy_locty; ++ ++ assert(TPM_TIS_IS_VALID_LOCTY(newlocty)); ++ ++ s->aborting_locty = locty; /* may also be TPM_TIS_NO_LOCALITY */ ++ s->next_locty = newlocty; /* locality after successful abort */ ++ ++ /* ++ * only abort a command using an interrupt if currently executing ++ * a command AND if there's a valid connection to the vTPM. ++ */ ++ for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) { ++ if (s->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) { ++ /* ++ * request the backend to cancel. Some backends may not ++ * support it ++ */ ++ tpm_backend_cancel_cmd(s->be_driver); ++ return; ++ } ++ } ++ ++ tpm_tis_abort(s); ++} ++ ++/* ++ * Callback from the TPM to indicate that the response was received. ++ */ ++void tpm_tis_request_completed(TPMState *s, int ret) ++{ ++ uint8_t locty = s->cmd.locty; ++ uint8_t l; ++ ++ assert(TPM_TIS_IS_VALID_LOCTY(locty)); ++ ++ if (s->cmd.selftest_done) { ++ for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { ++ s->loc[l].sts |= TPM_TIS_STS_SELFTEST_DONE; ++ } ++ } ++ ++ /* FIXME: report error if ret != 0 */ ++ tpm_tis_sts_set(&s->loc[locty], ++ TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); ++ s->loc[locty].state = TPM_TIS_STATE_COMPLETION; ++ s->rw_offset = 0; ++ ++ if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "From TPM"); ++ } ++ ++ if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) { ++ tpm_tis_abort(s); ++ } ++ ++ tpm_tis_raise_irq(s, locty, ++ TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID); ++} ++ ++/* ++ * Read a byte of response data ++ */ ++static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty) ++{ ++ uint32_t ret = TPM_TIS_NO_DATA_BYTE; ++ uint16_t len; ++ ++ if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { ++ len = MIN(tpm_cmd_get_size(&s->buffer), ++ s->be_buffer_size); ++ ++ ret = s->buffer[s->rw_offset++]; ++ if (s->rw_offset >= len) { ++ /* got last byte */ ++ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); ++ tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID); ++ } ++ trace_tpm_tis_data_read(ret, s->rw_offset - 1); ++ } ++ ++ return ret; ++} ++ ++#ifdef DEBUG_TIS ++static void tpm_tis_dump_state(TPMState *s, hwaddr addr) ++{ ++ static const unsigned regs[] = { ++ TPM_TIS_REG_ACCESS, ++ TPM_TIS_REG_INT_ENABLE, ++ TPM_TIS_REG_INT_VECTOR, ++ TPM_TIS_REG_INT_STATUS, ++ TPM_TIS_REG_INTF_CAPABILITY, ++ TPM_TIS_REG_STS, ++ TPM_TIS_REG_DID_VID, ++ TPM_TIS_REG_RID, ++ 0xfff}; ++ int idx; ++ uint8_t locty = tpm_tis_locality_from_addr(addr); ++ hwaddr base = addr & ~0xfff; ++ ++ printf("tpm_tis: active locality : %d\n" ++ "tpm_tis: state of locality %d : %d\n" ++ "tpm_tis: register dump:\n", ++ s->active_locty, ++ locty, s->loc[locty].state); ++ ++ for (idx = 0; regs[idx] != 0xfff; idx++) { ++ printf("tpm_tis: 0x%04x : 0x%08x\n", regs[idx], ++ (int)tpm_tis_mmio_read(s, base + regs[idx], 4)); ++ } ++ ++ printf("tpm_tis: r/w offset : %d\n" ++ "tpm_tis: result buffer : ", ++ s->rw_offset); ++ for (idx = 0; ++ idx < MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size); ++ idx++) { ++ printf("%c%02x%s", ++ s->rw_offset == idx ? '>' : ' ', ++ s->buffer[idx], ++ ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : ""); ++ } ++ printf("\n"); ++} ++#endif ++ ++/* ++ * Read a register of the TIS interface ++ * See specs pages 33-63 for description of the registers ++ */ ++static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, ++ unsigned size) ++{ ++ TPMState *s = opaque; ++ uint16_t offset = addr & 0xffc; ++ uint8_t shift = (addr & 0x3) * 8; ++ uint32_t val = 0xffffffff; ++ uint8_t locty = tpm_tis_locality_from_addr(addr); ++ uint32_t avail; ++ uint8_t v; ++ ++ if (tpm_backend_had_startup_error(s->be_driver)) { ++ return 0; ++ } ++ ++ switch (offset) { ++ case TPM_TIS_REG_ACCESS: ++ /* never show the SEIZE flag even though we use it internally */ ++ val = s->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE; ++ /* the pending flag is always calculated */ ++ if (tpm_tis_check_request_use_except(s, locty)) { ++ val |= TPM_TIS_ACCESS_PENDING_REQUEST; ++ } ++ val |= !tpm_backend_get_tpm_established_flag(s->be_driver); ++ break; ++ case TPM_TIS_REG_INT_ENABLE: ++ val = s->loc[locty].inte; ++ break; ++ case TPM_TIS_REG_INT_VECTOR: ++ val = s->irq_num; ++ break; ++ case TPM_TIS_REG_INT_STATUS: ++ val = s->loc[locty].ints; ++ break; ++ case TPM_TIS_REG_INTF_CAPABILITY: ++ switch (s->be_tpm_version) { ++ case TPM_VERSION_UNSPEC: ++ val = 0; ++ break; ++ case TPM_VERSION_1_2: ++ val = TPM_TIS_CAPABILITIES_SUPPORTED1_3; ++ break; ++ case TPM_VERSION_2_0: ++ val = TPM_TIS_CAPABILITIES_SUPPORTED2_0; ++ break; ++ } ++ break; ++ case TPM_TIS_REG_STS: ++ if (s->active_locty == locty) { ++ if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { ++ val = TPM_TIS_BURST_COUNT( ++ MIN(tpm_cmd_get_size(&s->buffer), ++ s->be_buffer_size) ++ - s->rw_offset) | s->loc[locty].sts; ++ } else { ++ avail = s->be_buffer_size - s->rw_offset; ++ /* ++ * byte-sized reads should not return 0x00 for 0x100 ++ * available bytes. ++ */ ++ if (size == 1 && avail > 0xff) { ++ avail = 0xff; ++ } ++ val = TPM_TIS_BURST_COUNT(avail) | s->loc[locty].sts; ++ } ++ } ++ break; ++ case TPM_TIS_REG_DATA_FIFO: ++ case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END: ++ if (s->active_locty == locty) { ++ if (size > 4 - (addr & 0x3)) { ++ /* prevent access beyond FIFO */ ++ size = 4 - (addr & 0x3); ++ } ++ val = 0; ++ shift = 0; ++ while (size > 0) { ++ switch (s->loc[locty].state) { ++ case TPM_TIS_STATE_COMPLETION: ++ v = tpm_tis_data_read(s, locty); ++ break; ++ default: ++ v = TPM_TIS_NO_DATA_BYTE; ++ break; ++ } ++ val |= (v << shift); ++ shift += 8; ++ size--; ++ } ++ shift = 0; /* no more adjustments */ ++ } ++ break; ++ case TPM_TIS_REG_INTERFACE_ID: ++ val = s->loc[locty].iface_id; ++ break; ++ case TPM_TIS_REG_DID_VID: ++ val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID; ++ break; ++ case TPM_TIS_REG_RID: ++ val = TPM_TIS_TPM_RID; ++ break; ++#ifdef DEBUG_TIS ++ case TPM_TIS_REG_DEBUG: ++ tpm_tis_dump_state(s, addr); ++ break; ++#endif ++ } ++ ++ if (shift) { ++ val >>= shift; ++ } ++ ++ trace_tpm_tis_mmio_read(size, addr, val); ++ ++ return val; ++} ++ ++/* ++ * Write a value to a register of the TIS interface ++ * See specs pages 33-63 for description of the registers ++ */ ++static void tpm_tis_mmio_write(void *opaque, hwaddr addr, ++ uint64_t val, unsigned size) ++{ ++ TPMState *s = opaque; ++ uint16_t off = addr & 0xffc; ++ uint8_t shift = (addr & 0x3) * 8; ++ uint8_t locty = tpm_tis_locality_from_addr(addr); ++ uint8_t active_locty, l; ++ int c, set_new_locty = 1; ++ uint16_t len; ++ uint32_t mask = (size == 1) ? 0xff : ((size == 2) ? 0xffff : ~0); ++ ++ trace_tpm_tis_mmio_write(size, addr, val); ++ ++ if (locty == 4) { ++ trace_tpm_tis_mmio_write_locty4(); ++ return; ++ } ++ ++ if (tpm_backend_had_startup_error(s->be_driver)) { ++ return; ++ } ++ ++ val &= mask; ++ ++ if (shift) { ++ val <<= shift; ++ mask <<= shift; ++ } ++ ++ mask ^= 0xffffffff; ++ ++ switch (off) { ++ case TPM_TIS_REG_ACCESS: ++ ++ if ((val & TPM_TIS_ACCESS_SEIZE)) { ++ val &= ~(TPM_TIS_ACCESS_REQUEST_USE | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ } ++ ++ active_locty = s->active_locty; ++ ++ if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) { ++ /* give up locality if currently owned */ ++ if (s->active_locty == locty) { ++ trace_tpm_tis_mmio_write_release_locty(locty); ++ ++ uint8_t newlocty = TPM_TIS_NO_LOCALITY; ++ /* anybody wants the locality ? */ ++ for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) { ++ if ((s->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) { ++ trace_tpm_tis_mmio_write_locty_req_use(c); ++ newlocty = c; ++ break; ++ } ++ } ++ trace_tpm_tis_mmio_write_next_locty(newlocty); ++ ++ if (TPM_TIS_IS_VALID_LOCTY(newlocty)) { ++ set_new_locty = 0; ++ tpm_tis_prep_abort(s, locty, newlocty); ++ } else { ++ active_locty = TPM_TIS_NO_LOCALITY; ++ } ++ } else { ++ /* not currently the owner; clear a pending request */ ++ s->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE; ++ } ++ } ++ ++ if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) { ++ s->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED; ++ } ++ ++ if ((val & TPM_TIS_ACCESS_SEIZE)) { ++ /* ++ * allow seize if a locality is active and the requesting ++ * locality is higher than the one that's active ++ * OR ++ * allow seize for requesting locality if no locality is ++ * active ++ */ ++ while ((TPM_TIS_IS_VALID_LOCTY(s->active_locty) && ++ locty > s->active_locty) || ++ !TPM_TIS_IS_VALID_LOCTY(s->active_locty)) { ++ bool higher_seize = FALSE; ++ ++ /* already a pending SEIZE ? */ ++ if ((s->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) { ++ break; ++ } ++ ++ /* check for ongoing seize by a higher locality */ ++ for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) { ++ if ((s->loc[l].access & TPM_TIS_ACCESS_SEIZE)) { ++ higher_seize = TRUE; ++ break; ++ } ++ } ++ ++ if (higher_seize) { ++ break; ++ } ++ ++ /* cancel any seize by a lower locality */ ++ for (l = 0; l < locty; l++) { ++ s->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE; ++ } ++ ++ s->loc[locty].access |= TPM_TIS_ACCESS_SEIZE; ++ ++ trace_tpm_tis_mmio_write_locty_seized(locty, s->active_locty); ++ trace_tpm_tis_mmio_write_init_abort(); ++ ++ set_new_locty = 0; ++ tpm_tis_prep_abort(s, s->active_locty, locty); ++ break; ++ } ++ } ++ ++ if ((val & TPM_TIS_ACCESS_REQUEST_USE)) { ++ if (s->active_locty != locty) { ++ if (TPM_TIS_IS_VALID_LOCTY(s->active_locty)) { ++ s->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE; ++ } else { ++ /* no locality active -> make this one active now */ ++ active_locty = locty; ++ } ++ } ++ } ++ ++ if (set_new_locty) { ++ tpm_tis_new_active_locality(s, active_locty); ++ } ++ ++ break; ++ case TPM_TIS_REG_INT_ENABLE: ++ if (s->active_locty != locty) { ++ break; ++ } ++ ++ s->loc[locty].inte &= mask; ++ s->loc[locty].inte |= (val & (TPM_TIS_INT_ENABLED | ++ TPM_TIS_INT_POLARITY_MASK | ++ TPM_TIS_INTERRUPTS_SUPPORTED)); ++ break; ++ case TPM_TIS_REG_INT_VECTOR: ++ /* hard wired -- ignore */ ++ break; ++ case TPM_TIS_REG_INT_STATUS: ++ if (s->active_locty != locty) { ++ break; ++ } ++ ++ /* clearing of interrupt flags */ ++ if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) && ++ (s->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) { ++ s->loc[locty].ints &= ~val; ++ if (s->loc[locty].ints == 0) { ++ qemu_irq_lower(s->irq); ++ trace_tpm_tis_mmio_write_lowering_irq(); ++ } ++ } ++ s->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED); ++ break; ++ case TPM_TIS_REG_STS: ++ if (s->active_locty != locty) { ++ break; ++ } ++ ++ if (s->be_tpm_version == TPM_VERSION_2_0) { ++ /* some flags that are only supported for TPM 2 */ ++ if (val & TPM_TIS_STS_COMMAND_CANCEL) { ++ if (s->loc[locty].state == TPM_TIS_STATE_EXECUTION) { ++ /* ++ * request the backend to cancel. Some backends may not ++ * support it ++ */ ++ tpm_backend_cancel_cmd(s->be_driver); ++ } ++ } ++ ++ if (val & TPM_TIS_STS_RESET_ESTABLISHMENT_BIT) { ++ if (locty == 3 || locty == 4) { ++ tpm_backend_reset_tpm_established_flag(s->be_driver, locty); ++ } ++ } ++ } ++ ++ val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO | ++ TPM_TIS_STS_RESPONSE_RETRY); ++ ++ if (val == TPM_TIS_STS_COMMAND_READY) { ++ switch (s->loc[locty].state) { ++ ++ case TPM_TIS_STATE_READY: ++ s->rw_offset = 0; ++ break; ++ ++ case TPM_TIS_STATE_IDLE: ++ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_COMMAND_READY); ++ s->loc[locty].state = TPM_TIS_STATE_READY; ++ tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY); ++ break; ++ ++ case TPM_TIS_STATE_EXECUTION: ++ case TPM_TIS_STATE_RECEPTION: ++ /* abort currently running command */ ++ trace_tpm_tis_mmio_write_init_abort(); ++ tpm_tis_prep_abort(s, locty, locty); ++ break; ++ ++ case TPM_TIS_STATE_COMPLETION: ++ s->rw_offset = 0; ++ /* shortcut to ready state with C/R set */ ++ s->loc[locty].state = TPM_TIS_STATE_READY; ++ if (!(s->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) { ++ tpm_tis_sts_set(&s->loc[locty], ++ TPM_TIS_STS_COMMAND_READY); ++ tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY); ++ } ++ s->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE); ++ break; ++ ++ } ++ } else if (val == TPM_TIS_STS_TPM_GO) { ++ switch (s->loc[locty].state) { ++ case TPM_TIS_STATE_RECEPTION: ++ if ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) { ++ tpm_tis_tpm_send(s, locty); ++ } ++ break; ++ default: ++ /* ignore */ ++ break; ++ } ++ } else if (val == TPM_TIS_STS_RESPONSE_RETRY) { ++ switch (s->loc[locty].state) { ++ case TPM_TIS_STATE_COMPLETION: ++ s->rw_offset = 0; ++ tpm_tis_sts_set(&s->loc[locty], ++ TPM_TIS_STS_VALID| ++ TPM_TIS_STS_DATA_AVAILABLE); ++ break; ++ default: ++ /* ignore */ ++ break; ++ } ++ } ++ break; ++ case TPM_TIS_REG_DATA_FIFO: ++ case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END: ++ /* data fifo */ ++ if (s->active_locty != locty) { ++ break; ++ } ++ ++ if (s->loc[locty].state == TPM_TIS_STATE_IDLE || ++ s->loc[locty].state == TPM_TIS_STATE_EXECUTION || ++ s->loc[locty].state == TPM_TIS_STATE_COMPLETION) { ++ /* drop the byte */ ++ } else { ++ trace_tpm_tis_mmio_write_data2send(val, size); ++ if (s->loc[locty].state == TPM_TIS_STATE_READY) { ++ s->loc[locty].state = TPM_TIS_STATE_RECEPTION; ++ tpm_tis_sts_set(&s->loc[locty], ++ TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); ++ } ++ ++ val >>= shift; ++ if (size > 4 - (addr & 0x3)) { ++ /* prevent access beyond FIFO */ ++ size = 4 - (addr & 0x3); ++ } ++ ++ while ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) { ++ if (s->rw_offset < s->be_buffer_size) { ++ s->buffer[s->rw_offset++] = ++ (uint8_t)val; ++ val >>= 8; ++ size--; ++ } else { ++ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); ++ } ++ } ++ ++ /* check for complete packet */ ++ if (s->rw_offset > 5 && ++ (s->loc[locty].sts & TPM_TIS_STS_EXPECT)) { ++ /* we have a packet length - see if we have all of it */ ++ bool need_irq = !(s->loc[locty].sts & TPM_TIS_STS_VALID); ++ ++ len = tpm_cmd_get_size(&s->buffer); ++ if (len > s->rw_offset) { ++ tpm_tis_sts_set(&s->loc[locty], ++ TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); ++ } else { ++ /* packet complete */ ++ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); ++ } ++ if (need_irq) { ++ tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID); ++ } ++ } ++ } ++ break; ++ case TPM_TIS_REG_INTERFACE_ID: ++ if (val & TPM_TIS_IFACE_ID_INT_SEL_LOCK) { ++ for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { ++ s->loc[l].iface_id |= TPM_TIS_IFACE_ID_INT_SEL_LOCK; ++ } ++ } ++ break; ++ } ++} ++ ++const MemoryRegionOps tpm_tis_memory_ops = { ++ .read = tpm_tis_mmio_read, ++ .write = tpm_tis_mmio_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = { ++ .min_access_size = 1, ++ .max_access_size = 4, ++ }, ++}; ++ ++/* ++ * Get the TPMVersion of the backend device being used ++ */ ++enum TPMVersion tpm_tis_get_tpm_version(TPMState *s) ++{ ++ if (tpm_backend_had_startup_error(s->be_driver)) { ++ return TPM_VERSION_UNSPEC; ++ } ++ ++ return tpm_backend_get_tpm_version(s->be_driver); ++} ++ ++/* ++ * This function is called when the machine starts, resets or due to ++ * S3 resume. ++ */ ++void tpm_tis_reset(TPMState *s) ++{ ++ int c; ++ ++ s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); ++ s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver), ++ TPM_TIS_BUFFER_MAX); ++ ++ if (s->ppi_enabled) { ++ tpm_ppi_reset(&s->ppi); ++ } ++ tpm_backend_reset(s->be_driver); ++ ++ s->active_locty = TPM_TIS_NO_LOCALITY; ++ s->next_locty = TPM_TIS_NO_LOCALITY; ++ s->aborting_locty = TPM_TIS_NO_LOCALITY; ++ ++ for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) { ++ s->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS; ++ switch (s->be_tpm_version) { ++ case TPM_VERSION_UNSPEC: ++ break; ++ case TPM_VERSION_1_2: ++ s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY1_2; ++ s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3; ++ break; ++ case TPM_VERSION_2_0: ++ s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY2_0; ++ s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0; ++ break; ++ } ++ s->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL; ++ s->loc[c].ints = 0; ++ s->loc[c].state = TPM_TIS_STATE_IDLE; ++ ++ s->rw_offset = 0; ++ } ++ ++ if (tpm_backend_startup_tpm(s->be_driver, s->be_buffer_size) < 0) { ++ exit(1); ++ } ++} ++ ++/* persistent state handling */ ++ ++int tpm_tis_pre_save(TPMState *s) ++{ ++ uint8_t locty = s->active_locty; ++ ++ trace_tpm_tis_pre_save(locty, s->rw_offset); ++ ++ if (DEBUG_TIS) { ++ tpm_tis_dump_state(s, 0); ++ } ++ ++ /* ++ * Synchronize with backend completion. ++ */ ++ tpm_backend_finish_sync(s->be_driver); ++ ++ return 0; ++} ++ ++const VMStateDescription vmstate_locty = { ++ .name = "tpm-tis/locty", ++ .version_id = 0, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT32(state, TPMLocality), ++ VMSTATE_UINT32(inte, TPMLocality), ++ VMSTATE_UINT32(ints, TPMLocality), ++ VMSTATE_UINT8(access, TPMLocality), ++ VMSTATE_UINT32(sts, TPMLocality), ++ VMSTATE_UINT32(iface_id, TPMLocality), ++ VMSTATE_END_OF_LIST(), ++ } ++}; ++ +diff --git a/hw/tpm/tpm_tis_isa.c b/hw/tpm/tpm_tis_isa.c +new file mode 100644 +index 00000000..45e25c02 +--- /dev/null ++++ b/hw/tpm/tpm_tis_isa.c +@@ -0,0 +1,170 @@ ++/* ++ * tpm_tis_isa.c - QEMU's TPM TIS ISA Device ++ * ++ * Copyright (C) 2006,2010-2013 IBM Corporation ++ * ++ * Authors: ++ * Stefan Berger ++ * David Safford ++ * ++ * Xen 4 support: Andrease Niederl ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ * Implementation of the TIS interface according to specs found at ++ * http://www.trustedcomputinggroup.org. This implementation currently ++ * supports version 1.3, 21 March 2013 ++ * In the developers menu choose the PC Client section then find the TIS ++ * specification. ++ * ++ * TPM TIS for TPM 2 implementation following TCG PC Client Platform ++ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/isa/isa.h" ++#include "hw/qdev-properties.h" ++#include "migration/vmstate.h" ++#include "tpm_util.h" ++#include "tpm_tis.h" ++ ++typedef struct TPMStateISA { ++ /*< private >*/ ++ ISADevice parent_obj; ++ ++ /*< public >*/ ++ TPMState state; /* not a QOM object */ ++} TPMStateISA; ++ ++#define TPM_TIS_ISA(obj) OBJECT_CHECK(TPMStateISA, (obj), TYPE_TPM_TIS_ISA) ++ ++static int tpm_tis_pre_save_isa(void *opaque) ++{ ++ TPMStateISA *isadev = opaque; ++ ++ return tpm_tis_pre_save(&isadev->state); ++} ++ ++static const VMStateDescription vmstate_tpm_tis_isa = { ++ .name = "tpm-tis", ++ .version_id = 0, ++ .pre_save = tpm_tis_pre_save_isa, ++ .fields = (VMStateField[]) { ++ VMSTATE_BUFFER(state.buffer, TPMStateISA), ++ VMSTATE_UINT16(state.rw_offset, TPMStateISA), ++ VMSTATE_UINT8(state.active_locty, TPMStateISA), ++ VMSTATE_UINT8(state.aborting_locty, TPMStateISA), ++ VMSTATE_UINT8(state.next_locty, TPMStateISA), ++ ++ VMSTATE_STRUCT_ARRAY(state.loc, TPMStateISA, TPM_TIS_NUM_LOCALITIES, 0, ++ vmstate_locty, TPMLocality), ++ ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++static void tpm_tis_isa_request_completed(TPMIf *ti, int ret) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(ti); ++ TPMState *s = &isadev->state; ++ ++ tpm_tis_request_completed(s, ret); ++} ++ ++static enum TPMVersion tpm_tis_isa_get_tpm_version(TPMIf *ti) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(ti); ++ TPMState *s = &isadev->state; ++ ++ return tpm_tis_get_tpm_version(s); ++} ++ ++static void tpm_tis_isa_reset(DeviceState *dev) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(dev); ++ TPMState *s = &isadev->state; ++ ++ return tpm_tis_reset(s); ++} ++ ++static Property tpm_tis_isa_properties[] = { ++ DEFINE_PROP_UINT32("irq", TPMStateISA, state.irq_num, TPM_TIS_IRQ), ++ DEFINE_PROP_TPMBE("tpmdev", TPMStateISA, state.be_driver), ++ DEFINE_PROP_BOOL("ppi", TPMStateISA, state.ppi_enabled, true), ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ ++static void tpm_tis_isa_initfn(Object *obj) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(obj); ++ TPMState *s = &isadev->state; ++ ++ memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops, ++ s, "tpm-tis-mmio", ++ TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); ++} ++ ++static void tpm_tis_isa_realizefn(DeviceState *dev, Error **errp) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(dev); ++ TPMState *s = &isadev->state; ++ ++ if (!tpm_find()) { ++ error_setg(errp, "at most one TPM device is permitted"); ++ return; ++ } ++ ++ if (!s->be_driver) { ++ error_setg(errp, "'tpmdev' property is required"); ++ return; ++ } ++ if (s->irq_num > 15) { ++ error_setg(errp, "IRQ %d is outside valid range of 0 to 15", ++ s->irq_num); ++ return; ++ } ++ ++ isa_init_irq(ISA_DEVICE(dev), &s->irq, s->irq_num); ++ ++ memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)), ++ TPM_TIS_ADDR_BASE, &s->mmio); ++ ++ if (s->ppi_enabled) { ++ tpm_ppi_init(&s->ppi, isa_address_space(ISA_DEVICE(dev)), ++ TPM_PPI_ADDR_BASE, OBJECT(dev)); ++ } ++} ++ ++static void tpm_tis_isa_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ TPMIfClass *tc = TPM_IF_CLASS(klass); ++ ++ dc->props = tpm_tis_isa_properties; ++ dc->vmsd = &vmstate_tpm_tis_isa; ++ tc->model = TPM_MODEL_TPM_TIS; ++ dc->realize = tpm_tis_isa_realizefn; ++ dc->reset = tpm_tis_isa_reset; ++ tc->request_completed = tpm_tis_isa_request_completed; ++ tc->get_version = tpm_tis_isa_get_tpm_version; ++} ++ ++static const TypeInfo tpm_tis_isa_info = { ++ .name = TYPE_TPM_TIS_ISA, ++ .parent = TYPE_ISA_DEVICE, ++ .instance_size = sizeof(TPMStateISA), ++ .instance_init = tpm_tis_isa_initfn, ++ .class_init = tpm_tis_isa_class_init, ++ .interfaces = (InterfaceInfo[]) { ++ { TYPE_TPM_IF }, ++ { } ++ } ++}; ++ ++static void tpm_tis_isa_register(void) ++{ ++ type_register_static(&tpm_tis_isa_info); ++} ++ ++type_init(tpm_tis_isa_register) +-- +2.23.0 + diff --git a/tpm-Use-TPMState-as-a-common-struct.patch b/tpm-Use-TPMState-as-a-common-struct.patch new file mode 100644 index 0000000000000000000000000000000000000000..61a1dd037bb2356cb7307d53f82732af404ed4e2 --- /dev/null +++ b/tpm-Use-TPMState-as-a-common-struct.patch @@ -0,0 +1,314 @@ +From c57e57c86f9d3c13b33746436bc1f09db88d4d42 Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Tue, 11 Aug 2020 02:52:12 +0000 +Subject: [PATCH 11/19] tpm: Use TPMState as a common struct + +As we plan to introduce a SysBus TPM TIS device, let's +make the TPMState a common struct usable by both the +ISADevice and the SysBusDevice. TPMStateISA embeds the +struct and inherits from the ISADevice. + +The prototype of functions bound to be used by both +the ISA and SysBus devices is changed to take TPMState +handle. + +A bunch of structs also are renamed to be specialized +for the ISA device. Besides those transformations, no +functional change is expected. + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Tested-by: Ard Biesheuvel +Acked-by: Ard Biesheuvel +Message-id: 20200305165149.618-3-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + hw/tpm/tpm_tis.c | 147 +++++++++++++++++++++++++++++------------------ + 1 file changed, 92 insertions(+), 55 deletions(-) + +diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c +index 49d44652..735a528f 100644 +--- a/hw/tpm/tpm_tis.c ++++ b/hw/tpm/tpm_tis.c +@@ -62,7 +62,6 @@ typedef struct TPMLocality { + } TPMLocality; + + typedef struct TPMState { +- ISADevice busdev; + MemoryRegion mmio; + + unsigned char buffer[TPM_TIS_BUFFER_MAX]; +@@ -88,7 +87,15 @@ typedef struct TPMState { + TPMPPI ppi; + } TPMState; + +-#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS_ISA) ++typedef struct TPMStateISA { ++ /*< private >*/ ++ ISADevice parent_obj; ++ ++ /*< public >*/ ++ TPMState state; /* not a QOM object */ ++} TPMStateISA; ++ ++#define TPM_TIS_ISA(obj) OBJECT_CHECK(TPMStateISA, (obj), TYPE_TPM_TIS_ISA) + + #define DEBUG_TIS 0 + +@@ -278,9 +285,8 @@ static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty) + /* + * Callback from the TPM to indicate that the response was received. + */ +-static void tpm_tis_request_completed(TPMIf *ti, int ret) ++static void tpm_tis_request_completed(TPMState *s, int ret) + { +- TPMState *s = TPM(ti); + uint8_t locty = s->cmd.locty; + uint8_t l; + +@@ -335,7 +341,7 @@ static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty) + } + + #ifdef DEBUG_TIS +-static void tpm_tis_dump_state(void *opaque, hwaddr addr) ++static void tpm_tis_dump_state(TPMState *s, hwaddr addr) + { + static const unsigned regs[] = { + TPM_TIS_REG_ACCESS, +@@ -350,7 +356,6 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr) + int idx; + uint8_t locty = tpm_tis_locality_from_addr(addr); + hwaddr base = addr & ~0xfff; +- TPMState *s = opaque; + + printf("tpm_tis: active locality : %d\n" + "tpm_tis: state of locality %d : %d\n" +@@ -360,7 +365,7 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr) + + for (idx = 0; regs[idx] != 0xfff; idx++) { + printf("tpm_tis: 0x%04x : 0x%08x\n", regs[idx], +- (int)tpm_tis_mmio_read(opaque, base + regs[idx], 4)); ++ (int)tpm_tis_mmio_read(s, base + regs[idx], 4)); + } + + printf("tpm_tis: r/w offset : %d\n" +@@ -485,7 +490,7 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, + break; + #ifdef DEBUG_TIS + case TPM_TIS_REG_DEBUG: +- tpm_tis_dump_state(opaque, addr); ++ tpm_tis_dump_state(s, addr); + break; + #endif + } +@@ -832,10 +837,8 @@ static const MemoryRegionOps tpm_tis_memory_ops = { + /* + * Get the TPMVersion of the backend device being used + */ +-static enum TPMVersion tpm_tis_get_tpm_version(TPMIf *ti) ++static enum TPMVersion tpm_tis_get_tpm_version(TPMState *s) + { +- TPMState *s = TPM(ti); +- + if (tpm_backend_had_startup_error(s->be_driver)) { + return TPM_VERSION_UNSPEC; + } +@@ -847,9 +850,8 @@ static enum TPMVersion tpm_tis_get_tpm_version(TPMIf *ti) + * This function is called when the machine starts, resets or due to + * S3 resume. + */ +-static void tpm_tis_reset(DeviceState *dev) ++static void tpm_tis_reset(TPMState *s) + { +- TPMState *s = TPM(dev); + int c; + + s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); +@@ -893,15 +895,14 @@ static void tpm_tis_reset(DeviceState *dev) + + /* persistent state handling */ + +-static int tpm_tis_pre_save(void *opaque) ++static int tpm_tis_pre_save(TPMState *s) + { +- TPMState *s = opaque; + uint8_t locty = s->active_locty; + + trace_tpm_tis_pre_save(locty, s->rw_offset); + + if (DEBUG_TIS) { +- tpm_tis_dump_state(opaque, 0); ++ tpm_tis_dump_state(s, 0); + } + + /* +@@ -926,34 +927,78 @@ static const VMStateDescription vmstate_locty = { + } + }; + +-static const VMStateDescription vmstate_tpm_tis = { ++/* ISA */ ++ ++static int tpm_tis_pre_save_isa(void *opaque) ++{ ++ TPMStateISA *isadev = opaque; ++ ++ return tpm_tis_pre_save(&isadev->state); ++} ++ ++static const VMStateDescription vmstate_tpm_tis_isa = { + .name = "tpm-tis", + .version_id = 0, +- .pre_save = tpm_tis_pre_save, ++ .pre_save = tpm_tis_pre_save_isa, + .fields = (VMStateField[]) { +- VMSTATE_BUFFER(buffer, TPMState), +- VMSTATE_UINT16(rw_offset, TPMState), +- VMSTATE_UINT8(active_locty, TPMState), +- VMSTATE_UINT8(aborting_locty, TPMState), +- VMSTATE_UINT8(next_locty, TPMState), ++ VMSTATE_BUFFER(state.buffer, TPMStateISA), ++ VMSTATE_UINT16(state.rw_offset, TPMStateISA), ++ VMSTATE_UINT8(state.active_locty, TPMStateISA), ++ VMSTATE_UINT8(state.aborting_locty, TPMStateISA), ++ VMSTATE_UINT8(state.next_locty, TPMStateISA), + +- VMSTATE_STRUCT_ARRAY(loc, TPMState, TPM_TIS_NUM_LOCALITIES, 0, ++ VMSTATE_STRUCT_ARRAY(state.loc, TPMStateISA, TPM_TIS_NUM_LOCALITIES, 0, + vmstate_locty, TPMLocality), + + VMSTATE_END_OF_LIST() + } + }; + +-static Property tpm_tis_properties[] = { +- DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ), +- DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver), +- DEFINE_PROP_BOOL("ppi", TPMState, ppi_enabled, true), ++static void tpm_tis_isa_request_completed(TPMIf *ti, int ret) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(ti); ++ TPMState *s = &isadev->state; ++ ++ tpm_tis_request_completed(s, ret); ++} ++ ++static enum TPMVersion tpm_tis_isa_get_tpm_version(TPMIf *ti) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(ti); ++ TPMState *s = &isadev->state; ++ ++ return tpm_tis_get_tpm_version(s); ++} ++ ++static void tpm_tis_isa_reset(DeviceState *dev) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(dev); ++ TPMState *s = &isadev->state; ++ ++ return tpm_tis_reset(s); ++} ++ ++static Property tpm_tis_isa_properties[] = { ++ DEFINE_PROP_UINT32("irq", TPMStateISA, state.irq_num, TPM_TIS_IRQ), ++ DEFINE_PROP_TPMBE("tpmdev", TPMStateISA, state.be_driver), ++ DEFINE_PROP_BOOL("ppi", TPMStateISA, state.ppi_enabled, true), + DEFINE_PROP_END_OF_LIST(), + }; + +-static void tpm_tis_realizefn(DeviceState *dev, Error **errp) ++static void tpm_tis_isa_initfn(Object *obj) + { +- TPMState *s = TPM(dev); ++ TPMStateISA *isadev = TPM_TIS_ISA(obj); ++ TPMState *s = &isadev->state; ++ ++ memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops, ++ s, "tpm-tis-mmio", ++ TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); ++} ++ ++static void tpm_tis_isa_realizefn(DeviceState *dev, Error **errp) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(dev); ++ TPMState *s = &isadev->state; + + if (!tpm_find()) { + error_setg(errp, "at most one TPM device is permitted"); +@@ -970,55 +1015,47 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp) + return; + } + +- isa_init_irq(&s->busdev, &s->irq, s->irq_num); ++ isa_init_irq(ISA_DEVICE(dev), &s->irq, s->irq_num); + + memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)), + TPM_TIS_ADDR_BASE, &s->mmio); + + if (s->ppi_enabled) { + tpm_ppi_init(&s->ppi, isa_address_space(ISA_DEVICE(dev)), +- TPM_PPI_ADDR_BASE, OBJECT(s)); ++ TPM_PPI_ADDR_BASE, OBJECT(dev)); + } + } + +-static void tpm_tis_initfn(Object *obj) +-{ +- TPMState *s = TPM(obj); +- +- memory_region_init_io(&s->mmio, OBJECT(s), &tpm_tis_memory_ops, +- s, "tpm-tis-mmio", +- TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); +-} +- +-static void tpm_tis_class_init(ObjectClass *klass, void *data) ++static void tpm_tis_isa_class_init(ObjectClass *klass, void *data) + { + DeviceClass *dc = DEVICE_CLASS(klass); + TPMIfClass *tc = TPM_IF_CLASS(klass); + +- dc->realize = tpm_tis_realizefn; +- dc->props = tpm_tis_properties; +- dc->reset = tpm_tis_reset; +- dc->vmsd = &vmstate_tpm_tis; ++ dc->props = tpm_tis_isa_properties; ++ dc->vmsd = &vmstate_tpm_tis_isa; + tc->model = TPM_MODEL_TPM_TIS; +- tc->get_version = tpm_tis_get_tpm_version; +- tc->request_completed = tpm_tis_request_completed; ++ dc->realize = tpm_tis_isa_realizefn; ++ dc->reset = tpm_tis_isa_reset; ++ tc->request_completed = tpm_tis_isa_request_completed; ++ tc->get_version = tpm_tis_isa_get_tpm_version; ++ + } + +-static const TypeInfo tpm_tis_info = { ++static const TypeInfo tpm_tis_isa_info = { + .name = TYPE_TPM_TIS_ISA, + .parent = TYPE_ISA_DEVICE, +- .instance_size = sizeof(TPMState), +- .instance_init = tpm_tis_initfn, +- .class_init = tpm_tis_class_init, ++ .instance_size = sizeof(TPMStateISA), ++ .instance_init = tpm_tis_isa_initfn, ++ .class_init = tpm_tis_isa_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_TPM_IF }, + { } + } + }; + +-static void tpm_tis_register(void) ++static void tpm_tis_isa_register(void) + { +- type_register_static(&tpm_tis_info); ++ type_register_static(&tpm_tis_isa_info); + } + +-type_init(tpm_tis_register) ++type_init(tpm_tis_isa_register) +-- +2.23.0 + diff --git a/tpm-ppi-page-align-PPI-RAM.patch b/tpm-ppi-page-align-PPI-RAM.patch new file mode 100644 index 0000000000000000000000000000000000000000..d7ba2c876605392e79d887b89a4a274cb51660d4 --- /dev/null +++ b/tpm-ppi-page-align-PPI-RAM.patch @@ -0,0 +1,43 @@ +From 26b54c545f253049faa633ff886132602ff47241 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Fri, 3 Jan 2020 11:39:59 +0400 +Subject: [PATCH 02/19] tpm-ppi: page-align PPI RAM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +post-copy migration fails on destination with error such as: +2019-12-26T10:22:44.714644Z qemu-kvm: ram_block_discard_range: +Unaligned start address: 0x559d2afae9a0 + +Use qemu_memalign() to constrain the PPI RAM memory alignment. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Marc-André Lureau +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Dr. David Alan Gilbert +Reviewed-by: Stefan Berger +Signed-off-by: Stefan Berger +Message-id: 20200103074000.1006389-3-marcandre.lureau@redhat.com +Signed-off-by: jiangfangjie +--- + hw/tpm/tpm_ppi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c +index cd8205f2..6509ffd4 100644 +--- a/hw/tpm/tpm_ppi.c ++++ b/hw/tpm/tpm_ppi.c +@@ -44,7 +44,8 @@ void tpm_ppi_reset(TPMPPI *tpmppi) + void tpm_ppi_init(TPMPPI *tpmppi, struct MemoryRegion *m, + hwaddr addr, Object *obj) + { +- tpmppi->buf = g_malloc0(HOST_PAGE_ALIGN(TPM_PPI_ADDR_SIZE)); ++ tpmppi->buf = qemu_memalign(qemu_real_host_page_size, ++ HOST_PAGE_ALIGN(TPM_PPI_ADDR_SIZE)); + memory_region_init_ram_device_ptr(&tpmppi->ram, obj, "tpm-ppi", + TPM_PPI_ADDR_SIZE, tpmppi->buf); + vmstate_register_ram(&tpmppi->ram, DEVICE(obj)); +-- +2.23.0 + diff --git a/tpm-rename-TPM_TIS-into-TPM_TIS_ISA.patch b/tpm-rename-TPM_TIS-into-TPM_TIS_ISA.patch new file mode 100644 index 0000000000000000000000000000000000000000..ea6e1d28a10cb6d29ba1c1c76245ef6749825ba2 --- /dev/null +++ b/tpm-rename-TPM_TIS-into-TPM_TIS_ISA.patch @@ -0,0 +1,101 @@ +From 7974f8ffd75171be106a1ce2705878abbb6c4477 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 5 Mar 2020 17:51:40 +0100 +Subject: [PATCH 10/19] tpm: rename TPM_TIS into TPM_TIS_ISA +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As we plan to introduce a sysbus TPM_TIS, let's rename +TPM_TIS into TPM_TIS_ISA. + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Ard Biesheuvel +Acked-by: Ard Biesheuvel +Message-id: 20200305165149.618-2-eric.auger@redhat.com +Signed-off-by: Stefan Berger +Signed-off-by: jiangfangjie +--- + hw/i386/acpi-build.c | 6 +++--- + hw/tpm/tpm_tis.c | 4 ++-- + include/sysemu/tpm.h | 6 +++--- + 3 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index c97731ec..093f7d93 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -2007,7 +2007,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, + } + } + +- if (TPM_IS_TIS(tpm_find())) { ++ if (TPM_IS_TIS_ISA(tpm_find())) { + aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE, + TPM_TIS_ADDR_SIZE, AML_READ_WRITE)); + } +@@ -2178,7 +2178,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, + /* Scan all PCI buses. Generate tables to support hotplug. */ + build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en); + +- if (TPM_IS_TIS(tpm)) { ++ if (TPM_IS_TIS_ISA(tpm)) { + if (misc->tpm_version == TPM_VERSION_2_0) { + dev = aml_device("TPM"); + aml_append(dev, aml_name_decl("_HID", +@@ -2285,7 +2285,7 @@ build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) + (char *)&tpm2_ptr->log_area_start_address - table_data->data; + + tpm2_ptr->platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT); +- if (TPM_IS_TIS(tpm_find())) { ++ if (TPM_IS_TIS_ISA(tpm_find())) { + tpm2_ptr->control_area_address = cpu_to_le64(0); + tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO); + } else if (TPM_IS_CRB(tpm_find())) { +diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c +index 96a9ac48..49d44652 100644 +--- a/hw/tpm/tpm_tis.c ++++ b/hw/tpm/tpm_tis.c +@@ -88,7 +88,7 @@ typedef struct TPMState { + TPMPPI ppi; + } TPMState; + +-#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS) ++#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS_ISA) + + #define DEBUG_TIS 0 + +@@ -1005,7 +1005,7 @@ static void tpm_tis_class_init(ObjectClass *klass, void *data) + } + + static const TypeInfo tpm_tis_info = { +- .name = TYPE_TPM_TIS, ++ .name = TYPE_TPM_TIS_ISA, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(TPMState), + .instance_init = tpm_tis_initfn, +diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h +index 15979a36..1691b92c 100644 +--- a/include/sysemu/tpm.h ++++ b/include/sysemu/tpm.h +@@ -43,12 +43,12 @@ typedef struct TPMIfClass { + enum TPMVersion (*get_version)(TPMIf *obj); + } TPMIfClass; + +-#define TYPE_TPM_TIS "tpm-tis" ++#define TYPE_TPM_TIS_ISA "tpm-tis" + #define TYPE_TPM_CRB "tpm-crb" + #define TYPE_TPM_SPAPR "tpm-spapr" + +-#define TPM_IS_TIS(chr) \ +- object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS) ++#define TPM_IS_TIS_ISA(chr) \ ++ object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS_ISA) + #define TPM_IS_CRB(chr) \ + object_dynamic_cast(OBJECT(chr), TYPE_TPM_CRB) + #define TPM_IS_SPAPR(chr) \ +-- +2.23.0 + diff --git a/tpm_spapr-Support-TPM-for-ppc64-using-CRQ-based-inte.patch b/tpm_spapr-Support-TPM-for-ppc64-using-CRQ-based-inte.patch new file mode 100644 index 0000000000000000000000000000000000000000..ffc0b62ed7ef655056cfd1280282b768f22ad501 --- /dev/null +++ b/tpm_spapr-Support-TPM-for-ppc64-using-CRQ-based-inte.patch @@ -0,0 +1,552 @@ +From 14402a8ca57fb722eb324d141fafb41ef06f4c2b Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 21 Jan 2020 10:29:32 -0500 +Subject: [PATCH 06/19] tpm_spapr: Support TPM for ppc64 using CRQ based + interface + +Implement support for TPM on ppc64 by implementing the vTPM CRQ interface +as a frontend. It can use the tpm_emulator driver backend with the external +swtpm. + +The Linux vTPM driver for ppc64 works with this emulation. + +This TPM emulator also handles the TPM 2 case. + +Signed-off-by: Stefan Berger +Reviewed-by: David Gibson +Message-Id: <20200121152935.649898-4-stefanb@linux.ibm.com> +Signed-off-by: David Gibson +Signed-off-by: jiangfangjie +--- + docs/specs/tpm.txt | 20 ++- + hw/tpm/Kconfig | 6 + + hw/tpm/Makefile.objs | 1 + + hw/tpm/tpm_spapr.c | 379 +++++++++++++++++++++++++++++++++++++++++++ + hw/tpm/trace-events | 12 ++ + include/sysemu/tpm.h | 3 + + qapi/tpm.json | 6 +- + 7 files changed, 423 insertions(+), 4 deletions(-) + create mode 100644 hw/tpm/tpm_spapr.c + +diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt +index 9c8cca04..9c3e67d8 100644 +--- a/docs/specs/tpm.txt ++++ b/docs/specs/tpm.txt +@@ -34,6 +34,12 @@ The CRB interface makes a memory mapped IO region in the area 0xfed40000 - + QEMU files related to TPM CRB interface: + - hw/tpm/tpm_crb.c + ++ ++pSeries (ppc64) machines offer a tpm-spapr device model. ++ ++QEMU files related to the SPAPR interface: ++ - hw/tpm/tpm_spapr.c ++ + = fw_cfg interface = + + The bios/firmware may read the "etc/tpm/config" fw_cfg entry for +@@ -281,7 +287,7 @@ swtpm socket --tpmstate dir=/tmp/mytpm1 \ + --log level=20 + + Command line to start QEMU with the TPM emulator device communicating with +-the swtpm: ++the swtpm (x86): + + qemu-system-x86_64 -display sdl -accel kvm \ + -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ +@@ -289,6 +295,18 @@ qemu-system-x86_64 -display sdl -accel kvm \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-tis,tpmdev=tpm0 test.img + ++In case a pSeries machine is emulated, use the following command line: ++ ++qemu-system-ppc64 -display sdl -machine pseries,accel=kvm \ ++ -m 1024 -bios slof.bin -boot menu=on \ ++ -nodefaults -device VGA -device pci-ohci -device usb-kbd \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-spapr,tpmdev=tpm0 \ ++ -device spapr-vscsi,id=scsi0,reg=0x00002000 \ ++ -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \ ++ -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0 ++ + + In case SeaBIOS is used as firmware, it should show the TPM menu item + after entering the menu with 'ESC'. +diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig +index 4c8ee87d..4d4ab085 100644 +--- a/hw/tpm/Kconfig ++++ b/hw/tpm/Kconfig +@@ -22,3 +22,9 @@ config TPM_EMULATOR + bool + default y + depends on TPMDEV ++ ++config TPM_SPAPR ++ bool ++ default n ++ depends on TPM && PSERIES ++ select TPMDEV +diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs +index de0b85d0..85eb99ae 100644 +--- a/hw/tpm/Makefile.objs ++++ b/hw/tpm/Makefile.objs +@@ -4,3 +4,4 @@ common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o + common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o + common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o + common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o ++obj-$(CONFIG_TPM_SPAPR) += tpm_spapr.o +diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c +new file mode 100644 +index 00000000..1db9696a +--- /dev/null ++++ b/hw/tpm/tpm_spapr.c +@@ -0,0 +1,379 @@ ++/* ++ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator ++ * ++ * PAPR Virtual TPM ++ * ++ * Copyright (c) 2015, 2017, 2019 IBM Corporation. ++ * ++ * Authors: ++ * Stefan Berger ++ * ++ * This code is licensed under the GPL version 2 or later. See the ++ * COPYING file in the top-level directory. ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/error-report.h" ++#include "qapi/error.h" ++#include "hw/qdev-properties.h" ++#include "migration/vmstate.h" ++ ++#include "sysemu/tpm_backend.h" ++#include "tpm_int.h" ++#include "tpm_util.h" ++ ++#include "hw/ppc/spapr.h" ++#include "hw/ppc/spapr_vio.h" ++#include "trace.h" ++ ++#define DEBUG_SPAPR 0 ++ ++#define VIO_SPAPR_VTPM(obj) \ ++ OBJECT_CHECK(SpaprTpmState, (obj), TYPE_TPM_SPAPR) ++ ++typedef struct TpmCrq { ++ uint8_t valid; /* 0x80: cmd; 0xc0: init crq */ ++ /* 0x81-0x83: CRQ message response */ ++ uint8_t msg; /* see below */ ++ uint16_t len; /* len of TPM request; len of TPM response */ ++ uint32_t data; /* rtce_dma_handle when sending TPM request */ ++ uint64_t reserved; ++} TpmCrq; ++ ++#define SPAPR_VTPM_VALID_INIT_CRQ_COMMAND 0xC0 ++#define SPAPR_VTPM_VALID_COMMAND 0x80 ++#define SPAPR_VTPM_MSG_RESULT 0x80 ++ ++/* msg types for valid = SPAPR_VTPM_VALID_INIT_CRQ */ ++#define SPAPR_VTPM_INIT_CRQ_RESULT 0x1 ++#define SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT 0x2 ++ ++/* msg types for valid = SPAPR_VTPM_VALID_CMD */ ++#define SPAPR_VTPM_GET_VERSION 0x1 ++#define SPAPR_VTPM_TPM_COMMAND 0x2 ++#define SPAPR_VTPM_GET_RTCE_BUFFER_SIZE 0x3 ++#define SPAPR_VTPM_PREPARE_TO_SUSPEND 0x4 ++ ++/* response error messages */ ++#define SPAPR_VTPM_VTPM_ERROR 0xff ++ ++/* error codes */ ++#define SPAPR_VTPM_ERR_COPY_IN_FAILED 0x3 ++#define SPAPR_VTPM_ERR_COPY_OUT_FAILED 0x4 ++ ++#define TPM_SPAPR_BUFFER_MAX 4096 ++ ++typedef struct { ++ SpaprVioDevice vdev; ++ ++ TpmCrq crq; /* track single TPM command */ ++ ++ uint8_t state; ++#define SPAPR_VTPM_STATE_NONE 0 ++#define SPAPR_VTPM_STATE_EXECUTION 1 ++#define SPAPR_VTPM_STATE_COMPLETION 2 ++ ++ unsigned char *buffer; ++ ++ TPMBackendCmd cmd; ++ ++ TPMBackend *be_driver; ++ TPMVersion be_tpm_version; ++ ++ size_t be_buffer_size; ++} SpaprTpmState; ++ ++/* ++ * Send a request to the TPM. ++ */ ++static void tpm_spapr_tpm_send(SpaprTpmState *s) ++{ ++ if (trace_event_get_state_backends(TRACE_TPM_SPAPR_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); ++ } ++ ++ s->state = SPAPR_VTPM_STATE_EXECUTION; ++ s->cmd = (TPMBackendCmd) { ++ .locty = 0, ++ .in = s->buffer, ++ .in_len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size), ++ .out = s->buffer, ++ .out_len = s->be_buffer_size, ++ }; ++ ++ tpm_backend_deliver_request(s->be_driver, &s->cmd); ++} ++ ++static int tpm_spapr_process_cmd(SpaprTpmState *s, uint64_t dataptr) ++{ ++ long rc; ++ ++ /* a max. of be_buffer_size bytes can be transported */ ++ rc = spapr_vio_dma_read(&s->vdev, dataptr, ++ s->buffer, s->be_buffer_size); ++ if (rc) { ++ error_report("tpm_spapr_got_payload: DMA read failure"); ++ } ++ /* let vTPM handle any malformed request */ ++ tpm_spapr_tpm_send(s); ++ ++ return rc; ++} ++ ++static inline int spapr_tpm_send_crq(struct SpaprVioDevice *dev, TpmCrq *crq) ++{ ++ return spapr_vio_send_crq(dev, (uint8_t *)crq); ++} ++ ++static int tpm_spapr_do_crq(struct SpaprVioDevice *dev, uint8_t *crq_data) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(dev); ++ TpmCrq local_crq; ++ TpmCrq *crq = &s->crq; /* requests only */ ++ int rc; ++ uint8_t valid = crq_data[0]; ++ uint8_t msg = crq_data[1]; ++ ++ trace_tpm_spapr_do_crq(valid, msg); ++ ++ switch (valid) { ++ case SPAPR_VTPM_VALID_INIT_CRQ_COMMAND: /* Init command/response */ ++ ++ /* Respond to initialization request */ ++ switch (msg) { ++ case SPAPR_VTPM_INIT_CRQ_RESULT: ++ trace_tpm_spapr_do_crq_crq_result(); ++ memset(&local_crq, 0, sizeof(local_crq)); ++ local_crq.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND; ++ local_crq.msg = SPAPR_VTPM_INIT_CRQ_RESULT; ++ spapr_tpm_send_crq(dev, &local_crq); ++ break; ++ ++ case SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT: ++ trace_tpm_spapr_do_crq_crq_complete_result(); ++ memset(&local_crq, 0, sizeof(local_crq)); ++ local_crq.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND; ++ local_crq.msg = SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT; ++ spapr_tpm_send_crq(dev, &local_crq); ++ break; ++ } ++ ++ break; ++ case SPAPR_VTPM_VALID_COMMAND: /* Payloads */ ++ switch (msg) { ++ case SPAPR_VTPM_TPM_COMMAND: ++ trace_tpm_spapr_do_crq_tpm_command(); ++ if (s->state == SPAPR_VTPM_STATE_EXECUTION) { ++ return H_BUSY; ++ } ++ memcpy(crq, crq_data, sizeof(*crq)); ++ ++ rc = tpm_spapr_process_cmd(s, be32_to_cpu(crq->data)); ++ ++ if (rc == H_SUCCESS) { ++ crq->valid = be16_to_cpu(0); ++ } else { ++ local_crq.valid = SPAPR_VTPM_MSG_RESULT; ++ local_crq.msg = SPAPR_VTPM_VTPM_ERROR; ++ local_crq.len = cpu_to_be16(0); ++ local_crq.data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_IN_FAILED); ++ spapr_tpm_send_crq(dev, &local_crq); ++ } ++ break; ++ ++ case SPAPR_VTPM_GET_RTCE_BUFFER_SIZE: ++ trace_tpm_spapr_do_crq_tpm_get_rtce_buffer_size(s->be_buffer_size); ++ local_crq.valid = SPAPR_VTPM_VALID_COMMAND; ++ local_crq.msg = SPAPR_VTPM_GET_RTCE_BUFFER_SIZE | ++ SPAPR_VTPM_MSG_RESULT; ++ local_crq.len = cpu_to_be16(s->be_buffer_size); ++ spapr_tpm_send_crq(dev, &local_crq); ++ break; ++ ++ case SPAPR_VTPM_GET_VERSION: ++ local_crq.valid = SPAPR_VTPM_VALID_COMMAND; ++ local_crq.msg = SPAPR_VTPM_GET_VERSION | SPAPR_VTPM_MSG_RESULT; ++ local_crq.len = cpu_to_be16(0); ++ switch (s->be_tpm_version) { ++ case TPM_VERSION_1_2: ++ local_crq.data = cpu_to_be32(1); ++ break; ++ case TPM_VERSION_2_0: ++ local_crq.data = cpu_to_be32(2); ++ break; ++ default: ++ g_assert_not_reached(); ++ break; ++ } ++ trace_tpm_spapr_do_crq_get_version(be32_to_cpu(local_crq.data)); ++ spapr_tpm_send_crq(dev, &local_crq); ++ break; ++ ++ case SPAPR_VTPM_PREPARE_TO_SUSPEND: ++ trace_tpm_spapr_do_crq_prepare_to_suspend(); ++ local_crq.valid = SPAPR_VTPM_VALID_COMMAND; ++ local_crq.msg = SPAPR_VTPM_PREPARE_TO_SUSPEND | ++ SPAPR_VTPM_MSG_RESULT; ++ spapr_tpm_send_crq(dev, &local_crq); ++ break; ++ ++ default: ++ trace_tpm_spapr_do_crq_unknown_msg_type(crq->msg); ++ } ++ break; ++ default: ++ trace_tpm_spapr_do_crq_unknown_crq(valid, msg); ++ }; ++ ++ return H_SUCCESS; ++} ++ ++static void tpm_spapr_request_completed(TPMIf *ti, int ret) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(ti); ++ TpmCrq *crq = &s->crq; ++ uint32_t len; ++ int rc; ++ ++ s->state = SPAPR_VTPM_STATE_COMPLETION; ++ ++ /* a max. of be_buffer_size bytes can be transported */ ++ len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size); ++ rc = spapr_vio_dma_write(&s->vdev, be32_to_cpu(crq->data), ++ s->buffer, len); ++ ++ if (trace_event_get_state_backends(TRACE_TPM_SPAPR_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, len, "From TPM"); ++ } ++ ++ crq->valid = SPAPR_VTPM_MSG_RESULT; ++ if (rc == H_SUCCESS) { ++ crq->msg = SPAPR_VTPM_TPM_COMMAND | SPAPR_VTPM_MSG_RESULT; ++ crq->len = cpu_to_be16(len); ++ } else { ++ error_report("%s: DMA write failure", __func__); ++ crq->msg = SPAPR_VTPM_VTPM_ERROR; ++ crq->len = cpu_to_be16(0); ++ crq->data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_OUT_FAILED); ++ } ++ ++ rc = spapr_tpm_send_crq(&s->vdev, crq); ++ if (rc) { ++ error_report("%s: Error sending response", __func__); ++ } ++} ++ ++static int tpm_spapr_do_startup_tpm(SpaprTpmState *s, size_t buffersize) ++{ ++ return tpm_backend_startup_tpm(s->be_driver, buffersize); ++} ++ ++static const char *tpm_spapr_get_dt_compatible(SpaprVioDevice *dev) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(dev); ++ ++ switch (s->be_tpm_version) { ++ case TPM_VERSION_1_2: ++ return "IBM,vtpm"; ++ case TPM_VERSION_2_0: ++ return "IBM,vtpm20"; ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static void tpm_spapr_reset(SpaprVioDevice *dev) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(dev); ++ ++ s->state = SPAPR_VTPM_STATE_NONE; ++ ++ s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); ++ ++ s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver), ++ TPM_SPAPR_BUFFER_MAX); ++ ++ tpm_backend_reset(s->be_driver); ++ tpm_spapr_do_startup_tpm(s, s->be_buffer_size); ++} ++ ++static enum TPMVersion tpm_spapr_get_version(TPMIf *ti) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(ti); ++ ++ if (tpm_backend_had_startup_error(s->be_driver)) { ++ return TPM_VERSION_UNSPEC; ++ } ++ ++ return tpm_backend_get_tpm_version(s->be_driver); ++} ++ ++static const VMStateDescription vmstate_spapr_vtpm = { ++ .name = "tpm-spapr", ++ .unmigratable = 1, ++}; ++ ++static Property tpm_spapr_properties[] = { ++ DEFINE_SPAPR_PROPERTIES(SpaprTpmState, vdev), ++ DEFINE_PROP_TPMBE("tpmdev", SpaprTpmState, be_driver), ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ ++static void tpm_spapr_realizefn(SpaprVioDevice *dev, Error **errp) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(dev); ++ ++ if (!tpm_find()) { ++ error_setg(errp, "at most one TPM device is permitted"); ++ return; ++ } ++ ++ dev->crq.SendFunc = tpm_spapr_do_crq; ++ ++ if (!s->be_driver) { ++ error_setg(errp, "'tpmdev' property is required"); ++ return; ++ } ++ s->buffer = g_malloc(TPM_SPAPR_BUFFER_MAX); ++} ++ ++static void tpm_spapr_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); ++ TPMIfClass *tc = TPM_IF_CLASS(klass); ++ ++ k->realize = tpm_spapr_realizefn; ++ k->reset = tpm_spapr_reset; ++ k->dt_name = "vtpm"; ++ k->dt_type = "IBM,vtpm"; ++ k->get_dt_compatible = tpm_spapr_get_dt_compatible; ++ k->signal_mask = 0x00000001; ++ set_bit(DEVICE_CATEGORY_MISC, dc->categories); ++ dc->props = tpm_spapr_properties; ++ k->rtce_window_size = 0x10000000; ++ dc->vmsd = &vmstate_spapr_vtpm; ++ ++ tc->model = TPM_MODEL_TPM_SPAPR; ++ tc->get_version = tpm_spapr_get_version; ++ tc->request_completed = tpm_spapr_request_completed; ++} ++ ++static const TypeInfo tpm_spapr_info = { ++ .name = TYPE_TPM_SPAPR, ++ .parent = TYPE_VIO_SPAPR_DEVICE, ++ .instance_size = sizeof(SpaprTpmState), ++ .class_init = tpm_spapr_class_init, ++ .interfaces = (InterfaceInfo[]) { ++ { TYPE_TPM_IF }, ++ { } ++ } ++}; ++ ++static void tpm_spapr_register_types(void) ++{ ++ type_register_static(&tpm_spapr_info); ++} ++ ++type_init(tpm_spapr_register_types) +diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events +index 82c45ee5..edbe1bd7 100644 +--- a/hw/tpm/trace-events ++++ b/hw/tpm/trace-events +@@ -55,3 +55,15 @@ tpm_tis_pre_save(uint8_t locty, uint32_t rw_offset) "locty: %d, rw_offset = %u" + + # tpm_ppi.c + tpm_ppi_memset(uint8_t *ptr, size_t size) "memset: %p %zu" ++ ++# hw/tpm/tpm_spapr.c ++tpm_spapr_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s" ++tpm_spapr_do_crq(uint8_t raw1, uint8_t raw2) "1st 2 bytes in CRQ: 0x%02x 0x%02x" ++tpm_spapr_do_crq_crq_result(void) "SPAPR_VTPM_INIT_CRQ_RESULT" ++tpm_spapr_do_crq_crq_complete_result(void) "SPAPR_VTPM_INIT_CRQ_COMP_RESULT" ++tpm_spapr_do_crq_tpm_command(void) "got TPM command payload" ++tpm_spapr_do_crq_tpm_get_rtce_buffer_size(size_t buffersize) "response: buffer size is %zu" ++tpm_spapr_do_crq_get_version(uint32_t version) "response: version %u" ++tpm_spapr_do_crq_prepare_to_suspend(void) "response: preparing to suspend" ++tpm_spapr_do_crq_unknown_msg_type(uint8_t type) "Unknown message type 0x%02x" ++tpm_spapr_do_crq_unknown_crq(uint8_t raw1, uint8_t raw2) "unknown CRQ 0x%02x 0x%02x ..." +diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h +index 5b541a71..15979a36 100644 +--- a/include/sysemu/tpm.h ++++ b/include/sysemu/tpm.h +@@ -45,11 +45,14 @@ typedef struct TPMIfClass { + + #define TYPE_TPM_TIS "tpm-tis" + #define TYPE_TPM_CRB "tpm-crb" ++#define TYPE_TPM_SPAPR "tpm-spapr" + + #define TPM_IS_TIS(chr) \ + object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS) + #define TPM_IS_CRB(chr) \ + object_dynamic_cast(OBJECT(chr), TYPE_TPM_CRB) ++#define TPM_IS_SPAPR(chr) \ ++ object_dynamic_cast(OBJECT(chr), TYPE_TPM_SPAPR) + + /* returns NULL unless there is exactly one TPM device */ + static inline TPMIf *tpm_find(void) +diff --git a/qapi/tpm.json b/qapi/tpm.json +index b30323bb..63878aa0 100644 +--- a/qapi/tpm.json ++++ b/qapi/tpm.json +@@ -12,11 +12,11 @@ + # + # @tpm-tis: TPM TIS model + # @tpm-crb: TPM CRB model (since 2.12) ++# @tpm-spapr: TPM SPAPR model (since 5.0) + # + # Since: 1.5 + ## +-{ 'enum': 'TpmModel', 'data': [ 'tpm-tis', 'tpm-crb' ] } +- ++{ 'enum': 'TpmModel', 'data': [ 'tpm-tis', 'tpm-crb', 'tpm-spapr' ] } + ## + # @query-tpm-models: + # +@@ -29,7 +29,7 @@ + # Example: + # + # -> { "execute": "query-tpm-models" } +-# <- { "return": [ "tpm-tis", "tpm-crb" ] } ++# <- { "return": [ "tpm-tis", "tpm-crb", "tpm-spapr" ] } + # + ## + { 'command': 'query-tpm-models', 'returns': ['TpmModel'] } +-- +2.23.0 + diff --git a/tpm_spapr-Support-suspend-and-resume.patch b/tpm_spapr-Support-suspend-and-resume.patch new file mode 100644 index 0000000000000000000000000000000000000000..55ed521a261fe5c058d9f6b95334c0884cdfd7ea --- /dev/null +++ b/tpm_spapr-Support-suspend-and-resume.patch @@ -0,0 +1,119 @@ +From 2948d9712a7058bcdca6732101874beb1a6e00a9 Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 21 Jan 2020 10:29:33 -0500 +Subject: [PATCH 07/19] tpm_spapr: Support suspend and resume +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Extend the tpm_spapr frontend with VM suspend and resume support. + +Signed-off-by: Stefan Berger +Message-Id: <20200121152935.649898-5-stefanb@linux.ibm.com> +Reviewed-by: Marc-André Lureau +Signed-off-by: David Gibson +Signed-off-by: jiangfangjie +--- + hw/tpm/tpm_spapr.c | 52 ++++++++++++++++++++++++++++++++++++++++++++- + hw/tpm/trace-events | 2 ++ + 2 files changed, 53 insertions(+), 1 deletion(-) + +diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c +index 1db9696a..8ba561f4 100644 +--- a/hw/tpm/tpm_spapr.c ++++ b/hw/tpm/tpm_spapr.c +@@ -76,6 +76,8 @@ typedef struct { + + unsigned char *buffer; + ++ uint32_t numbytes; /* number of bytes to deliver on resume */ ++ + TPMBackendCmd cmd; + + TPMBackend *be_driver; +@@ -240,6 +242,14 @@ static void tpm_spapr_request_completed(TPMIf *ti, int ret) + + /* a max. of be_buffer_size bytes can be transported */ + len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size); ++ ++ if (runstate_check(RUN_STATE_FINISH_MIGRATE)) { ++ trace_tpm_spapr_caught_response(len); ++ /* defer delivery of response until .post_load */ ++ s->numbytes = len; ++ return; ++ } ++ + rc = spapr_vio_dma_write(&s->vdev, be32_to_cpu(crq->data), + s->buffer, len); + +@@ -288,6 +298,7 @@ static void tpm_spapr_reset(SpaprVioDevice *dev) + SpaprTpmState *s = VIO_SPAPR_VTPM(dev); + + s->state = SPAPR_VTPM_STATE_NONE; ++ s->numbytes = 0; + + s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); + +@@ -309,9 +320,48 @@ static enum TPMVersion tpm_spapr_get_version(TPMIf *ti) + return tpm_backend_get_tpm_version(s->be_driver); + } + ++/* persistent state handling */ ++ ++static int tpm_spapr_pre_save(void *opaque) ++{ ++ SpaprTpmState *s = opaque; ++ ++ tpm_backend_finish_sync(s->be_driver); ++ /* ++ * we cannot deliver the results to the VM since DMA would touch VM memory ++ */ ++ ++ return 0; ++} ++ ++static int tpm_spapr_post_load(void *opaque, int version_id) ++{ ++ SpaprTpmState *s = opaque; ++ ++ if (s->numbytes) { ++ trace_tpm_spapr_post_load(); ++ /* deliver the results to the VM via DMA */ ++ tpm_spapr_request_completed(TPM_IF(s), 0); ++ s->numbytes = 0; ++ } ++ ++ return 0; ++} ++ + static const VMStateDescription vmstate_spapr_vtpm = { + .name = "tpm-spapr", +- .unmigratable = 1, ++ .pre_save = tpm_spapr_pre_save, ++ .post_load = tpm_spapr_post_load, ++ .fields = (VMStateField[]) { ++ VMSTATE_SPAPR_VIO(vdev, SpaprTpmState), ++ ++ VMSTATE_UINT8(state, SpaprTpmState), ++ VMSTATE_UINT32(numbytes, SpaprTpmState), ++ VMSTATE_VBUFFER_UINT32(buffer, SpaprTpmState, 0, NULL, numbytes), ++ /* remember DMA address */ ++ VMSTATE_UINT32(crq.data, SpaprTpmState), ++ VMSTATE_END_OF_LIST(), ++ } + }; + + static Property tpm_spapr_properties[] = { +diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events +index edbe1bd7..b97eea24 100644 +--- a/hw/tpm/trace-events ++++ b/hw/tpm/trace-events +@@ -67,3 +67,5 @@ tpm_spapr_do_crq_get_version(uint32_t version) "response: version %u" + tpm_spapr_do_crq_prepare_to_suspend(void) "response: preparing to suspend" + tpm_spapr_do_crq_unknown_msg_type(uint8_t type) "Unknown message type 0x%02x" + tpm_spapr_do_crq_unknown_crq(uint8_t raw1, uint8_t raw2) "unknown CRQ 0x%02x 0x%02x ..." ++tpm_spapr_post_load(void) "Delivering TPM response after resume" ++tpm_spapr_caught_response(uint32_t v) "Caught response to deliver after resume: %u bytes" +-- +2.23.0 + diff --git a/ui-Fix-hanging-up-Cocoa-display-on-macOS-10.15-Catal.patch b/ui-Fix-hanging-up-Cocoa-display-on-macOS-10.15-Catal.patch new file mode 100644 index 0000000000000000000000000000000000000000..30724cedb050b52be09a0b081ffe36cd7599d268 --- /dev/null +++ b/ui-Fix-hanging-up-Cocoa-display-on-macOS-10.15-Catal.patch @@ -0,0 +1,62 @@ +From 6705b9344f8d6f134f612c2e35e87cdda5aa6284 Mon Sep 17 00:00:00 2001 +From: Hikaru Nishida +Date: Tue, 15 Oct 2019 10:07:34 +0900 +Subject: [PATCH] ui: Fix hanging up Cocoa display on macOS 10.15 (Catalina) + +macOS API documentation says that before applicationDidFinishLaunching +is called, any events will not be processed. However, some events are +fired before it is called in macOS Catalina. This causes deadlock of +iothread_lock in handleEvent while it will be released after the +app_started_sem is posted. +This patch avoids processing events before the app_started_sem is +posted to prevent this deadlock. + +Buglink: https://bugs.launchpad.net/qemu/+bug/1847906 +Signed-off-by: Hikaru Nishida +Message-id: 20191015010734.85229-1-hikarupsp@gmail.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit dff742ad27efa474ec04accdbf422c9acfd3e30e) +Signed-off-by: Michael Roth +--- + ui/cocoa.m | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/ui/cocoa.m b/ui/cocoa.m +index c2984028c5..3026ead621 100644 +--- a/ui/cocoa.m ++++ b/ui/cocoa.m +@@ -132,6 +132,7 @@ NSArray * supportedImageFileTypes; + + static QemuSemaphore display_init_sem; + static QemuSemaphore app_started_sem; ++static bool allow_events; + + // Utility functions to run specified code block with iothread lock held + typedef void (^CodeBlock)(void); +@@ -727,6 +728,16 @@ QemuCocoaView *cocoaView; + + - (bool) handleEvent:(NSEvent *)event + { ++ if(!allow_events) { ++ /* ++ * Just let OSX have all events that arrive before ++ * applicationDidFinishLaunching. ++ * This avoids a deadlock on the iothread lock, which cocoa_display_init() ++ * will not drop until after the app_started_sem is posted. (In theory ++ * there should not be any such events, but OSX Catalina now emits some.) ++ */ ++ return false; ++ } + return bool_with_iothread_lock(^{ + return [self handleEventLocked:event]; + }); +@@ -1154,6 +1165,7 @@ QemuCocoaView *cocoaView; + - (void)applicationDidFinishLaunching: (NSNotification *) note + { + COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n"); ++ allow_events = true; + /* Tell cocoa_display_init to proceed */ + qemu_sem_post(&app_started_sem); + } +-- +2.23.0 diff --git a/util-add-slirp_fmt-helpers.patch b/util-add-slirp_fmt-helpers.patch new file mode 100644 index 0000000000000000000000000000000000000000..b752f1293a0b88ef0ae01410a2fc63f9ff875df8 --- /dev/null +++ b/util-add-slirp_fmt-helpers.patch @@ -0,0 +1,124 @@ +From f3475a4a22dd84be0d2d7daa11676ac861da64bc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureauls?= +Date: Tue, 14 Apr 2020 18:51:39 +0800 +Subject: [PATCH] util: add slirp_fmt() helpers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Various calls to snprintf() in libslirp assume that snprintf() returns +"only" the number of bytes written (excluding terminating NUL). + +https://pubs.opengroup.org/onlinepubs/9699919799/functions/snprintf.html#tag_16_159_04 + +"Upon successful completion, the snprintf() function shall return the +number of bytes that would be written to s had n been sufficiently +large excluding the terminating null byte." + +Introduce slirp_fmt() that handles several pathological cases the +way libslirp usually expect: + +- treat error as fatal (instead of silently returning -1) + +- fmt0() will always \0 end + +- return the number of bytes actually written (instead of what would +have been written, which would usually result in OOB later), including +the ending \0 for fmt0() + +- warn if truncation happened (instead of ignoring) + +Other less common cases can still be handled with strcpy/snprintf() etc. +Signed-off-by: default avatarMarc-André Lureau +Reviewed-by: Samuel Thibault's avatarSamuel Thibault +Message-Id: <20200127092414.169796-2-marcandre.lureau@redhat.com> +--- + slirp/src/util.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ + slirp/src/util.h | 3 +++ + 2 files changed, 66 insertions(+) + +diff --git a/slirp/src/util.c b/slirp/src/util.c +index e5960871..dcae899e 100644 +--- a/slirp/src/util.c ++++ b/slirp/src/util.c +@@ -364,3 +364,66 @@ void slirp_pstrcpy(char *buf, int buf_size, const char *str) + } + *q = '\0'; + } ++ ++static int slirp_vsnprintf(char *str, size_t size, ++ const char *format, va_list args) ++{ ++ int rv = vsnprintf(str, size, format, args); ++ ++ if (rv < 0) { ++ g_error("vsnprintf() failed: %s", g_strerror(errno)); ++ } ++ ++ return rv; ++} ++ ++/* ++ * A snprintf()-like function that: ++ * - returns the number of bytes written (excluding optional \0-ending) ++ * - dies on error ++ * - warn on truncation ++ */ ++int slirp_fmt(char *str, size_t size, const char *format, ...) ++{ ++ va_list args; ++ int rv; ++ ++ va_start(args, format); ++ rv = slirp_vsnprintf(str, size, format, args); ++ va_end(args); ++ ++ if (rv > size) { ++ g_critical("vsnprintf() truncation"); ++ } ++ ++ return MIN(rv, size); ++} ++ ++/* ++ * A snprintf()-like function that: ++ * - always \0-end (unless size == 0) ++ * - returns the number of bytes actually written, including \0 ending ++ * - dies on error ++ * - warn on truncation ++ */ ++int slirp_fmt0(char *str, size_t size, const char *format, ...) ++{ ++ va_list args; ++ int rv; ++ ++ va_start(args, format); ++ rv = slirp_vsnprintf(str, size, format, args); ++ va_end(args); ++ ++ if (rv >= size) { ++ g_critical("vsnprintf() truncation"); ++ if (size > 0) ++ str[size - 1] = '\0'; ++ rv = size; ++ } else { ++ rv += 1; /* include \0 */ ++ } ++ ++ return rv; ++} ++ +diff --git a/slirp/src/util.h b/slirp/src/util.h +index 3c6223ce..0558dfc2 100644 +--- a/slirp/src/util.h ++++ b/slirp/src/util.h +@@ -177,4 +177,7 @@ static inline int slirp_socket_set_fast_reuse(int fd) + + void slirp_pstrcpy(char *buf, int buf_size, const char *str); + ++int slirp_fmt(char *str, size_t size, const char *format, ...); ++int slirp_fmt0(char *str, size_t size, const char *format, ...); ++ + #endif +-- +2.23.0 diff --git a/util-hbitmap-strict-hbitmap_reset.patch b/util-hbitmap-strict-hbitmap_reset.patch new file mode 100644 index 0000000000000000000000000000000000000000..b7f568f1bc6d21ae6923a552c2536414d5d33fdd --- /dev/null +++ b/util-hbitmap-strict-hbitmap_reset.patch @@ -0,0 +1,77 @@ +From fcd7cba6acb7344aca70f5f8ec16626e817b35a5 Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Tue, 6 Aug 2019 18:26:11 +0300 +Subject: [PATCH] util/hbitmap: strict hbitmap_reset + +hbitmap_reset has an unobvious property: it rounds requested region up. +It may provoke bugs, like in recently fixed write-blocking mode of +mirror: user calls reset on unaligned region, not keeping in mind that +there are possible unrelated dirty bytes, covered by rounded-up region +and information of this unrelated "dirtiness" will be lost. + +Make hbitmap_reset strict: assert that arguments are aligned, allowing +only one exception when @start + @count == hb->orig_size. It's needed +to comfort users of hbitmap_next_dirty_area, which cares about +hb->orig_size. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Max Reitz +Message-Id: <20190806152611.280389-1-vsementsov@virtuozzo.com> +[Maintainer edit: Max's suggestions from on-list. --js] +[Maintainer edit: Eric's suggestion for aligned macro. --js] +Signed-off-by: John Snow +(cherry picked from commit 48557b138383aaf69c2617ca9a88bfb394fc50ec) +*prereq for fed33bd175f663cc8c13f8a490a4f35a19756cfe +Signed-off-by: Michael Roth +--- + include/qemu/hbitmap.h | 5 +++++ + tests/test-hbitmap.c | 2 +- + util/hbitmap.c | 4 ++++ + 3 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h +index 4afbe6292e..1bf944ca3d 100644 +--- a/include/qemu/hbitmap.h ++++ b/include/qemu/hbitmap.h +@@ -132,6 +132,11 @@ void hbitmap_set(HBitmap *hb, uint64_t start, uint64_t count); + * @count: Number of bits to reset. + * + * Reset a consecutive range of bits in an HBitmap. ++ * @start and @count must be aligned to bitmap granularity. The only exception ++ * is resetting the tail of the bitmap: @count may be equal to hb->orig_size - ++ * @start, in this case @count may be not aligned. The sum of @start + @count is ++ * allowed to be greater than hb->orig_size, but only if @start < hb->orig_size ++ * and @start + @count = ALIGN_UP(hb->orig_size, granularity). + */ + void hbitmap_reset(HBitmap *hb, uint64_t start, uint64_t count); + +diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c +index 592d8219db..2be56d1597 100644 +--- a/tests/test-hbitmap.c ++++ b/tests/test-hbitmap.c +@@ -423,7 +423,7 @@ static void test_hbitmap_granularity(TestHBitmapData *data, + hbitmap_test_check(data, 0); + hbitmap_test_set(data, 0, 3); + g_assert_cmpint(hbitmap_count(data->hb), ==, 4); +- hbitmap_test_reset(data, 0, 1); ++ hbitmap_test_reset(data, 0, 2); + g_assert_cmpint(hbitmap_count(data->hb), ==, 2); + } + +diff --git a/util/hbitmap.c b/util/hbitmap.c +index bcc0acdc6a..71c6ba2c52 100644 +--- a/util/hbitmap.c ++++ b/util/hbitmap.c +@@ -476,6 +476,10 @@ void hbitmap_reset(HBitmap *hb, uint64_t start, uint64_t count) + /* Compute range in the last layer. */ + uint64_t first; + uint64_t last = start + count - 1; ++ uint64_t gran = 1ULL << hb->granularity; ++ ++ assert(QEMU_IS_ALIGNED(start, gran)); ++ assert(QEMU_IS_ALIGNED(count, gran) || (start + count == hb->orig_size)); + + trace_hbitmap_reset(hb, start, count, + start >> hb->granularity, last >> hb->granularity); +-- +2.23.0 diff --git a/util-iov-improve-qemu_iovec_is_zero.patch b/util-iov-improve-qemu_iovec_is_zero.patch new file mode 100644 index 0000000000000000000000000000000000000000..0cca67b8b1ed17eb873514c177eb6e371ae21f17 --- /dev/null +++ b/util-iov-improve-qemu_iovec_is_zero.patch @@ -0,0 +1,102 @@ +From b3b76fc643912d2c86b13caff30a1151f2958702 Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Tue, 4 Jun 2019 19:15:04 +0300 +Subject: [PATCH] util/iov: improve qemu_iovec_is_zero + +We'll need to check a part of qiov soon, so implement it now. + +Optimization with align down to 4 * sizeof(long) is dropped due to: +1. It is strange: it aligns length of the buffer, but where is a + guarantee that buffer pointer is aligned itself? +2. buffer_is_zero() is a better place for optimizations and it has + them. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Acked-by: Stefan Hajnoczi +Message-id: 20190604161514.262241-3-vsementsov@virtuozzo.com +Message-Id: <20190604161514.262241-3-vsementsov@virtuozzo.com> +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit f76889e7b947d896db51be8a4d9c941c2f70365a) +*prereq for 292d06b9 +Signed-off-by: Michael Roth +--- + block/io.c | 2 +- + include/qemu/iov.h | 2 +- + util/iov.c | 31 +++++++++++++++++++------------ + 3 files changed, 21 insertions(+), 14 deletions(-) + +diff --git a/block/io.c b/block/io.c +index 06305c6ea6..dccf687acc 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -1715,7 +1715,7 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, + + if (!ret && bs->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF && + !(flags & BDRV_REQ_ZERO_WRITE) && drv->bdrv_co_pwrite_zeroes && +- qemu_iovec_is_zero(qiov)) { ++ qemu_iovec_is_zero(qiov, 0, qiov->size)) { + flags |= BDRV_REQ_ZERO_WRITE; + if (bs->detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP) { + flags |= BDRV_REQ_MAY_UNMAP; +diff --git a/include/qemu/iov.h b/include/qemu/iov.h +index f3787a0cf7..29957c8a72 100644 +--- a/include/qemu/iov.h ++++ b/include/qemu/iov.h +@@ -212,7 +212,7 @@ void qemu_iovec_concat(QEMUIOVector *dst, + size_t qemu_iovec_concat_iov(QEMUIOVector *dst, + struct iovec *src_iov, unsigned int src_cnt, + size_t soffset, size_t sbytes); +-bool qemu_iovec_is_zero(QEMUIOVector *qiov); ++bool qemu_iovec_is_zero(QEMUIOVector *qiov, size_t qiov_offeset, size_t bytes); + void qemu_iovec_destroy(QEMUIOVector *qiov); + void qemu_iovec_reset(QEMUIOVector *qiov); + size_t qemu_iovec_to_buf(QEMUIOVector *qiov, size_t offset, +diff --git a/util/iov.c b/util/iov.c +index 366ff9cdd1..9ac0261853 100644 +--- a/util/iov.c ++++ b/util/iov.c +@@ -451,23 +451,30 @@ void qemu_iovec_init_extended( + } + + /* +- * Check if the contents of the iovecs are all zero ++ * Check if the contents of subrange of qiov data is all zeroes. + */ +-bool qemu_iovec_is_zero(QEMUIOVector *qiov) ++bool qemu_iovec_is_zero(QEMUIOVector *qiov, size_t offset, size_t bytes) + { +- int i; +- for (i = 0; i < qiov->niov; i++) { +- size_t offs = QEMU_ALIGN_DOWN(qiov->iov[i].iov_len, 4 * sizeof(long)); +- uint8_t *ptr = qiov->iov[i].iov_base; +- if (offs && !buffer_is_zero(qiov->iov[i].iov_base, offs)) { ++ struct iovec *iov; ++ size_t current_offset; ++ ++ assert(offset + bytes <= qiov->size); ++ ++ iov = iov_skip_offset(qiov->iov, offset, ¤t_offset); ++ ++ while (bytes) { ++ uint8_t *base = (uint8_t *)iov->iov_base + current_offset; ++ size_t len = MIN(iov->iov_len - current_offset, bytes); ++ ++ if (!buffer_is_zero(base, len)) { + return false; + } +- for (; offs < qiov->iov[i].iov_len; offs++) { +- if (ptr[offs]) { +- return false; +- } +- } ++ ++ current_offset = 0; ++ bytes -= len; ++ iov++; + } ++ + return true; + } + +-- +2.23.0 diff --git a/util-iov-introduce-qemu_iovec_init_extended.patch b/util-iov-introduce-qemu_iovec_init_extended.patch new file mode 100644 index 0000000000000000000000000000000000000000..0a488a63413b69816576ff8394f1e282c292e7d7 --- /dev/null +++ b/util-iov-introduce-qemu_iovec_init_extended.patch @@ -0,0 +1,177 @@ +From cff024fe856ab36db3056ba4cb1d7cfa4c39795d Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Tue, 4 Jun 2019 19:15:03 +0300 +Subject: [PATCH] util/iov: introduce qemu_iovec_init_extended + +Introduce new initialization API, to create requests with padding. Will +be used in the following patch. New API uses qemu_iovec_init_buf if +resulting io vector has only one element, to avoid extra allocations. +So, we need to update qemu_iovec_destroy to support destroying such +QIOVs. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Acked-by: Stefan Hajnoczi +Message-id: 20190604161514.262241-2-vsementsov@virtuozzo.com +Message-Id: <20190604161514.262241-2-vsementsov@virtuozzo.com> +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit d953169d4840f312d3b9a54952f4a7ccfcb3b311) +*prereq for 292d06b9 +Signed-off-by: Michael Roth +--- + include/qemu/iov.h | 7 +++ + util/iov.c | 112 +++++++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 114 insertions(+), 5 deletions(-) + +diff --git a/include/qemu/iov.h b/include/qemu/iov.h +index 48b45987b7..f3787a0cf7 100644 +--- a/include/qemu/iov.h ++++ b/include/qemu/iov.h +@@ -199,6 +199,13 @@ static inline void *qemu_iovec_buf(QEMUIOVector *qiov) + + void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint); + void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov); ++void qemu_iovec_init_extended( ++ QEMUIOVector *qiov, ++ void *head_buf, size_t head_len, ++ QEMUIOVector *mid_qiov, size_t mid_offset, size_t mid_len, ++ void *tail_buf, size_t tail_len); ++void qemu_iovec_init_slice(QEMUIOVector *qiov, QEMUIOVector *source, ++ size_t offset, size_t len); + void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len); + void qemu_iovec_concat(QEMUIOVector *dst, + QEMUIOVector *src, size_t soffset, size_t sbytes); +diff --git a/util/iov.c b/util/iov.c +index 74e6ca8ed7..366ff9cdd1 100644 +--- a/util/iov.c ++++ b/util/iov.c +@@ -353,6 +353,103 @@ void qemu_iovec_concat(QEMUIOVector *dst, + qemu_iovec_concat_iov(dst, src->iov, src->niov, soffset, sbytes); + } + ++/* ++ * qiov_find_iov ++ * ++ * Return pointer to iovec structure, where byte at @offset in original vector ++ * @iov exactly is. ++ * Set @remaining_offset to be offset inside that iovec to the same byte. ++ */ ++static struct iovec *iov_skip_offset(struct iovec *iov, size_t offset, ++ size_t *remaining_offset) ++{ ++ while (offset > 0 && offset >= iov->iov_len) { ++ offset -= iov->iov_len; ++ iov++; ++ } ++ *remaining_offset = offset; ++ ++ return iov; ++} ++ ++/* ++ * qiov_slice ++ * ++ * Find subarray of iovec's, containing requested range. @head would ++ * be offset in first iov (returned by the function), @tail would be ++ * count of extra bytes in last iovec (returned iov + @niov - 1). ++ */ ++static struct iovec *qiov_slice(QEMUIOVector *qiov, ++ size_t offset, size_t len, ++ size_t *head, size_t *tail, int *niov) ++{ ++ struct iovec *iov, *end_iov; ++ ++ assert(offset + len <= qiov->size); ++ ++ iov = iov_skip_offset(qiov->iov, offset, head); ++ end_iov = iov_skip_offset(iov, *head + len, tail); ++ ++ if (*tail > 0) { ++ assert(*tail < end_iov->iov_len); ++ *tail = end_iov->iov_len - *tail; ++ end_iov++; ++ } ++ ++ *niov = end_iov - iov; ++ ++ return iov; ++} ++ ++/* ++ * Compile new iovec, combining @head_buf buffer, sub-qiov of @mid_qiov, ++ * and @tail_buf buffer into new qiov. ++ */ ++void qemu_iovec_init_extended( ++ QEMUIOVector *qiov, ++ void *head_buf, size_t head_len, ++ QEMUIOVector *mid_qiov, size_t mid_offset, size_t mid_len, ++ void *tail_buf, size_t tail_len) ++{ ++ size_t mid_head, mid_tail; ++ int total_niov, mid_niov = 0; ++ struct iovec *p, *mid_iov; ++ ++ if (mid_len) { ++ mid_iov = qiov_slice(mid_qiov, mid_offset, mid_len, ++ &mid_head, &mid_tail, &mid_niov); ++ } ++ ++ total_niov = !!head_len + mid_niov + !!tail_len; ++ if (total_niov == 1) { ++ qemu_iovec_init_buf(qiov, NULL, 0); ++ p = &qiov->local_iov; ++ } else { ++ qiov->niov = qiov->nalloc = total_niov; ++ qiov->size = head_len + mid_len + tail_len; ++ p = qiov->iov = g_new(struct iovec, qiov->niov); ++ } ++ ++ if (head_len) { ++ p->iov_base = head_buf; ++ p->iov_len = head_len; ++ p++; ++ } ++ ++ if (mid_len) { ++ memcpy(p, mid_iov, mid_niov * sizeof(*p)); ++ p[0].iov_base = (uint8_t *)p[0].iov_base + mid_head; ++ p[0].iov_len -= mid_head; ++ p[mid_niov - 1].iov_len -= mid_tail; ++ p += mid_niov; ++ } ++ ++ if (tail_len) { ++ p->iov_base = tail_buf; ++ p->iov_len = tail_len; ++ } ++} ++ + /* + * Check if the contents of the iovecs are all zero + */ +@@ -374,14 +471,19 @@ bool qemu_iovec_is_zero(QEMUIOVector *qiov) + return true; + } + ++void qemu_iovec_init_slice(QEMUIOVector *qiov, QEMUIOVector *source, ++ size_t offset, size_t len) ++{ ++ qemu_iovec_init_extended(qiov, NULL, 0, source, offset, len, NULL, 0); ++} ++ + void qemu_iovec_destroy(QEMUIOVector *qiov) + { +- assert(qiov->nalloc != -1); ++ if (qiov->nalloc != -1) { ++ g_free(qiov->iov); ++ } + +- qemu_iovec_reset(qiov); +- g_free(qiov->iov); +- qiov->nalloc = 0; +- qiov->iov = NULL; ++ memset(qiov, 0, sizeof(*qiov)); + } + + void qemu_iovec_reset(QEMUIOVector *qiov) +-- +2.23.0 diff --git a/vhost-user-save-features-if-the-char-dev-is-closed.patch b/vhost-user-save-features-if-the-char-dev-is-closed.patch new file mode 100644 index 0000000000000000000000000000000000000000..9a0d04f4d7d98fd97e84bfba35f99d4871605b37 --- /dev/null +++ b/vhost-user-save-features-if-the-char-dev-is-closed.patch @@ -0,0 +1,42 @@ +From 7b404cae7fa2850d476c29258f03b8e77a5b4bd0 Mon Sep 17 00:00:00 2001 +From: Adrian Moreno +Date: Tue, 24 Sep 2019 18:20:44 +0200 +Subject: [PATCH] vhost-user: save features if the char dev is closed + +That way the state can be correctly restored when the device is opened +again. This might happen if the backend is restarted. + +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1738768 +Reported-by: Pei Zhang +Fixes: 6ab79a20af3a ("do not call vhost_net_cleanup() on running net from char user event") +Cc: ddstreet@canonical.com +Cc: Michael S. Tsirkin +Cc: qemu-stable@nongnu.org +Signed-off-by: Adrian Moreno +Message-Id: <20190924162044.11414-1-amorenoz@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit c6beefd674fff8d41b90365dfccad32e53a5abcb) +Signed-off-by: Michael Roth +--- + net/vhost-user.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/vhost-user.c b/net/vhost-user.c +index 51921de443..014199d600 100644 +--- a/net/vhost-user.c ++++ b/net/vhost-user.c +@@ -235,6 +235,10 @@ static void chr_closed_bh(void *opaque) + + s = DO_UPCAST(NetVhostUserState, nc, ncs[0]); + ++ if (s->vhost_net) { ++ s->acked_features = vhost_net_get_acked_features(s->vhost_net); ++ } ++ + qmp_set_link(name, false, &err); + + qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, net_vhost_user_event, +-- +2.23.0 diff --git a/vhost-user-scsi-prevent-using-uninitialized-vqs.patch b/vhost-user-scsi-prevent-using-uninitialized-vqs.patch index 9c4f92316d4da5e9e53ddc17e9915427e3cd9c36..d1bf2a087bf4fcbedf2a8c0fbb8b62188737d1e7 100644 --- a/vhost-user-scsi-prevent-using-uninitialized-vqs.patch +++ b/vhost-user-scsi-prevent-using-uninitialized-vqs.patch @@ -1,7 +1,7 @@ -From 19d56f560879081de411f359417eaaa2998c9e3a Mon Sep 17 00:00:00 2001 +From 4d8f2885b3f1219c3df2cf1a00dc0c55b23ee715 Mon Sep 17 00:00:00 2001 From: Raphael Norwitz -Date: Tue, 11 Jun 2019 17:35:17 -0700 -Subject: [PATCH 5/5] vhost-user-scsi: prevent using uninitialized vqs +Date: Tue, 14 Apr 2020 21:39:05 +0800 +Subject: [PATCH] vhost-user-scsi: prevent using uninitialized vqs Of the 3 virtqueues, seabios only sets cmd, leaving ctrl and event without a physical address. This can cause @@ -26,18 +26,17 @@ Signed-off-by: Stefan Hajnoczi 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c -index 8b1e687..241631f 100644 +index fcee67d5..affc2431 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c -@@ -90,7 +90,7 @@ static void vhost_user_scsi_realize(DeviceState *dev, Error **errp) +@@ -91,7 +91,7 @@ static void vhost_user_scsi_realize(DeviceState *dev, Error **errp) } - + vsc->dev.nvqs = 2 + vs->conf.num_queues; - vsc->dev.vqs = g_new(struct vhost_virtqueue, vsc->dev.nvqs); + vsc->dev.vqs = g_new0(struct vhost_virtqueue, vsc->dev.nvqs); vsc->dev.vq_index = 0; vsc->dev.backend_features = 0; - --- -1.8.3.1 - + vqs = vsc->dev.vqs; +-- +2.23.0 diff --git a/virtio-blk-Cancel-the-pending-BH-when-the-dataplane-.patch b/virtio-blk-Cancel-the-pending-BH-when-the-dataplane-.patch new file mode 100644 index 0000000000000000000000000000000000000000..3c2a3f2a424bd30ff95b8fcb53ae23c324d43153 --- /dev/null +++ b/virtio-blk-Cancel-the-pending-BH-when-the-dataplane-.patch @@ -0,0 +1,80 @@ +From 01be50603be4f17af4318a7a3fe58dcc6dab1b31 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Fri, 16 Aug 2019 19:15:03 +0200 +Subject: [PATCH] virtio-blk: Cancel the pending BH when the dataplane is reset +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When 'system_reset' is called, the main loop clear the memory +region cache before the BH has a chance to execute. Later when +the deferred function is called, some assumptions that were +made when scheduling them are no longer true when they actually +execute. + +This is what happens using a virtio-blk device (fresh RHEL7.8 install): + + $ (sleep 12.3; echo system_reset; sleep 12.3; echo system_reset; sleep 1; echo q) \ + | qemu-system-x86_64 -m 4G -smp 8 -boot menu=on \ + -device virtio-blk-pci,id=image1,drive=drive_image1 \ + -drive file=/var/lib/libvirt/images/rhel78.qcow2,if=none,id=drive_image1,format=qcow2,cache=none \ + -device virtio-net-pci,netdev=net0,id=nic0,mac=52:54:00:c4:e7:84 \ + -netdev tap,id=net0,script=/bin/true,downscript=/bin/true,vhost=on \ + -monitor stdio -serial null -nographic + (qemu) system_reset + (qemu) system_reset + (qemu) qemu-system-x86_64: hw/virtio/virtio.c:225: vring_get_region_caches: Assertion `caches != NULL' failed. + Aborted + + (gdb) bt + Thread 1 (Thread 0x7f109c17b680 (LWP 10939)): + #0 0x00005604083296d1 in vring_get_region_caches (vq=0x56040a24bdd0) at hw/virtio/virtio.c:227 + #1 0x000056040832972b in vring_avail_flags (vq=0x56040a24bdd0) at hw/virtio/virtio.c:235 + #2 0x000056040832d13d in virtio_should_notify (vdev=0x56040a240630, vq=0x56040a24bdd0) at hw/virtio/virtio.c:1648 + #3 0x000056040832d1f8 in virtio_notify_irqfd (vdev=0x56040a240630, vq=0x56040a24bdd0) at hw/virtio/virtio.c:1662 + #4 0x00005604082d213d in notify_guest_bh (opaque=0x56040a243ec0) at hw/block/dataplane/virtio-blk.c:75 + #5 0x000056040883dc35 in aio_bh_call (bh=0x56040a243f10) at util/async.c:90 + #6 0x000056040883dccd in aio_bh_poll (ctx=0x560409161980) at util/async.c:118 + #7 0x0000560408842af7 in aio_dispatch (ctx=0x560409161980) at util/aio-posix.c:460 + #8 0x000056040883e068 in aio_ctx_dispatch (source=0x560409161980, callback=0x0, user_data=0x0) at util/async.c:261 + #9 0x00007f10a8fca06d in g_main_context_dispatch () at /lib64/libglib-2.0.so.0 + #10 0x0000560408841445 in glib_pollfds_poll () at util/main-loop.c:215 + #11 0x00005604088414bf in os_host_main_loop_wait (timeout=0) at util/main-loop.c:238 + #12 0x00005604088415c4 in main_loop_wait (nonblocking=0) at util/main-loop.c:514 + #13 0x0000560408416b1e in main_loop () at vl.c:1923 + #14 0x000056040841e0e8 in main (argc=20, argv=0x7ffc2c3f9c58, envp=0x7ffc2c3f9d00) at vl.c:4578 + +Fix this by cancelling the BH when the virtio dataplane is stopped. + +[This is version of the patch was modified as discussed with Philippe on +the mailing list thread. +--Stefan] + +Reported-by: Yihuang Yu +Suggested-by: Stefan Hajnoczi +Fixes: https://bugs.launchpad.net/qemu/+bug/1839428 +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20190816171503.24761-1-philmd@redhat.com> +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit ebb6ff25cd888a52a64a9adc3692541c6d1d9a42) +Signed-off-by: Michael Roth +--- + hw/block/dataplane/virtio-blk.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c +index 158c78f852..5fea76df85 100644 +--- a/hw/block/dataplane/virtio-blk.c ++++ b/hw/block/dataplane/virtio-blk.c +@@ -297,6 +297,9 @@ void virtio_blk_data_plane_stop(VirtIODevice *vdev) + virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); + } + ++ qemu_bh_cancel(s->bh); ++ notify_guest_bh(s); /* final chance to notify guest */ ++ + /* Clean up guest notifier (irq) */ + k->set_guest_notifiers(qbus->parent, nvqs, false); + +-- +2.23.0 diff --git a/virtio-net-prevent-offloads-reset-on-migration.patch b/virtio-net-prevent-offloads-reset-on-migration.patch new file mode 100644 index 0000000000000000000000000000000000000000..ab8fbe26115279359c6a3928e93bf134ca88a2cb --- /dev/null +++ b/virtio-net-prevent-offloads-reset-on-migration.patch @@ -0,0 +1,122 @@ +From 4887acf574a573137660aa98d9d422ece0a41a5a Mon Sep 17 00:00:00 2001 +From: Mikhail Sennikovsky +Date: Fri, 11 Oct 2019 15:58:04 +0200 +Subject: [PATCH] virtio-net: prevent offloads reset on migration + +Currently offloads disabled by guest via the VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET +command are not preserved on VM migration. +Instead all offloads reported by guest features (via VIRTIO_PCI_GUEST_FEATURES) +get enabled. +What happens is: first the VirtIONet::curr_guest_offloads gets restored and offloads +are getting set correctly: + + #0 qemu_set_offload (nc=0x555556a11400, csum=1, tso4=0, tso6=0, ecn=0, ufo=0) at net/net.c:474 + #1 virtio_net_apply_guest_offloads (n=0x555557701ca0) at hw/net/virtio-net.c:720 + #2 virtio_net_post_load_device (opaque=0x555557701ca0, version_id=11) at hw/net/virtio-net.c:2334 + #3 vmstate_load_state (f=0x5555569dc010, vmsd=0x555556577c80 , opaque=0x555557701ca0, version_id=11) + at migration/vmstate.c:168 + #4 virtio_load (vdev=0x555557701ca0, f=0x5555569dc010, version_id=11) at hw/virtio/virtio.c:2197 + #5 virtio_device_get (f=0x5555569dc010, opaque=0x555557701ca0, size=0, field=0x55555668cd00 <__compound_literal.5>) at hw/virtio/virtio.c:2036 + #6 vmstate_load_state (f=0x5555569dc010, vmsd=0x555556577ce0 , opaque=0x555557701ca0, version_id=11) at migration/vmstate.c:143 + #7 vmstate_load (f=0x5555569dc010, se=0x5555578189e0) at migration/savevm.c:829 + #8 qemu_loadvm_section_start_full (f=0x5555569dc010, mis=0x5555569eee20) at migration/savevm.c:2211 + #9 qemu_loadvm_state_main (f=0x5555569dc010, mis=0x5555569eee20) at migration/savevm.c:2395 + #10 qemu_loadvm_state (f=0x5555569dc010) at migration/savevm.c:2467 + #11 process_incoming_migration_co (opaque=0x0) at migration/migration.c:449 + +However later on the features are getting restored, and offloads get reset to +everything supported by features: + + #0 qemu_set_offload (nc=0x555556a11400, csum=1, tso4=1, tso6=1, ecn=0, ufo=0) at net/net.c:474 + #1 virtio_net_apply_guest_offloads (n=0x555557701ca0) at hw/net/virtio-net.c:720 + #2 virtio_net_set_features (vdev=0x555557701ca0, features=5104441767) at hw/net/virtio-net.c:773 + #3 virtio_set_features_nocheck (vdev=0x555557701ca0, val=5104441767) at hw/virtio/virtio.c:2052 + #4 virtio_load (vdev=0x555557701ca0, f=0x5555569dc010, version_id=11) at hw/virtio/virtio.c:2220 + #5 virtio_device_get (f=0x5555569dc010, opaque=0x555557701ca0, size=0, field=0x55555668cd00 <__compound_literal.5>) at hw/virtio/virtio.c:2036 + #6 vmstate_load_state (f=0x5555569dc010, vmsd=0x555556577ce0 , opaque=0x555557701ca0, version_id=11) at migration/vmstate.c:143 + #7 vmstate_load (f=0x5555569dc010, se=0x5555578189e0) at migration/savevm.c:829 + #8 qemu_loadvm_section_start_full (f=0x5555569dc010, mis=0x5555569eee20) at migration/savevm.c:2211 + #9 qemu_loadvm_state_main (f=0x5555569dc010, mis=0x5555569eee20) at migration/savevm.c:2395 + #10 qemu_loadvm_state (f=0x5555569dc010) at migration/savevm.c:2467 + #11 process_incoming_migration_co (opaque=0x0) at migration/migration.c:449 + +Fix this by preserving the state in saved_guest_offloads field and +pushing out offload initialization to the new post load hook. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Mikhail Sennikovsky +Signed-off-by: Jason Wang +(cherry picked from commit 7788c3f2e21e35902d45809b236791383bbb613e) +Signed-off-by: Michael Roth +--- + hw/net/virtio-net.c | 27 ++++++++++++++++++++++++--- + include/hw/virtio/virtio-net.h | 2 ++ + 2 files changed, 26 insertions(+), 3 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index b9e1cd71cf..6adb0fe252 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -2330,9 +2330,13 @@ static int virtio_net_post_load_device(void *opaque, int version_id) + n->curr_guest_offloads = virtio_net_supported_guest_offloads(n); + } + +- if (peer_has_vnet_hdr(n)) { +- virtio_net_apply_guest_offloads(n); +- } ++ /* ++ * curr_guest_offloads will be later overwritten by the ++ * virtio_set_features_nocheck call done from the virtio_load. ++ * Here we make sure it is preserved and restored accordingly ++ * in the virtio_net_post_load_virtio callback. ++ */ ++ n->saved_guest_offloads = n->curr_guest_offloads; + + virtio_net_set_queues(n); + +@@ -2367,6 +2371,22 @@ static int virtio_net_post_load_device(void *opaque, int version_id) + return 0; + } + ++static int virtio_net_post_load_virtio(VirtIODevice *vdev) ++{ ++ VirtIONet *n = VIRTIO_NET(vdev); ++ /* ++ * The actual needed state is now in saved_guest_offloads, ++ * see virtio_net_post_load_device for detail. ++ * Restore it back and apply the desired offloads. ++ */ ++ n->curr_guest_offloads = n->saved_guest_offloads; ++ if (peer_has_vnet_hdr(n)) { ++ virtio_net_apply_guest_offloads(n); ++ } ++ ++ return 0; ++} ++ + /* tx_waiting field of a VirtIONetQueue */ + static const VMStateDescription vmstate_virtio_net_queue_tx_waiting = { + .name = "virtio-net-queue-tx_waiting", +@@ -2909,6 +2929,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) + vdc->guest_notifier_mask = virtio_net_guest_notifier_mask; + vdc->guest_notifier_pending = virtio_net_guest_notifier_pending; + vdc->legacy_features |= (0x1 << VIRTIO_NET_F_GSO); ++ vdc->post_load = virtio_net_post_load_virtio; + vdc->vmsd = &vmstate_virtio_net_device; + } + +diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h +index b96f0c643f..07a9319f4b 100644 +--- a/include/hw/virtio/virtio-net.h ++++ b/include/hw/virtio/virtio-net.h +@@ -182,6 +182,8 @@ struct VirtIONet { + char *netclient_name; + char *netclient_type; + uint64_t curr_guest_offloads; ++ /* used on saved state restore phase to preserve the curr_guest_offloads */ ++ uint64_t saved_guest_offloads; + AnnounceTimer announce_timer; + bool needs_vnet_hdr_swap; + bool mtu_bypass_backend; +-- +2.23.0 diff --git a/virtio-new-post_load-hook.patch b/virtio-new-post_load-hook.patch new file mode 100644 index 0000000000000000000000000000000000000000..974f286c6730c66cc3cb0a64b046bea341dd262b --- /dev/null +++ b/virtio-new-post_load-hook.patch @@ -0,0 +1,63 @@ +From 8010d3fce008dd13f155bc0babfe236ea44a2712 Mon Sep 17 00:00:00 2001 +From: "Michael S. Tsirkin" +Date: Fri, 11 Oct 2019 15:58:03 +0200 +Subject: [PATCH] virtio: new post_load hook + +Post load hook in virtio vmsd is called early while device is processed, +and when VirtIODevice core isn't fully initialized. Most device +specific code isn't ready to deal with a device in such state, and +behaves weirdly. + +Add a new post_load hook in a device class instead. Devices should use +this unless they specifically want to verify the migration stream as +it's processed, e.g. for bounds checking. + +Cc: qemu-stable@nongnu.org +Suggested-by: "Dr. David Alan Gilbert" +Cc: Mikhail Sennikovsky +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +(cherry picked from commit 1dd713837cac8ec5a97d3b8492d72ce5ac94803c) +Signed-off-by: Michael Roth +--- + hw/virtio/virtio.c | 7 +++++++ + include/hw/virtio/virtio.h | 6 ++++++ + 2 files changed, 13 insertions(+) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index a94ea18a9c..7c3822c3a0 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -2287,6 +2287,13 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) + } + rcu_read_unlock(); + ++ if (vdc->post_load) { ++ ret = vdc->post_load(vdev); ++ if (ret) { ++ return ret; ++ } ++ } ++ + return 0; + } + +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index b189788cb2..f9f62370e9 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -158,6 +158,12 @@ typedef struct VirtioDeviceClass { + */ + void (*save)(VirtIODevice *vdev, QEMUFile *f); + int (*load)(VirtIODevice *vdev, QEMUFile *f, int version_id); ++ /* Post load hook in vmsd is called early while device is processed, and ++ * when VirtIODevice isn't fully initialized. Devices should use this instead, ++ * unless they specifically want to verify the migration stream as it's ++ * processed, e.g. for bounds checking. ++ */ ++ int (*post_load)(VirtIODevice *vdev); + const VMStateDescription *vmsd; + } VirtioDeviceClass; + +-- +2.23.0 diff --git a/vpc-Return-0-from-vpc_co_create-on-success.patch b/vpc-Return-0-from-vpc_co_create-on-success.patch new file mode 100644 index 0000000000000000000000000000000000000000..46fbd90d1bd39f5549ce5d0185d58bbd437a82aa --- /dev/null +++ b/vpc-Return-0-from-vpc_co_create-on-success.patch @@ -0,0 +1,49 @@ +From 97c478c355fee96eb2b740313f50561e69b6f305 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 2 Sep 2019 21:33:16 +0200 +Subject: [PATCH] vpc: Return 0 from vpc_co_create() on success + +blockdev_create_run() directly uses .bdrv_co_create()'s return value as +the job's return value. Jobs must return 0 on success, not just any +nonnegative value. Therefore, using blockdev-create for VPC images may +currently fail as the vpc driver may return a positive integer. + +Because there is no point in returning a positive integer anywhere in +the block layer (all non-negative integers are generally treated as +complete success), we probably do not want to add more such cases. +Therefore, fix this problem by making the vpc driver always return 0 in +case of success. + +Suggested-by: Kevin Wolf +Cc: qemu-stable@nongnu.org +Signed-off-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 1a37e3124407b5a145d44478d3ecbdb89c63789f) +Signed-off-by: Michael Roth +--- + block/vpc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/block/vpc.c b/block/vpc.c +index d4776ee8a5..3a88e28e2b 100644 +--- a/block/vpc.c ++++ b/block/vpc.c +@@ -885,6 +885,7 @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf, + goto fail; + } + ++ ret = 0; + fail: + return ret; + } +@@ -908,7 +909,7 @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf, + return ret; + } + +- return ret; ++ return 0; + } + + static int calculate_rounded_image_size(BlockdevCreateOptionsVpc *vpc_opts, +-- +2.23.0 diff --git a/vtimer-Drop-vtimer-virtual-timer-adjust.patch b/vtimer-Drop-vtimer-virtual-timer-adjust.patch new file mode 100644 index 0000000000000000000000000000000000000000..726498fb6c778f8d5739e9614ae451d54a11bb56 --- /dev/null +++ b/vtimer-Drop-vtimer-virtual-timer-adjust.patch @@ -0,0 +1,144 @@ +From b1782119bcfac96d8a541d8d60ee00f954d721db Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Wed, 27 May 2020 17:48:54 +0800 +Subject: [PATCH] vtimer: Drop vtimer virtual timer adjust + +This patch drops the vtimer virtual timer adjust, cross version migration +from openEuler qemu-4.0.1 to qemu-4.1.0 is not supported as a consequence. + +By default openEuler qemu-4.1.0 use kvm_adjvtime as the virtual timer. + +Signed-off-by: Ying Fang + +diff --git a/cpus.c b/cpus.c +index 6a28bdef..927a00aa 100644 +--- a/cpus.c ++++ b/cpus.c +@@ -1066,34 +1066,6 @@ void cpu_synchronize_all_pre_loadvm(void) + } + } + +-#ifdef __aarch64__ +-static bool kvm_adjvtime_enabled(CPUState *cs) +-{ +- ARMCPU *cpu = ARM_CPU(cs); +- return cpu->kvm_adjvtime == true; +-} +- +-static void get_vcpu_timer_tick(CPUState *cs) +-{ +- CPUARMState *env = &ARM_CPU(cs)->env; +- int err; +- struct kvm_one_reg reg; +- uint64_t timer_tick; +- +- reg.id = KVM_REG_ARM_TIMER_CNT; +- reg.addr = (uintptr_t) &timer_tick; +- +- err = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); +- if (err < 0) { +- error_report("get vcpu tick failed, ret = %d", err); +- env->vtimer = 0; +- return; +- } +- env->vtimer = timer_tick; +- return; +-} +-#endif +- + static int do_vm_stop(RunState state, bool send_stop) + { + int ret = 0; +@@ -1101,17 +1073,6 @@ static int do_vm_stop(RunState state, bool send_stop) + if (runstate_is_running()) { + cpu_disable_ticks(); + pause_all_vcpus(); +-#ifdef __aarch64__ +- /* vtimer adjust is used in openEuler qemu-4.0.1, however kvm_adjvtime +- * is introduced in openEuler qemu-4.1.0. To maintain the compatibility +- * and enable cross version migration, let's enable vtimer adjust only +- * if kvm_adjvtime is not enabled, otherwise there may be conflicts +- * between vtimer adjust and kvm_adjvtime. +- */ +- if (first_cpu && !kvm_adjvtime_enabled(first_cpu)) { +- get_vcpu_timer_tick(first_cpu); +- } +-#endif + runstate_set(state); + vm_state_notify(0, state); + if (send_stop) { +@@ -1957,46 +1918,11 @@ void cpu_resume(CPUState *cpu) + qemu_cpu_kick(cpu); + } + +-#ifdef __aarch64__ +- +-static void set_vcpu_timer_tick(CPUState *cs) +-{ +- CPUARMState *env = &ARM_CPU(cs)->env; +- +- if (env->vtimer == 0) { +- return; +- } +- +- int err; +- struct kvm_one_reg reg; +- uint64_t timer_tick = env->vtimer; +- env->vtimer = 0; +- +- reg.id = KVM_REG_ARM_TIMER_CNT; +- reg.addr = (uintptr_t) &timer_tick; +- +- err = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); +- if (err < 0) { +- error_report("Set vcpu tick failed, ret = %d", err); +- return; +- } +- return; +-} +-#endif +- + void resume_all_vcpus(void) + { + CPUState *cpu; + + qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true); +-#ifdef __aarch64__ +- /* Enable vtimer adjust only if kvm_adjvtime is not enabled, otherwise +- * there may be conflicts between vtimer adjust and kvm_adjvtime. +- */ +- if (first_cpu && !kvm_adjvtime_enabled(first_cpu)) { +- set_vcpu_timer_tick(first_cpu); +- } +-#endif + CPU_FOREACH(cpu) { + cpu_resume(cpu); + } +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index aec6a214..86eb79cd 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -262,8 +262,6 @@ typedef struct CPUARMState { + uint64_t sp_el[4]; /* AArch64 banked stack pointers */ + + +- uint64_t vtimer; /* Timer tick when vcpu stop */ +- + /* System control coprocessor (cp15) */ + struct { + uint32_t c0_cpuid; +diff --git a/target/arm/machine.c b/target/arm/machine.c +index ec28b839..ee3c59a6 100644 +--- a/target/arm/machine.c ++++ b/target/arm/machine.c +@@ -814,7 +814,6 @@ const VMStateDescription vmstate_arm_cpu = { + VMSTATE_UINT32(env.exception.syndrome, ARMCPU), + VMSTATE_UINT32(env.exception.fsr, ARMCPU), + VMSTATE_UINT64(env.exception.vaddress, ARMCPU), +- VMSTATE_UINT64(env.vtimer, ARMCPU), + VMSTATE_TIMER_PTR(gt_timer[GTIMER_PHYS], ARMCPU), + VMSTATE_TIMER_PTR(gt_timer[GTIMER_VIRT], ARMCPU), + { +-- +2.23.0 + diff --git a/vtimer-compat-cross-version-migration-from-v4.0.1.patch b/vtimer-compat-cross-version-migration-from-v4.0.1.patch new file mode 100644 index 0000000000000000000000000000000000000000..f452948fd29818c9551899e5044de1e3b33bc235 --- /dev/null +++ b/vtimer-compat-cross-version-migration-from-v4.0.1.patch @@ -0,0 +1,41 @@ +From aec34c33730c36b34e4442548885463f57100e13 Mon Sep 17 00:00:00 2001 +From: Ying Fang +Date: Fri, 8 May 2020 11:25:28 +0800 +Subject: [PATCH] vtimer: compat cross version migration from v4.0.1 + +vtimer feature was added to qemu v4.0.1 to record timer tick when vcpu +is stopped. However this feature is discared and the new virtual time +adjustment is introduced. + +This patch add the missing vtimer parameter to ARMCPUState in order +to compat cross version migration fromm v4.0.1 openEuler 2003 lts release. + +Singed-off-by: Ying Fang + +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 219c222b..2609113d 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -261,6 +261,8 @@ typedef struct CPUARMState { + uint64_t elr_el[4]; /* AArch64 exception link regs */ + uint64_t sp_el[4]; /* AArch64 banked stack pointers */ + ++ uint64_t vtimer; /* Timer tick when vcpu is stopped */ ++ + /* System control coprocessor (cp15) */ + struct { + uint32_t c0_cpuid; +diff --git a/target/arm/machine.c b/target/arm/machine.c +index ee3c59a6..ec28b839 100644 +--- a/target/arm/machine.c ++++ b/target/arm/machine.c +@@ -814,6 +814,7 @@ const VMStateDescription vmstate_arm_cpu = { + VMSTATE_UINT32(env.exception.syndrome, ARMCPU), + VMSTATE_UINT32(env.exception.fsr, ARMCPU), + VMSTATE_UINT64(env.exception.vaddress, ARMCPU), ++ VMSTATE_UINT64(env.vtimer, ARMCPU), + VMSTATE_TIMER_PTR(gt_timer[GTIMER_PHYS], ARMCPU), + VMSTATE_TIMER_PTR(gt_timer[GTIMER_VIRT], ARMCPU), + { +-- +2.23.0 diff --git a/x86-do-not-advertise-die-id-in-query-hotpluggbale-cp.patch b/x86-do-not-advertise-die-id-in-query-hotpluggbale-cp.patch new file mode 100644 index 0000000000000000000000000000000000000000..fc17f48b7a395bafffaf7ef9763d04bff110af0a --- /dev/null +++ b/x86-do-not-advertise-die-id-in-query-hotpluggbale-cp.patch @@ -0,0 +1,60 @@ +From 725dfa851f8e1de8653f41a4bd38c7f98757eb40 Mon Sep 17 00:00:00 2001 +From: Igor Mammedov +Date: Mon, 2 Sep 2019 08:02:22 -0400 +Subject: [PATCH] x86: do not advertise die-id in query-hotpluggbale-cpus if + '-smp dies' is not set + +Commit 176d2cda0 (i386/cpu: Consolidate die-id validity in smp context) added +new 'die-id' topology property to CPUs and exposed it via QMP command +query-hotpluggable-cpus, which broke -device/device_add cpu-foo for existing +users that do not support die-id/dies yet. That's would be fine if it happened +to new machine type only but it also happened to old machine types, +which breaks migration from old QEMU to the new one, for example following CLI: + + OLD-QEMU -M pc-i440fx-4.0 -smp 1,max_cpus=2 \ + -device qemu64-x86_64-cpu,socket-id=1,core-id=0,thread-id +is not able to start with new QEMU, complaining about invalid die-id. + +After discovering regression, the patch + "pc: Don't make die-id mandatory unless necessary" +makes die-id optional so old CLI would work. + +However it's not enough as new QEMU still exposes die-id via query-hotpluggbale-cpus +QMP command, so the users that started old machine type on new QEMU, using all +properties (including die-id) received from QMP command (as required), won't be +able to start old QEMU using the same properties since it doesn't support die-id. + +Fix it by hiding die-id in query-hotpluggbale-cpus for all machine types in case +'-smp dies' is not provided on CLI or -smp dies = 1', in which case smp_dies == 1 +and APIC ID is calculated in default way (as it was before DIE support) so we won't +need compat code as in both cases the topology provided to guest via CPUID is the same. + +Signed-off-by: Igor Mammedov +Message-Id: <20190902120222.6179-1-imammedo@redhat.com> +Reviewed-by: Eduardo Habkost +Signed-off-by: Eduardo Habkost +(cherry picked from commit c6c1bb89fb46f3b88f832e654cf5a6f7941aac51) +Signed-off-by: Michael Roth +--- + hw/i386/pc.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index 947f81070f..d011733ff7 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -2887,8 +2887,10 @@ static const CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *ms) + ms->smp.threads, &topo); + ms->possible_cpus->cpus[i].props.has_socket_id = true; + ms->possible_cpus->cpus[i].props.socket_id = topo.pkg_id; +- ms->possible_cpus->cpus[i].props.has_die_id = true; +- ms->possible_cpus->cpus[i].props.die_id = topo.die_id; ++ if (pcms->smp_dies > 1) { ++ ms->possible_cpus->cpus[i].props.has_die_id = true; ++ ms->possible_cpus->cpus[i].props.die_id = topo.die_id; ++ } + ms->possible_cpus->cpus[i].props.has_core_id = true; + ms->possible_cpus->cpus[i].props.core_id = topo.core_id; + ms->possible_cpus->cpus[i].props.has_thread_id = true; +-- +2.23.0