From 0288d98f0ef4d17a73cf2bad1b928cd7c044e318 Mon Sep 17 00:00:00 2001
From: Keqian Zhu <zhukeqian1@huawei.com>
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 <zhukeqian1@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
 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
