qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 00/20] microvm: add acpi support
@ 2020-07-07 12:53 Gerd Hoffmann
  2020-07-07 12:53 ` [PATCH v5 01/20] microvm: name qboot binary qboot.rom Gerd Hoffmann
                   ` (21 more replies)
  0 siblings, 22 replies; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

I know that not supporting ACPI in microvm is intentional.  If you still
don't want ACPI this is perfectly fine, you can use the usual -no-acpi
switch to toggle ACPI support.

These are the advantages you are going to loose then:

  (1) virtio-mmio device discovery without command line hacks (tweaking
      the command line is a problem when not using direct kernel boot).
  (2) Better IO-APIC support, we can use IRQ lines 16-23.
  (3) ACPI power button (aka powerdown request) works.
  (4) machine poweroff (aka S5 state) works.

Together with seabios patches for virtio-mmio support this allows to
boot standard fedora images (cloud, coreos, workstation live) with the
microvm machine type.

git branch for testing (including updated seabios):
	https://git.kraxel.org/cgit/qemu/log/?h=sirius/microvm

changes in v2:
  * some acpi cleanups are an separate patch series now.
  * switched to hw reduced acpi & generic event device.
  * misc fixes here and there.

changes in v3:
  * depeds on "[PATCH v6 00/16] acpi: i386 tweaks" series.
  * renamed qboot to qboot.bin
  * updated seabios to master branch snapshot.
    - this version boots fine with rtc=off
  * generic event device tweaks (Igor's comments).
  * make SMP work.
  * add RfC patches to turn off acpi by default for microvm.
  * misc fixes here and there.

changes in v4:
  * rebase to latest master
    - this also depends on the pending seabios update
  * drop some patches which got cherry-picked.
  * wire up cpu hotplug (also does coldplug cpu init).
  * add microvm acpi test case.
  * dropped RfC patches to turn off acpi by default for microvm.
  * misc fixes here and there.

changes in v5:
  * rebase to latest master (seabios dependency is merged meanwhile)
  * fix DSDT version (mst).
  * add comments referencing the ACPI spec for easier review (mst).

take care,
  Gerd

Gerd Hoffmann (20):
  microvm: name qboot binary qboot.rom
  seabios: add microvm config, update build rules
  seabios: add bios-microvm.bin binary
  acpi: ged: add control regs
  acpi: ged: add x86 device variant.
  acpi: move acpi_dsdt_add_power_button() to ged
  microvm: make virtio irq base runtime configurable
  microvm/acpi: add minimal acpi support
  microvm/acpi: add acpi_dsdt_add_virtio() for x86
  microvm/acpi: use GSI 16-23 for virtio
  microvm/acpi: use seabios with acpi=on
  microvm/acpi: disable virtio-mmio cmdline hack
  x86: constify x86_machine_is_*_enabled
  x86: move acpi_dev from pc/microvm
  x86: move cpu plug from pc to x86
  microvm: wire up hotplug
  tests/acpi: allow microvm test data updates.
  tests/acpi: allow override blkdev
  tests/acpi: add microvm test
  tests/acpi: update expected data files for microvm

 hw/i386/acpi-microvm.h                 |   8 +
 include/hw/acpi/generic_event_device.h |  12 ++
 include/hw/i386/microvm.h              |  10 +-
 include/hw/i386/pc.h                   |   1 -
 include/hw/i386/x86.h                  |  11 +-
 hw/acpi/generic_event_device.c         |  52 +++++
 hw/arm/virt-acpi-build.c               |   8 -
 hw/i386/acpi-build.c                   |   2 +-
 hw/i386/acpi-microvm.c                 | 248 +++++++++++++++++++++++
 hw/i386/generic_event_device_x86.c     |  36 ++++
 hw/i386/microvm.c                      | 105 +++++++++-
 hw/i386/pc.c                           | 260 ++-----------------------
 hw/i386/pc_piix.c                      |   2 +-
 hw/i386/pc_q35.c                       |   2 +-
 hw/i386/x86.c                          | 226 ++++++++++++++++++++-
 tests/qtest/bios-tables-test.c         |  21 +-
 hw/i386/Kconfig                        |   1 +
 hw/i386/Makefile.objs                  |   2 +
 pc-bios/bios-microvm.bin               | Bin 65536 -> 131072 bytes
 pc-bios/qboot.rom                      | Bin 0 -> 65536 bytes
 roms/Makefile                          |  11 +-
 roms/config.seabios-microvm            |  26 +++
 tests/data/acpi/microvm/APIC           | Bin 0 -> 70 bytes
 tests/data/acpi/microvm/DSDT           | Bin 0 -> 365 bytes
 tests/data/acpi/microvm/FACP           | Bin 0 -> 268 bytes
 25 files changed, 775 insertions(+), 269 deletions(-)
 create mode 100644 hw/i386/acpi-microvm.h
 create mode 100644 hw/i386/acpi-microvm.c
 create mode 100644 hw/i386/generic_event_device_x86.c
 create mode 100644 pc-bios/qboot.rom
 create mode 100644 roms/config.seabios-microvm
 create mode 100644 tests/data/acpi/microvm/APIC
 create mode 100644 tests/data/acpi/microvm/DSDT
 create mode 100644 tests/data/acpi/microvm/FACP

-- 
2.18.4



^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v5 01/20] microvm: name qboot binary qboot.rom
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-07 12:53 ` [PATCH v5 02/20] seabios: add microvm config, update build rules Gerd Hoffmann
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

qboot isn't a bios and shouldnt be named that way.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/i386/microvm.c                       |   4 ++--
 pc-bios/{bios-microvm.bin => qboot.rom} | Bin
 roms/Makefile                           |   6 +++---
 3 files changed, 5 insertions(+), 5 deletions(-)
 rename pc-bios/{bios-microvm.bin => qboot.rom} (100%)

diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
index 5e931975a06d..1300c396947b 100644
--- a/hw/i386/microvm.c
+++ b/hw/i386/microvm.c
@@ -47,7 +47,7 @@
 #include "kvm_i386.h"
 #include "hw/xen/start_info.h"
 
-#define MICROVM_BIOS_FILENAME "bios-microvm.bin"
+#define MICROVM_QBOOT_FILENAME "qboot.rom"
 
 static void microvm_set_rtc(MicrovmMachineState *mms, ISADevice *s)
 {
@@ -158,7 +158,7 @@ static void microvm_devices_init(MicrovmMachineState *mms)
     }
 
     if (bios_name == NULL) {
-        bios_name = MICROVM_BIOS_FILENAME;
+        bios_name = MICROVM_QBOOT_FILENAME;
     }
     x86_bios_rom_init(get_system_memory(), true);
 }
diff --git a/pc-bios/bios-microvm.bin b/pc-bios/qboot.rom
similarity index 100%
rename from pc-bios/bios-microvm.bin
rename to pc-bios/qboot.rom
diff --git a/roms/Makefile b/roms/Makefile
index f9acf39954dc..b185c880541c 100644
--- a/roms/Makefile
+++ b/roms/Makefile
@@ -68,7 +68,7 @@ default help:
 	@echo "  opensbi64-virt     -- update OpenSBI for 64-bit virt machine"
 	@echo "  opensbi32-sifive_u -- update OpenSBI for 32-bit sifive_u machine"
 	@echo "  opensbi64-sifive_u -- update OpenSBI for 64-bit sifive_u machine"
-	@echo "  bios-microvm       -- update bios-microvm.bin (qboot)"
+	@echo "  qboot              -- update qboot"
 	@echo "  clean              -- delete the files generated by the previous" \
 	                              "build targets"
 
@@ -194,9 +194,9 @@ opensbi64-sifive_u:
 		PLATFORM="sifive/fu540"
 	cp opensbi/build/platform/sifive/fu540/firmware/fw_jump.bin ../pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin
 
-bios-microvm:
+qboot:
 	$(MAKE) -C qboot
-	cp qboot/bios.bin ../pc-bios/bios-microvm.bin
+	cp qboot/bios.bin ../pc-bios/qboot.rom
 
 clean:
 	rm -rf seabios/.config seabios/out seabios/builds
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 02/20] seabios: add microvm config, update build rules
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
  2020-07-07 12:53 ` [PATCH v5 01/20] microvm: name qboot binary qboot.rom Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-07 12:53 ` [PATCH v5 03/20] seabios: add bios-microvm.bin binary Gerd Hoffmann
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 roms/Makefile               |  5 ++++-
 roms/config.seabios-microvm | 26 ++++++++++++++++++++++++++
 2 files changed, 30 insertions(+), 1 deletion(-)
 create mode 100644 roms/config.seabios-microvm

diff --git a/roms/Makefile b/roms/Makefile
index b185c880541c..1a9d14674464 100644
--- a/roms/Makefile
+++ b/roms/Makefile
@@ -72,9 +72,12 @@ default help:
 	@echo "  clean              -- delete the files generated by the previous" \
 	                              "build targets"
 
-bios: build-seabios-config-seabios-128k build-seabios-config-seabios-256k
+bios: build-seabios-config-seabios-128k \
+		build-seabios-config-seabios-256k \
+		build-seabios-config-seabios-microvm
 	cp seabios/builds/seabios-128k/bios.bin ../pc-bios/bios.bin
 	cp seabios/builds/seabios-256k/bios.bin ../pc-bios/bios-256k.bin
+	cp seabios/builds/seabios-microvm/bios.bin ../pc-bios/bios-microvm.bin
 
 vgabios seavgabios: $(patsubst %,seavgabios-%,$(vgabios_variants))
 
diff --git a/roms/config.seabios-microvm b/roms/config.seabios-microvm
new file mode 100644
index 000000000000..a253e2edc6ec
--- /dev/null
+++ b/roms/config.seabios-microvm
@@ -0,0 +1,26 @@
+CONFIG_QEMU=y
+CONFIG_QEMU_HARDWARE=y
+CONFIG_PERMIT_UNALIGNED_PCIROM=y
+CONFIG_ROM_SIZE=128
+CONFIG_XEN=n
+CONFIG_BOOTSPLASH=n
+CONFIG_ATA=n
+CONFIG_AHCI=n
+CONFIG_SDCARD=n
+CONFIG_PVSCSI=n
+CONFIG_ESP_SCSI=n
+CONFIG_LSI_SCSI=n
+CONFIG_MEGASAS=n
+CONFIG_MPT_SCSI=n
+CONFIG_FLOPPY=n
+CONFIG_FLASH_FLOPPY=n
+CONFIG_NVME=n
+CONFIG_PS2PORT=n
+CONFIG_USB=n
+CONFIG_LPT=n
+CONFIG_RTC_TIMER=n
+CONFIG_USE_SMM=n
+CONFIG_PMTIMER=n
+CONFIG_TCGBIOS=n
+CONFIG_HARDWARE_IRQ=n
+CONFIG_ACPI_PARSE=y
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 03/20] seabios: add bios-microvm.bin binary
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
  2020-07-07 12:53 ` [PATCH v5 01/20] microvm: name qboot binary qboot.rom Gerd Hoffmann
  2020-07-07 12:53 ` [PATCH v5 02/20] seabios: add microvm config, update build rules Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-07 12:53 ` [PATCH v5 04/20] acpi: ged: add control regs Gerd Hoffmann
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 pc-bios/bios-microvm.bin | Bin 0 -> 131072 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 pc-bios/bios-microvm.bin

diff --git a/pc-bios/bios-microvm.bin b/pc-bios/bios-microvm.bin
new file mode 100644
index 0000000000000000000000000000000000000000..352c82692e11155c3e2c70d226c789a7c2b055f4
GIT binary patch
literal 131072
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

literal 0
HcmV?d00001

-- 
2.18.4



^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v5 04/20] acpi: ged: add control regs
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (2 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 03/20] seabios: add bios-microvm.bin binary Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-10 19:07   ` Igor Mammedov
  2020-07-07 12:53 ` [PATCH v5 05/20] acpi: ged: add x86 device variant Gerd Hoffmann
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

Add control regs (sleep, reset) for hw-reduced acpi.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 include/hw/acpi/generic_event_device.h |  7 ++++
 hw/acpi/generic_event_device.c         | 44 ++++++++++++++++++++++++++
 2 files changed, 51 insertions(+)

diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h
index 90a9180db572..474c92198080 100644
--- a/include/hw/acpi/generic_event_device.h
+++ b/include/hw/acpi/generic_event_device.h
@@ -72,6 +72,12 @@
 #define ACPI_GED_EVT_SEL_OFFSET    0x0
 #define ACPI_GED_EVT_SEL_LEN       0x4
 
+#define ACPI_GED_REG_SLEEP_CTL     0x00
+#define ACPI_GED_REG_SLEEP_STS     0x01
+#define ACPI_GED_REG_RESET         0x02
+#define   ACPI_GED_RESET_VALUE     0x42
+#define ACPI_GED_REG_COUNT         0x03
+
 #define GED_DEVICE      "GED"
 #define AML_GED_EVT_REG "EREG"
 #define AML_GED_EVT_SEL "ESEL"
@@ -87,6 +93,7 @@
 
 typedef struct GEDState {
     MemoryRegion evt;
+    MemoryRegion regs;
     uint32_t     sel;
 } GEDState;
 
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
index b8abdefa1c77..491df80a5cc7 100644
--- a/hw/acpi/generic_event_device.c
+++ b/hw/acpi/generic_event_device.c
@@ -20,6 +20,7 @@
 #include "hw/qdev-properties.h"
 #include "migration/vmstate.h"
 #include "qemu/error-report.h"
+#include "sysemu/runstate.h"
 
 static const uint32_t ged_supported_events[] = {
     ACPI_GED_MEM_HOTPLUG_EVT,
@@ -176,6 +177,45 @@ static const MemoryRegionOps ged_evt_ops = {
     },
 };
 
+static uint64_t ged_regs_read(void *opaque, hwaddr addr, unsigned size)
+{
+    return 0;
+}
+
+static void ged_regs_write(void *opaque, hwaddr addr, uint64_t data,
+                           unsigned int size)
+{
+    bool slp_en;
+    int slp_typ;
+
+    switch (addr) {
+    case ACPI_GED_REG_SLEEP_CTL:
+        slp_typ = (data >> 2) & 0x07;
+        slp_en  = (data >> 5) & 0x01;
+        if (slp_en && slp_typ == 5) {
+            qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
+        }
+        return;
+    case ACPI_GED_REG_SLEEP_STS:
+        return;
+    case ACPI_GED_REG_RESET:
+        if (data == ACPI_GED_RESET_VALUE) {
+            qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
+        }
+        return;
+    }
+}
+
+static const MemoryRegionOps ged_regs_ops = {
+    .read = ged_regs_read,
+    .write = ged_regs_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
 static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
                                     DeviceState *dev, Error **errp)
 {
@@ -332,6 +372,10 @@ 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);
+
+    memory_region_init_io(&ged_st->regs, obj, &ged_regs_ops, ged_st,
+                          TYPE_ACPI_GED "-regs", ACPI_GED_REG_COUNT);
+    sysbus_init_mmio(sbd, &ged_st->regs);
 }
 
 static void acpi_ged_class_init(ObjectClass *class, void *data)
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 05/20] acpi: ged: add x86 device variant.
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (3 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 04/20] acpi: ged: add control regs Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-07 12:53 ` [PATCH v5 06/20] acpi: move acpi_dsdt_add_power_button() to ged Gerd Hoffmann
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

Set AcpiDeviceIfClass->madt_cpu,
otherwise identical to TYPE_ACPI_GED.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
---
 include/hw/acpi/generic_event_device.h |  4 +++
 hw/i386/generic_event_device_x86.c     | 36 ++++++++++++++++++++++++++
 hw/i386/Makefile.objs                  |  1 +
 3 files changed, 41 insertions(+)
 create mode 100644 hw/i386/generic_event_device_x86.c

diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h
index 474c92198080..9687cb524258 100644
--- a/include/hw/acpi/generic_event_device.h
+++ b/include/hw/acpi/generic_event_device.h
@@ -69,6 +69,10 @@
 #define ACPI_GED(obj) \
     OBJECT_CHECK(AcpiGedState, (obj), TYPE_ACPI_GED)
 
+#define TYPE_ACPI_GED_X86 "acpi-ged-x86"
+#define ACPI_GED_X86(obj) \
+    OBJECT_CHECK(AcpiGedX86State, (obj), TYPE_ACPI_GED_X86)
+
 #define ACPI_GED_EVT_SEL_OFFSET    0x0
 #define ACPI_GED_EVT_SEL_LEN       0x4
 
diff --git a/hw/i386/generic_event_device_x86.c b/hw/i386/generic_event_device_x86.c
new file mode 100644
index 000000000000..e26fb02a2ef6
--- /dev/null
+++ b/hw/i386/generic_event_device_x86.c
@@ -0,0 +1,36 @@
+/*
+ * x86 variant of the generic event device for hw reduced acpi
+ *
+ * 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 "hw/acpi/generic_event_device.h"
+#include "hw/i386/pc.h"
+
+static void acpi_ged_x86_class_init(ObjectClass *class, void *data)
+{
+    AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class);
+
+    adevc->madt_cpu = pc_madt_cpu_entry;
+}
+
+static const TypeInfo acpi_ged_x86_info = {
+    .name          = TYPE_ACPI_GED_X86,
+    .parent        = TYPE_ACPI_GED,
+    .class_init    = acpi_ged_x86_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_HOTPLUG_HANDLER },
+        { TYPE_ACPI_DEVICE_IF },
+        { }
+    }
+};
+
+static void acpi_ged_x86_register_types(void)
+{
+    type_register_static(&acpi_ged_x86_info);
+}
+
+type_init(acpi_ged_x86_register_types)
diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index 6abc74551a72..622739305882 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -17,4 +17,5 @@ obj-$(CONFIG_PC) += port92.o
 
 obj-y += kvmvapic.o
 obj-$(CONFIG_ACPI) += acpi-common.o
+obj-$(CONFIG_ACPI_HW_REDUCED) += generic_event_device_x86.o
 obj-$(CONFIG_PC) += acpi-build.o
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 06/20] acpi: move acpi_dsdt_add_power_button() to ged
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (4 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 05/20] acpi: ged: add x86 device variant Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-07 12:53 ` [PATCH v5 07/20] microvm: make virtio irq base runtime configurable Gerd Hoffmann
                   ` (15 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

Allow reuse for microvm.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
---
 include/hw/acpi/generic_event_device.h | 1 +
 hw/acpi/generic_event_device.c         | 8 ++++++++
 hw/arm/virt-acpi-build.c               | 8 --------
 3 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h
index 9687cb524258..ebed1ffe4231 100644
--- a/include/hw/acpi/generic_event_device.h
+++ b/include/hw/acpi/generic_event_device.h
@@ -113,5 +113,6 @@ typedef struct AcpiGedState {
 
 void build_ged_aml(Aml *table, const char* name, HotplugHandler *hotplug_dev,
                    uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base);
+void acpi_dsdt_add_power_button(Aml *scope);
 
 #endif
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
index 491df80a5cc7..6df400e1ee16 100644
--- a/hw/acpi/generic_event_device.c
+++ b/hw/acpi/generic_event_device.c
@@ -142,6 +142,14 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev,
     aml_append(table, dev);
 }
 
+void acpi_dsdt_add_power_button(Aml *scope)
+{
+    Aml *dev = aml_device(ACPI_POWER_BUTTON_DEVICE);
+    aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C0C")));
+    aml_append(dev, aml_name_decl("_UID", aml_int(0)));
+    aml_append(scope, dev);
+}
+
 /* Memory read by the GED _EVT AML dynamic method */
 static uint64_t ged_evt_read(void *opaque, hwaddr addr, unsigned size)
 {
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 91f0df7b13a3..775b2acd28c9 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -357,14 +357,6 @@ static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap,
     aml_append(scope, dev);
 }
 
-static void acpi_dsdt_add_power_button(Aml *scope)
-{
-    Aml *dev = aml_device(ACPI_POWER_BUTTON_DEVICE);
-    aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C0C")));
-    aml_append(dev, aml_name_decl("_UID", aml_int(0)));
-    aml_append(scope, dev);
-}
-
 static void acpi_dsdt_add_tpm(Aml *scope, VirtMachineState *vms)
 {
     PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 07/20] microvm: make virtio irq base runtime configurable
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (5 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 06/20] acpi: move acpi_dsdt_add_power_button() to ged Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-10 19:09   ` Igor Mammedov
  2020-07-07 12:53 ` [PATCH v5 08/20] microvm/acpi: add minimal acpi support Gerd Hoffmann
                   ` (14 subsequent siblings)
  21 siblings, 1 reply; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Sergio Lopez <slp@redhat.com>
---
 include/hw/i386/microvm.h |  2 +-
 hw/i386/microvm.c         | 11 +++++++----
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h
index fd34b78e0d2a..03e735723726 100644
--- a/include/hw/i386/microvm.h
+++ b/include/hw/i386/microvm.h
@@ -27,7 +27,6 @@
 
 /* Platform virtio definitions */
 #define VIRTIO_MMIO_BASE      0xfeb00000
-#define VIRTIO_IRQ_BASE       5
 #define VIRTIO_NUM_TRANSPORTS 8
 #define VIRTIO_CMDLINE_MAXLEN 64
 
@@ -57,6 +56,7 @@ typedef struct {
     bool auto_kernel_cmdline;
 
     /* Machine state */
+    uint32_t virtio_irq_base;
     bool kernel_cmdline_fixed;
 } MicrovmMachineState;
 
diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
index 1300c396947b..ab6ee6c67b1a 100644
--- a/hw/i386/microvm.c
+++ b/hw/i386/microvm.c
@@ -121,10 +121,11 @@ static void microvm_devices_init(MicrovmMachineState *mms)
 
     kvmclock_create();
 
+    mms->virtio_irq_base = 5;
     for (i = 0; i < VIRTIO_NUM_TRANSPORTS; i++) {
         sysbus_create_simple("virtio-mmio",
                              VIRTIO_MMIO_BASE + i * 512,
-                             x86ms->gsi[VIRTIO_IRQ_BASE + i]);
+                             x86ms->gsi[mms->virtio_irq_base + i]);
     }
 
     /* Optional and legacy devices */
@@ -227,7 +228,7 @@ static void microvm_memory_init(MicrovmMachineState *mms)
     x86ms->ioapic_as = &address_space_memory;
 }
 
-static gchar *microvm_get_mmio_cmdline(gchar *name)
+static gchar *microvm_get_mmio_cmdline(gchar *name, uint32_t virtio_irq_base)
 {
     gchar *cmdline;
     gchar *separator;
@@ -247,7 +248,7 @@ static gchar *microvm_get_mmio_cmdline(gchar *name)
     ret = g_snprintf(cmdline, VIRTIO_CMDLINE_MAXLEN,
                      " virtio_mmio.device=512@0x%lx:%ld",
                      VIRTIO_MMIO_BASE + index * 512,
-                     VIRTIO_IRQ_BASE + index);
+                     virtio_irq_base + index);
     if (ret < 0 || ret >= VIRTIO_CMDLINE_MAXLEN) {
         g_free(cmdline);
         return NULL;
@@ -259,6 +260,7 @@ static gchar *microvm_get_mmio_cmdline(gchar *name)
 static void microvm_fix_kernel_cmdline(MachineState *machine)
 {
     X86MachineState *x86ms = X86_MACHINE(machine);
+    MicrovmMachineState *mms = MICROVM_MACHINE(machine);
     BusState *bus;
     BusChild *kid;
     char *cmdline;
@@ -282,7 +284,8 @@ static void microvm_fix_kernel_cmdline(MachineState *machine)
             BusState *mmio_bus = &mmio_virtio_bus->parent_obj;
 
             if (!QTAILQ_EMPTY(&mmio_bus->children)) {
-                gchar *mmio_cmdline = microvm_get_mmio_cmdline(mmio_bus->name);
+                gchar *mmio_cmdline = microvm_get_mmio_cmdline
+                    (mmio_bus->name, mms->virtio_irq_base);
                 if (mmio_cmdline) {
                     char *newcmd = g_strjoin(NULL, cmdline, mmio_cmdline, NULL);
                     g_free(mmio_cmdline);
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 08/20] microvm/acpi: add minimal acpi support
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (6 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 07/20] microvm: make virtio irq base runtime configurable Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-08 16:52   ` Michael S. Tsirkin
  2020-07-07 12:53 ` [PATCH v5 09/20] microvm/acpi: add acpi_dsdt_add_virtio() for x86 Gerd Hoffmann
                   ` (13 subsequent siblings)
  21 siblings, 1 reply; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

$subject says all.  Can be controlled using -M microvm,acpi=on/off.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/i386/acpi-microvm.h    |   8 ++
 include/hw/i386/microvm.h |   9 ++
 hw/i386/acpi-microvm.c    | 195 ++++++++++++++++++++++++++++++++++++++
 hw/i386/microvm.c         |  40 ++++++++
 hw/i386/Kconfig           |   1 +
 hw/i386/Makefile.objs     |   1 +
 6 files changed, 254 insertions(+)
 create mode 100644 hw/i386/acpi-microvm.h
 create mode 100644 hw/i386/acpi-microvm.c

diff --git a/hw/i386/acpi-microvm.h b/hw/i386/acpi-microvm.h
new file mode 100644
index 000000000000..dfe853690e15
--- /dev/null
+++ b/hw/i386/acpi-microvm.h
@@ -0,0 +1,8 @@
+#ifndef HW_I386_ACPI_MICROVM_H
+#define HW_I386_ACPI_MICROVM_H
+
+#include "hw/i386/microvm.h"
+
+void acpi_setup_microvm(MicrovmMachineState *mms);
+
+#endif
diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h
index 03e735723726..b6e0d4395af7 100644
--- a/include/hw/i386/microvm.h
+++ b/include/hw/i386/microvm.h
@@ -24,12 +24,18 @@
 
 #include "hw/boards.h"
 #include "hw/i386/x86.h"
+#include "hw/acpi/acpi_dev_interface.h"
 
 /* Platform virtio definitions */
 #define VIRTIO_MMIO_BASE      0xfeb00000
 #define VIRTIO_NUM_TRANSPORTS 8
 #define VIRTIO_CMDLINE_MAXLEN 64
 
+#define GED_MMIO_BASE         0xfea00000
+#define GED_MMIO_BASE_MEMHP   (GED_MMIO_BASE + 0x100)
+#define GED_MMIO_BASE_REGS    (GED_MMIO_BASE + 0x200)
+#define GED_MMIO_IRQ          9
+
 /* Machine type options */
 #define MICROVM_MACHINE_PIT                 "pit"
 #define MICROVM_MACHINE_PIC                 "pic"
@@ -58,6 +64,9 @@ typedef struct {
     /* Machine state */
     uint32_t virtio_irq_base;
     bool kernel_cmdline_fixed;
+    Notifier machine_done;
+    Notifier powerdown_req;
+    AcpiDeviceIf *acpi_dev;
 } MicrovmMachineState;
 
 #define TYPE_MICROVM_MACHINE   MACHINE_TYPE_NAME("microvm")
diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c
new file mode 100644
index 000000000000..6c4178caefee
--- /dev/null
+++ b/hw/i386/acpi-microvm.c
@@ -0,0 +1,195 @@
+/* Support for generating ACPI tables and passing them to Guests
+ *
+ * Copyright (C) 2008-2010  Kevin O'Connor <kevin@koconnor.net>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2013 Red Hat Inc
+ *
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+
+#include "exec/memory.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/aml-build.h"
+#include "hw/acpi/bios-linker-loader.h"
+#include "hw/acpi/generic_event_device.h"
+#include "hw/acpi/utils.h"
+#include "hw/boards.h"
+#include "hw/i386/fw_cfg.h"
+#include "hw/i386/microvm.h"
+
+#include "acpi-common.h"
+#include "acpi-microvm.h"
+
+static void
+build_dsdt_microvm(GArray *table_data, BIOSLinker *linker,
+                   MicrovmMachineState *mms)
+{
+    X86MachineState *x86ms = X86_MACHINE(mms);
+    Aml *dsdt, *sb_scope, *scope, *pkg;
+    bool ambiguous;
+    Object *isabus;
+
+    isabus = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous);
+    assert(isabus);
+    assert(!ambiguous);
+
+    dsdt = init_aml_allocator();
+
+    /* Reserve space for header */
+    acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader));
+
+    sb_scope = aml_scope("_SB");
+    fw_cfg_add_acpi_dsdt(sb_scope, x86ms->fw_cfg);
+    isa_build_aml(ISA_BUS(isabus), sb_scope);
+    build_ged_aml(sb_scope, GED_DEVICE, HOTPLUG_HANDLER(mms->acpi_dev),
+                  GED_MMIO_IRQ, AML_SYSTEM_MEMORY, GED_MMIO_BASE);
+    acpi_dsdt_add_power_button(sb_scope);
+    aml_append(dsdt, sb_scope);
+
+    scope = aml_scope("\\");
+    pkg = aml_package(4);
+    aml_append(pkg, aml_int(5)); /* SLEEP_CONTROL_REG.SLP_TYP */
+    aml_append(pkg, aml_int(0)); /* ignored */
+    aml_append(pkg, aml_int(0)); /* reserved */
+    aml_append(pkg, aml_int(0)); /* reserved */
+    aml_append(scope, aml_name_decl("_S5", pkg));
+    aml_append(dsdt, scope);
+
+    /* copy AML table into ACPI tables blob and patch header there */
+    g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
+    build_header(linker, table_data,
+        (void *)(table_data->data + table_data->len - dsdt->buf->len),
+        "DSDT", dsdt->buf->len, 2, NULL, NULL);
+    free_aml_allocator();
+}
+
+static void acpi_build_microvm(AcpiBuildTables *tables,
+                               MicrovmMachineState *mms)
+{
+    MachineState *machine = MACHINE(mms);
+    GArray *table_offsets;
+    GArray *tables_blob = tables->table_data;
+    unsigned dsdt, xsdt;
+    AcpiFadtData pmfadt = {
+        /*
+         * minimum version for ACPI_FADT_F_HW_REDUCED_ACPI,
+         * see acpi spec "4.1 Hardware-Reduced ACPI"
+         */
+        .rev = 5,
+        .minor_ver = 1,
+
+        .flags = ((1 << ACPI_FADT_F_HW_REDUCED_ACPI) |
+                  (1 << ACPI_FADT_F_RESET_REG_SUP)),
+
+        /* Table 5-33 FADT Format -- SLEEP_CONTROL_REG */
+        .sleep_ctl = {
+            .space_id = AML_AS_SYSTEM_MEMORY,
+            .bit_width = 8,
+            .address = GED_MMIO_BASE_REGS + ACPI_GED_REG_SLEEP_CTL,
+        },
+
+        /* Table 5-33 FADT Format -- SLEEP_STATUS_REG */
+        .sleep_sts = {
+            .space_id = AML_AS_SYSTEM_MEMORY,
+            .bit_width = 8,
+            .address = GED_MMIO_BASE_REGS + ACPI_GED_REG_SLEEP_STS,
+        },
+
+        /* Table 5-33 FADT Format -- RESET_REG */
+        .reset_reg = {
+            .space_id = AML_AS_SYSTEM_MEMORY,
+            .bit_width = 8,
+            .address = GED_MMIO_BASE_REGS + ACPI_GED_REG_RESET,
+        },
+
+        /* Table 5-33 FADT Format -- RESET_VALUE */
+        .reset_val = ACPI_GED_RESET_VALUE,
+    };
+
+    table_offsets = g_array_new(false, true /* clear */,
+                                        sizeof(uint32_t));
+    bios_linker_loader_alloc(tables->linker,
+                             ACPI_BUILD_TABLE_FILE, tables_blob,
+                             64 /* Ensure FACS is aligned */,
+                             false /* high memory */);
+
+    dsdt = tables_blob->len;
+    build_dsdt_microvm(tables_blob, tables->linker, mms);
+
+    pmfadt.dsdt_tbl_offset = &dsdt;
+    pmfadt.xdsdt_tbl_offset = &dsdt;
+    acpi_add_table(table_offsets, tables_blob);
+    build_fadt(tables_blob, tables->linker, &pmfadt, NULL, NULL);
+
+    acpi_add_table(table_offsets, tables_blob);
+    acpi_build_madt(tables_blob, tables->linker, X86_MACHINE(machine),
+                    mms->acpi_dev, false);
+
+    xsdt = tables_blob->len;
+    build_xsdt(tables_blob, tables->linker, table_offsets, NULL, NULL);
+
+    /* RSDP is in FSEG memory, so allocate it separately */
+    {
+        AcpiRsdpData rsdp_data = {
+            /* Table 5-27 RSDP Structure */
+            .revision = 2, /* rev2 needed for xsdt support */
+            .oem_id = ACPI_BUILD_APPNAME6,
+            .xsdt_tbl_offset = &xsdt,
+            .rsdt_tbl_offset = NULL,
+        };
+        build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
+    }
+
+    /* Cleanup memory that's no longer used. */
+    g_array_free(table_offsets, true);
+}
+
+static void acpi_build_no_update(void *build_opaque)
+{
+    /* nothing, microvm tables don't change at runtime */
+}
+
+void acpi_setup_microvm(MicrovmMachineState *mms)
+{
+    X86MachineState *x86ms = X86_MACHINE(mms);
+    AcpiBuildTables tables;
+
+    assert(x86ms->fw_cfg);
+
+    if (!x86_machine_is_acpi_enabled(x86ms)) {
+        return;
+    }
+
+    acpi_build_tables_init(&tables);
+    acpi_build_microvm(&tables, mms);
+
+    /* Now expose it all to Guest */
+    acpi_add_rom_blob(acpi_build_no_update, NULL,
+                      tables.table_data,
+                      ACPI_BUILD_TABLE_FILE,
+                      ACPI_BUILD_TABLE_MAX_SIZE);
+    acpi_add_rom_blob(acpi_build_no_update, NULL,
+                      tables.linker->cmd_blob,
+                      "etc/table-loader", 0);
+    acpi_add_rom_blob(acpi_build_no_update, NULL,
+                      tables.rsdp,
+                      ACPI_BUILD_RSDP_FILE, 0);
+
+    acpi_build_tables_cleanup(&tables, false);
+}
diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
index ab6ee6c67b1a..75eca7306b11 100644
--- a/hw/i386/microvm.c
+++ b/hw/i386/microvm.c
@@ -26,6 +26,8 @@
 #include "sysemu/cpus.h"
 #include "sysemu/numa.h"
 #include "sysemu/reset.h"
+#include "sysemu/runstate.h"
+#include "acpi-microvm.h"
 
 #include "hw/loader.h"
 #include "hw/irq.h"
@@ -41,6 +43,8 @@
 #include "hw/i386/e820_memory_layout.h"
 #include "hw/i386/fw_cfg.h"
 #include "hw/virtio/virtio-mmio.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/generic_event_device.h"
 
 #include "cpu.h"
 #include "elf.h"
@@ -129,6 +133,17 @@ static void microvm_devices_init(MicrovmMachineState *mms)
     }
 
     /* Optional and legacy devices */
+    if (x86_machine_is_acpi_enabled(x86ms)) {
+        DeviceState *dev = qdev_new(TYPE_ACPI_GED_X86);
+        qdev_prop_set_uint32(dev, "ged-event", ACPI_GED_PWR_DOWN_EVT);
+        sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, GED_MMIO_BASE);
+        /* sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, GED_MMIO_BASE_MEMHP); */
+        sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, GED_MMIO_BASE_REGS);
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
+                           x86ms->gsi[GED_MMIO_IRQ]);
+        sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
+        mms->acpi_dev = ACPI_DEVICE_IF(dev);
+    }
 
     if (mms->pic == ON_OFF_AUTO_ON || mms->pic == ON_OFF_AUTO_AUTO) {
         qemu_irq *i8259;
@@ -438,6 +453,26 @@ static void microvm_machine_set_auto_kernel_cmdline(Object *obj, bool value,
     mms->auto_kernel_cmdline = value;
 }
 
+static void microvm_machine_done(Notifier *notifier, void *data)
+{
+    MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
+                                            machine_done);
+
+    acpi_setup_microvm(mms);
+}
+
+static void microvm_powerdown_req(Notifier *notifier, void *data)
+{
+    MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
+                                            powerdown_req);
+
+    if (mms->acpi_dev) {
+        Object *obj = OBJECT(mms->acpi_dev);
+        AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
+        adevc->send_event(mms->acpi_dev, ACPI_POWER_DOWN_STATUS);
+    }
+}
+
 static void microvm_machine_initfn(Object *obj)
 {
     MicrovmMachineState *mms = MICROVM_MACHINE(obj);
@@ -452,6 +487,11 @@ static void microvm_machine_initfn(Object *obj)
 
     /* State */
     mms->kernel_cmdline_fixed = false;
+
+    mms->machine_done.notify = microvm_machine_done;
+    qemu_add_machine_init_done_notifier(&mms->machine_done);
+    mms->powerdown_req.notify = microvm_powerdown_req;
+    qemu_register_powerdown_notifier(&mms->powerdown_req);
 }
 
 static void microvm_class_init(ObjectClass *oc, void *data)
diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig
index c93f32f6579d..be746bcb49eb 100644
--- a/hw/i386/Kconfig
+++ b/hw/i386/Kconfig
@@ -102,6 +102,7 @@ config MICROVM
     select I8259
     select MC146818RTC
     select VIRTIO_MMIO
+    select ACPI_HW_REDUCED
 
 config X86_IOMMU
     bool
diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index 622739305882..bbb2fe78f3cd 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -19,3 +19,4 @@ obj-y += kvmvapic.o
 obj-$(CONFIG_ACPI) += acpi-common.o
 obj-$(CONFIG_ACPI_HW_REDUCED) += generic_event_device_x86.o
 obj-$(CONFIG_PC) += acpi-build.o
+obj-$(CONFIG_MICROVM) += acpi-microvm.o
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 09/20] microvm/acpi: add acpi_dsdt_add_virtio() for x86
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (7 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 08/20] microvm/acpi: add minimal acpi support Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-07 12:53 ` [PATCH v5 10/20] microvm/acpi: use GSI 16-23 for virtio Gerd Hoffmann
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

Makes x86 linux kernel find virtio-mmio devices automatically.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Sergio Lopez <slp@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
---
 hw/i386/acpi-microvm.c | 52 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c
index 6c4178caefee..d44d7b0cb234 100644
--- a/hw/i386/acpi-microvm.c
+++ b/hw/i386/acpi-microvm.c
@@ -21,6 +21,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/cutils.h"
 #include "qapi/error.h"
 
 #include "exec/memory.h"
@@ -32,10 +33,60 @@
 #include "hw/boards.h"
 #include "hw/i386/fw_cfg.h"
 #include "hw/i386/microvm.h"
+#include "hw/virtio/virtio-mmio.h"
 
 #include "acpi-common.h"
 #include "acpi-microvm.h"
 
+static void acpi_dsdt_add_virtio(Aml *scope,
+                                 MicrovmMachineState *mms)
+{
+    gchar *separator;
+    long int index;
+    BusState *bus;
+    BusChild *kid;
+
+    bus = sysbus_get_default();
+    QTAILQ_FOREACH(kid, &bus->children, sibling) {
+        DeviceState *dev = kid->child;
+        Object *obj = object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MMIO);
+
+        if (obj) {
+            VirtIOMMIOProxy *mmio = VIRTIO_MMIO(obj);
+            VirtioBusState *mmio_virtio_bus = &mmio->bus;
+            BusState *mmio_bus = &mmio_virtio_bus->parent_obj;
+
+            if (QTAILQ_EMPTY(&mmio_bus->children)) {
+                continue;
+            }
+            separator = g_strrstr(mmio_bus->name, ".");
+            if (!separator) {
+                continue;
+            }
+            if (qemu_strtol(separator + 1, NULL, 10, &index) != 0) {
+                continue;
+            }
+
+            uint32_t irq = mms->virtio_irq_base + index;
+            hwaddr base = VIRTIO_MMIO_BASE + index * 512;
+            hwaddr size = 512;
+
+            Aml *dev = aml_device("VR%02u", (unsigned)index);
+            aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0005")));
+            aml_append(dev, aml_name_decl("_UID", aml_int(index)));
+            aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
+
+            Aml *crs = aml_resource_template();
+            aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE));
+            aml_append(crs,
+                       aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
+                                     AML_EXCLUSIVE, &irq, 1));
+            aml_append(dev, aml_name_decl("_CRS", crs));
+            aml_append(scope, dev);
+        }
+    }
+}
+
 static void
 build_dsdt_microvm(GArray *table_data, BIOSLinker *linker,
                    MicrovmMachineState *mms)
@@ -60,6 +111,7 @@ build_dsdt_microvm(GArray *table_data, BIOSLinker *linker,
     build_ged_aml(sb_scope, GED_DEVICE, HOTPLUG_HANDLER(mms->acpi_dev),
                   GED_MMIO_IRQ, AML_SYSTEM_MEMORY, GED_MMIO_BASE);
     acpi_dsdt_add_power_button(sb_scope);
+    acpi_dsdt_add_virtio(sb_scope, mms);
     aml_append(dsdt, sb_scope);
 
     scope = aml_scope("\\");
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 10/20] microvm/acpi: use GSI 16-23 for virtio
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (8 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 09/20] microvm/acpi: add acpi_dsdt_add_virtio() for x86 Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-07 12:53 ` [PATCH v5 11/20] microvm/acpi: use seabios with acpi=on Gerd Hoffmann
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

With ACPI enabled and IO-APIC being properly declared in the ACPI tables
we can use interrupt lines 16-23 for virtio and avoid shared interrupts.

With acpi disabled we continue to use lines 5-12.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Sergio Lopez <slp@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
---
 hw/i386/microvm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
index 75eca7306b11..1bcd57a6fd80 100644
--- a/hw/i386/microvm.c
+++ b/hw/i386/microvm.c
@@ -125,7 +125,7 @@ static void microvm_devices_init(MicrovmMachineState *mms)
 
     kvmclock_create();
 
-    mms->virtio_irq_base = 5;
+    mms->virtio_irq_base = x86_machine_is_acpi_enabled(x86ms) ? 16 : 5;
     for (i = 0; i < VIRTIO_NUM_TRANSPORTS; i++) {
         sysbus_create_simple("virtio-mmio",
                              VIRTIO_MMIO_BASE + i * 512,
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 11/20] microvm/acpi: use seabios with acpi=on
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (9 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 10/20] microvm/acpi: use GSI 16-23 for virtio Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-07 12:53 ` [PATCH v5 12/20] microvm/acpi: disable virtio-mmio cmdline hack Gerd Hoffmann
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

With acpi=off continue to use qboot.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
---
 hw/i386/microvm.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
index 1bcd57a6fd80..ac605d92b984 100644
--- a/hw/i386/microvm.c
+++ b/hw/i386/microvm.c
@@ -52,6 +52,7 @@
 #include "hw/xen/start_info.h"
 
 #define MICROVM_QBOOT_FILENAME "qboot.rom"
+#define MICROVM_BIOS_FILENAME  "bios-microvm.bin"
 
 static void microvm_set_rtc(MicrovmMachineState *mms, ISADevice *s)
 {
@@ -174,7 +175,9 @@ static void microvm_devices_init(MicrovmMachineState *mms)
     }
 
     if (bios_name == NULL) {
-        bios_name = MICROVM_QBOOT_FILENAME;
+        bios_name = x86_machine_is_acpi_enabled(x86ms)
+            ? MICROVM_BIOS_FILENAME
+            : MICROVM_QBOOT_FILENAME;
     }
     x86_bios_rom_init(get_system_memory(), true);
 }
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 12/20] microvm/acpi: disable virtio-mmio cmdline hack
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (10 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 11/20] microvm/acpi: use seabios with acpi=on Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-07 12:53 ` [PATCH v5 13/20] x86: constify x86_machine_is_*_enabled Gerd Hoffmann
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

... in case we are using ACPI.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
---
 hw/i386/microvm.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
index ac605d92b984..fbda323f3b2a 100644
--- a/hw/i386/microvm.c
+++ b/hw/i386/microvm.c
@@ -343,7 +343,8 @@ static void microvm_machine_reset(MachineState *machine)
     CPUState *cs;
     X86CPU *cpu;
 
-    if (machine->kernel_filename != NULL &&
+    if (!x86_machine_is_acpi_enabled(X86_MACHINE(machine)) &&
+        machine->kernel_filename != NULL &&
         mms->auto_kernel_cmdline && !mms->kernel_cmdline_fixed) {
         microvm_fix_kernel_cmdline(machine);
         mms->kernel_cmdline_fixed = true;
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 13/20] x86: constify x86_machine_is_*_enabled
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (11 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 12/20] microvm/acpi: disable virtio-mmio cmdline hack Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-07 12:53 ` [PATCH v5 14/20] x86: move acpi_dev from pc/microvm Gerd Hoffmann
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 include/hw/i386/x86.h | 4 ++--
 hw/i386/x86.c         | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h
index b79f24e28545..a350ea3609f5 100644
--- a/include/hw/i386/x86.h
+++ b/include/hw/i386/x86.h
@@ -110,8 +110,8 @@ void x86_load_linux(X86MachineState *x86ms,
                     bool pvh_enabled,
                     bool linuxboot_dma_enabled);
 
-bool x86_machine_is_smm_enabled(X86MachineState *x86ms);
-bool x86_machine_is_acpi_enabled(X86MachineState *x86ms);
+bool x86_machine_is_smm_enabled(const X86MachineState *x86ms);
+bool x86_machine_is_acpi_enabled(const X86MachineState *x86ms);
 
 /* Global System Interrupts */
 
diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index 93f7371a5693..2d2beff3d4f6 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -848,7 +848,7 @@ void x86_bios_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw)
                                 bios);
 }
 
-bool x86_machine_is_smm_enabled(X86MachineState *x86ms)
+bool x86_machine_is_smm_enabled(const X86MachineState *x86ms)
 {
     bool smm_available = false;
 
@@ -890,7 +890,7 @@ static void x86_machine_set_smm(Object *obj, Visitor *v, const char *name,
     visit_type_OnOffAuto(v, name, &x86ms->smm, errp);
 }
 
-bool x86_machine_is_acpi_enabled(X86MachineState *x86ms)
+bool x86_machine_is_acpi_enabled(const X86MachineState *x86ms)
 {
     if (x86ms->acpi == ON_OFF_AUTO_OFF) {
         return false;
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 14/20] x86: move acpi_dev from pc/microvm
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (12 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 13/20] x86: constify x86_machine_is_*_enabled Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-07 12:53 ` [PATCH v5 15/20] x86: move cpu plug from pc to x86 Gerd Hoffmann
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

Both pc and microvm machine types have a acpi_dev field.
Move it to the common base type.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 include/hw/i386/microvm.h |  1 -
 include/hw/i386/pc.h      |  1 -
 include/hw/i386/x86.h     |  1 +
 hw/i386/acpi-build.c      |  2 +-
 hw/i386/acpi-microvm.c    |  5 +++--
 hw/i386/microvm.c         | 10 ++++++----
 hw/i386/pc.c              | 34 +++++++++++++++++++---------------
 hw/i386/pc_piix.c         |  2 +-
 hw/i386/pc_q35.c          |  2 +-
 9 files changed, 32 insertions(+), 26 deletions(-)

diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h
index b6e0d4395af7..b8ec99aeb051 100644
--- a/include/hw/i386/microvm.h
+++ b/include/hw/i386/microvm.h
@@ -66,7 +66,6 @@ typedef struct {
     bool kernel_cmdline_fixed;
     Notifier machine_done;
     Notifier powerdown_req;
-    AcpiDeviceIf *acpi_dev;
 } MicrovmMachineState;
 
 #define TYPE_MICROVM_MACHINE   MACHINE_TYPE_NAME("microvm")
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index dce1273c7dad..5e4126fe817d 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -29,7 +29,6 @@ struct PCMachineState {
     Notifier machine_done;
 
     /* Pointers to devices and objects: */
-    HotplugHandler *acpi_dev;
     PCIBus *bus;
     I2CBus *smbus;
     PFlashCFI01 *flash[2];
diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h
index a350ea3609f5..de74c831c3ab 100644
--- a/include/hw/i386/x86.h
+++ b/include/hw/i386/x86.h
@@ -50,6 +50,7 @@ typedef struct {
     FWCfgState *fw_cfg;
     qemu_irq *gsi;
     GMappedFile *initrd_mapped_file;
+    HotplugHandler *acpi_dev;
 
     /* RAM information (sizes, addresses, configuration): */
     ram_addr_t below_4g_mem_size, above_4g_mem_size;
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index b7bcbbbb2a35..c356cc71fe08 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -2431,7 +2431,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
 
     acpi_add_table(table_offsets, tables_blob);
     acpi_build_madt(tables_blob, tables->linker, x86ms,
-                    ACPI_DEVICE_IF(pcms->acpi_dev), true);
+                    ACPI_DEVICE_IF(x86ms->acpi_dev), true);
 
     vmgenid_dev = find_vmgenid_dev();
     if (vmgenid_dev) {
diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c
index d44d7b0cb234..70fba7ca04dd 100644
--- a/hw/i386/acpi-microvm.c
+++ b/hw/i386/acpi-microvm.c
@@ -108,7 +108,7 @@ build_dsdt_microvm(GArray *table_data, BIOSLinker *linker,
     sb_scope = aml_scope("_SB");
     fw_cfg_add_acpi_dsdt(sb_scope, x86ms->fw_cfg);
     isa_build_aml(ISA_BUS(isabus), sb_scope);
-    build_ged_aml(sb_scope, GED_DEVICE, HOTPLUG_HANDLER(mms->acpi_dev),
+    build_ged_aml(sb_scope, GED_DEVICE, x86ms->acpi_dev,
                   GED_MMIO_IRQ, AML_SYSTEM_MEMORY, GED_MMIO_BASE);
     acpi_dsdt_add_power_button(sb_scope);
     acpi_dsdt_add_virtio(sb_scope, mms);
@@ -135,6 +135,7 @@ static void acpi_build_microvm(AcpiBuildTables *tables,
                                MicrovmMachineState *mms)
 {
     MachineState *machine = MACHINE(mms);
+    X86MachineState *x86ms = X86_MACHINE(mms);
     GArray *table_offsets;
     GArray *tables_blob = tables->table_data;
     unsigned dsdt, xsdt;
@@ -191,7 +192,7 @@ static void acpi_build_microvm(AcpiBuildTables *tables,
 
     acpi_add_table(table_offsets, tables_blob);
     acpi_build_madt(tables_blob, tables->linker, X86_MACHINE(machine),
-                    mms->acpi_dev, false);
+                    ACPI_DEVICE_IF(x86ms->acpi_dev), false);
 
     xsdt = tables_blob->len;
     build_xsdt(tables_blob, tables->linker, table_offsets, NULL, NULL);
diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
index fbda323f3b2a..3d8a66cfc3ac 100644
--- a/hw/i386/microvm.c
+++ b/hw/i386/microvm.c
@@ -143,7 +143,7 @@ static void microvm_devices_init(MicrovmMachineState *mms)
         sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
                            x86ms->gsi[GED_MMIO_IRQ]);
         sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
-        mms->acpi_dev = ACPI_DEVICE_IF(dev);
+        x86ms->acpi_dev = HOTPLUG_HANDLER(dev);
     }
 
     if (mms->pic == ON_OFF_AUTO_ON || mms->pic == ON_OFF_AUTO_AUTO) {
@@ -469,11 +469,13 @@ static void microvm_powerdown_req(Notifier *notifier, void *data)
 {
     MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
                                             powerdown_req);
+    X86MachineState *x86ms = X86_MACHINE(mms);
 
-    if (mms->acpi_dev) {
-        Object *obj = OBJECT(mms->acpi_dev);
+    if (x86ms->acpi_dev) {
+        Object *obj = OBJECT(x86ms->acpi_dev);
         AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
-        adevc->send_event(mms->acpi_dev, ACPI_POWER_DOWN_STATUS);
+        adevc->send_event(ACPI_DEVICE_IF(x86ms->acpi_dev),
+                          ACPI_POWER_DOWN_STATUS);
     }
 }
 
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 4af9679d039b..98d29ead09b0 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1270,6 +1270,7 @@ static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
                                Error **errp)
 {
     const PCMachineState *pcms = PC_MACHINE(hotplug_dev);
+    const X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
     const PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
     const MachineState *ms = MACHINE(hotplug_dev);
     const bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
@@ -1281,7 +1282,7 @@ static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
      * but pcms->acpi_dev is still created. Check !acpi_enabled in
      * addition to cover this case.
      */
-    if (!pcms->acpi_dev || !x86_machine_is_acpi_enabled(X86_MACHINE(pcms))) {
+    if (!x86ms->acpi_dev || !x86_machine_is_acpi_enabled(x86ms)) {
         error_setg(errp,
                    "memory hotplug is not enabled: missing acpi device or acpi disabled");
         return;
@@ -1292,7 +1293,7 @@ static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
         return;
     }
 
-    hotplug_handler_pre_plug(pcms->acpi_dev, dev, &local_err);
+    hotplug_handler_pre_plug(x86ms->acpi_dev, dev, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         return;
@@ -1307,6 +1308,7 @@ static void pc_memory_plug(HotplugHandler *hotplug_dev,
 {
     Error *local_err = NULL;
     PCMachineState *pcms = PC_MACHINE(hotplug_dev);
+    X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
     MachineState *ms = MACHINE(hotplug_dev);
     bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
 
@@ -1319,7 +1321,7 @@ static void pc_memory_plug(HotplugHandler *hotplug_dev,
         nvdimm_plug(ms->nvdimms_state);
     }
 
-    hotplug_handler_plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &error_abort);
+    hotplug_handler_plug(x86ms->acpi_dev, dev, &error_abort);
 out:
     error_propagate(errp, local_err);
 }
@@ -1328,14 +1330,14 @@ static void pc_memory_unplug_request(HotplugHandler *hotplug_dev,
                                      DeviceState *dev, Error **errp)
 {
     Error *local_err = NULL;
-    PCMachineState *pcms = PC_MACHINE(hotplug_dev);
+    X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
 
     /*
      * When -no-acpi is used with Q35 machine type, no ACPI is built,
      * but pcms->acpi_dev is still created. Check !acpi_enabled in
      * addition to cover this case.
      */
-    if (!pcms->acpi_dev || !x86_machine_is_acpi_enabled(X86_MACHINE(pcms))) {
+    if (!x86ms->acpi_dev || !x86_machine_is_acpi_enabled(x86ms)) {
         error_setg(&local_err,
                    "memory hotplug is not enabled: missing acpi device or acpi disabled");
         goto out;
@@ -1347,7 +1349,7 @@ static void pc_memory_unplug_request(HotplugHandler *hotplug_dev,
         goto out;
     }
 
-    hotplug_handler_unplug_request(HOTPLUG_HANDLER(pcms->acpi_dev), dev,
+    hotplug_handler_unplug_request(x86ms->acpi_dev, dev,
                                    &local_err);
 out:
     error_propagate(errp, local_err);
@@ -1357,9 +1359,10 @@ static void pc_memory_unplug(HotplugHandler *hotplug_dev,
                              DeviceState *dev, Error **errp)
 {
     PCMachineState *pcms = PC_MACHINE(hotplug_dev);
+    X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
     Error *local_err = NULL;
 
-    hotplug_handler_unplug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
+    hotplug_handler_unplug(x86ms->acpi_dev, dev, &local_err);
     if (local_err) {
         goto out;
     }
@@ -1403,10 +1406,10 @@ static void pc_cpu_plug(HotplugHandler *hotplug_dev,
     Error *local_err = NULL;
     X86CPU *cpu = X86_CPU(dev);
     PCMachineState *pcms = PC_MACHINE(hotplug_dev);
-    X86MachineState *x86ms = X86_MACHINE(pcms);
+    X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
 
-    if (pcms->acpi_dev) {
-        hotplug_handler_plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
+    if (x86ms->acpi_dev) {
+        hotplug_handler_plug(x86ms->acpi_dev, dev, &local_err);
         if (local_err) {
             goto out;
         }
@@ -1433,8 +1436,9 @@ static void pc_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
     Error *local_err = NULL;
     X86CPU *cpu = X86_CPU(dev);
     PCMachineState *pcms = PC_MACHINE(hotplug_dev);
+    X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
 
-    if (!pcms->acpi_dev) {
+    if (!x86ms->acpi_dev) {
         error_setg(&local_err, "CPU hot unplug not supported without ACPI");
         goto out;
     }
@@ -1446,7 +1450,7 @@ static void pc_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
         goto out;
     }
 
-    hotplug_handler_unplug_request(HOTPLUG_HANDLER(pcms->acpi_dev), dev,
+    hotplug_handler_unplug_request(x86ms->acpi_dev, dev,
                                    &local_err);
     if (local_err) {
         goto out;
@@ -1464,9 +1468,9 @@ static void pc_cpu_unplug_cb(HotplugHandler *hotplug_dev,
     Error *local_err = NULL;
     X86CPU *cpu = X86_CPU(dev);
     PCMachineState *pcms = PC_MACHINE(hotplug_dev);
-    X86MachineState *x86ms = X86_MACHINE(pcms);
+    X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
 
-    hotplug_handler_unplug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
+    hotplug_handler_unplug(x86ms->acpi_dev, dev, &local_err);
     if (local_err) {
         goto out;
     }
@@ -1495,7 +1499,7 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev,
     CPUX86State *env = &cpu->env;
     MachineState *ms = MACHINE(hotplug_dev);
     PCMachineState *pcms = PC_MACHINE(hotplug_dev);
-    X86MachineState *x86ms = X86_MACHINE(pcms);
+    X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
     unsigned int smp_cores = ms->smp.cores;
     unsigned int smp_threads = ms->smp.threads;
     X86CPUTopoInfo topo_info;
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 1d832b2878b1..34944bd383e3 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -291,7 +291,7 @@ static void pc_init1(MachineState *machine,
 
         object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
                                  TYPE_HOTPLUG_HANDLER,
-                                 (Object **)&pcms->acpi_dev,
+                                 (Object **)&x86ms->acpi_dev,
                                  object_property_allow_set_link,
                                  OBJ_PROP_LINK_STRONG);
         object_property_set_link(OBJECT(machine), OBJECT(piix4_pm),
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 047ea8db28ea..92a104059076 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -240,7 +240,7 @@ static void pc_q35_init(MachineState *machine)
 
     object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
                              TYPE_HOTPLUG_HANDLER,
-                             (Object **)&pcms->acpi_dev,
+                             (Object **)&x86ms->acpi_dev,
                              object_property_allow_set_link,
                              OBJ_PROP_LINK_STRONG);
     object_property_set_link(OBJECT(machine), OBJECT(lpc),
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 15/20] x86: move cpu plug from pc to x86
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (13 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 14/20] x86: move acpi_dev from pc/microvm Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-10 19:37   ` Igor Mammedov
  2020-07-07 12:53 ` [PATCH v5 16/20] microvm: wire up hotplug Gerd Hoffmann
                   ` (6 subsequent siblings)
  21 siblings, 1 reply; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

The cpu hotplug code handles the initialization of coldplugged cpus
too, so it is needed even in case cpu hotplug is not supported.

Move the code from pc to x86, so microvm can use it.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 include/hw/i386/x86.h |   6 ++
 hw/i386/pc.c          | 234 ++----------------------------------------
 hw/i386/x86.c         | 222 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 234 insertions(+), 228 deletions(-)

diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h
index de74c831c3ab..23c964471802 100644
--- a/include/hw/i386/x86.h
+++ b/include/hw/i386/x86.h
@@ -102,6 +102,12 @@ CpuInstanceProperties x86_cpu_index_to_props(MachineState *ms,
                                              unsigned cpu_index);
 int64_t x86_get_default_cpu_node_id(const MachineState *ms, int idx);
 const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms);
+CPUArchId *x86_find_cpu_slot(MachineState *ms, uint32_t id, int *idx);
+void x86_rtc_set_cpus_count(ISADevice *rtc, uint16_t cpus_count);
+void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
+                      DeviceState *dev, Error **errp);
+void x86_cpu_plug(HotplugHandler *hotplug_dev,
+                  DeviceState *dev, Error **errp);
 
 void x86_bios_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw);
 
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 98d29ead09b0..14036fcd4e3a 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -798,19 +798,6 @@ void pc_hot_add_cpu(MachineState *ms, const int64_t id, Error **errp)
     }
 }
 
-static void rtc_set_cpus_count(ISADevice *rtc, uint16_t cpus_count)
-{
-    if (cpus_count > 0xff) {
-        /* If the number of CPUs can't be represented in 8 bits, the
-         * BIOS must use "FW_CFG_NB_CPUS". Set RTC field to 0 just
-         * to make old BIOSes fail more predictably.
-         */
-        rtc_set_memory(rtc, 0x5f, 0);
-    } else {
-        rtc_set_memory(rtc, 0x5f, cpus_count - 1);
-    }
-}
-
 static
 void pc_machine_done(Notifier *notifier, void *data)
 {
@@ -820,7 +807,7 @@ void pc_machine_done(Notifier *notifier, void *data)
     PCIBus *bus = pcms->bus;
 
     /* set the number of CPUs */
-    rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
+    x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
 
     if (bus) {
         int extra_hosts = 0;
@@ -1373,62 +1360,6 @@ static void pc_memory_unplug(HotplugHandler *hotplug_dev,
     error_propagate(errp, local_err);
 }
 
-static int pc_apic_cmp(const void *a, const void *b)
-{
-   CPUArchId *apic_a = (CPUArchId *)a;
-   CPUArchId *apic_b = (CPUArchId *)b;
-
-   return apic_a->arch_id - apic_b->arch_id;
-}
-
-/* returns pointer to CPUArchId descriptor that matches CPU's apic_id
- * in ms->possible_cpus->cpus, if ms->possible_cpus->cpus has no
- * entry corresponding to CPU's apic_id returns NULL.
- */
-static CPUArchId *pc_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
-{
-    CPUArchId apic_id, *found_cpu;
-
-    apic_id.arch_id = id;
-    found_cpu = bsearch(&apic_id, ms->possible_cpus->cpus,
-        ms->possible_cpus->len, sizeof(*ms->possible_cpus->cpus),
-        pc_apic_cmp);
-    if (found_cpu && idx) {
-        *idx = found_cpu - ms->possible_cpus->cpus;
-    }
-    return found_cpu;
-}
-
-static void pc_cpu_plug(HotplugHandler *hotplug_dev,
-                        DeviceState *dev, Error **errp)
-{
-    CPUArchId *found_cpu;
-    Error *local_err = NULL;
-    X86CPU *cpu = X86_CPU(dev);
-    PCMachineState *pcms = PC_MACHINE(hotplug_dev);
-    X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
-
-    if (x86ms->acpi_dev) {
-        hotplug_handler_plug(x86ms->acpi_dev, dev, &local_err);
-        if (local_err) {
-            goto out;
-        }
-    }
-
-    /* increment the number of CPUs */
-    x86ms->boot_cpus++;
-    if (x86ms->rtc) {
-        rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
-    }
-    if (x86ms->fw_cfg) {
-        fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus);
-    }
-
-    found_cpu = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, NULL);
-    found_cpu->cpu = OBJECT(dev);
-out:
-    error_propagate(errp, local_err);
-}
 static void pc_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
                                      DeviceState *dev, Error **errp)
 {
@@ -1443,7 +1374,7 @@ static void pc_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
         goto out;
     }
 
-    pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, &idx);
+    x86_find_cpu_slot(MACHINE(pcms), cpu->apic_id, &idx);
     assert(idx != -1);
     if (idx == 0) {
         error_setg(&local_err, "Boot CPU is unpluggable");
@@ -1475,172 +1406,19 @@ static void pc_cpu_unplug_cb(HotplugHandler *hotplug_dev,
         goto out;
     }
 
-    found_cpu = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, NULL);
+    found_cpu = x86_find_cpu_slot(MACHINE(pcms), cpu->apic_id, NULL);
     found_cpu->cpu = NULL;
     qdev_unrealize(dev);
 
     /* decrement the number of CPUs */
     x86ms->boot_cpus--;
     /* Update the number of CPUs in CMOS */
-    rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
+    x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
     fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus);
  out:
     error_propagate(errp, local_err);
 }
 
-static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev,
-                            DeviceState *dev, Error **errp)
-{
-    int idx;
-    CPUState *cs;
-    CPUArchId *cpu_slot;
-    X86CPUTopoIDs topo_ids;
-    X86CPU *cpu = X86_CPU(dev);
-    CPUX86State *env = &cpu->env;
-    MachineState *ms = MACHINE(hotplug_dev);
-    PCMachineState *pcms = PC_MACHINE(hotplug_dev);
-    X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
-    unsigned int smp_cores = ms->smp.cores;
-    unsigned int smp_threads = ms->smp.threads;
-    X86CPUTopoInfo topo_info;
-
-    if(!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) {
-        error_setg(errp, "Invalid CPU type, expected cpu type: '%s'",
-                   ms->cpu_type);
-        return;
-    }
-
-    init_topo_info(&topo_info, x86ms);
-
-    env->nr_dies = x86ms->smp_dies;
-    env->nr_nodes = topo_info.nodes_per_pkg;
-    env->pkg_offset = x86ms->apicid_pkg_offset(&topo_info);
-
-    /*
-     * If APIC ID is not set,
-     * set it based on socket/die/core/thread properties.
-     */
-    if (cpu->apic_id == UNASSIGNED_APIC_ID) {
-        int max_socket = (ms->smp.max_cpus - 1) /
-                                smp_threads / smp_cores / x86ms->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 && x86ms->smp_dies == 1) {
-            cpu->die_id = 0;
-        }
-
-        if (cpu->socket_id < 0) {
-            error_setg(errp, "CPU socket-id is not set");
-            return;
-        } else if (cpu->socket_id > max_socket) {
-            error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u",
-                       cpu->socket_id, max_socket);
-            return;
-        }
-        if (cpu->die_id < 0) {
-            error_setg(errp, "CPU die-id is not set");
-            return;
-        } else if (cpu->die_id > x86ms->smp_dies - 1) {
-            error_setg(errp, "Invalid CPU die-id: %u must be in range 0:%u",
-                       cpu->die_id, x86ms->smp_dies - 1);
-            return;
-        }
-        if (cpu->core_id < 0) {
-            error_setg(errp, "CPU core-id is not set");
-            return;
-        } else if (cpu->core_id > (smp_cores - 1)) {
-            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) {
-            error_setg(errp, "CPU thread-id is not set");
-            return;
-        } else if (cpu->thread_id > (smp_threads - 1)) {
-            error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u",
-                       cpu->thread_id, smp_threads - 1);
-            return;
-        }
-
-        topo_ids.pkg_id = cpu->socket_id;
-        topo_ids.die_id = cpu->die_id;
-        topo_ids.core_id = cpu->core_id;
-        topo_ids.smt_id = cpu->thread_id;
-        cpu->apic_id = x86ms->apicid_from_topo_ids(&topo_info, &topo_ids);
-    }
-
-    cpu_slot = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, &idx);
-    if (!cpu_slot) {
-        MachineState *ms = MACHINE(pcms);
-
-        x86ms->topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
-        error_setg(errp,
-            "Invalid CPU [socket: %u, die: %u, core: %u, thread: %u] with"
-            " APIC ID %" PRIu32 ", valid index range 0:%d",
-            topo_ids.pkg_id, topo_ids.die_id, topo_ids.core_id, topo_ids.smt_id,
-            cpu->apic_id, ms->possible_cpus->len - 1);
-        return;
-    }
-
-    if (cpu_slot->cpu) {
-        error_setg(errp, "CPU[%d] with APIC ID %" PRIu32 " exists",
-                   idx, cpu->apic_id);
-        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
-     */
-    /* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn()
-     * once -smp refactoring is complete and there will be CPU private
-     * CPUState::nr_cores and CPUState::nr_threads fields instead of globals */
-    x86ms->topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
-    if (cpu->socket_id != -1 && cpu->socket_id != topo_ids.pkg_id) {
-        error_setg(errp, "property socket-id: %u doesn't match set apic-id:"
-            " 0x%x (socket-id: %u)", cpu->socket_id, cpu->apic_id,
-            topo_ids.pkg_id);
-        return;
-    }
-    cpu->socket_id = topo_ids.pkg_id;
-
-    if (cpu->die_id != -1 && cpu->die_id != topo_ids.die_id) {
-        error_setg(errp, "property die-id: %u doesn't match set apic-id:"
-            " 0x%x (die-id: %u)", cpu->die_id, cpu->apic_id, topo_ids.die_id);
-        return;
-    }
-    cpu->die_id = topo_ids.die_id;
-
-    if (cpu->core_id != -1 && cpu->core_id != topo_ids.core_id) {
-        error_setg(errp, "property core-id: %u doesn't match set apic-id:"
-            " 0x%x (core-id: %u)", cpu->core_id, cpu->apic_id,
-            topo_ids.core_id);
-        return;
-    }
-    cpu->core_id = topo_ids.core_id;
-
-    if (cpu->thread_id != -1 && cpu->thread_id != topo_ids.smt_id) {
-        error_setg(errp, "property thread-id: %u doesn't match set apic-id:"
-            " 0x%x (thread-id: %u)", cpu->thread_id, cpu->apic_id,
-            topo_ids.smt_id);
-        return;
-    }
-    cpu->thread_id = topo_ids.smt_id;
-
-    if (hyperv_feat_enabled(cpu, HYPERV_FEAT_VPINDEX) &&
-        !kvm_hv_vpindex_settable()) {
-        error_setg(errp, "kernel doesn't allow setting HyperV VP_INDEX");
-        return;
-    }
-
-    cs = CPU(cpu);
-    cs->cpu_index = idx;
-
-    numa_cpu_pre_plug(cpu_slot, dev, errp);
-}
-
 static void pc_virtio_pmem_pci_pre_plug(HotplugHandler *hotplug_dev,
                                         DeviceState *dev, Error **errp)
 {
@@ -1706,7 +1484,7 @@ static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
         pc_memory_pre_plug(hotplug_dev, dev, errp);
     } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
-        pc_cpu_pre_plug(hotplug_dev, dev, errp);
+        x86_cpu_pre_plug(hotplug_dev, dev, errp);
     } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) {
         pc_virtio_pmem_pci_pre_plug(hotplug_dev, dev, errp);
     }
@@ -1718,7 +1496,7 @@ static void pc_machine_device_plug_cb(HotplugHandler *hotplug_dev,
     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
         pc_memory_plug(hotplug_dev, dev, errp);
     } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
-        pc_cpu_plug(hotplug_dev, dev, errp);
+        x86_cpu_plug(hotplug_dev, dev, errp);
     } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) {
         pc_virtio_pmem_pci_plug(hotplug_dev, dev, errp);
     }
diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index 2d2beff3d4f6..b11fcb90b9cd 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -41,6 +41,7 @@
 #include "hw/i386/topology.h"
 #include "hw/i386/fw_cfg.h"
 #include "hw/intc/i8259.h"
+#include "hw/rtc/mc146818rtc.h"
 
 #include "hw/acpi/cpu_hotplug.h"
 #include "hw/irq.h"
@@ -168,6 +169,227 @@ void x86_cpus_init(X86MachineState *x86ms, int default_cpu_version)
     }
 }
 
+void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
+                      DeviceState *dev, Error **errp)
+{
+    int idx;
+    CPUState *cs;
+    CPUArchId *cpu_slot;
+    X86CPUTopoIDs topo_ids;
+    X86CPU *cpu = X86_CPU(dev);
+    CPUX86State *env = &cpu->env;
+    MachineState *ms = MACHINE(hotplug_dev);
+    X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
+    unsigned int smp_cores = ms->smp.cores;
+    unsigned int smp_threads = ms->smp.threads;
+    X86CPUTopoInfo topo_info;
+
+    if(!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) {
+        error_setg(errp, "Invalid CPU type, expected cpu type: '%s'",
+                   ms->cpu_type);
+        return;
+    }
+
+    init_topo_info(&topo_info, x86ms);
+
+    env->nr_dies = x86ms->smp_dies;
+    env->nr_nodes = topo_info.nodes_per_pkg;
+    env->pkg_offset = x86ms->apicid_pkg_offset(&topo_info);
+
+    /*
+     * If APIC ID is not set,
+     * set it based on socket/die/core/thread properties.
+     */
+    if (cpu->apic_id == UNASSIGNED_APIC_ID) {
+        int max_socket = (ms->smp.max_cpus - 1) /
+                                smp_threads / smp_cores / x86ms->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 && x86ms->smp_dies == 1) {
+            cpu->die_id = 0;
+        }
+
+        if (cpu->socket_id < 0) {
+            error_setg(errp, "CPU socket-id is not set");
+            return;
+        } else if (cpu->socket_id > max_socket) {
+            error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u",
+                       cpu->socket_id, max_socket);
+            return;
+        }
+        if (cpu->die_id < 0) {
+            error_setg(errp, "CPU die-id is not set");
+            return;
+        } else if (cpu->die_id > x86ms->smp_dies - 1) {
+            error_setg(errp, "Invalid CPU die-id: %u must be in range 0:%u",
+                       cpu->die_id, x86ms->smp_dies - 1);
+            return;
+        }
+        if (cpu->core_id < 0) {
+            error_setg(errp, "CPU core-id is not set");
+            return;
+        } else if (cpu->core_id > (smp_cores - 1)) {
+            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) {
+            error_setg(errp, "CPU thread-id is not set");
+            return;
+        } else if (cpu->thread_id > (smp_threads - 1)) {
+            error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u",
+                       cpu->thread_id, smp_threads - 1);
+            return;
+        }
+
+        topo_ids.pkg_id = cpu->socket_id;
+        topo_ids.die_id = cpu->die_id;
+        topo_ids.core_id = cpu->core_id;
+        topo_ids.smt_id = cpu->thread_id;
+        cpu->apic_id = x86ms->apicid_from_topo_ids(&topo_info, &topo_ids);
+    }
+
+    cpu_slot = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, &idx);
+    if (!cpu_slot) {
+        MachineState *ms = MACHINE(x86ms);
+
+        x86ms->topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
+        error_setg(errp,
+            "Invalid CPU [socket: %u, die: %u, core: %u, thread: %u] with"
+            " APIC ID %" PRIu32 ", valid index range 0:%d",
+            topo_ids.pkg_id, topo_ids.die_id, topo_ids.core_id, topo_ids.smt_id,
+            cpu->apic_id, ms->possible_cpus->len - 1);
+        return;
+    }
+
+    if (cpu_slot->cpu) {
+        error_setg(errp, "CPU[%d] with APIC ID %" PRIu32 " exists",
+                   idx, cpu->apic_id);
+        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
+     */
+    /* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn()
+     * once -smp refactoring is complete and there will be CPU private
+     * CPUState::nr_cores and CPUState::nr_threads fields instead of globals */
+    x86ms->topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
+    if (cpu->socket_id != -1 && cpu->socket_id != topo_ids.pkg_id) {
+        error_setg(errp, "property socket-id: %u doesn't match set apic-id:"
+            " 0x%x (socket-id: %u)", cpu->socket_id, cpu->apic_id,
+            topo_ids.pkg_id);
+        return;
+    }
+    cpu->socket_id = topo_ids.pkg_id;
+
+    if (cpu->die_id != -1 && cpu->die_id != topo_ids.die_id) {
+        error_setg(errp, "property die-id: %u doesn't match set apic-id:"
+            " 0x%x (die-id: %u)", cpu->die_id, cpu->apic_id, topo_ids.die_id);
+        return;
+    }
+    cpu->die_id = topo_ids.die_id;
+
+    if (cpu->core_id != -1 && cpu->core_id != topo_ids.core_id) {
+        error_setg(errp, "property core-id: %u doesn't match set apic-id:"
+            " 0x%x (core-id: %u)", cpu->core_id, cpu->apic_id,
+            topo_ids.core_id);
+        return;
+    }
+    cpu->core_id = topo_ids.core_id;
+
+    if (cpu->thread_id != -1 && cpu->thread_id != topo_ids.smt_id) {
+        error_setg(errp, "property thread-id: %u doesn't match set apic-id:"
+            " 0x%x (thread-id: %u)", cpu->thread_id, cpu->apic_id,
+            topo_ids.smt_id);
+        return;
+    }
+    cpu->thread_id = topo_ids.smt_id;
+
+    if (hyperv_feat_enabled(cpu, HYPERV_FEAT_VPINDEX) &&
+        !kvm_hv_vpindex_settable()) {
+        error_setg(errp, "kernel doesn't allow setting HyperV VP_INDEX");
+        return;
+    }
+
+    cs = CPU(cpu);
+    cs->cpu_index = idx;
+
+    numa_cpu_pre_plug(cpu_slot, dev, errp);
+}
+
+void x86_rtc_set_cpus_count(ISADevice *rtc, uint16_t cpus_count)
+{
+    if (cpus_count > 0xff) {
+        /* If the number of CPUs can't be represented in 8 bits, the
+         * BIOS must use "FW_CFG_NB_CPUS". Set RTC field to 0 just
+         * to make old BIOSes fail more predictably.
+         */
+        rtc_set_memory(rtc, 0x5f, 0);
+    } else {
+        rtc_set_memory(rtc, 0x5f, cpus_count - 1);
+    }
+}
+
+static int x86_apic_cmp(const void *a, const void *b)
+{
+   CPUArchId *apic_a = (CPUArchId *)a;
+   CPUArchId *apic_b = (CPUArchId *)b;
+
+   return apic_a->arch_id - apic_b->arch_id;
+}
+
+/* returns pointer to CPUArchId descriptor that matches CPU's apic_id
+ * in ms->possible_cpus->cpus, if ms->possible_cpus->cpus has no
+ * entry corresponding to CPU's apic_id returns NULL.
+ */
+CPUArchId *x86_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
+{
+    CPUArchId apic_id, *found_cpu;
+
+    apic_id.arch_id = id;
+    found_cpu = bsearch(&apic_id, ms->possible_cpus->cpus,
+        ms->possible_cpus->len, sizeof(*ms->possible_cpus->cpus),
+        x86_apic_cmp);
+    if (found_cpu && idx) {
+        *idx = found_cpu - ms->possible_cpus->cpus;
+    }
+    return found_cpu;
+}
+
+void x86_cpu_plug(HotplugHandler *hotplug_dev,
+                  DeviceState *dev, Error **errp)
+{
+    CPUArchId *found_cpu;
+    Error *local_err = NULL;
+    X86CPU *cpu = X86_CPU(dev);
+    X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
+
+    if (x86ms->acpi_dev) {
+        hotplug_handler_plug(x86ms->acpi_dev, dev, &local_err);
+        if (local_err) {
+            goto out;
+        }
+    }
+
+    /* increment the number of CPUs */
+    x86ms->boot_cpus++;
+    if (x86ms->rtc) {
+        x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
+    }
+    if (x86ms->fw_cfg) {
+        fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus);
+    }
+
+    found_cpu = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, NULL);
+    found_cpu->cpu = OBJECT(dev);
+out:
+    error_propagate(errp, local_err);
+}
+
 CpuInstanceProperties
 x86_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
 {
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 16/20] microvm: wire up hotplug
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (14 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 15/20] x86: move cpu plug from pc to x86 Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-10 19:44   ` Igor Mammedov
  2020-07-07 12:53 ` [PATCH v5 17/20] tests/acpi: allow microvm test data updates Gerd Hoffmann
                   ` (5 subsequent siblings)
  21 siblings, 1 reply; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

The cpu hotplug code handles the initialization of coldplugged cpus
too, so it is needed even in case cpu hotplug is not supported.

Wire cpu hotplug up for microvm.
Without this we get a broken MADT table.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/i386/microvm.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
index 3d8a66cfc3ac..a5b16b728f9f 100644
--- a/hw/i386/microvm.c
+++ b/hw/i386/microvm.c
@@ -320,6 +320,39 @@ static void microvm_fix_kernel_cmdline(MachineState *machine)
     g_free(cmdline);
 }
 
+static void microvm_device_pre_plug_cb(HotplugHandler *hotplug_dev,
+                                       DeviceState *dev, Error **errp)
+{
+    x86_cpu_pre_plug(hotplug_dev, dev, errp);
+}
+
+static void microvm_device_plug_cb(HotplugHandler *hotplug_dev,
+                                   DeviceState *dev, Error **errp)
+{
+    x86_cpu_plug(hotplug_dev, dev, errp);
+}
+
+static void microvm_device_unplug_request_cb(HotplugHandler *hotplug_dev,
+                                             DeviceState *dev, Error **errp)
+{
+    error_setg(errp, "unplug not supported by microvm");
+}
+
+static void microvm_device_unplug_cb(HotplugHandler *hotplug_dev,
+                                     DeviceState *dev, Error **errp)
+{
+    error_setg(errp, "unplug not supported by microvm");
+}
+
+static HotplugHandler *microvm_get_hotplug_handler(MachineState *machine,
+                                                   DeviceState *dev)
+{
+    if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+        return HOTPLUG_HANDLER(machine);
+    }
+    return NULL;
+}
+
 static void microvm_machine_state_init(MachineState *machine)
 {
     MicrovmMachineState *mms = MICROVM_MACHINE(machine);
@@ -503,6 +536,7 @@ static void microvm_machine_initfn(Object *obj)
 static void microvm_class_init(ObjectClass *oc, void *data)
 {
     MachineClass *mc = MACHINE_CLASS(oc);
+    HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
 
     mc->init = microvm_machine_state_init;
 
@@ -523,6 +557,13 @@ static void microvm_class_init(ObjectClass *oc, void *data)
     /* Machine class handlers */
     mc->reset = microvm_machine_reset;
 
+    /* hotplug (for cpu coldplug) */
+    mc->get_hotplug_handler = microvm_get_hotplug_handler;
+    hc->pre_plug = microvm_device_pre_plug_cb;
+    hc->plug = microvm_device_plug_cb;
+    hc->unplug_request = microvm_device_unplug_request_cb;
+    hc->unplug = microvm_device_unplug_cb;
+
     object_class_property_add(oc, MICROVM_MACHINE_PIC, "OnOffAuto",
                               microvm_machine_get_pic,
                               microvm_machine_set_pic,
@@ -572,6 +613,7 @@ static const TypeInfo microvm_machine_info = {
     .class_size    = sizeof(MicrovmMachineClass),
     .class_init    = microvm_class_init,
     .interfaces = (InterfaceInfo[]) {
+         { TYPE_HOTPLUG_HANDLER },
          { }
     },
 };
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 17/20] tests/acpi: allow microvm test data updates.
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (15 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 16/20] microvm: wire up hotplug Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-07 12:53 ` [PATCH v5 18/20] tests/acpi: allow override blkdev Gerd Hoffmann
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

Also add empty test data files.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 tests/qtest/bios-tables-test-allowed-diff.h | 3 +++
 tests/data/acpi/microvm/APIC                | 0
 tests/data/acpi/microvm/DSDT                | 0
 tests/data/acpi/microvm/FACP                | 0
 4 files changed, 3 insertions(+)
 create mode 100644 tests/data/acpi/microvm/APIC
 create mode 100644 tests/data/acpi/microvm/DSDT
 create mode 100644 tests/data/acpi/microvm/FACP

diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index dfb8523c8bf4..97c3fa621b7f 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1 +1,4 @@
 /* List of comma-separated changed AML files to ignore */
+"tests/data/acpi/microvm/APIC",
+"tests/data/acpi/microvm/DSDT",
+"tests/data/acpi/microvm/FACP",
diff --git a/tests/data/acpi/microvm/APIC b/tests/data/acpi/microvm/APIC
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/data/acpi/microvm/DSDT b/tests/data/acpi/microvm/DSDT
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/data/acpi/microvm/FACP b/tests/data/acpi/microvm/FACP
new file mode 100644
index 000000000000..e69de29bb2d1
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 18/20] tests/acpi: allow override blkdev
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (16 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 17/20] tests/acpi: allow microvm test data updates Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-10 19:48   ` Igor Mammedov
  2020-07-07 12:53 ` [PATCH v5 19/20] tests/acpi: add microvm test Gerd Hoffmann
                   ` (3 subsequent siblings)
  21 siblings, 1 reply; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

microvm needs virtio-blk instead of ide.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 tests/qtest/bios-tables-test.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index c315156858f4..24b715dce780 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -72,6 +72,7 @@ typedef struct {
     const char *variant;
     const char *uefi_fl1;
     const char *uefi_fl2;
+    const char *blkdev;
     const char *cd;
     const uint64_t ram_start;
     const uint64_t scan_len;
@@ -635,9 +636,10 @@ static void test_acpi_one(const char *params, test_data *data)
         args = g_strdup_printf("-machine %s,kernel-irqchip=off %s -accel tcg "
             "-net none -display none %s "
             "-drive id=hd0,if=none,file=%s,format=raw "
-            "-device ide-hd,drive=hd0 ",
+            "-device %s,drive=hd0 ",
              data->machine, data->tcg_only ? "" : "-accel kvm",
-             params ? params : "", disk);
+             params ? params : "", disk,
+             data->blkdev ?: "ide-hd");
     }
 
     data->qts = qtest_init(args);
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 19/20] tests/acpi: add microvm test
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (17 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 18/20] tests/acpi: allow override blkdev Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-10 19:49   ` Igor Mammedov
  2020-07-07 12:53 ` [PATCH v5 20/20] tests/acpi: update expected data files for microvm Gerd Hoffmann
                   ` (2 subsequent siblings)
  21 siblings, 1 reply; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 tests/qtest/bios-tables-test.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index 24b715dce780..b5b98d5c0742 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -1007,6 +1007,20 @@ static void test_acpi_virt_tcg_memhp(void)
 
 }
 
+static void test_acpi_microvm_tcg(void)
+{
+    test_data data;
+
+    memset(&data, 0, sizeof(data));
+    data.machine = "microvm";
+    data.required_struct_types = base_required_struct_types;
+    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
+    data.blkdev = "virtio-blk-device";
+    test_acpi_one(" -machine microvm,acpi=on,rtc=off",
+                  &data);
+    free_test_data(&data);
+}
+
 static void test_acpi_virt_tcg_numamem(void)
 {
     test_data data = {
@@ -1118,6 +1132,7 @@ int main(int argc, char *argv[])
         qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm);
         qtest_add_func("acpi/piix4/acpihmat", test_acpi_piix4_tcg_acpi_hmat);
         qtest_add_func("acpi/q35/acpihmat", test_acpi_q35_tcg_acpi_hmat);
+        qtest_add_func("acpi/microvm", test_acpi_microvm_tcg);
     } 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);
-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 20/20] tests/acpi: update expected data files for microvm
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (18 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 19/20] tests/acpi: add microvm test Gerd Hoffmann
@ 2020-07-07 12:53 ` Gerd Hoffmann
  2020-07-07 13:34 ` [PATCH v5 00/20] microvm: add acpi support no-reply
  2020-07-07 13:35 ` no-reply
  21 siblings, 0 replies; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-07 12:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, Shannon Zhao, qemu-arm,
	Gerd Hoffmann, Igor Mammedov, Paolo Bonzini, Richard Henderson

Also clear tests/qtest/bios-tables-test-allowed-diff.h

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 tests/qtest/bios-tables-test-allowed-diff.h |   3 ---
 tests/data/acpi/microvm/APIC                | Bin 0 -> 70 bytes
 tests/data/acpi/microvm/DSDT                | Bin 0 -> 365 bytes
 tests/data/acpi/microvm/FACP                | Bin 0 -> 268 bytes
 4 files changed, 3 deletions(-)

diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index 97c3fa621b7f..dfb8523c8bf4 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1,4 +1 @@
 /* List of comma-separated changed AML files to ignore */
-"tests/data/acpi/microvm/APIC",
-"tests/data/acpi/microvm/DSDT",
-"tests/data/acpi/microvm/FACP",
diff --git a/tests/data/acpi/microvm/APIC b/tests/data/acpi/microvm/APIC
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7472c7e830b6c7139720e93dd544d4441556661d 100644
GIT binary patch
literal 70
zcmZ<^@N{-#U|?Xp?&R<65v<@85#a0y6k`O6f!H9Lf#JbFFwFr}2jnsGfW!{`1CcCj
H|A7Jk<Z=uF

literal 0
HcmV?d00001

diff --git a/tests/data/acpi/microvm/DSDT b/tests/data/acpi/microvm/DSDT
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b7297dfe9a34bede2ad0d65281f0bc7497bbd358 100644
GIT binary patch
literal 365
zcmX9(%WA?v6uqN~#;dW@2S^JA=?9e2B3&nwF$SVZGd>C_j6YE5wz#n_gs%GoenLN`
zpW{k;$86@Fd(Irrxsi_M?+m~-VJ0WKAHL=?B917q*iIf_8y%W*_c&h3v1cYp<iDut
zLI^Pg&**u8ZO_O;U;2nK<1Tku=M&1^P-fG?`F|()bD3urNkp$TTvP^*e$0;bV;#H)
z4%U-4VilPxB#?O`#NdfS$mx?n$mVph{oQ~%Yf(EgZB?OS=l~o}=#*b=yGo^1+P}Fs
zYB_Ix*kyg-Kbtky0BievRfM=LcefT)Vfic<QphTciiFOx5YLsC&Wen#9aSPWsf7&a
j65Hhtd;1nJ=>DFd20*<S>z#XX{ze8pGFMFpU84R0a<feV

literal 0
HcmV?d00001

diff --git a/tests/data/acpi/microvm/FACP b/tests/data/acpi/microvm/FACP
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e52b16d24ac4f7b95a7d11a5f2ad801c0cb87147 100644
GIT binary patch
literal 268
zcmZ>BbPnKQWME*eb@F%i2v%^42yk`-iUEZfKx`0ARlp*^z`()4z{IrRAIMxM1_r8I
SLD0QG`x&72gWSRhWdi`;u?ztK

literal 0
HcmV?d00001

-- 
2.18.4



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 00/20] microvm: add acpi support
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (19 preceding siblings ...)
  2020-07-07 12:53 ` [PATCH v5 20/20] tests/acpi: update expected data files for microvm Gerd Hoffmann
@ 2020-07-07 13:34 ` no-reply
  2020-07-07 13:35 ` no-reply
  21 siblings, 0 replies; 35+ messages in thread
From: no-reply @ 2020-07-07 13:34 UTC (permalink / raw)
  To: kraxel
  Cc: lvivier, peter.maydell, thuth, ehabkost, slp, mst, qemu-devel,
	shannon.zhaosl, qemu-arm, kraxel, pbonzini, imammedo, rth

Patchew URL: https://patchew.org/QEMU/20200707125356.32450-1-kraxel@redhat.com/



Hi,

This series seems to have some coding style problems. See output below for
more information:

Type: series
Message-id: 20200707125356.32450-1-kraxel@redhat.com
Subject: [PATCH v5 00/20] microvm: add acpi support

=== TEST SCRIPT BEGIN ===
#!/bin/bash
git rev-parse base > /dev/null || exit 0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
./scripts/checkpatch.pl --mailback base..
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
From https://github.com/patchew-project/qemu
 * [new tag]         patchew/20200707132116.26207-1-f4bug@amsat.org -> patchew/20200707132116.26207-1-f4bug@amsat.org
Switched to a new branch 'test'
d5b6102 tests/acpi: update expected data files for microvm
4016e67 tests/acpi: add microvm test
7a0b05e tests/acpi: allow override blkdev
9855e16 tests/acpi: allow microvm test data updates.
e96b4cf microvm: wire up hotplug
c0f5744 x86: move cpu plug from pc to x86
d7dc51c x86: move acpi_dev from pc/microvm
c98bafc x86: constify x86_machine_is_*_enabled
9bf3547 microvm/acpi: disable virtio-mmio cmdline hack
c725465 microvm/acpi: use seabios with acpi=on
856eae6 microvm/acpi: use GSI 16-23 for virtio
4b04f91 microvm/acpi: add acpi_dsdt_add_virtio() for x86
1d5e0bf microvm/acpi: add minimal acpi support
6ec826e microvm: make virtio irq base runtime configurable
c3ca775 acpi: move acpi_dsdt_add_power_button() to ged
7d7d83c acpi: ged: add x86 device variant.
18cd04d acpi: ged: add control regs
c64763a seabios: add bios-microvm.bin binary
91801f8 seabios: add microvm config, update build rules
31f51e5 microvm: name qboot binary qboot.rom

=== OUTPUT BEGIN ===
1/20 Checking commit 31f51e53edea (microvm: name qboot binary qboot.rom)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#36: 
rename from pc-bios/bios-microvm.bin

total: 0 errors, 1 warnings, 35 lines checked

Patch 1/20 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
2/20 Checking commit 91801f804550 (seabios: add microvm config, update build rules)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#29: 
new file mode 100644

total: 0 errors, 1 warnings, 39 lines checked

Patch 2/20 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
3/20 Checking commit c64763a56c6a (seabios: add bios-microvm.bin binary)
4/20 Checking commit 18cd04d78b56 (acpi: ged: add control regs)
5/20 Checking commit 7d7d83cd1c2c (acpi: ged: add x86 device variant.)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#25: 
new file mode 100644

total: 0 errors, 1 warnings, 51 lines checked

Patch 5/20 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
6/20 Checking commit c3ca775f6e35 (acpi: move acpi_dsdt_add_power_button() to ged)
7/20 Checking commit 6ec826ec31e9 (microvm: make virtio irq base runtime configurable)
8/20 Checking commit 1d5e0bff7fc1 (microvm/acpi: add minimal acpi support)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#34: 
new file mode 100644

WARNING: Block comments use a leading /* on a separate line
#39: FILE: hw/i386/acpi-microvm.c:1:
+/* Support for generating ACPI tables and passing them to Guests

WARNING: Block comments use a leading /* on a separate line
#163: FILE: hw/i386/acpi-microvm.c:125:
+    table_offsets = g_array_new(false, true /* clear */,

WARNING: Block comments use a leading /* on a separate line
#167: FILE: hw/i386/acpi-microvm.c:129:
+                             64 /* Ensure FACS is aligned */,

WARNING: Block comments use a leading /* on a separate line
#168: FILE: hw/i386/acpi-microvm.c:130:
+                             false /* high memory */);

total: 0 errors, 5 warnings, 311 lines checked

Patch 8/20 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
9/20 Checking commit 4b04f911df7a (microvm/acpi: add acpi_dsdt_add_virtio() for x86)
10/20 Checking commit 856eae6a8af7 (microvm/acpi: use GSI 16-23 for virtio)
11/20 Checking commit c7254650d200 (microvm/acpi: use seabios with acpi=on)
12/20 Checking commit 9bf3547b321c (microvm/acpi: disable virtio-mmio cmdline hack)
13/20 Checking commit c98bafce4745 (x86: constify x86_machine_is_*_enabled)
14/20 Checking commit d7dc51c13d40 (x86: move acpi_dev from pc/microvm)
15/20 Checking commit c0f57441ad6c (x86: move cpu plug from pc to x86)
ERROR: space required before the open parenthesis '('
#344: FILE: hw/i386/x86.c:187:
+    if(!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) {

WARNING: Block comments use a leading /* on a separate line
#431: FILE: hw/i386/x86.c:274:
+    /* if 'address' properties socket-id/core-id/thread-id are not set, set them

WARNING: Block comments use a leading /* on a separate line
#434: FILE: hw/i386/x86.c:277:
+    /* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn()

WARNING: Block comments use a trailing */ on a separate line
#436: FILE: hw/i386/x86.c:279:
+     * CPUState::nr_cores and CPUState::nr_threads fields instead of globals */

WARNING: Block comments use a leading /* on a separate line
#484: FILE: hw/i386/x86.c:327:
+        /* If the number of CPUs can't be represented in 8 bits, the

WARNING: Block comments use a leading /* on a separate line
#502: FILE: hw/i386/x86.c:345:
+/* returns pointer to CPUArchId descriptor that matches CPU's apic_id

total: 1 errors, 5 warnings, 533 lines checked

Patch 15/20 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

16/20 Checking commit e96b4cfdddca (microvm: wire up hotplug)
17/20 Checking commit 9855e16bac52 (tests/acpi: allow microvm test data updates.)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#13: 
new file mode 100644

total: 0 errors, 1 warnings, 4 lines checked

Patch 17/20 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
18/20 Checking commit 7a0b05e95471 (tests/acpi: allow override blkdev)
19/20 Checking commit 4016e6747755 (tests/acpi: add microvm test)
20/20 Checking commit d5b610245ac6 (tests/acpi: update expected data files for microvm)
=== OUTPUT END ===

Test command exited with code: 1


The full log is available at
http://patchew.org/logs/20200707125356.32450-1-kraxel@redhat.com/testing.checkpatch/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 00/20] microvm: add acpi support
  2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
                   ` (20 preceding siblings ...)
  2020-07-07 13:34 ` [PATCH v5 00/20] microvm: add acpi support no-reply
@ 2020-07-07 13:35 ` no-reply
  21 siblings, 0 replies; 35+ messages in thread
From: no-reply @ 2020-07-07 13:35 UTC (permalink / raw)
  To: kraxel
  Cc: lvivier, peter.maydell, thuth, ehabkost, slp, mst, qemu-devel,
	shannon.zhaosl, qemu-arm, kraxel, pbonzini, imammedo, rth

Patchew URL: https://patchew.org/QEMU/20200707125356.32450-1-kraxel@redhat.com/



Hi,

This series failed the docker-quick@centos7 build test. Please find the testing commands and
their output below. If you have Docker installed, you can probably reproduce it
locally.

=== TEST SCRIPT BEGIN ===
#!/bin/bash
make docker-image-centos7 V=1 NETWORK=1
time make docker-test-quick@centos7 SHOW_ENV=1 J=14 NETWORK=1
=== TEST SCRIPT END ===

acpi-test: Warning! DSDT binary file mismatch. Actual [aml:/tmp/aml-YB3SN0], Expected [aml:tests/data/acpi/microvm/DSDT].
See source file tests/qtest/bios-tables-test.c for instructions on how to update expected files.
to see ASL diff between mismatched files install IASL, rebuild QEMU from scratch and re-run tests with V=1 environment variable set**
ERROR:/tmp/qemu-test/src/tests/qtest/bios-tables-test.c:495:test_acpi_asl: assertion failed: (all_tables_match)
ERROR - Bail out! ERROR:/tmp/qemu-test/src/tests/qtest/bios-tables-test.c:495:test_acpi_asl: assertion failed: (all_tables_match)
make: *** [check-qtest-x86_64] Error 1
make: *** Waiting for unfinished jobs....
  TEST    iotest-qcow2: 030
  TEST    iotest-qcow2: 031
---
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['sudo', '-n', 'docker', 'run', '--label', 'com.qemu.instance.uuid=8f5f41e386b845a9a0f5edc2ade231c7', '-u', '1003', '--security-opt', 'seccomp=unconfined', '--rm', '-e', 'TARGET_LIST=', '-e', 'EXTRA_CONFIGURE_OPTS=', '-e', 'V=', '-e', 'J=14', '-e', 'DEBUG=', '-e', 'SHOW_ENV=1', '-e', 'CCACHE_DIR=/var/tmp/ccache', '-v', '/home/patchew2/.cache/qemu-docker-ccache:/var/tmp/ccache:z', '-v', '/var/tmp/patchew-tester-tmp-dd7_unsg/src/docker-src.2020-07-07-09.19.21.10455:/var/tmp/qemu:z,ro', 'qemu:centos7', '/var/tmp/qemu/run', 'test-quick']' returned non-zero exit status 2.
filter=--filter=label=com.qemu.instance.uuid=8f5f41e386b845a9a0f5edc2ade231c7
make[1]: *** [docker-run] Error 1
make[1]: Leaving directory `/var/tmp/patchew-tester-tmp-dd7_unsg/src'
make: *** [docker-run-test-quick@centos7] Error 2

real    15m42.335s
user    0m8.981s


The full log is available at
http://patchew.org/logs/20200707125356.32450-1-kraxel@redhat.com/testing.docker-quick@centos7/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 08/20] microvm/acpi: add minimal acpi support
  2020-07-07 12:53 ` [PATCH v5 08/20] microvm/acpi: add minimal acpi support Gerd Hoffmann
@ 2020-07-08 16:52   ` Michael S. Tsirkin
  2020-07-09 12:33     ` Gerd Hoffmann
  0 siblings, 1 reply; 35+ messages in thread
From: Michael S. Tsirkin @ 2020-07-08 16:52 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, qemu-devel, Shannon Zhao, qemu-arm, Igor Mammedov,
	Paolo Bonzini, Richard Henderson

On Tue, Jul 07, 2020 at 02:53:44PM +0200, Gerd Hoffmann wrote:
> $subject says all.  Can be controlled using -M microvm,acpi=on/off.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

Overall I don't see bugs here. Some comments are bit confusing
and I point that out below. With that addressed:

Reviewed-by: Michael S. Tsirkin <mst@redhat.com>



> ---
>  hw/i386/acpi-microvm.h    |   8 ++
>  include/hw/i386/microvm.h |   9 ++
>  hw/i386/acpi-microvm.c    | 195 ++++++++++++++++++++++++++++++++++++++
>  hw/i386/microvm.c         |  40 ++++++++
>  hw/i386/Kconfig           |   1 +
>  hw/i386/Makefile.objs     |   1 +
>  6 files changed, 254 insertions(+)
>  create mode 100644 hw/i386/acpi-microvm.h
>  create mode 100644 hw/i386/acpi-microvm.c
> 
> diff --git a/hw/i386/acpi-microvm.h b/hw/i386/acpi-microvm.h
> new file mode 100644
> index 000000000000..dfe853690e15
> --- /dev/null
> +++ b/hw/i386/acpi-microvm.h
> @@ -0,0 +1,8 @@
> +#ifndef HW_I386_ACPI_MICROVM_H
> +#define HW_I386_ACPI_MICROVM_H
> +
> +#include "hw/i386/microvm.h"
> +
> +void acpi_setup_microvm(MicrovmMachineState *mms);
> +
> +#endif
> diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h
> index 03e735723726..b6e0d4395af7 100644
> --- a/include/hw/i386/microvm.h
> +++ b/include/hw/i386/microvm.h
> @@ -24,12 +24,18 @@
>  
>  #include "hw/boards.h"
>  #include "hw/i386/x86.h"
> +#include "hw/acpi/acpi_dev_interface.h"
>  
>  /* Platform virtio definitions */
>  #define VIRTIO_MMIO_BASE      0xfeb00000
>  #define VIRTIO_NUM_TRANSPORTS 8
>  #define VIRTIO_CMDLINE_MAXLEN 64
>  
> +#define GED_MMIO_BASE         0xfea00000
> +#define GED_MMIO_BASE_MEMHP   (GED_MMIO_BASE + 0x100)
> +#define GED_MMIO_BASE_REGS    (GED_MMIO_BASE + 0x200)
> +#define GED_MMIO_IRQ          9
> +
>  /* Machine type options */
>  #define MICROVM_MACHINE_PIT                 "pit"
>  #define MICROVM_MACHINE_PIC                 "pic"
> @@ -58,6 +64,9 @@ typedef struct {
>      /* Machine state */
>      uint32_t virtio_irq_base;
>      bool kernel_cmdline_fixed;
> +    Notifier machine_done;
> +    Notifier powerdown_req;
> +    AcpiDeviceIf *acpi_dev;
>  } MicrovmMachineState;
>  
>  #define TYPE_MICROVM_MACHINE   MACHINE_TYPE_NAME("microvm")
> diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c
> new file mode 100644
> index 000000000000..6c4178caefee
> --- /dev/null
> +++ b/hw/i386/acpi-microvm.c
> @@ -0,0 +1,195 @@
> +/* Support for generating ACPI tables and passing them to Guests
> + *
> + * Copyright (C) 2008-2010  Kevin O'Connor <kevin@koconnor.net>
> + * Copyright (C) 2006 Fabrice Bellard
> + * Copyright (C) 2013 Red Hat Inc
> + *
> + * Author: Michael S. Tsirkin <mst@redhat.com>
> + *
> + * 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 <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +
> +#include "exec/memory.h"
> +#include "hw/acpi/acpi.h"
> +#include "hw/acpi/aml-build.h"
> +#include "hw/acpi/bios-linker-loader.h"
> +#include "hw/acpi/generic_event_device.h"
> +#include "hw/acpi/utils.h"
> +#include "hw/boards.h"
> +#include "hw/i386/fw_cfg.h"
> +#include "hw/i386/microvm.h"
> +
> +#include "acpi-common.h"
> +#include "acpi-microvm.h"
> +
> +static void
> +build_dsdt_microvm(GArray *table_data, BIOSLinker *linker,
> +                   MicrovmMachineState *mms)
> +{
> +    X86MachineState *x86ms = X86_MACHINE(mms);
> +    Aml *dsdt, *sb_scope, *scope, *pkg;
> +    bool ambiguous;
> +    Object *isabus;
> +
> +    isabus = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous);
> +    assert(isabus);
> +    assert(!ambiguous);
> +
> +    dsdt = init_aml_allocator();
> +
> +    /* Reserve space for header */
> +    acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader));
> +
> +    sb_scope = aml_scope("_SB");
> +    fw_cfg_add_acpi_dsdt(sb_scope, x86ms->fw_cfg);
> +    isa_build_aml(ISA_BUS(isabus), sb_scope);
> +    build_ged_aml(sb_scope, GED_DEVICE, HOTPLUG_HANDLER(mms->acpi_dev),
> +                  GED_MMIO_IRQ, AML_SYSTEM_MEMORY, GED_MMIO_BASE);
> +    acpi_dsdt_add_power_button(sb_scope);
> +    aml_append(dsdt, sb_scope);
> +
> +    scope = aml_scope("\\");
> +    pkg = aml_package(4);
> +    aml_append(pkg, aml_int(5)); /* SLEEP_CONTROL_REG.SLP_TYP */

I'm not sure what does the comment refer to here.
Does this 5 match
the value IO handler tests against? A macro might make sense then ...

Below is from "7.3.4 System \_Sx states" right?


> +    aml_append(pkg, aml_int(0)); /* ignored */
> +    aml_append(pkg, aml_int(0)); /* reserved */
> +    aml_append(pkg, aml_int(0)); /* reserved */
> +    aml_append(scope, aml_name_decl("_S5", pkg));
> +    aml_append(dsdt, scope);
> +
> +    /* copy AML table into ACPI tables blob and patch header there */
> +    g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
> +    build_header(linker, table_data,
> +        (void *)(table_data->data + table_data->len - dsdt->buf->len),
> +        "DSDT", dsdt->buf->len, 2, NULL, NULL);

/* DSDT always uses revision 2 */.


> +    free_aml_allocator();
> +}
> +
> +static void acpi_build_microvm(AcpiBuildTables *tables,
> +                               MicrovmMachineState *mms)
> +{
> +    MachineState *machine = MACHINE(mms);
> +    GArray *table_offsets;
> +    GArray *tables_blob = tables->table_data;
> +    unsigned dsdt, xsdt;
> +    AcpiFadtData pmfadt = {
> +        /*
> +         * minimum version for ACPI_FADT_F_HW_REDUCED_ACPI,
> +         * see acpi spec "4.1 Hardware-Reduced ACPI"

Spec version - I'm guessing ACPI spec 5.0.
And I think here is where you refer to
	Table 5-34 Fixed ACPI Description Table (FADT) Format

> +         */
> +        .rev = 5,
> +        .minor_ver = 1,

So 5.1 I am guessing just copied from virt/arm?
Or do you know why?
If not all we can say is     /* ACPI v5.1 */
like ARM does, rest is guesswork ...

> +
> +        .flags = ((1 << ACPI_FADT_F_HW_REDUCED_ACPI) |
> +                  (1 << ACPI_FADT_F_RESET_REG_SUP)),
> +
> +        /* Table 5-33 FADT Format -- SLEEP_CONTROL_REG */

You need to use the earliest spec version that includes
a specific feature - and document which one it is.
In version 5 table 5-33 is XSDT.

Generally it took me a while to understand this comment.
It makes it look like
one needs to find SLEEP_CONTROL_REG in Table 5-33 
You mean the address refers to SLEEP_CONTROL_REG.
So put the comment near the address pls.


But the main poit is AcpiFadtData actually has nothing to do with
FADT format. It's an abstracted API 


> +        .sleep_ctl = {
> +            .space_id = AML_AS_SYSTEM_MEMORY,
> +            .bit_width = 8,
> +            .address = GED_MMIO_BASE_REGS + ACPI_GED_REG_SLEEP_CTL,
> +        },
> +
> +        /* Table 5-33 FADT Format -- SLEEP_STATUS_REG */
> +        .sleep_sts = {
> +            .space_id = AML_AS_SYSTEM_MEMORY,
> +            .bit_width = 8,
> +            .address = GED_MMIO_BASE_REGS + ACPI_GED_REG_SLEEP_STS,
> +        },
> +
> +        /* Table 5-33 FADT Format -- RESET_REG */
> +        .reset_reg = {
> +            .space_id = AML_AS_SYSTEM_MEMORY,
> +            .bit_width = 8,
> +            .address = GED_MMIO_BASE_REGS + ACPI_GED_REG_RESET,
> +        },
> +
> +        /* Table 5-33 FADT Format -- RESET_VALUE */
> +        .reset_val = ACPI_GED_RESET_VALUE,
> +    };
> +
> +    table_offsets = g_array_new(false, true /* clear */,
> +                                        sizeof(uint32_t));
> +    bios_linker_loader_alloc(tables->linker,
> +                             ACPI_BUILD_TABLE_FILE, tables_blob,
> +                             64 /* Ensure FACS is aligned */,
> +                             false /* high memory */);
> +
> +    dsdt = tables_blob->len;
> +    build_dsdt_microvm(tables_blob, tables->linker, mms);
> +
> +    pmfadt.dsdt_tbl_offset = &dsdt;
> +    pmfadt.xdsdt_tbl_offset = &dsdt;
> +    acpi_add_table(table_offsets, tables_blob);
> +    build_fadt(tables_blob, tables->linker, &pmfadt, NULL, NULL);
> +
> +    acpi_add_table(table_offsets, tables_blob);
> +    acpi_build_madt(tables_blob, tables->linker, X86_MACHINE(machine),
> +                    mms->acpi_dev, false);
> +
> +    xsdt = tables_blob->len;
> +    build_xsdt(tables_blob, tables->linker, table_offsets, NULL, NULL);
> +
> +    /* RSDP is in FSEG memory, so allocate it separately */
> +    {
> +        AcpiRsdpData rsdp_data = {
> +            /* Table 5-27 RSDP Structure */

RSDP is since ACPI 2.0, table number there is different.

> +            .revision = 2, /* rev2 needed for xsdt support */
> +            .oem_id = ACPI_BUILD_APPNAME6,
> +            .xsdt_tbl_offset = &xsdt,
> +            .rsdt_tbl_offset = NULL,
> +        };
> +        build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
> +    }
> +
> +    /* Cleanup memory that's no longer used. */
> +    g_array_free(table_offsets, true);
> +}
> +
> +static void acpi_build_no_update(void *build_opaque)
> +{
> +    /* nothing, microvm tables don't change at runtime */
> +}
> +
> +void acpi_setup_microvm(MicrovmMachineState *mms)
> +{
> +    X86MachineState *x86ms = X86_MACHINE(mms);
> +    AcpiBuildTables tables;
> +
> +    assert(x86ms->fw_cfg);
> +
> +    if (!x86_machine_is_acpi_enabled(x86ms)) {
> +        return;
> +    }
> +
> +    acpi_build_tables_init(&tables);
> +    acpi_build_microvm(&tables, mms);
> +
> +    /* Now expose it all to Guest */
> +    acpi_add_rom_blob(acpi_build_no_update, NULL,
> +                      tables.table_data,
> +                      ACPI_BUILD_TABLE_FILE,
> +                      ACPI_BUILD_TABLE_MAX_SIZE);
> +    acpi_add_rom_blob(acpi_build_no_update, NULL,
> +                      tables.linker->cmd_blob,
> +                      "etc/table-loader", 0);
> +    acpi_add_rom_blob(acpi_build_no_update, NULL,
> +                      tables.rsdp,
> +                      ACPI_BUILD_RSDP_FILE, 0);
> +
> +    acpi_build_tables_cleanup(&tables, false);
> +}
> diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
> index ab6ee6c67b1a..75eca7306b11 100644
> --- a/hw/i386/microvm.c
> +++ b/hw/i386/microvm.c
> @@ -26,6 +26,8 @@
>  #include "sysemu/cpus.h"
>  #include "sysemu/numa.h"
>  #include "sysemu/reset.h"
> +#include "sysemu/runstate.h"
> +#include "acpi-microvm.h"
>  
>  #include "hw/loader.h"
>  #include "hw/irq.h"
> @@ -41,6 +43,8 @@
>  #include "hw/i386/e820_memory_layout.h"
>  #include "hw/i386/fw_cfg.h"
>  #include "hw/virtio/virtio-mmio.h"
> +#include "hw/acpi/acpi.h"
> +#include "hw/acpi/generic_event_device.h"
>  
>  #include "cpu.h"
>  #include "elf.h"
> @@ -129,6 +133,17 @@ static void microvm_devices_init(MicrovmMachineState *mms)
>      }
>  
>      /* Optional and legacy devices */
> +    if (x86_machine_is_acpi_enabled(x86ms)) {
> +        DeviceState *dev = qdev_new(TYPE_ACPI_GED_X86);
> +        qdev_prop_set_uint32(dev, "ged-event", ACPI_GED_PWR_DOWN_EVT);
> +        sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, GED_MMIO_BASE);
> +        /* sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, GED_MMIO_BASE_MEMHP); */
> +        sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, GED_MMIO_BASE_REGS);
> +        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
> +                           x86ms->gsi[GED_MMIO_IRQ]);
> +        sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
> +        mms->acpi_dev = ACPI_DEVICE_IF(dev);
> +    }
>  
>      if (mms->pic == ON_OFF_AUTO_ON || mms->pic == ON_OFF_AUTO_AUTO) {
>          qemu_irq *i8259;
> @@ -438,6 +453,26 @@ static void microvm_machine_set_auto_kernel_cmdline(Object *obj, bool value,
>      mms->auto_kernel_cmdline = value;
>  }
>  
> +static void microvm_machine_done(Notifier *notifier, void *data)
> +{
> +    MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
> +                                            machine_done);
> +
> +    acpi_setup_microvm(mms);
> +}
> +
> +static void microvm_powerdown_req(Notifier *notifier, void *data)
> +{
> +    MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
> +                                            powerdown_req);
> +
> +    if (mms->acpi_dev) {
> +        Object *obj = OBJECT(mms->acpi_dev);
> +        AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
> +        adevc->send_event(mms->acpi_dev, ACPI_POWER_DOWN_STATUS);
> +    }
> +}
> +
>  static void microvm_machine_initfn(Object *obj)
>  {
>      MicrovmMachineState *mms = MICROVM_MACHINE(obj);
> @@ -452,6 +487,11 @@ static void microvm_machine_initfn(Object *obj)
>  
>      /* State */
>      mms->kernel_cmdline_fixed = false;
> +
> +    mms->machine_done.notify = microvm_machine_done;
> +    qemu_add_machine_init_done_notifier(&mms->machine_done);
> +    mms->powerdown_req.notify = microvm_powerdown_req;
> +    qemu_register_powerdown_notifier(&mms->powerdown_req);
>  }
>  
>  static void microvm_class_init(ObjectClass *oc, void *data)
> diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig
> index c93f32f6579d..be746bcb49eb 100644
> --- a/hw/i386/Kconfig
> +++ b/hw/i386/Kconfig
> @@ -102,6 +102,7 @@ config MICROVM
>      select I8259
>      select MC146818RTC
>      select VIRTIO_MMIO
> +    select ACPI_HW_REDUCED
>  
>  config X86_IOMMU
>      bool
> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
> index 622739305882..bbb2fe78f3cd 100644
> --- a/hw/i386/Makefile.objs
> +++ b/hw/i386/Makefile.objs
> @@ -19,3 +19,4 @@ obj-y += kvmvapic.o
>  obj-$(CONFIG_ACPI) += acpi-common.o
>  obj-$(CONFIG_ACPI_HW_REDUCED) += generic_event_device_x86.o
>  obj-$(CONFIG_PC) += acpi-build.o
> +obj-$(CONFIG_MICROVM) += acpi-microvm.o
> -- 
> 2.18.4



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 08/20] microvm/acpi: add minimal acpi support
  2020-07-08 16:52   ` Michael S. Tsirkin
@ 2020-07-09 12:33     ` Gerd Hoffmann
  2020-07-10 19:30       ` Igor Mammedov
  0 siblings, 1 reply; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-09 12:33 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, qemu-devel, Shannon Zhao, qemu-arm, Igor Mammedov,
	Paolo Bonzini, Richard Henderson

  Hi,

> > +    scope = aml_scope("\\");
> > +    pkg = aml_package(4);
> > +    aml_append(pkg, aml_int(5)); /* SLEEP_CONTROL_REG.SLP_TYP */
> 
> I'm not sure what does the comment refer to here.

It's the register field the value gets written to.
With full acpi this is PM1a_CNT.SLP_TYP, hw-reduced uses
SLEEP_CONTROL_REG.SLP_TYP instead.  This is cut&paste from pc/q35
version + adapted for hw-reduced.

> Does this 5 match
> the value IO handler tests against?

Yes.  "5" for S5 state (aka poweroff).  Can add a #define.

> Below is from "7.3.4 System \_Sx states" right?

"7.4.2 \_Sx (System States)" here (ACPI 6.3), guess that is the same.

> > +    AcpiFadtData pmfadt = {
> > +        /*
> > +         * minimum version for ACPI_FADT_F_HW_REDUCED_ACPI,
> > +         * see acpi spec "4.1 Hardware-Reduced ACPI"
> 
> Spec version - I'm guessing ACPI spec 5.0.

6.3

> And I think here is where you refer to
> 	Table 5-34 Fixed ACPI Description Table (FADT) Format

Table 5-33 FADT Format

> > +         */
> > +        .rev = 5,
> > +        .minor_ver = 1,
> 
> So 5.1 I am guessing just copied from virt/arm?

Yes.

> > +        .flags = ((1 << ACPI_FADT_F_HW_REDUCED_ACPI) |
> > +                  (1 << ACPI_FADT_F_RESET_REG_SUP)),
> > +
> > +        /* Table 5-33 FADT Format -- SLEEP_CONTROL_REG */
> 
> You need to use the earliest spec version that includes
> a specific feature - and document which one it is.

Phew.  Isn't it easier to just use table and field name then, so it is
easy to find in whatever version of the spec you have at hand?  Also how
can I figure the earliest spec version easily?

Sometimes the 6.3 spec documents which table version added specific
fields, sometimes not ...

Is the table version synced with the acpi spec version?  Does DSDT v2
mean the DSDT format was updated for ACPI 2.0 and hasn't changed since?

> But the main poit is AcpiFadtData actually has nothing to do with
> FADT format. It's an abstracted API 

The FADT is generated from AcpiFadtData.  There is a 1:1 relationship
between most AcpiFadtData fields and FADT table entries.  This isn't
what I would call "has nothing to do with" ...

> > +    xsdt = tables_blob->len;
> > +    build_xsdt(tables_blob, tables->linker, table_offsets, NULL, NULL);
> > +
> > +    /* RSDP is in FSEG memory, so allocate it separately */
> > +    {
> > +        AcpiRsdpData rsdp_data = {
> > +            /* Table 5-27 RSDP Structure */
> 
> RSDP is since ACPI 2.0, table number there is different.

References to ACPI 2.0 are almost useless.  ACPI 5.0 is the oldest
version uefi.org offers for download.

Guess that underlines the point I made above that referencing specific
versions of the spec doesn't work very well ...

take care,
  Gerd



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 04/20] acpi: ged: add control regs
  2020-07-07 12:53 ` [PATCH v5 04/20] acpi: ged: add control regs Gerd Hoffmann
@ 2020-07-10 19:07   ` Igor Mammedov
  0 siblings, 0 replies; 35+ messages in thread
From: Igor Mammedov @ 2020-07-10 19:07 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, qemu-devel, Shannon Zhao,
	qemu-arm, Paolo Bonzini, Richard Henderson

On Tue,  7 Jul 2020 14:53:40 +0200
Gerd Hoffmann <kraxel@redhat.com> wrote:

> Add control regs (sleep, reset) for hw-reduced acpi.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

with below comments addressed:

   Reviewed-by: Igor Mammedov <imammedo@redhat.com>

> ---
>  include/hw/acpi/generic_event_device.h |  7 ++++
>  hw/acpi/generic_event_device.c         | 44 ++++++++++++++++++++++++++
>  2 files changed, 51 insertions(+)
> 
> diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h
> index 90a9180db572..474c92198080 100644
> --- a/include/hw/acpi/generic_event_device.h
> +++ b/include/hw/acpi/generic_event_device.h
> @@ -72,6 +72,12 @@
>  #define ACPI_GED_EVT_SEL_OFFSET    0x0
>  #define ACPI_GED_EVT_SEL_LEN       0x4
>  
> +#define ACPI_GED_REG_SLEEP_CTL     0x00
> +#define ACPI_GED_REG_SLEEP_STS     0x01
> +#define ACPI_GED_REG_RESET         0x02
> +#define   ACPI_GED_RESET_VALUE     0x42
          ^^ too many ' '

also it would be nice to point out where vaule comes from
(if it's from spec then ref to spec pls)

> +#define ACPI_GED_REG_COUNT         0x03
> +
>  #define GED_DEVICE      "GED"
>  #define AML_GED_EVT_REG "EREG"
>  #define AML_GED_EVT_SEL "ESEL"
> @@ -87,6 +93,7 @@
>  
>  typedef struct GEDState {
>      MemoryRegion evt;
> +    MemoryRegion regs;
>      uint32_t     sel;
>  } GEDState;
>  
> diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
> index b8abdefa1c77..491df80a5cc7 100644
> --- a/hw/acpi/generic_event_device.c
> +++ b/hw/acpi/generic_event_device.c
> @@ -20,6 +20,7 @@
>  #include "hw/qdev-properties.h"
>  #include "migration/vmstate.h"
>  #include "qemu/error-report.h"
> +#include "sysemu/runstate.h"
>  
>  static const uint32_t ged_supported_events[] = {
>      ACPI_GED_MEM_HOTPLUG_EVT,
> @@ -176,6 +177,45 @@ static const MemoryRegionOps ged_evt_ops = {
>      },
>  };
>  
> +static uint64_t ged_regs_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    return 0;
> +}
> +
> +static void ged_regs_write(void *opaque, hwaddr addr, uint64_t data,
> +                           unsigned int size)
> +{
> +    bool slp_en;
> +    int slp_typ;
> +
> +    switch (addr) {
> +    case ACPI_GED_REG_SLEEP_CTL:
> +        slp_typ = (data >> 2) & 0x07;
> +        slp_en  = (data >> 5) & 0x01;
> +        if (slp_en && slp_typ == 5) {

replace magic 5 with something more descriptive and use it also in 8/20
during initializing _S5 package

> +            qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
> +        }
> +        return;
> +    case ACPI_GED_REG_SLEEP_STS:
> +        return;
> +    case ACPI_GED_REG_RESET:
> +        if (data == ACPI_GED_RESET_VALUE) {
> +            qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
> +        }
> +        return;
> +    }
> +}
> +
> +static const MemoryRegionOps ged_regs_ops = {
> +    .read = ged_regs_read,
> +    .write = ged_regs_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +
>  static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
>                                      DeviceState *dev, Error **errp)
>  {
> @@ -332,6 +372,10 @@ 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);
> +
> +    memory_region_init_io(&ged_st->regs, obj, &ged_regs_ops, ged_st,
> +                          TYPE_ACPI_GED "-regs", ACPI_GED_REG_COUNT);
> +    sysbus_init_mmio(sbd, &ged_st->regs);
>  }
>  
>  static void acpi_ged_class_init(ObjectClass *class, void *data)



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 07/20] microvm: make virtio irq base runtime configurable
  2020-07-07 12:53 ` [PATCH v5 07/20] microvm: make virtio irq base runtime configurable Gerd Hoffmann
@ 2020-07-10 19:09   ` Igor Mammedov
  0 siblings, 0 replies; 35+ messages in thread
From: Igor Mammedov @ 2020-07-10 19:09 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, qemu-devel, Shannon Zhao,
	qemu-arm, Paolo Bonzini, Richard Henderson

On Tue,  7 Jul 2020 14:53:43 +0200
Gerd Hoffmann <kraxel@redhat.com> wrote:

> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> Reviewed-by: Sergio Lopez <slp@redhat.com>

Reviewed-by: Igor Mammedov <imammedo@redhat.com>


> ---
>  include/hw/i386/microvm.h |  2 +-
>  hw/i386/microvm.c         | 11 +++++++----
>  2 files changed, 8 insertions(+), 5 deletions(-)
> 
> diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h
> index fd34b78e0d2a..03e735723726 100644
> --- a/include/hw/i386/microvm.h
> +++ b/include/hw/i386/microvm.h
> @@ -27,7 +27,6 @@
>  
>  /* Platform virtio definitions */
>  #define VIRTIO_MMIO_BASE      0xfeb00000
> -#define VIRTIO_IRQ_BASE       5
>  #define VIRTIO_NUM_TRANSPORTS 8
>  #define VIRTIO_CMDLINE_MAXLEN 64
>  
> @@ -57,6 +56,7 @@ typedef struct {
>      bool auto_kernel_cmdline;
>  
>      /* Machine state */
> +    uint32_t virtio_irq_base;
>      bool kernel_cmdline_fixed;
>  } MicrovmMachineState;
>  
> diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
> index 1300c396947b..ab6ee6c67b1a 100644
> --- a/hw/i386/microvm.c
> +++ b/hw/i386/microvm.c
> @@ -121,10 +121,11 @@ static void microvm_devices_init(MicrovmMachineState *mms)
>  
>      kvmclock_create();
>  
> +    mms->virtio_irq_base = 5;
>      for (i = 0; i < VIRTIO_NUM_TRANSPORTS; i++) {
>          sysbus_create_simple("virtio-mmio",
>                               VIRTIO_MMIO_BASE + i * 512,
> -                             x86ms->gsi[VIRTIO_IRQ_BASE + i]);
> +                             x86ms->gsi[mms->virtio_irq_base + i]);
>      }
>  
>      /* Optional and legacy devices */
> @@ -227,7 +228,7 @@ static void microvm_memory_init(MicrovmMachineState *mms)
>      x86ms->ioapic_as = &address_space_memory;
>  }
>  
> -static gchar *microvm_get_mmio_cmdline(gchar *name)
> +static gchar *microvm_get_mmio_cmdline(gchar *name, uint32_t virtio_irq_base)
>  {
>      gchar *cmdline;
>      gchar *separator;
> @@ -247,7 +248,7 @@ static gchar *microvm_get_mmio_cmdline(gchar *name)
>      ret = g_snprintf(cmdline, VIRTIO_CMDLINE_MAXLEN,
>                       " virtio_mmio.device=512@0x%lx:%ld",
>                       VIRTIO_MMIO_BASE + index * 512,
> -                     VIRTIO_IRQ_BASE + index);
> +                     virtio_irq_base + index);
>      if (ret < 0 || ret >= VIRTIO_CMDLINE_MAXLEN) {
>          g_free(cmdline);
>          return NULL;
> @@ -259,6 +260,7 @@ static gchar *microvm_get_mmio_cmdline(gchar *name)
>  static void microvm_fix_kernel_cmdline(MachineState *machine)
>  {
>      X86MachineState *x86ms = X86_MACHINE(machine);
> +    MicrovmMachineState *mms = MICROVM_MACHINE(machine);
>      BusState *bus;
>      BusChild *kid;
>      char *cmdline;
> @@ -282,7 +284,8 @@ static void microvm_fix_kernel_cmdline(MachineState *machine)
>              BusState *mmio_bus = &mmio_virtio_bus->parent_obj;
>  
>              if (!QTAILQ_EMPTY(&mmio_bus->children)) {
> -                gchar *mmio_cmdline = microvm_get_mmio_cmdline(mmio_bus->name);
> +                gchar *mmio_cmdline = microvm_get_mmio_cmdline
> +                    (mmio_bus->name, mms->virtio_irq_base);
>                  if (mmio_cmdline) {
>                      char *newcmd = g_strjoin(NULL, cmdline, mmio_cmdline, NULL);
>                      g_free(mmio_cmdline);



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 08/20] microvm/acpi: add minimal acpi support
  2020-07-09 12:33     ` Gerd Hoffmann
@ 2020-07-10 19:30       ` Igor Mammedov
  2020-07-16  8:52         ` Gerd Hoffmann
  0 siblings, 1 reply; 35+ messages in thread
From: Igor Mammedov @ 2020-07-10 19:30 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, qemu-devel, Shannon Zhao,
	qemu-arm, Paolo Bonzini, Richard Henderson

On Thu, 9 Jul 2020 14:33:32 +0200
Gerd Hoffmann <kraxel@redhat.com> wrote:

>   Hi,
> 
> > > +    scope = aml_scope("\\");
> > > +    pkg = aml_package(4);
> > > +    aml_append(pkg, aml_int(5)); /* SLEEP_CONTROL_REG.SLP_TYP */  
> > 
> > I'm not sure what does the comment refer to here.  
> 
> It's the register field the value gets written to.
> With full acpi this is PM1a_CNT.SLP_TYP, hw-reduced uses
> SLEEP_CONTROL_REG.SLP_TYP instead.  This is cut&paste from pc/q35
> version + adapted for hw-reduced.
> 
> > Does this 5 match
> > the value IO handler tests against?  
> 
> Yes.  "5" for S5 state (aka poweroff).  Can add a #define.
> 
> > Below is from "7.3.4 System \_Sx states" right?  
> 
> "7.4.2 \_Sx (System States)" here (ACPI 6.3), guess that is the same.
> 
> > > +    AcpiFadtData pmfadt = {
> > > +        /*
> > > +         * minimum version for ACPI_FADT_F_HW_REDUCED_ACPI,
> > > +         * see acpi spec "4.1 Hardware-Reduced ACPI"  
> > 
> > Spec version - I'm guessing ACPI spec 5.0.  
> 
> 6.3
> 
> > And I think here is where you refer to
> > 	Table 5-34 Fixed ACPI Description Table (FADT) Format  
> 
> Table 5-33 FADT Format
> 
> > > +         */
> > > +        .rev = 5,
> > > +        .minor_ver = 1,  
> > 
> > So 5.1 I am guessing just copied from virt/arm?  
> 
> Yes.
> 
> > > +        .flags = ((1 << ACPI_FADT_F_HW_REDUCED_ACPI) |
> > > +                  (1 << ACPI_FADT_F_RESET_REG_SUP)),
> > > +
> > > +        /* Table 5-33 FADT Format -- SLEEP_CONTROL_REG */  
> > 
> > You need to use the earliest spec version that includes
> > a specific feature - and document which one it is.  
> 
> Phew.  Isn't it easier to just use table and field name then, so it is
> easy to find in whatever version of the spec you have at hand?  Also how
> can I figure the earliest spec version easily?
> 
> Sometimes the 6.3 spec documents which table version added specific
> fields, sometimes not ...
> 
> Is the table version synced with the acpi spec version?  Does DSDT v2
> mean the DSDT format was updated for ACPI 2.0 and hasn't changed since?

not necessarily, even if it's pain to check for earliest spec where
feature appeared, it's the best and the least ambiguos comment format to
refference spec, i.e. (do not count on chapter/table numbering/naming being
stable accross versions)

/* Spec name + ver: chapter/table where the feature is described */

something like:

/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefObjectType */                 
Aml *aml_object_type(Aml *object)  

> 
> > But the main poit is AcpiFadtData actually has nothing to do with
> > FADT format. It's an abstracted API   
> 
> The FADT is generated from AcpiFadtData.  There is a 1:1 relationship
> between most AcpiFadtData fields and FADT table entries.  This isn't
> what I would call "has nothing to do with" ...
> 
> > > +    xsdt = tables_blob->len;
> > > +    build_xsdt(tables_blob, tables->linker, table_offsets, NULL, NULL);
> > > +
> > > +    /* RSDP is in FSEG memory, so allocate it separately */
> > > +    {
> > > +        AcpiRsdpData rsdp_data = {
> > > +            /* Table 5-27 RSDP Structure */  
> > 
> > RSDP is since ACPI 2.0, table number there is different.  
> 
> References to ACPI 2.0 are almost useless.  ACPI 5.0 is the oldest
> version uefi.org offers for download.
all versions are at (starting from 1.0)
https://uefi.org/acpi/specs

> Guess that underlines the point I made above that referencing specific
> versions of the spec doesn't work very well ...

so far that worked well, effect of requiring spec+version was less
questions during review as reviewer doesn't have to guess where
it's documented.

> 
> take care,
>   Gerd
> 



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 15/20] x86: move cpu plug from pc to x86
  2020-07-07 12:53 ` [PATCH v5 15/20] x86: move cpu plug from pc to x86 Gerd Hoffmann
@ 2020-07-10 19:37   ` Igor Mammedov
  0 siblings, 0 replies; 35+ messages in thread
From: Igor Mammedov @ 2020-07-10 19:37 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, qemu-devel, Shannon Zhao,
	qemu-arm, Paolo Bonzini, Richard Henderson

On Tue,  7 Jul 2020 14:53:51 +0200
Gerd Hoffmann <kraxel@redhat.com> wrote:

> The cpu hotplug code handles the initialization of coldplugged cpus
> too, so it is needed even in case cpu hotplug is not supported.
> 
> Move the code from pc to x86, so microvm can use it.

it's very convinient to have all hotplug handles in one place,
so maybe move along unplug[_request] variants as well?

> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  include/hw/i386/x86.h |   6 ++
>  hw/i386/pc.c          | 234 ++----------------------------------------
>  hw/i386/x86.c         | 222 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 234 insertions(+), 228 deletions(-)
> 
> diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h
> index de74c831c3ab..23c964471802 100644
> --- a/include/hw/i386/x86.h
> +++ b/include/hw/i386/x86.h
> @@ -102,6 +102,12 @@ CpuInstanceProperties x86_cpu_index_to_props(MachineState *ms,
>                                               unsigned cpu_index);
>  int64_t x86_get_default_cpu_node_id(const MachineState *ms, int idx);
>  const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms);
> +CPUArchId *x86_find_cpu_slot(MachineState *ms, uint32_t id, int *idx);
> +void x86_rtc_set_cpus_count(ISADevice *rtc, uint16_t cpus_count);
> +void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
> +                      DeviceState *dev, Error **errp);
> +void x86_cpu_plug(HotplugHandler *hotplug_dev,
> +                  DeviceState *dev, Error **errp);
>  
>  void x86_bios_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw);
>  
> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> index 98d29ead09b0..14036fcd4e3a 100644
> --- a/hw/i386/pc.c
> +++ b/hw/i386/pc.c
> @@ -798,19 +798,6 @@ void pc_hot_add_cpu(MachineState *ms, const int64_t id, Error **errp)
>      }
>  }
>  
> -static void rtc_set_cpus_count(ISADevice *rtc, uint16_t cpus_count)
> -{
> -    if (cpus_count > 0xff) {
> -        /* If the number of CPUs can't be represented in 8 bits, the
> -         * BIOS must use "FW_CFG_NB_CPUS". Set RTC field to 0 just
> -         * to make old BIOSes fail more predictably.
> -         */
> -        rtc_set_memory(rtc, 0x5f, 0);
> -    } else {
> -        rtc_set_memory(rtc, 0x5f, cpus_count - 1);
> -    }
> -}
> -
>  static
>  void pc_machine_done(Notifier *notifier, void *data)
>  {
> @@ -820,7 +807,7 @@ void pc_machine_done(Notifier *notifier, void *data)
>      PCIBus *bus = pcms->bus;
>  
>      /* set the number of CPUs */
> -    rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
> +    x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
>  
>      if (bus) {
>          int extra_hosts = 0;
> @@ -1373,62 +1360,6 @@ static void pc_memory_unplug(HotplugHandler *hotplug_dev,
>      error_propagate(errp, local_err);
>  }
>  
> -static int pc_apic_cmp(const void *a, const void *b)
> -{
> -   CPUArchId *apic_a = (CPUArchId *)a;
> -   CPUArchId *apic_b = (CPUArchId *)b;
> -
> -   return apic_a->arch_id - apic_b->arch_id;
> -}
> -
> -/* returns pointer to CPUArchId descriptor that matches CPU's apic_id
> - * in ms->possible_cpus->cpus, if ms->possible_cpus->cpus has no
> - * entry corresponding to CPU's apic_id returns NULL.
> - */
> -static CPUArchId *pc_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
> -{
> -    CPUArchId apic_id, *found_cpu;
> -
> -    apic_id.arch_id = id;
> -    found_cpu = bsearch(&apic_id, ms->possible_cpus->cpus,
> -        ms->possible_cpus->len, sizeof(*ms->possible_cpus->cpus),
> -        pc_apic_cmp);
> -    if (found_cpu && idx) {
> -        *idx = found_cpu - ms->possible_cpus->cpus;
> -    }
> -    return found_cpu;
> -}
> -
> -static void pc_cpu_plug(HotplugHandler *hotplug_dev,
> -                        DeviceState *dev, Error **errp)
> -{
> -    CPUArchId *found_cpu;
> -    Error *local_err = NULL;
> -    X86CPU *cpu = X86_CPU(dev);
> -    PCMachineState *pcms = PC_MACHINE(hotplug_dev);
> -    X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
> -
> -    if (x86ms->acpi_dev) {
> -        hotplug_handler_plug(x86ms->acpi_dev, dev, &local_err);
> -        if (local_err) {
> -            goto out;
> -        }
> -    }
> -
> -    /* increment the number of CPUs */
> -    x86ms->boot_cpus++;
> -    if (x86ms->rtc) {
> -        rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
> -    }
> -    if (x86ms->fw_cfg) {
> -        fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus);
> -    }
> -
> -    found_cpu = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, NULL);
> -    found_cpu->cpu = OBJECT(dev);
> -out:
> -    error_propagate(errp, local_err);
> -}
>  static void pc_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
>                                       DeviceState *dev, Error **errp)
>  {
> @@ -1443,7 +1374,7 @@ static void pc_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
>          goto out;
>      }
>  
> -    pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, &idx);
> +    x86_find_cpu_slot(MACHINE(pcms), cpu->apic_id, &idx);
>      assert(idx != -1);
>      if (idx == 0) {
>          error_setg(&local_err, "Boot CPU is unpluggable");
> @@ -1475,172 +1406,19 @@ static void pc_cpu_unplug_cb(HotplugHandler *hotplug_dev,
>          goto out;
>      }
>  
> -    found_cpu = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, NULL);
> +    found_cpu = x86_find_cpu_slot(MACHINE(pcms), cpu->apic_id, NULL);
>      found_cpu->cpu = NULL;
>      qdev_unrealize(dev);
>  
>      /* decrement the number of CPUs */
>      x86ms->boot_cpus--;
>      /* Update the number of CPUs in CMOS */
> -    rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
> +    x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
>      fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus);
>   out:
>      error_propagate(errp, local_err);
>  }
>  
> -static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev,
> -                            DeviceState *dev, Error **errp)
> -{
> -    int idx;
> -    CPUState *cs;
> -    CPUArchId *cpu_slot;
> -    X86CPUTopoIDs topo_ids;
> -    X86CPU *cpu = X86_CPU(dev);
> -    CPUX86State *env = &cpu->env;
> -    MachineState *ms = MACHINE(hotplug_dev);
> -    PCMachineState *pcms = PC_MACHINE(hotplug_dev);
> -    X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
> -    unsigned int smp_cores = ms->smp.cores;
> -    unsigned int smp_threads = ms->smp.threads;
> -    X86CPUTopoInfo topo_info;
> -
> -    if(!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) {
> -        error_setg(errp, "Invalid CPU type, expected cpu type: '%s'",
> -                   ms->cpu_type);
> -        return;
> -    }
> -
> -    init_topo_info(&topo_info, x86ms);
> -
> -    env->nr_dies = x86ms->smp_dies;
> -    env->nr_nodes = topo_info.nodes_per_pkg;
> -    env->pkg_offset = x86ms->apicid_pkg_offset(&topo_info);
> -
> -    /*
> -     * If APIC ID is not set,
> -     * set it based on socket/die/core/thread properties.
> -     */
> -    if (cpu->apic_id == UNASSIGNED_APIC_ID) {
> -        int max_socket = (ms->smp.max_cpus - 1) /
> -                                smp_threads / smp_cores / x86ms->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 && x86ms->smp_dies == 1) {
> -            cpu->die_id = 0;
> -        }
> -
> -        if (cpu->socket_id < 0) {
> -            error_setg(errp, "CPU socket-id is not set");
> -            return;
> -        } else if (cpu->socket_id > max_socket) {
> -            error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u",
> -                       cpu->socket_id, max_socket);
> -            return;
> -        }
> -        if (cpu->die_id < 0) {
> -            error_setg(errp, "CPU die-id is not set");
> -            return;
> -        } else if (cpu->die_id > x86ms->smp_dies - 1) {
> -            error_setg(errp, "Invalid CPU die-id: %u must be in range 0:%u",
> -                       cpu->die_id, x86ms->smp_dies - 1);
> -            return;
> -        }
> -        if (cpu->core_id < 0) {
> -            error_setg(errp, "CPU core-id is not set");
> -            return;
> -        } else if (cpu->core_id > (smp_cores - 1)) {
> -            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) {
> -            error_setg(errp, "CPU thread-id is not set");
> -            return;
> -        } else if (cpu->thread_id > (smp_threads - 1)) {
> -            error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u",
> -                       cpu->thread_id, smp_threads - 1);
> -            return;
> -        }
> -
> -        topo_ids.pkg_id = cpu->socket_id;
> -        topo_ids.die_id = cpu->die_id;
> -        topo_ids.core_id = cpu->core_id;
> -        topo_ids.smt_id = cpu->thread_id;
> -        cpu->apic_id = x86ms->apicid_from_topo_ids(&topo_info, &topo_ids);
> -    }
> -
> -    cpu_slot = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, &idx);
> -    if (!cpu_slot) {
> -        MachineState *ms = MACHINE(pcms);
> -
> -        x86ms->topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
> -        error_setg(errp,
> -            "Invalid CPU [socket: %u, die: %u, core: %u, thread: %u] with"
> -            " APIC ID %" PRIu32 ", valid index range 0:%d",
> -            topo_ids.pkg_id, topo_ids.die_id, topo_ids.core_id, topo_ids.smt_id,
> -            cpu->apic_id, ms->possible_cpus->len - 1);
> -        return;
> -    }
> -
> -    if (cpu_slot->cpu) {
> -        error_setg(errp, "CPU[%d] with APIC ID %" PRIu32 " exists",
> -                   idx, cpu->apic_id);
> -        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
> -     */
> -    /* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn()
> -     * once -smp refactoring is complete and there will be CPU private
> -     * CPUState::nr_cores and CPUState::nr_threads fields instead of globals */
> -    x86ms->topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
> -    if (cpu->socket_id != -1 && cpu->socket_id != topo_ids.pkg_id) {
> -        error_setg(errp, "property socket-id: %u doesn't match set apic-id:"
> -            " 0x%x (socket-id: %u)", cpu->socket_id, cpu->apic_id,
> -            topo_ids.pkg_id);
> -        return;
> -    }
> -    cpu->socket_id = topo_ids.pkg_id;
> -
> -    if (cpu->die_id != -1 && cpu->die_id != topo_ids.die_id) {
> -        error_setg(errp, "property die-id: %u doesn't match set apic-id:"
> -            " 0x%x (die-id: %u)", cpu->die_id, cpu->apic_id, topo_ids.die_id);
> -        return;
> -    }
> -    cpu->die_id = topo_ids.die_id;
> -
> -    if (cpu->core_id != -1 && cpu->core_id != topo_ids.core_id) {
> -        error_setg(errp, "property core-id: %u doesn't match set apic-id:"
> -            " 0x%x (core-id: %u)", cpu->core_id, cpu->apic_id,
> -            topo_ids.core_id);
> -        return;
> -    }
> -    cpu->core_id = topo_ids.core_id;
> -
> -    if (cpu->thread_id != -1 && cpu->thread_id != topo_ids.smt_id) {
> -        error_setg(errp, "property thread-id: %u doesn't match set apic-id:"
> -            " 0x%x (thread-id: %u)", cpu->thread_id, cpu->apic_id,
> -            topo_ids.smt_id);
> -        return;
> -    }
> -    cpu->thread_id = topo_ids.smt_id;
> -
> -    if (hyperv_feat_enabled(cpu, HYPERV_FEAT_VPINDEX) &&
> -        !kvm_hv_vpindex_settable()) {
> -        error_setg(errp, "kernel doesn't allow setting HyperV VP_INDEX");
> -        return;
> -    }
> -
> -    cs = CPU(cpu);
> -    cs->cpu_index = idx;
> -
> -    numa_cpu_pre_plug(cpu_slot, dev, errp);
> -}
> -
>  static void pc_virtio_pmem_pci_pre_plug(HotplugHandler *hotplug_dev,
>                                          DeviceState *dev, Error **errp)
>  {
> @@ -1706,7 +1484,7 @@ static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
>      if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
>          pc_memory_pre_plug(hotplug_dev, dev, errp);
>      } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
> -        pc_cpu_pre_plug(hotplug_dev, dev, errp);
> +        x86_cpu_pre_plug(hotplug_dev, dev, errp);
>      } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) {
>          pc_virtio_pmem_pci_pre_plug(hotplug_dev, dev, errp);
>      }
> @@ -1718,7 +1496,7 @@ static void pc_machine_device_plug_cb(HotplugHandler *hotplug_dev,
>      if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
>          pc_memory_plug(hotplug_dev, dev, errp);
>      } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
> -        pc_cpu_plug(hotplug_dev, dev, errp);
> +        x86_cpu_plug(hotplug_dev, dev, errp);
>      } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) {
>          pc_virtio_pmem_pci_plug(hotplug_dev, dev, errp);
>      }
> diff --git a/hw/i386/x86.c b/hw/i386/x86.c
> index 2d2beff3d4f6..b11fcb90b9cd 100644
> --- a/hw/i386/x86.c
> +++ b/hw/i386/x86.c
> @@ -41,6 +41,7 @@
>  #include "hw/i386/topology.h"
>  #include "hw/i386/fw_cfg.h"
>  #include "hw/intc/i8259.h"
> +#include "hw/rtc/mc146818rtc.h"
>  
>  #include "hw/acpi/cpu_hotplug.h"
>  #include "hw/irq.h"
> @@ -168,6 +169,227 @@ void x86_cpus_init(X86MachineState *x86ms, int default_cpu_version)
>      }
>  }
>  
> +void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
> +                      DeviceState *dev, Error **errp)
> +{
> +    int idx;
> +    CPUState *cs;
> +    CPUArchId *cpu_slot;
> +    X86CPUTopoIDs topo_ids;
> +    X86CPU *cpu = X86_CPU(dev);
> +    CPUX86State *env = &cpu->env;
> +    MachineState *ms = MACHINE(hotplug_dev);
> +    X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
> +    unsigned int smp_cores = ms->smp.cores;
> +    unsigned int smp_threads = ms->smp.threads;
> +    X86CPUTopoInfo topo_info;
> +
> +    if(!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) {
> +        error_setg(errp, "Invalid CPU type, expected cpu type: '%s'",
> +                   ms->cpu_type);
> +        return;
> +    }
> +
> +    init_topo_info(&topo_info, x86ms);
> +
> +    env->nr_dies = x86ms->smp_dies;
> +    env->nr_nodes = topo_info.nodes_per_pkg;
> +    env->pkg_offset = x86ms->apicid_pkg_offset(&topo_info);
> +
> +    /*
> +     * If APIC ID is not set,
> +     * set it based on socket/die/core/thread properties.
> +     */
> +    if (cpu->apic_id == UNASSIGNED_APIC_ID) {
> +        int max_socket = (ms->smp.max_cpus - 1) /
> +                                smp_threads / smp_cores / x86ms->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 && x86ms->smp_dies == 1) {
> +            cpu->die_id = 0;
> +        }
> +
> +        if (cpu->socket_id < 0) {
> +            error_setg(errp, "CPU socket-id is not set");
> +            return;
> +        } else if (cpu->socket_id > max_socket) {
> +            error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u",
> +                       cpu->socket_id, max_socket);
> +            return;
> +        }
> +        if (cpu->die_id < 0) {
> +            error_setg(errp, "CPU die-id is not set");
> +            return;
> +        } else if (cpu->die_id > x86ms->smp_dies - 1) {
> +            error_setg(errp, "Invalid CPU die-id: %u must be in range 0:%u",
> +                       cpu->die_id, x86ms->smp_dies - 1);
> +            return;
> +        }
> +        if (cpu->core_id < 0) {
> +            error_setg(errp, "CPU core-id is not set");
> +            return;
> +        } else if (cpu->core_id > (smp_cores - 1)) {
> +            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) {
> +            error_setg(errp, "CPU thread-id is not set");
> +            return;
> +        } else if (cpu->thread_id > (smp_threads - 1)) {
> +            error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u",
> +                       cpu->thread_id, smp_threads - 1);
> +            return;
> +        }
> +
> +        topo_ids.pkg_id = cpu->socket_id;
> +        topo_ids.die_id = cpu->die_id;
> +        topo_ids.core_id = cpu->core_id;
> +        topo_ids.smt_id = cpu->thread_id;
> +        cpu->apic_id = x86ms->apicid_from_topo_ids(&topo_info, &topo_ids);
> +    }
> +
> +    cpu_slot = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, &idx);
> +    if (!cpu_slot) {
> +        MachineState *ms = MACHINE(x86ms);
> +
> +        x86ms->topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
> +        error_setg(errp,
> +            "Invalid CPU [socket: %u, die: %u, core: %u, thread: %u] with"
> +            " APIC ID %" PRIu32 ", valid index range 0:%d",
> +            topo_ids.pkg_id, topo_ids.die_id, topo_ids.core_id, topo_ids.smt_id,
> +            cpu->apic_id, ms->possible_cpus->len - 1);
> +        return;
> +    }
> +
> +    if (cpu_slot->cpu) {
> +        error_setg(errp, "CPU[%d] with APIC ID %" PRIu32 " exists",
> +                   idx, cpu->apic_id);
> +        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
> +     */
> +    /* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn()
> +     * once -smp refactoring is complete and there will be CPU private
> +     * CPUState::nr_cores and CPUState::nr_threads fields instead of globals */
> +    x86ms->topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
> +    if (cpu->socket_id != -1 && cpu->socket_id != topo_ids.pkg_id) {
> +        error_setg(errp, "property socket-id: %u doesn't match set apic-id:"
> +            " 0x%x (socket-id: %u)", cpu->socket_id, cpu->apic_id,
> +            topo_ids.pkg_id);
> +        return;
> +    }
> +    cpu->socket_id = topo_ids.pkg_id;
> +
> +    if (cpu->die_id != -1 && cpu->die_id != topo_ids.die_id) {
> +        error_setg(errp, "property die-id: %u doesn't match set apic-id:"
> +            " 0x%x (die-id: %u)", cpu->die_id, cpu->apic_id, topo_ids.die_id);
> +        return;
> +    }
> +    cpu->die_id = topo_ids.die_id;
> +
> +    if (cpu->core_id != -1 && cpu->core_id != topo_ids.core_id) {
> +        error_setg(errp, "property core-id: %u doesn't match set apic-id:"
> +            " 0x%x (core-id: %u)", cpu->core_id, cpu->apic_id,
> +            topo_ids.core_id);
> +        return;
> +    }
> +    cpu->core_id = topo_ids.core_id;
> +
> +    if (cpu->thread_id != -1 && cpu->thread_id != topo_ids.smt_id) {
> +        error_setg(errp, "property thread-id: %u doesn't match set apic-id:"
> +            " 0x%x (thread-id: %u)", cpu->thread_id, cpu->apic_id,
> +            topo_ids.smt_id);
> +        return;
> +    }
> +    cpu->thread_id = topo_ids.smt_id;
> +
> +    if (hyperv_feat_enabled(cpu, HYPERV_FEAT_VPINDEX) &&
> +        !kvm_hv_vpindex_settable()) {
> +        error_setg(errp, "kernel doesn't allow setting HyperV VP_INDEX");
> +        return;
> +    }
> +
> +    cs = CPU(cpu);
> +    cs->cpu_index = idx;
> +
> +    numa_cpu_pre_plug(cpu_slot, dev, errp);
> +}
> +
> +void x86_rtc_set_cpus_count(ISADevice *rtc, uint16_t cpus_count)
> +{
> +    if (cpus_count > 0xff) {
> +        /* If the number of CPUs can't be represented in 8 bits, the
> +         * BIOS must use "FW_CFG_NB_CPUS". Set RTC field to 0 just
> +         * to make old BIOSes fail more predictably.
> +         */
> +        rtc_set_memory(rtc, 0x5f, 0);
> +    } else {
> +        rtc_set_memory(rtc, 0x5f, cpus_count - 1);
> +    }
> +}
> +
> +static int x86_apic_cmp(const void *a, const void *b)
> +{
> +   CPUArchId *apic_a = (CPUArchId *)a;
> +   CPUArchId *apic_b = (CPUArchId *)b;
> +
> +   return apic_a->arch_id - apic_b->arch_id;
> +}
> +
> +/* returns pointer to CPUArchId descriptor that matches CPU's apic_id
> + * in ms->possible_cpus->cpus, if ms->possible_cpus->cpus has no
> + * entry corresponding to CPU's apic_id returns NULL.
> + */
> +CPUArchId *x86_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
> +{
> +    CPUArchId apic_id, *found_cpu;
> +
> +    apic_id.arch_id = id;
> +    found_cpu = bsearch(&apic_id, ms->possible_cpus->cpus,
> +        ms->possible_cpus->len, sizeof(*ms->possible_cpus->cpus),
> +        x86_apic_cmp);
> +    if (found_cpu && idx) {
> +        *idx = found_cpu - ms->possible_cpus->cpus;
> +    }
> +    return found_cpu;
> +}
> +
> +void x86_cpu_plug(HotplugHandler *hotplug_dev,
> +                  DeviceState *dev, Error **errp)
> +{
> +    CPUArchId *found_cpu;
> +    Error *local_err = NULL;
> +    X86CPU *cpu = X86_CPU(dev);
> +    X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
> +
> +    if (x86ms->acpi_dev) {
> +        hotplug_handler_plug(x86ms->acpi_dev, dev, &local_err);
> +        if (local_err) {
> +            goto out;
> +        }
> +    }
> +
> +    /* increment the number of CPUs */
> +    x86ms->boot_cpus++;
> +    if (x86ms->rtc) {
> +        x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
> +    }
> +    if (x86ms->fw_cfg) {
> +        fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus);
> +    }
> +
> +    found_cpu = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, NULL);
> +    found_cpu->cpu = OBJECT(dev);
> +out:
> +    error_propagate(errp, local_err);
> +}
> +
>  CpuInstanceProperties
>  x86_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
>  {



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 16/20] microvm: wire up hotplug
  2020-07-07 12:53 ` [PATCH v5 16/20] microvm: wire up hotplug Gerd Hoffmann
@ 2020-07-10 19:44   ` Igor Mammedov
  0 siblings, 0 replies; 35+ messages in thread
From: Igor Mammedov @ 2020-07-10 19:44 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, qemu-devel, Shannon Zhao,
	qemu-arm, Paolo Bonzini, Richard Henderson

On Tue,  7 Jul 2020 14:53:52 +0200
Gerd Hoffmann <kraxel@redhat.com> wrote:

> The cpu hotplug code handles the initialization of coldplugged cpus
> too, so it is needed even in case cpu hotplug is not supported.
> 
> Wire cpu hotplug up for microvm.
> Without this we get a broken MADT table.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

Blame is on me for calling it hotplug, HotplugHandlerClass is basically
a set of hooks to wire things up regardless if it's hotplug or coldplug.
In hindsight it was obvious at the time it was introduced.

Reviewed-by: Igor Mammedov <imammedo@redhat.com>

> ---
>  hw/i386/microvm.c | 42 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 42 insertions(+)
> 
> diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
> index 3d8a66cfc3ac..a5b16b728f9f 100644
> --- a/hw/i386/microvm.c
> +++ b/hw/i386/microvm.c
> @@ -320,6 +320,39 @@ static void microvm_fix_kernel_cmdline(MachineState *machine)
>      g_free(cmdline);
>  }
>  
> +static void microvm_device_pre_plug_cb(HotplugHandler *hotplug_dev,
> +                                       DeviceState *dev, Error **errp)
> +{
> +    x86_cpu_pre_plug(hotplug_dev, dev, errp);
> +}
> +
> +static void microvm_device_plug_cb(HotplugHandler *hotplug_dev,
> +                                   DeviceState *dev, Error **errp)
> +{
> +    x86_cpu_plug(hotplug_dev, dev, errp);
> +}
> +
> +static void microvm_device_unplug_request_cb(HotplugHandler *hotplug_dev,
> +                                             DeviceState *dev, Error **errp)
> +{
> +    error_setg(errp, "unplug not supported by microvm");
> +}
> +
> +static void microvm_device_unplug_cb(HotplugHandler *hotplug_dev,
> +                                     DeviceState *dev, Error **errp)
> +{
> +    error_setg(errp, "unplug not supported by microvm");
> +}
> +
> +static HotplugHandler *microvm_get_hotplug_handler(MachineState *machine,
> +                                                   DeviceState *dev)
> +{
> +    if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
> +        return HOTPLUG_HANDLER(machine);
> +    }
> +    return NULL;
> +}
> +
>  static void microvm_machine_state_init(MachineState *machine)
>  {
>      MicrovmMachineState *mms = MICROVM_MACHINE(machine);
> @@ -503,6 +536,7 @@ static void microvm_machine_initfn(Object *obj)
>  static void microvm_class_init(ObjectClass *oc, void *data)
>  {
>      MachineClass *mc = MACHINE_CLASS(oc);
> +    HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
>  
>      mc->init = microvm_machine_state_init;
>  
> @@ -523,6 +557,13 @@ static void microvm_class_init(ObjectClass *oc, void *data)
>      /* Machine class handlers */
>      mc->reset = microvm_machine_reset;
>  
> +    /* hotplug (for cpu coldplug) */
> +    mc->get_hotplug_handler = microvm_get_hotplug_handler;
> +    hc->pre_plug = microvm_device_pre_plug_cb;
> +    hc->plug = microvm_device_plug_cb;
> +    hc->unplug_request = microvm_device_unplug_request_cb;
> +    hc->unplug = microvm_device_unplug_cb;
> +
>      object_class_property_add(oc, MICROVM_MACHINE_PIC, "OnOffAuto",
>                                microvm_machine_get_pic,
>                                microvm_machine_set_pic,
> @@ -572,6 +613,7 @@ static const TypeInfo microvm_machine_info = {
>      .class_size    = sizeof(MicrovmMachineClass),
>      .class_init    = microvm_class_init,
>      .interfaces = (InterfaceInfo[]) {
> +         { TYPE_HOTPLUG_HANDLER },
>           { }
>      },
>  };



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 18/20] tests/acpi: allow override blkdev
  2020-07-07 12:53 ` [PATCH v5 18/20] tests/acpi: allow override blkdev Gerd Hoffmann
@ 2020-07-10 19:48   ` Igor Mammedov
  0 siblings, 0 replies; 35+ messages in thread
From: Igor Mammedov @ 2020-07-10 19:48 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, qemu-devel, Shannon Zhao,
	qemu-arm, Paolo Bonzini, Richard Henderson

On Tue,  7 Jul 2020 14:53:54 +0200
Gerd Hoffmann <kraxel@redhat.com> wrote:

> microvm needs virtio-blk instead of ide.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

Reviewed-by: Igor Mammedov <imammedo@redhat.com>

> ---
>  tests/qtest/bios-tables-test.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
> index c315156858f4..24b715dce780 100644
> --- a/tests/qtest/bios-tables-test.c
> +++ b/tests/qtest/bios-tables-test.c
> @@ -72,6 +72,7 @@ typedef struct {
>      const char *variant;
>      const char *uefi_fl1;
>      const char *uefi_fl2;
> +    const char *blkdev;
>      const char *cd;
>      const uint64_t ram_start;
>      const uint64_t scan_len;
> @@ -635,9 +636,10 @@ static void test_acpi_one(const char *params, test_data *data)
>          args = g_strdup_printf("-machine %s,kernel-irqchip=off %s -accel tcg "
>              "-net none -display none %s "
>              "-drive id=hd0,if=none,file=%s,format=raw "
> -            "-device ide-hd,drive=hd0 ",
> +            "-device %s,drive=hd0 ",
>               data->machine, data->tcg_only ? "" : "-accel kvm",
> -             params ? params : "", disk);
> +             params ? params : "", disk,
> +             data->blkdev ?: "ide-hd");
>      }
>  
>      data->qts = qtest_init(args);



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 19/20] tests/acpi: add microvm test
  2020-07-07 12:53 ` [PATCH v5 19/20] tests/acpi: add microvm test Gerd Hoffmann
@ 2020-07-10 19:49   ` Igor Mammedov
  2020-07-16  9:10     ` Gerd Hoffmann
  0 siblings, 1 reply; 35+ messages in thread
From: Igor Mammedov @ 2020-07-10 19:49 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, qemu-devel, Shannon Zhao,
	qemu-arm, Paolo Bonzini, Richard Henderson

On Tue,  7 Jul 2020 14:53:55 +0200
Gerd Hoffmann <kraxel@redhat.com> wrote:

> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  tests/qtest/bios-tables-test.c | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
> index 24b715dce780..b5b98d5c0742 100644
> --- a/tests/qtest/bios-tables-test.c
> +++ b/tests/qtest/bios-tables-test.c
> @@ -1007,6 +1007,20 @@ static void test_acpi_virt_tcg_memhp(void)
>  
>  }
>  
> +static void test_acpi_microvm_tcg(void)
> +{
> +    test_data data;
> +
> +    memset(&data, 0, sizeof(data));
> +    data.machine = "microvm";

> +    data.required_struct_types = base_required_struct_types;
> +    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
I vaguely recall this belongs to smbios tables, does actually microvm provide them?

> +    data.blkdev = "virtio-blk-device";
> +    test_acpi_one(" -machine microvm,acpi=on,rtc=off",
> +                  &data);
> +    free_test_data(&data);
> +}
> +
>  static void test_acpi_virt_tcg_numamem(void)
>  {
>      test_data data = {
> @@ -1118,6 +1132,7 @@ int main(int argc, char *argv[])
>          qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm);
>          qtest_add_func("acpi/piix4/acpihmat", test_acpi_piix4_tcg_acpi_hmat);
>          qtest_add_func("acpi/q35/acpihmat", test_acpi_q35_tcg_acpi_hmat);
> +        qtest_add_func("acpi/microvm", test_acpi_microvm_tcg);
>      } 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);



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 08/20] microvm/acpi: add minimal acpi support
  2020-07-10 19:30       ` Igor Mammedov
@ 2020-07-16  8:52         ` Gerd Hoffmann
  0 siblings, 0 replies; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-16  8:52 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, qemu-devel, Shannon Zhao,
	qemu-arm, Paolo Bonzini, Richard Henderson

  Hi,

> > References to ACPI 2.0 are almost useless.  ACPI 5.0 is the oldest
> > version uefi.org offers for download.
> all versions are at (starting from 1.0)
> https://uefi.org/acpi/specs

Ah, there are the old ones hidden.
Thanks for the pointer.

Fetched latest errata of each version (assuming errata will not put
chapter numbers upside down ;)

take care,
  Gerd



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 19/20] tests/acpi: add microvm test
  2020-07-10 19:49   ` Igor Mammedov
@ 2020-07-16  9:10     ` Gerd Hoffmann
  2020-07-16 13:05       ` Igor Mammedov
  0 siblings, 1 reply; 35+ messages in thread
From: Gerd Hoffmann @ 2020-07-16  9:10 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, qemu-devel, Shannon Zhao,
	qemu-arm, Paolo Bonzini, Richard Henderson

  Hi,

> > +    data.required_struct_types = base_required_struct_types;
> > +    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
> I vaguely recall this belongs to smbios tables, does actually microvm provide them?

Checked.  Yes, it tests smbios tables.

seabios generates something in case qemu doesn't provide smbios tables,
so the test works.  We don't actually test qemu though, so it probably
makes sense to drop that for microvm until we actually generate smbios
tables.  Should we?

take care,
  Gerd



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 19/20] tests/acpi: add microvm test
  2020-07-16  9:10     ` Gerd Hoffmann
@ 2020-07-16 13:05       ` Igor Mammedov
  0 siblings, 0 replies; 35+ messages in thread
From: Igor Mammedov @ 2020-07-16 13:05 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Eduardo Habkost,
	Sergio Lopez, Michael S. Tsirkin, qemu-devel, Shannon Zhao,
	qemu-arm, Paolo Bonzini, Richard Henderson

On Thu, 16 Jul 2020 11:10:35 +0200
Gerd Hoffmann <kraxel@redhat.com> wrote:

>   Hi,
> 
> > > +    data.required_struct_types = base_required_struct_types;
> > > +    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);  
> > I vaguely recall this belongs to smbios tables, does actually microvm provide them?  
> 
> Checked.  Yes, it tests smbios tables.
> 
> seabios generates something in case qemu doesn't provide smbios tables,
> so the test works.  We don't actually test qemu though, so it probably
> makes sense to drop that for microvm until we actually generate smbios
> tables.  Should we?

if dropping it just works, then yes, otherwise I wouldn't bother.

> 
> take care,
>   Gerd
> 



^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2020-07-16 13:07 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-07 12:53 [PATCH v5 00/20] microvm: add acpi support Gerd Hoffmann
2020-07-07 12:53 ` [PATCH v5 01/20] microvm: name qboot binary qboot.rom Gerd Hoffmann
2020-07-07 12:53 ` [PATCH v5 02/20] seabios: add microvm config, update build rules Gerd Hoffmann
2020-07-07 12:53 ` [PATCH v5 03/20] seabios: add bios-microvm.bin binary Gerd Hoffmann
2020-07-07 12:53 ` [PATCH v5 04/20] acpi: ged: add control regs Gerd Hoffmann
2020-07-10 19:07   ` Igor Mammedov
2020-07-07 12:53 ` [PATCH v5 05/20] acpi: ged: add x86 device variant Gerd Hoffmann
2020-07-07 12:53 ` [PATCH v5 06/20] acpi: move acpi_dsdt_add_power_button() to ged Gerd Hoffmann
2020-07-07 12:53 ` [PATCH v5 07/20] microvm: make virtio irq base runtime configurable Gerd Hoffmann
2020-07-10 19:09   ` Igor Mammedov
2020-07-07 12:53 ` [PATCH v5 08/20] microvm/acpi: add minimal acpi support Gerd Hoffmann
2020-07-08 16:52   ` Michael S. Tsirkin
2020-07-09 12:33     ` Gerd Hoffmann
2020-07-10 19:30       ` Igor Mammedov
2020-07-16  8:52         ` Gerd Hoffmann
2020-07-07 12:53 ` [PATCH v5 09/20] microvm/acpi: add acpi_dsdt_add_virtio() for x86 Gerd Hoffmann
2020-07-07 12:53 ` [PATCH v5 10/20] microvm/acpi: use GSI 16-23 for virtio Gerd Hoffmann
2020-07-07 12:53 ` [PATCH v5 11/20] microvm/acpi: use seabios with acpi=on Gerd Hoffmann
2020-07-07 12:53 ` [PATCH v5 12/20] microvm/acpi: disable virtio-mmio cmdline hack Gerd Hoffmann
2020-07-07 12:53 ` [PATCH v5 13/20] x86: constify x86_machine_is_*_enabled Gerd Hoffmann
2020-07-07 12:53 ` [PATCH v5 14/20] x86: move acpi_dev from pc/microvm Gerd Hoffmann
2020-07-07 12:53 ` [PATCH v5 15/20] x86: move cpu plug from pc to x86 Gerd Hoffmann
2020-07-10 19:37   ` Igor Mammedov
2020-07-07 12:53 ` [PATCH v5 16/20] microvm: wire up hotplug Gerd Hoffmann
2020-07-10 19:44   ` Igor Mammedov
2020-07-07 12:53 ` [PATCH v5 17/20] tests/acpi: allow microvm test data updates Gerd Hoffmann
2020-07-07 12:53 ` [PATCH v5 18/20] tests/acpi: allow override blkdev Gerd Hoffmann
2020-07-10 19:48   ` Igor Mammedov
2020-07-07 12:53 ` [PATCH v5 19/20] tests/acpi: add microvm test Gerd Hoffmann
2020-07-10 19:49   ` Igor Mammedov
2020-07-16  9:10     ` Gerd Hoffmann
2020-07-16 13:05       ` Igor Mammedov
2020-07-07 12:53 ` [PATCH v5 20/20] tests/acpi: update expected data files for microvm Gerd Hoffmann
2020-07-07 13:34 ` [PATCH v5 00/20] microvm: add acpi support no-reply
2020-07-07 13:35 ` no-reply

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).