diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index d786df1a2c..35e57f9824 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -508,6 +508,7 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
             Aml *uid = aml_int(i);
             GArray *madt_buf = g_array_new(0, 1, 1);
             int arch_id = arch_ids->cpus[i].arch_id;
+            int processor_id = i;
 
             if (opts.acpi_1_compatible && arch_id < 255) {
                 dev = aml_processor(i, 0, 0, CPU_NAME_FMT, i);
@@ -525,18 +526,8 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
             assert(adevc);
             apic_id = arch_ids->cpus[i].arch_id;
             if (apic_id < 255) {
-                AcpiMadtProcessorApic *apic = acpi_data_push(madt_buf,
-                                                             sizeof *apic);
-
-                apic->type = ACPI_APIC_PROCESSOR;
-                apic->length = sizeof(*apic);
-                apic->processor_id = i;
-                apic->local_apic_id = apic_id;
-                if (arch_ids->cpus[i].cpu != NULL) {
-                    apic->flags = cpu_to_le32(1);
-                } else {
-                    apic->flags = cpu_to_le32(0);
-                }
+                assert(adevc->madt_sub[ACPI_APIC_PROCESSOR]);
+                adevc->madt_sub[ACPI_APIC_PROCESSOR](madt_buf, &processor_id);
             } else {
                 AcpiMadtProcessorX2Apic *apic = acpi_data_push(madt_buf,
                                                                sizeof *apic);
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 76fde125a3..f4336b9238 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -722,6 +722,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data)
     hc->unplug = piix4_device_unplug_cb;
     adevc->ospm_status = piix4_ospm_status;
     adevc->send_event = piix4_send_gpe;
+    adevc->madt_sub = i386_madt_sub;
 }
 
 static const TypeInfo piix4_pm_info = {
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 54b70e62ac..dfcdcaeaf7 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -301,12 +301,37 @@ build_facs(GArray *table_data)
     facs->length = cpu_to_le32(sizeof(*facs));
 }
 
+static void pc_madt_apic_entry(GArray *entry, void *opaque)
+{
+    MachineState *machine = MACHINE(qdev_get_machine());
+    MachineClass *mc = MACHINE_GET_CLASS(machine);
+    const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(machine);
+    int *processor_id = opaque;
+    AcpiMadtProcessorApic *apic = acpi_data_push(entry, sizeof *apic);
+
+    apic->type = ACPI_APIC_PROCESSOR;
+    apic->length = sizeof(*apic);
+    apic->processor_id = *processor_id;
+    apic->local_apic_id = apic_ids->cpus[*processor_id].arch_id;
+    if (apic_ids->cpus[*processor_id].cpu != NULL) {
+        apic->flags = cpu_to_le32(1);
+    } else {
+        apic->flags = cpu_to_le32(0);
+    }
+}
+
+madt_operations i386_madt_sub = {
+    [ACPI_APIC_PROCESSOR] = pc_madt_apic_entry,
+};
+
 static void
 build_madt(GArray *table_data, BIOSLinker *linker, PCMachineState *pcms)
 {
     MachineClass *mc = MACHINE_GET_CLASS(pcms);
     const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(pcms));
     int madt_start = table_data->len;
+    AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(pcms->acpi_dev);
+
     bool x2apic_mode = false;
 
     AcpiMultipleApicTable *madt;
@@ -320,19 +345,9 @@ build_madt(GArray *table_data, BIOSLinker *linker, PCMachineState *pcms)
 
     for (i = 0; i < apic_ids->len; i++) {
         uint32_t apic_id = apic_ids->cpus[i].arch_id;
+        int processor_id = i;
         if (apic_id < 255) {
-            AcpiMadtProcessorApic *apic = acpi_data_push(table_data,
-                                                         sizeof *apic);
-
-            apic->type = ACPI_APIC_PROCESSOR;
-            apic->length = sizeof(*apic);
-            apic->processor_id = i;
-            apic->local_apic_id = apic_id;
-            if (apic_ids->cpus[i].cpu != NULL) {
-                apic->flags = cpu_to_le32(1);
-            } else {
-                apic->flags = cpu_to_le32(0);
-            }
+            adevc->madt_sub[ACPI_APIC_PROCESSOR](table_data, &processor_id);
         } else {
             AcpiMadtProcessorX2Apic *apic = acpi_data_push(table_data,
                                                            sizeof *apic);
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index 8e00504cd9..efb0fd8e94 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -811,6 +811,7 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data)
     hc->unplug = ich9_pm_device_unplug_cb;
     adevc->ospm_status = ich9_pm_ospm_status;
     adevc->send_event = ich9_send_gpe;
+    adevc->madt_sub = i386_madt_sub;
 }
 
 static const TypeInfo ich9_lpc_info = {
diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h
index 160b785045..3a3a12d543 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/acpi-defs.h"
 
 /* These values are part of guest ABI, and can not be changed */
 typedef enum {
@@ -29,6 +30,9 @@ typedef struct AcpiDeviceIf AcpiDeviceIf;
 
 void acpi_send_event(DeviceState *dev, AcpiEventStatusBits event);
 
+typedef void (*madt_operation)(GArray *entry, void *opaque);
+typedef madt_operation madt_operations[ACPI_APIC_RESERVED];
+
 /**
  * AcpiDeviceIfClass:
  *
@@ -48,5 +52,6 @@ typedef struct AcpiDeviceIfClass {
     /* <public> */
     void (*ospm_status)(AcpiDeviceIf *adev, ACPIOSTInfoList ***list);
     void (*send_event)(AcpiDeviceIf *adev, AcpiEventStatusBits ev);
+    madt_operation *madt_sub;
 } AcpiDeviceIfClass;
 #endif
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index ca65ef18af..db4ec693d3 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -281,6 +281,7 @@ void pc_system_firmware_init(PCMachineState *pcms, MemoryRegion *rom_memory);
 /* acpi-build.c */
 void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
                        const CPUArchIdList *apic_ids, GArray *entry);
+extern madt_operations i386_madt_sub;
 
 /* e820 types */
 #define E820_RAM        1
