All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID
@ 2017-02-05  9:11 ben
  2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 01/10] ACPI: Add a function for building named qword entries ben
                   ` (10 more replies)
  0 siblings, 11 replies; 70+ messages in thread
From: ben @ 2017-02-05  9:11 UTC (permalink / raw)
  To: qemu-devel; +Cc: lersek, mst, imammedo, Ben Warren

From: Ben Warren <ben@skyportsystems.com>

This patch set adds support for passing a GUID to Windows guests.  It is a
re-implementation of previous patch sets written by Igor Mammedov et al, but
this time passing the GUID data as a fw_cfg blob.

This patch set has dependencies on new guest functionality, in particular the
support for a new linker-loader command and the ability to write back data
to QEMU over a DMA link.  Work is in flight in both SeaBIOS and OVMF to support this.

v4->v5:
    - Added significantly more detail to the documentation.
    - Replaced the previously-implemented linker-loader command with a new one:
      "write pointer".  This allows writing the guest address of a fw_cfg blob back
      to an arbitrary offset in a writeable fw_cfg file visible to QEMU.  This will
      require support in SeaBIOS and OVMF (ongoing).
    - Fixed endianness issues throughout.
    - Several styling cleanups.

v3->v4:
    - Rebased to top of tree.
    - Re-added document patch that was accidentally dropped from the last revision.
    - Added VMState functionality so that VGIA is restored properly.
    - Added Unit tests
v2->v3:
    - Added second writeable fw_cfg for storing the VM Generaiton ID
      address.  This uses a new linker-loader command for instructing the
      guest to write back the allocated address.  A patch for SeaBIOS has been
      submitted (https://www.seabios.org/pipermail/seabios/2017-January/011079.html)
      and the resulting binary will need to be pulled into QEMU once accepted.
    - Setting VM Generation ID by command line or qmp/hmp now accepts an "auto"
      value, whereby QEMU generates a random GUID.
    - Incorporated review comments from v2 mainly around code styling and AML syntax
    - Changed to use the E05 ACPI event instead of E00
v1->v2:
    - Removed "changed" boolean parameter as it is unneeded
    - Added ACPI Notify logic
    - Style changes to pass checkpatch.pl
    - Added support for dynamic sysbus to pc_piix boards


Ben Warren (8):
  ACPI: Add a function for building named qword entries
  linker-loader: Add new 'write pointer' command
  docs: VM Generation ID device description
  ACPI: Add vmgenid storage entries to the build tables
  ACPI: Add Virtual Machine Generation ID support
  PC: Support dynamic sysbus on pc_i440fx
  tests: Move reusable ACPI macros into a new header file
  tests: Add unit tests for the VM Generation ID feature

Igor Mammedov (2):
  qmp/hmp: add query-vm-generation-id and 'info vm-generation-id'
    commands
  qmp/hmp: add set-vm-generation-id commands

 default-configs/i386-softmmu.mak     |   1 +
 default-configs/x86_64-softmmu.mak   |   1 +
 docs/specs/vmgenid.txt               | 239 +++++++++++++++++++++++++++++++++++
 hmp-commands-info.hx                 |  13 ++
 hmp-commands.hx                      |  13 ++
 hmp.c                                |  21 +++
 hmp.h                                |   2 +
 hw/acpi/Makefile.objs                |   1 +
 hw/acpi/aml-build.c                  |  39 +++++-
 hw/acpi/bios-linker-loader.c         |  35 +++--
 hw/acpi/nvdimm.c                     |   2 +-
 hw/acpi/vmgenid.c                    | 238 ++++++++++++++++++++++++++++++++++
 hw/arm/virt-acpi-build.c             |   4 +-
 hw/i386/acpi-build.c                 |  18 ++-
 hw/i386/pc_piix.c                    |   1 +
 include/hw/acpi/acpi_dev_interface.h |   1 +
 include/hw/acpi/aml-build.h          |   5 +
 include/hw/acpi/bios-linker-loader.h |   3 +-
 include/hw/acpi/vmgenid.h            |  37 ++++++
 qapi-schema.json                     |  31 +++++
 stubs/Makefile.objs                  |   1 +
 stubs/vmgenid.c                      |  14 ++
 tests/Makefile.include               |   2 +
 tests/acpi-utils.h                   |  75 +++++++++++
 tests/bios-tables-test.c             |  72 +----------
 tests/vmgenid-test.c                 | 184 +++++++++++++++++++++++++++
 26 files changed, 962 insertions(+), 91 deletions(-)
 create mode 100644 docs/specs/vmgenid.txt
 create mode 100644 hw/acpi/vmgenid.c
 create mode 100644 include/hw/acpi/vmgenid.h
 create mode 100644 stubs/vmgenid.c
 create mode 100644 tests/acpi-utils.h
 create mode 100644 tests/vmgenid-test.c

-- 
2.7.4

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

* [Qemu-devel] [PATCH v5 01/10] ACPI: Add a function for building named qword entries
  2017-02-05  9:11 [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID ben
@ 2017-02-05  9:11 ` ben
  2017-02-07 13:51   ` Igor Mammedov
  2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 02/10] linker-loader: Add new 'write pointer' command ben
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 70+ messages in thread
From: ben @ 2017-02-05  9:11 UTC (permalink / raw)
  To: qemu-devel; +Cc: lersek, mst, imammedo, Ben Warren

From: Ben Warren <ben@skyportsystems.com>

This is initially used to patch a 64-bit address into
the VM Generation ID SSDT

Signed-off-by: Ben Warren <ben@skyportsystems.com>
---
 hw/acpi/aml-build.c         | 35 +++++++++++++++++++++++++++++++++++
 include/hw/acpi/aml-build.h |  4 ++++
 2 files changed, 39 insertions(+)

diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index b2a1e40..9fc54c9 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -264,6 +264,9 @@ static void build_append_int(GArray *table, uint64_t value)
  * Warning: runtime patching is best avoided. Only use this as
  * a replacement for DataTableRegion (for guests that don't
  * support it).
+ *
+ * ACPI 5.0: 19.2.5
+ * 32-bit integers are supported beginning with ACPI 1.0
  */
 int
 build_append_named_dword(GArray *array, const char *name_format, ...)
@@ -285,6 +288,38 @@ build_append_named_dword(GArray *array, const char *name_format, ...)
     return offset;
 }
 
+/*
+ * Build NAME(XXXX, 0x0000000000000000) where 0x0000000000000000
+ * is encoded as a qword, and return the offset to 0x0000000000000000
+ * for runtime patching.
+ *
+ * Warning: runtime patching is best avoided. Only use this as
+ * a replacement for DataTableRegion (for guests that don't
+ * support it).
+ *
+ * ACPI 5.0: 19.2.5
+ * 64-bit integers are supported beginning with ACPI 2.0
+ */
+int
+build_append_named_qword(GArray *array, const char *name_format, ...)
+{
+    int offset;
+    va_list ap;
+
+    build_append_byte(array, 0x08); /* NameOp */
+    va_start(ap, name_format);
+    build_append_namestringv(array, name_format, ap);
+    va_end(ap);
+
+    build_append_byte(array, 0x0E); /* QWordPrefix */
+
+    offset = array->len;
+    build_append_int_noprefix(array, 0x0000000000000000, 8);
+    assert(array->len == offset + 8);
+
+    return offset;
+}
+
 static GPtrArray *alloc_list;
 
 static Aml *aml_alloc(void)
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index 559326c..dbf63cf 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -385,6 +385,10 @@ int
 build_append_named_dword(GArray *array, const char *name_format, ...)
 GCC_FMT_ATTR(2, 3);
 
+int
+build_append_named_qword(GArray *array, const char *name_format, ...)
+GCC_FMT_ATTR(2, 3);
+
 void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
                        uint64_t len, int node, MemoryAffinityFlags flags);
 
-- 
2.7.4

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

* [Qemu-devel] [PATCH v5 02/10] linker-loader: Add new 'write pointer' command
  2017-02-05  9:11 [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID ben
  2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 01/10] ACPI: Add a function for building named qword entries ben
@ 2017-02-05  9:11 ` ben
  2017-02-06 14:56   ` Michael S. Tsirkin
  2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 03/10] docs: VM Generation ID device description ben
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 70+ messages in thread
From: ben @ 2017-02-05  9:11 UTC (permalink / raw)
  To: qemu-devel; +Cc: lersek, mst, imammedo, Ben Warren

From: Ben Warren <ben@skyportsystems.com>

This adds to the existing 'add pointer' functionality in that it
instructs the guest (BIOS or UEFI) to not patch memory but to instead
write the changes back to QEMU via a writeable fw_cfg file.

Signed-off-by: Ben Warren <ben@skyportsystems.com>
---
 hw/acpi/aml-build.c                  |  2 +-
 hw/acpi/bios-linker-loader.c         | 35 ++++++++++++++++++++++++-----------
 hw/acpi/nvdimm.c                     |  2 +-
 hw/arm/virt-acpi-build.c             |  4 ++--
 hw/i386/acpi-build.c                 |  8 ++++----
 include/hw/acpi/bios-linker-loader.h |  3 ++-
 6 files changed, 34 insertions(+), 20 deletions(-)

diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 9fc54c9..03b6c6c 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1626,7 +1626,7 @@ build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets,
         /* rsdt->table_offset_entry to be filled by Guest linker */
         bios_linker_loader_add_pointer(linker,
             ACPI_BUILD_TABLE_FILE, rsdt_entry_offset, rsdt_entry_size,
-            ACPI_BUILD_TABLE_FILE, ref_tbl_offset);
+            ACPI_BUILD_TABLE_FILE, ref_tbl_offset, false);
     }
     build_header(linker, table_data,
                  (void *)rsdt, "RSDT", rsdt_len, 1, oem_id, oem_table_id);
diff --git a/hw/acpi/bios-linker-loader.c b/hw/acpi/bios-linker-loader.c
index d963ebe..e46bc29 100644
--- a/hw/acpi/bios-linker-loader.c
+++ b/hw/acpi/bios-linker-loader.c
@@ -52,10 +52,13 @@ struct BiosLinkerLoaderEntry {
         } alloc;
 
         /*
-         * COMMAND_ADD_POINTER - patch the table (originating from
-         * @dest_file) at @pointer.offset, by adding a pointer to the table
+         * COMMAND_ADD_POINTER &
+         * COMMAND_WRITE_POINTER - patch guest memory (originating from
+         * @dest_file) at @pointer.offset, by adding a pointer to the memory
          * originating from @src_file. 1,2,4 or 8 byte unsigned
          * addition is used depending on @pointer.size.
+         * Instead of patching memory, COMMAND_WRITE_POINTER writes the changes
+         * to @dest_file in QEMU via fw_cfg DMA.
          */
         struct {
             char dest_file[BIOS_LINKER_LOADER_FILESZ];
@@ -85,9 +88,10 @@ struct BiosLinkerLoaderEntry {
 typedef struct BiosLinkerLoaderEntry BiosLinkerLoaderEntry;
 
 enum {
-    BIOS_LINKER_LOADER_COMMAND_ALLOCATE     = 0x1,
-    BIOS_LINKER_LOADER_COMMAND_ADD_POINTER  = 0x2,
-    BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM = 0x3,
+    BIOS_LINKER_LOADER_COMMAND_ALLOCATE          = 0x1,
+    BIOS_LINKER_LOADER_COMMAND_ADD_POINTER       = 0x2,
+    BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM      = 0x3,
+    BIOS_LINKER_LOADER_COMMAND_WRITE_POINTER     = 0x4,
 };
 
 enum {
@@ -242,13 +246,15 @@ void bios_linker_loader_add_checksum(BIOSLinker *linker, const char *file_name,
  * @src_offset: location within source file blob to which
  *              @dest_file+@dst_patched_offset will point to after
  *              firmware's executed ADD_POINTER command
+ * @write_back: guest should write change contents back to QEMU after patching
  */
 void bios_linker_loader_add_pointer(BIOSLinker *linker,
                                     const char *dest_file,
                                     uint32_t dst_patched_offset,
                                     uint8_t dst_patched_size,
                                     const char *src_file,
-                                    uint32_t src_offset)
+                                    uint32_t src_offset,
+                                    bool write_back)
 {
     uint64_t le_src_offset;
     BiosLinkerLoaderEntry entry;
@@ -257,8 +263,11 @@ void bios_linker_loader_add_pointer(BIOSLinker *linker,
     const BiosLinkerFileEntry *source_file =
         bios_linker_find_file(linker, src_file);
 
-    assert(dst_patched_offset < dst_file->blob->len);
-    assert(dst_patched_offset + dst_patched_size <= dst_file->blob->len);
+    /* dst_file need not exist if writing back */
+    if (!write_back) {
+        assert(dst_patched_offset < dst_file->blob->len);
+        assert(dst_patched_offset + dst_patched_size <= dst_file->blob->len);
+    }
     assert(src_offset < source_file->blob->len);
 
     memset(&entry, 0, sizeof entry);
@@ -266,15 +275,19 @@ void bios_linker_loader_add_pointer(BIOSLinker *linker,
             sizeof entry.pointer.dest_file - 1);
     strncpy(entry.pointer.src_file, src_file,
             sizeof entry.pointer.src_file - 1);
-    entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ADD_POINTER);
+    entry.command = cpu_to_le32(write_back ?
+                                BIOS_LINKER_LOADER_COMMAND_WRITE_POINTER :
+                                BIOS_LINKER_LOADER_COMMAND_ADD_POINTER);
     entry.pointer.offset = cpu_to_le32(dst_patched_offset);
     entry.pointer.size = dst_patched_size;
     assert(dst_patched_size == 1 || dst_patched_size == 2 ||
            dst_patched_size == 4 || dst_patched_size == 8);
 
     le_src_offset = cpu_to_le64(src_offset);
-    memcpy(dst_file->blob->data + dst_patched_offset,
-           &le_src_offset, dst_patched_size);
+    if (!write_back) {
+        memcpy(dst_file->blob->data + dst_patched_offset,
+               &le_src_offset, dst_patched_size);
+    }
 
     g_array_append_vals(linker->cmd_blob, &entry, sizeof entry);
 }
diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c
index 8e7d6ec..175996e 100644
--- a/hw/acpi/nvdimm.c
+++ b/hw/acpi/nvdimm.c
@@ -1266,7 +1266,7 @@ static void nvdimm_build_ssdt(GArray *table_offsets, GArray *table_data,
                              sizeof(NvdimmDsmIn), false /* high memory */);
     bios_linker_loader_add_pointer(linker,
         ACPI_BUILD_TABLE_FILE, mem_addr_offset, sizeof(uint32_t),
-        NVDIMM_DSM_MEM_FILE, 0);
+        NVDIMM_DSM_MEM_FILE, 0, false);
     build_header(linker, table_data,
         (void *)(table_data->data + nvdimm_ssdt),
         "SSDT", table_data->len - nvdimm_ssdt, 1, NULL, "NVDIMM");
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 07a10ac..a13f40d 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -380,7 +380,7 @@ build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset)
     /* Address to be filled by Guest linker */
     bios_linker_loader_add_pointer(linker,
         ACPI_BUILD_RSDP_FILE, rsdt_pa_offset, rsdt_pa_size,
-        ACPI_BUILD_TABLE_FILE, rsdt_tbl_offset);
+        ACPI_BUILD_TABLE_FILE, rsdt_tbl_offset, false);
 
     /* Checksum to be filled by Guest linker */
     bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
@@ -684,7 +684,7 @@ static void build_fadt(GArray *table_data, BIOSLinker *linker,
     /* DSDT address to be filled by Guest linker */
     bios_linker_loader_add_pointer(linker,
         ACPI_BUILD_TABLE_FILE, dsdt_entry_offset, sizeof(fadt->dsdt),
-        ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset);
+        ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset, false);
 
     build_header(linker, table_data,
                  (void *)fadt, "FACP", sizeof(*fadt), 5, NULL, NULL);
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 1c928ab..78a1d84 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -319,13 +319,13 @@ build_fadt(GArray *table_data, BIOSLinker *linker, AcpiPmInfo *pm,
     /* FACS address to be filled by Guest linker */
     bios_linker_loader_add_pointer(linker,
         ACPI_BUILD_TABLE_FILE, fw_ctrl_offset, sizeof(fadt->firmware_ctrl),
-        ACPI_BUILD_TABLE_FILE, facs_tbl_offset);
+        ACPI_BUILD_TABLE_FILE, facs_tbl_offset, false);
 
     /* DSDT address to be filled by Guest linker */
     fadt_setup(fadt, pm);
     bios_linker_loader_add_pointer(linker,
         ACPI_BUILD_TABLE_FILE, dsdt_entry_offset, sizeof(fadt->dsdt),
-        ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset);
+        ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset, false);
 
     build_header(linker, table_data,
                  (void *)fadt, "FACP", sizeof(*fadt), 1, oem_id, oem_table_id);
@@ -2262,7 +2262,7 @@ build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, GArray *tcpalog)
     /* log area start address to be filled by Guest linker */
     bios_linker_loader_add_pointer(linker,
         ACPI_BUILD_TABLE_FILE, log_addr_offset, log_addr_size,
-        ACPI_BUILD_TPMLOG_FILE, 0);
+        ACPI_BUILD_TPMLOG_FILE, 0, false);
 
     build_header(linker, table_data,
                  (void *)tcpa, "TCPA", sizeof(*tcpa), 2, NULL, NULL);
@@ -2552,7 +2552,7 @@ build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset)
     /* Address to be filled by Guest linker */
     bios_linker_loader_add_pointer(linker,
         ACPI_BUILD_RSDP_FILE, rsdt_pa_offset, rsdt_pa_size,
-        ACPI_BUILD_TABLE_FILE, rsdt_tbl_offset);
+        ACPI_BUILD_TABLE_FILE, rsdt_tbl_offset, false);
 
     /* Checksum to be filled by Guest linker */
     bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
diff --git a/include/hw/acpi/bios-linker-loader.h b/include/hw/acpi/bios-linker-loader.h
index fa1e5d1..d97e39d 100644
--- a/include/hw/acpi/bios-linker-loader.h
+++ b/include/hw/acpi/bios-linker-loader.h
@@ -24,7 +24,8 @@ void bios_linker_loader_add_pointer(BIOSLinker *linker,
                                     uint32_t dst_patched_offset,
                                     uint8_t dst_patched_size,
                                     const char *src_file,
-                                    uint32_t src_offset);
+                                    uint32_t src_offset,
+                                    bool write_back);
 
 void bios_linker_loader_cleanup(BIOSLinker *linker);
 #endif
-- 
2.7.4

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

* [Qemu-devel] [PATCH v5 03/10] docs: VM Generation ID device description
  2017-02-05  9:11 [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID ben
  2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 01/10] ACPI: Add a function for building named qword entries ben
  2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 02/10] linker-loader: Add new 'write pointer' command ben
@ 2017-02-05  9:11 ` ben
  2017-02-06 20:18   ` Eric Blake
                     ` (2 more replies)
  2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 04/10] ACPI: Add vmgenid storage entries to the build tables ben
                   ` (7 subsequent siblings)
  10 siblings, 3 replies; 70+ messages in thread
From: ben @ 2017-02-05  9:11 UTC (permalink / raw)
  To: qemu-devel; +Cc: lersek, mst, imammedo, Ben Warren, Gal Hammer

From: Ben Warren <ben@skyportsystems.com>

This patch is based off an earlier version by
Gal Hammer (ghammer@redhat.com)

Requirements section, ASCII diagrams and overall help
provided by Laszlo Ersek (lersek@redhat.com)

Signed-off-by: Gal Hammer <ghammer@redhat.com>
Signed-off-by: Ben Warren <ben@skyportsystems.com>
---
 docs/specs/vmgenid.txt | 239 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 239 insertions(+)
 create mode 100644 docs/specs/vmgenid.txt

diff --git a/docs/specs/vmgenid.txt b/docs/specs/vmgenid.txt
new file mode 100644
index 0000000..d36f8bd
--- /dev/null
+++ b/docs/specs/vmgenid.txt
@@ -0,0 +1,239 @@
+VIRTUAL MACHINE GENERATION ID
+=============================
+
+Copyright (C) 2016 Red Hat, Inc.
+Copyright (C) 2017 Skyport Systems, Inc.
+
+This work is licensed under the terms of the GNU GPL, version 2 or later.
+See the COPYING file in the top-level directory.
+
+===
+
+The VM generation ID (vmgenid) device is an emulated device which
+exposes a 128-bit, cryptographically random, integer value identifier,
+referred to as a Globally Unique Identifier, or GUID.
+
+This allows management applications (e.g. libvirt) to notify the guest
+operating system when the virtual machine is executed with a different
+configuration (e.g. snapshot execution or creation from a template).  The
+guest operating system notices the change, and is then able to react as
+appropriate by marking its copies of distributed databases as dirty,
+re-initializing its random number generator etc.
+
+
+Requirements
+------------
+
+These requirements are extracted from the "How to implement virtual machine
+generation ID support in a virtualization platform" section of the
+specification, dated August 1, 2012.
+
+
+The document may be found on the web at:
+  http://go.microsoft.com/fwlink/?LinkId=260709
+
+R1a. The generation ID shall live in an 8-byte aligned buffer.
+
+R1b. The buffer holding the generation ID shall be in guest RAM, ROM, or device
+     MMIO range.
+
+R1c. The buffer holding the generation ID shall be kept separate from areas
+     used by the operating system.
+
+R1d. The buffer shall not be covered by an AddressRangeMemory or
+     AddressRangeACPI entry in the E820 or UEFI memory map.
+
+R1e. The generation ID shall not live in a page frame that could be mapped with
+     caching disabled. (In other words, regardless of whether the generation ID
+     lives in RAM, ROM or MMIO, it shall only be mapped as cacheable.)
+
+R2 to R5. [These AML requirements are isolated well enough in the Microsoft
+          specification for us to simply refer to them here.]
+
+R6. The hypervisor shall expose a _HID (hardware identifier) object in the
+    VMGenId device's scope that is unique to the hypervisor vendor.
+
+
+QEMU Implementation
+-------------------
+
+The above-mentioned specification does not dictate which ACPI descriptor table
+will contain the VM Generation ID device.  Other implementations (Hyper-V and
+Xen) put it in the main descriptor table (Differentiated System Description
+Table or DSDT).  For ease of debugging and implementation, we have decided to
+put it in its own Secondary System Description Table, or SSDT.
+
+The following is a dump of the contents from a running system:
+
+# iasl -p ./SSDT -d /sys/firmware/acpi/tables/SSDT
+
+Intel ACPI Component Architecture
+ASL+ Optimizing Compiler version 20150717-64
+Copyright (c) 2000 - 2015 Intel Corporation
+
+Reading ACPI table from file /sys/firmware/acpi/tables/SSDT - Length
+00000198 (0x0000C6)
+ACPI: SSDT 0x0000000000000000 0000C6 (v01 BOCHS  VMGENID  00000001 BXPC
+00000001)
+Acpi table [SSDT] successfully installed and loaded
+Pass 1 parse of [SSDT]
+Pass 2 parse of [SSDT]
+Parsing Deferred Opcodes (Methods/Buffers/Packages/Regions)
+
+Parsing completed
+Disassembly completed
+ASL Output:    ./SSDT.dsl - 1631 bytes
+# cat SSDT.dsl
+/*
+ * Intel ACPI Component Architecture
+ * AML/ASL+ Disassembler version 20150717-64
+ * Copyright (c) 2000 - 2015 Intel Corporation
+ *
+ * Disassembling to symbolic ASL+ operators
+ *
+ * Disassembly of /sys/firmware/acpi/tables/SSDT, Sun Feb  5 00:19:37 2017
+ *
+ * Original Table Header:
+ *     Signature        "SSDT"
+ *     Length           0x000000CA (202)
+ *     Revision         0x01
+ *     Checksum         0x4B
+ *     OEM ID           "BOCHS "
+ *     OEM Table ID     "VMGENID"
+ *     OEM Revision     0x00000001 (1)
+ *     Compiler ID      "BXPC"
+ *     Compiler Version 0x00000001 (1)
+ */
+DefinitionBlock ("/sys/firmware/acpi/tables/SSDT.aml", "SSDT", 1, "BOCHS ",
+"VMGENID", 0x00000001)
+{
+    Name (VGIA, 0x07FFF000)
+    Scope (\_SB)
+    {
+        Device (VGEN)
+        {
+            Name (_HID, "QEMUVGID")  // _HID: Hardware ID
+            Name (_CID, "VM_Gen_Counter")  // _CID: Compatible ID
+            Name (_DDN, "VM_Gen_Counter")  // _DDN: DOS Device Name
+            Method (_STA, 0, NotSerialized)  // _STA: Status
+            {
+                Local0 = 0x0F
+                If ((VGIA == Zero))
+                {
+                    Local0 = Zero
+                }
+
+                Return (Local0)
+            }
+
+            Method (ADDR, 0, NotSerialized)
+            {
+                Local0 = Package (0x02) {}
+                Index (Local0, Zero) = (VGIA + 0x28)
+                Index (Local0, One) = Zero
+                Return (Local0)
+            }
+        }
+    }
+
+    Method (\_GPE._E05, 0, NotSerialized)  // _Exx: Edge-Triggered GPE
+    {
+        Notify (\_SB.VGEN, 0x80) // Status Change
+    }
+}
+
+
+Design Details:
+---------------
+
+Requirements R1a through R1e dicate that the memory holding the
+VM Generation ID must be allocated and owned by the guest operating system,
+in this case BIOS or UEFI.  However, to be useful, QEMU must be able to
+change the contents of the memory at runtime, specifically when starting a
+backed-up or snapshotted image.  In order to do this, QEMU must know the
+address that has been allocated.
+
+The mechanism chosen for this memory sharing is writeable fw_cfg blobs.
+These are in-memory data structures that are visible to both QEMU and guests,
+and are addressable as files.
+
+Two fw_cfg blobs are used in this case:
+
+/etc/vmgenid      - contains the actual VM Generation ID GUID
+                  - read-only to the guest
+/etc/vmgenid_addr - contains the address of the GUID
+                  - writeable by the guest
+
+
+QEMU sends the following commands to the guest at startup:
+
+1. Allocate memory for vmgenid fw_cfg blob.
+2. Write the address of vmgenid into the SSDT (VGIA ACPI variable as
+   shown above in the iasl dump).  Note that this change is not propagated
+   back to QEMU.
+3. Write the address of vmgenid back to QEMU's copy of vmgenid_addr
+   via the fw_cfg DMA interface.
+
+After step 3, QEMU is able to update the contents of vmgenid at will.
+
+Since BIOS or UEFI does not necessarily run when we wish to change the GUID,
+the value of VGIA is persisted via the VMState mechanism.
+
+As spelled out in the specification, any change to the GUID executes an
+ACPI notification.  The exact handler to use is not specified, so the vmgenid
+device uses the first unused one:  \_GPE._E05.
+
+
+Endian-ness Considerations:
+---------------------------
+
+Although not specified in Microsoft's document, it is assumed that the
+device is expected to use little-endian format.
+
+All GUID passed in via command line or monitor are treated as big-endian.
+GUID values displayed via monitor are shown in big-endian format.
+
+
+GUID Storage Format:
+--------------------
+
+In order to work with OVMF "SDT Header Probe Supressor", the contents of
+the vmgenid fw_cfg blob are not simply a 128-bit GUID.  There is also
+significant padding in order to align and fill a memory page, as shown in the
+following diagram:
+
++----------------------------------+
+| SSDT with OEM Table ID = VMGENID |
++----------------------------------+
+| ...                              |       TOP OF PAGE
+| VGIA dword object ---------------|-----> +---------------------------+
+| ...                              |       | fw-allocated array for    |
+| _STA method referring to VGIA    |       | "etc/vmgenid"        |
+| ...                              |       +---------------------------+
+| ADDR method referring to VGIA    |       |  0: OVMF SDT Header probe |
+| ...                              |       |     suppressor            |
++----------------------------------+       | 36: padding for 8-byte    |
+                                           |     alignment             |
+                                           | 40: GUID                  |
+                                           | 56: padding to page size  |
+                                           +---------------------------+
+                                           END OF PAGE
+
+
+Device Usage:
+-------------
+
+The device has one property, which can be set using the command line
+argument or the QMP interface:
+
+ guid - sets the value of the GUID.  A special value "auto" instructs
+        QEMU to generate a new random GUID.
+
+For example:
+
+ QEMU  -device vmgenid,guid="324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87"
+
+Or to change guid in runtime use:
+
+ set-vm-generation-id guid=124e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87
+ set-vm-generation-id guid=auto
-- 
2.7.4

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

* [Qemu-devel] [PATCH v5 04/10] ACPI: Add vmgenid storage entries to the build tables
  2017-02-05  9:11 [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID ben
                   ` (2 preceding siblings ...)
  2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 03/10] docs: VM Generation ID device description ben
@ 2017-02-05  9:11 ` ben
  2017-02-07 22:06   ` Laszlo Ersek
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support ben
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 70+ messages in thread
From: ben @ 2017-02-05  9:11 UTC (permalink / raw)
  To: qemu-devel; +Cc: lersek, mst, imammedo, Ben Warren

From: Ben Warren <ben@skyportsystems.com>

This allows them to be centrally initialized and destroyed

Signed-off-by: Ben Warren <ben@skyportsystems.com>
---
 hw/acpi/aml-build.c         | 2 ++
 include/hw/acpi/aml-build.h | 1 +
 2 files changed, 3 insertions(+)

diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 03b6c6c..0f39eaf 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1594,6 +1594,7 @@ void acpi_build_tables_init(AcpiBuildTables *tables)
     tables->rsdp = g_array_new(false, true /* clear */, 1);
     tables->table_data = g_array_new(false, true /* clear */, 1);
     tables->tcpalog = g_array_new(false, true /* clear */, 1);
+    tables->vmgenid = g_array_new(false, true /* clear */, 1);
     tables->linker = bios_linker_loader_init();
 }
 
@@ -1603,6 +1604,7 @@ void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
     g_array_free(tables->rsdp, true);
     g_array_free(tables->table_data, true);
     g_array_free(tables->tcpalog, mfre);
+    g_array_free(tables->vmgenid, mfre);
 }
 
 /* Build rsdt table */
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index dbf63cf..6f4e239 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -210,6 +210,7 @@ struct AcpiBuildTables {
     GArray *table_data;
     GArray *rsdp;
     GArray *tcpalog;
+    GArray *vmgenid;
     BIOSLinker *linker;
 } AcpiBuildTables;
 
-- 
2.7.4

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

* [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-05  9:11 [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID ben
                   ` (3 preceding siblings ...)
  2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 04/10] ACPI: Add vmgenid storage entries to the build tables ben
@ 2017-02-05  9:12 ` ben
  2017-02-06 16:15   ` Michael S. Tsirkin
                     ` (3 more replies)
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 06/10] qmp/hmp: add query-vm-generation-id and 'info vm-generation-id' commands ben
                   ` (5 subsequent siblings)
  10 siblings, 4 replies; 70+ messages in thread
From: ben @ 2017-02-05  9:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: lersek, mst, imammedo, Ben Warren

From: Ben Warren <ben@skyportsystems.com>

This implements the VM Generation ID feature by passing a 128-bit
GUID to the guest via a fw_cfg blob.
Any time the GUID changes, an ACPI notify event is sent to the guest

The user interface is a simple device with one parameter:
 - guid (string, must be "auto" or in UUID format
   xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)

Signed-off-by: Ben Warren <ben@skyportsystems.com>
---
 default-configs/i386-softmmu.mak     |   1 +
 default-configs/x86_64-softmmu.mak   |   1 +
 hw/acpi/Makefile.objs                |   1 +
 hw/acpi/vmgenid.c                    | 206 +++++++++++++++++++++++++++++++++++
 hw/i386/acpi-build.c                 |  10 ++
 include/hw/acpi/acpi_dev_interface.h |   1 +
 include/hw/acpi/vmgenid.h            |  37 +++++++
 7 files changed, 257 insertions(+)
 create mode 100644 hw/acpi/vmgenid.c
 create mode 100644 include/hw/acpi/vmgenid.h

diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 384cefb..1a43542 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -58,3 +58,4 @@ CONFIG_I82801B11=y
 CONFIG_SMBIOS=y
 CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
 CONFIG_PXB=y
+CONFIG_ACPI_VMGENID=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index 491a191..aee8b08 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -58,3 +58,4 @@ CONFIG_I82801B11=y
 CONFIG_SMBIOS=y
 CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
 CONFIG_PXB=y
+CONFIG_ACPI_VMGENID=y
diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
index 6acf798..11c35bc 100644
--- a/hw/acpi/Makefile.objs
+++ b/hw/acpi/Makefile.objs
@@ -5,6 +5,7 @@ common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
 common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
 common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
 common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
+common-obj-$(CONFIG_ACPI_VMGENID) += vmgenid.o
 common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
 
 common-obj-y += acpi_interface.o
diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
new file mode 100644
index 0000000..6c9ecfd
--- /dev/null
+++ b/hw/acpi/vmgenid.c
@@ -0,0 +1,206 @@
+/*
+ *  Virtual Machine Generation ID Device
+ *
+ *  Copyright (C) 2017 Skyport Systems.
+ *
+ *  Author: Ben Warren <ben@skyportsystems.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qmp-commands.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/aml-build.h"
+#include "hw/acpi/vmgenid.h"
+#include "hw/nvram/fw_cfg.h"
+#include "sysemu/sysemu.h"
+
+void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker *linker)
+{
+    Object *obj;
+    VmGenIdState *s;
+    Aml *ssdt, *dev, *scope, *method, *addr, *if_ctx;
+    uint32_t vgia_offset;
+
+    obj = find_vmgenid_dev(NULL);
+    assert(obj);
+    s = VMGENID(obj);
+
+    /* Fill in the GUID values */
+    if (guid->len != VMGENID_FW_CFG_SIZE) {
+        g_array_set_size(guid, VMGENID_FW_CFG_SIZE);
+    }
+    g_array_insert_vals(guid, VMGENID_GUID_OFFSET, s->guid.data, 16);
+
+    /* Put this in a separate SSDT table */
+    ssdt = init_aml_allocator();
+
+    /* Reserve space for header */
+    acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader));
+
+    /* Storage for the GUID address */
+    vgia_offset = table_data->len +
+        build_append_named_dword(ssdt->buf, "VGIA");
+    scope = aml_scope("\\_SB");
+    dev = aml_device("VGEN");
+    aml_append(dev, aml_name_decl("_HID", aml_string("QEMUVGID")));
+    aml_append(dev, aml_name_decl("_CID", aml_string("VM_Gen_Counter")));
+    aml_append(dev, aml_name_decl("_DDN", aml_string("VM_Gen_Counter")));
+
+    /* Simple status method to check that address is linked and non-zero */
+    method = aml_method("_STA", 0, AML_NOTSERIALIZED);
+    addr = aml_local(0);
+    aml_append(method, aml_store(aml_int(0xf), addr));
+    if_ctx = aml_if(aml_equal(aml_name("VGIA"), aml_int(0)));
+    aml_append(if_ctx, aml_store(aml_int(0), addr));
+    aml_append(method, if_ctx);
+    aml_append(method, aml_return(addr));
+    aml_append(dev, method);
+
+    /* the ADDR method returns two 32-bit words representing the lower and
+     * upper halves * of the physical address of the fw_cfg blob
+     * (holding the GUID) */
+    method = aml_method("ADDR", 0, AML_NOTSERIALIZED);
+
+    addr = aml_local(0);
+    aml_append(method, aml_store(aml_package(2), addr));
+
+    aml_append(method, aml_store(aml_add(aml_name("VGIA"),
+                                         aml_int(VMGENID_GUID_OFFSET), NULL),
+                                 aml_index(addr, aml_int(0))));
+    aml_append(method, aml_store(aml_int(0), aml_index(addr, aml_int(1))));
+    aml_append(method, aml_return(addr));
+
+    aml_append(dev, method);
+    aml_append(scope, dev);
+    aml_append(ssdt, scope);
+
+    /* attach an ACPI notify */
+    method = aml_method("\\_GPE._E05", 0, AML_NOTSERIALIZED);
+    aml_append(method, aml_notify(aml_name("\\_SB.VGEN"), aml_int(0x80)));
+    aml_append(ssdt, method);
+
+    g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len);
+
+    /* Allocate guest memory for the Data fw_cfg blob */
+    bios_linker_loader_alloc(linker, VMGENID_GUID_FW_CFG_FILE, guid, 4096,
+                             false /* page boundary, high memory */);
+
+    /* Patch address of GUID fw_cfg blob into the ADDR fw_cfg blob */
+    bios_linker_loader_add_pointer(linker,
+        VMGENID_ADDR_FW_CFG_FILE, 0, sizeof(uint32_t),
+        VMGENID_GUID_FW_CFG_FILE, 0, true);
+
+    /* Patch address of GUID fw_cfg blob into the AML */
+    bios_linker_loader_add_pointer(linker,
+        ACPI_BUILD_TABLE_FILE, vgia_offset, sizeof(uint32_t),
+        VMGENID_GUID_FW_CFG_FILE, 0, false);
+
+    build_header(linker, table_data,
+        (void *)(table_data->data + table_data->len - ssdt->buf->len),
+        "SSDT", ssdt->buf->len, 1, NULL, "VMGENID");
+    free_aml_allocator();
+}
+
+void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid)
+{
+    Object *obj = find_vmgenid_dev(NULL);
+    assert(obj);
+    VmGenIdState *vms = VMGENID(obj);
+
+    /* Create a read-only fw_cfg file for GUID */
+    fw_cfg_add_file(s, VMGENID_GUID_FW_CFG_FILE, guid->data,
+                    VMGENID_FW_CFG_SIZE);
+    /* Create a read-write fw_cfg file for Address */
+    fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL, NULL,
+                             vms->vgia_le, sizeof(uint32_t), false);
+}
+
+static void vmgenid_update_guest(VmGenIdState *s)
+{
+    Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL);
+    uint32_t vgia;
+
+    if (obj) {
+        /* Write the GUID to guest memory */
+        memcpy(&vgia, s->vgia_le, sizeof(vgia));
+        vgia = le32_to_cpu(vgia);
+        if (vgia) {
+            cpu_physical_memory_write(vgia + VMGENID_GUID_OFFSET,
+                                      s->guid.data, sizeof(s->guid.data));
+            /* Send _GPE.E05 event */
+            acpi_send_event(DEVICE(obj), ACPI_VMGENID_CHANGE_STATUS);
+        }
+    }
+}
+
+static void vmgenid_set_guid(Object *obj, const char *value, Error **errp)
+{
+    VmGenIdState *s = VMGENID(obj);
+
+    if (!strncmp(value, "auto", 4)) {
+        qemu_uuid_generate(&s->guid);
+    } else if (qemu_uuid_parse(value, &s->guid) < 0) {
+        error_setg(errp, "'%s. %s': Failed to parse GUID string: %s",
+                   object_get_typename(OBJECT(s)), VMGENID_GUID, value);
+        return;
+    }
+    /* QemuUUID has the first three words as big-endian, and expect that any
+     * GUIDs passed in will always be BE.  The guest, however will expect
+     * the fields to be little-endian, so store that way internally.  Make
+     * sure to swap back whenever reporting via monitor */
+    qemu_uuid_bswap(&s->guid);
+
+    /* Send the ACPI notify */
+    vmgenid_update_guest(s);
+}
+
+/* After restoring an image, we need to update the guest memory and notify
+ * it of a potential change to VM Generation ID */
+static int vmgenid_post_load(void *opaque, int version_id)
+{
+    VmGenIdState *s = opaque;
+    vmgenid_update_guest(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_vmgenid = {
+    .name = "vmgenid",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = vmgenid_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8_ARRAY(vgia_le, VmGenIdState, sizeof(uint32_t)),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static void vmgenid_initfn(Object *obj)
+{
+    object_property_add_str(obj, VMGENID_GUID, NULL, vmgenid_set_guid, NULL);
+}
+
+static void vmgenid_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd = &vmstate_vmgenid;
+}
+
+static const TypeInfo vmgenid_device_info = {
+    .name          = VMGENID_DEVICE,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(VmGenIdState),
+    .instance_init = vmgenid_initfn,
+    .class_init    = vmgenid_device_class_init,
+};
+
+static void vmgenid_register_types(void)
+{
+    type_register_static(&vmgenid_device_info);
+}
+
+type_init(vmgenid_register_types)
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 78a1d84..4c40f76 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -42,6 +42,7 @@
 #include "hw/acpi/memory_hotplug.h"
 #include "sysemu/tpm.h"
 #include "hw/acpi/tpm.h"
+#include "hw/acpi/vmgenid.h"
 #include "sysemu/tpm_backend.h"
 #include "hw/timer/mc146818rtc_regs.h"
 #include "sysemu/numa.h"
@@ -2653,6 +2654,11 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
     acpi_add_table(table_offsets, tables_blob);
     build_madt(tables_blob, tables->linker, pcms);
 
+    if (find_vmgenid_dev(NULL)) {
+        acpi_add_table(table_offsets, tables_blob);
+        vmgenid_build_acpi(tables_blob, tables->vmgenid, tables->linker);
+    }
+
     if (misc.has_hpet) {
         acpi_add_table(table_offsets, tables_blob);
         build_hpet(tables_blob, tables->linker);
@@ -2859,6 +2865,10 @@ void acpi_setup(void)
     fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
                     tables.tcpalog->data, acpi_data_len(tables.tcpalog));
 
+    if (find_vmgenid_dev(NULL)) {
+        vmgenid_add_fw_cfg(pcms->fw_cfg, tables.vmgenid);
+    }
+
     if (!pcmc->rsdp_in_ram) {
         /*
          * Keep for compatibility with old machine types.
diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h
index 71d3c48..3c2e4e9 100644
--- a/include/hw/acpi/acpi_dev_interface.h
+++ b/include/hw/acpi/acpi_dev_interface.h
@@ -11,6 +11,7 @@ typedef enum {
     ACPI_CPU_HOTPLUG_STATUS = 4,
     ACPI_MEMORY_HOTPLUG_STATUS = 8,
     ACPI_NVDIMM_HOTPLUG_STATUS = 16,
+    ACPI_VMGENID_CHANGE_STATUS = 32,
 } AcpiEventStatusBits;
 
 #define TYPE_ACPI_DEVICE_IF "acpi-device-interface"
diff --git a/include/hw/acpi/vmgenid.h b/include/hw/acpi/vmgenid.h
new file mode 100644
index 0000000..b60437a
--- /dev/null
+++ b/include/hw/acpi/vmgenid.h
@@ -0,0 +1,37 @@
+#ifndef ACPI_VMGENID_H
+#define ACPI_VMGENID_H
+
+#include "hw/acpi/bios-linker-loader.h"
+#include "hw/sysbus.h"
+#include "qemu/uuid.h"
+
+#define VMGENID_DEVICE           "vmgenid"
+#define VMGENID_GUID             "guid"
+#define VMGENID_GUID_FW_CFG_FILE      "etc/vmgenid"
+#define VMGENID_ADDR_FW_CFG_FILE      "etc/vmgenid_addr"
+
+#define VMGENID_FW_CFG_SIZE      4096 /* Occupy a page of memory */
+#define VMGENID_GUID_OFFSET      40   /* allow space for
+                                       * OVMF SDT Header Probe Supressor */
+
+void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid);
+void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker *linker);
+
+#define VMGENID(obj) OBJECT_CHECK(VmGenIdState, (obj), VMGENID_DEVICE)
+
+typedef struct VmGenIdState {
+    SysBusDevice parent_obj;
+    QemuUUID guid;
+    uint8_t vgia_le[4];
+} VmGenIdState;
+
+static Object *find_vmgenid_dev(Error **errp)
+{
+    Object *obj = object_resolve_path_type("", VMGENID_DEVICE, NULL);
+    if (!obj && errp) {
+        error_setg(errp, "%s is not found", VMGENID_DEVICE);
+    }
+    return obj;
+}
+
+#endif
-- 
2.7.4

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

* [Qemu-devel] [PATCH v5 06/10] qmp/hmp: add query-vm-generation-id and 'info vm-generation-id' commands
  2017-02-05  9:11 [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID ben
                   ` (4 preceding siblings ...)
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support ben
@ 2017-02-05  9:12 ` ben
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 07/10] qmp/hmp: add set-vm-generation-id commands ben
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 70+ messages in thread
From: ben @ 2017-02-05  9:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: lersek, mst, imammedo, Ben Warren

From: Igor Mammedov <imammedo@redhat.com>

Add commands to query Virtual Machine Generation ID counter.

QMP command example:
    { "execute": "query-vm-generation-id" }

HMP command example:
    info vm-generation-id

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Ben Warren <ben@skyportsystems.com>
---
 hmp-commands-info.hx | 13 +++++++++++++
 hmp.c                |  9 +++++++++
 hmp.h                |  1 +
 hw/acpi/vmgenid.c    | 20 ++++++++++++++++++++
 qapi-schema.json     | 20 ++++++++++++++++++++
 stubs/Makefile.objs  |  1 +
 stubs/vmgenid.c      |  8 ++++++++
 7 files changed, 72 insertions(+)
 create mode 100644 stubs/vmgenid.c

diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index b0f35e6..f3df793 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -802,6 +802,19 @@ Show information about hotpluggable CPUs
 ETEXI
 
 STEXI
+@item info vm-generation-id
+Show Virtual Machine Generation ID
+ETEXI
+
+    {
+        .name       = "vm-generation-id",
+        .args_type  = "",
+        .params     = "",
+        .help       = "Show Virtual Machine Generation ID",
+        .cmd = hmp_info_vm_generation_id,
+    },
+
+STEXI
 @end table
 ETEXI
 
diff --git a/hmp.c b/hmp.c
index 2bc4f06..535613d 100644
--- a/hmp.c
+++ b/hmp.c
@@ -2565,3 +2565,12 @@ void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict)
 
     qapi_free_HotpluggableCPUList(saved);
 }
+
+void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict)
+{
+    GuidInfo *info = qmp_query_vm_generation_id(NULL);
+    if (info) {
+        monitor_printf(mon, "%s\n", info->guid);
+    }
+    qapi_free_GuidInfo(info);
+}
diff --git a/hmp.h b/hmp.h
index 05daf7c..799fd37 100644
--- a/hmp.h
+++ b/hmp.h
@@ -137,5 +137,6 @@ void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict);
 void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict);
 void hmp_info_dump(Monitor *mon, const QDict *qdict);
 void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict);
+void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
index 6c9ecfd..e148051 100644
--- a/hw/acpi/vmgenid.c
+++ b/hw/acpi/vmgenid.c
@@ -204,3 +204,23 @@ static void vmgenid_register_types(void)
 }
 
 type_init(vmgenid_register_types)
+
+GuidInfo *qmp_query_vm_generation_id(Error **errp)
+{
+    GuidInfo *info;
+    VmGenIdState *vdev;
+    QemuUUID guid;
+    Object *obj = find_vmgenid_dev(errp);
+
+    if (!obj) {
+        return NULL;
+    }
+    vdev = VMGENID(obj);
+    /* Convert GUID back to big-endian before displaying */
+    memcpy(&guid, &vdev->guid, sizeof(guid));
+    qemu_uuid_bswap(&guid);
+
+    info = g_malloc0(sizeof(*info));
+    info->guid = qemu_uuid_unparse_strdup(&guid);
+    return info;
+}
diff --git a/qapi-schema.json b/qapi-schema.json
index cbdffdd..384a7f3 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -6031,3 +6031,23 @@
 #
 ##
 { 'command': 'query-hotpluggable-cpus', 'returns': ['HotpluggableCPU'] }
+
+##
+# @GuidInfo:
+#
+# GUID information.
+#
+# @guid: the globally unique identifier
+#
+# Since: 2.9
+##
+{ 'struct': 'GuidInfo', 'data': {'guid': 'str'} }
+
+##
+# @query-vm-generation-id:
+#
+# Show Virtual Machine Generation ID
+#
+# Since 2.9
+##
+{ 'command': 'query-vm-generation-id', 'returns': 'GuidInfo' }
diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs
index a187295..0bffca6 100644
--- a/stubs/Makefile.objs
+++ b/stubs/Makefile.objs
@@ -35,3 +35,4 @@ stub-obj-y += qmp_pc_dimm_device_list.o
 stub-obj-y += target-monitor-defs.o
 stub-obj-y += target-get-monitor-def.o
 stub-obj-y += pc_madt_cpu_entry.o
+stub-obj-y += vmgenid.o
diff --git a/stubs/vmgenid.c b/stubs/vmgenid.c
new file mode 100644
index 0000000..8c448ac
--- /dev/null
+++ b/stubs/vmgenid.c
@@ -0,0 +1,8 @@
+#include "qemu/osdep.h"
+#include "qmp-commands.h"
+
+GuidInfo *qmp_query_vm_generation_id(Error **errp)
+{
+    error_setg(errp, "this command is not currently supported");
+    return NULL;
+}
-- 
2.7.4

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

* [Qemu-devel] [PATCH v5 07/10] qmp/hmp: add set-vm-generation-id commands
  2017-02-05  9:11 [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID ben
                   ` (5 preceding siblings ...)
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 06/10] qmp/hmp: add query-vm-generation-id and 'info vm-generation-id' commands ben
@ 2017-02-05  9:12 ` ben
  2017-02-07 13:50   ` Igor Mammedov
  2017-02-08 22:01   ` Laszlo Ersek
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 08/10] PC: Support dynamic sysbus on pc_i440fx ben
                   ` (3 subsequent siblings)
  10 siblings, 2 replies; 70+ messages in thread
From: ben @ 2017-02-05  9:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: lersek, mst, imammedo, Ben Warren

From: Igor Mammedov <imammedo@redhat.com>

Add set-vm-generation-id command to set Virtual Machine
Generation ID counter.

QMP command example:
    { "execute": "set-vm-generation-id",
          "arguments": {
              "guid": "324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87"
          }
    }

HMP command example:
    set-vm-generation-id guid=324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Ben Warren <ben@skyportsystems.com>
---
 hmp-commands.hx   | 13 +++++++++++++
 hmp.c             | 12 ++++++++++++
 hmp.h             |  1 +
 hw/acpi/vmgenid.c | 12 ++++++++++++
 qapi-schema.json  | 11 +++++++++++
 stubs/vmgenid.c   |  6 ++++++
 6 files changed, 55 insertions(+)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 8819281..56744aa 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1775,5 +1775,18 @@ ETEXI
     },
 
 STEXI
+@item set-vm-generation-id @var{uuid}
+Set Virtual Machine Generation ID counter to @var{guid}
+ETEXI
+
+    {
+        .name       = "set-vm-generation-id",
+        .args_type  = "guid:s",
+        .params     = "guid",
+        .help       = "Set Virtual Machine Generation ID counter",
+        .cmd = hmp_set_vm_generation_id,
+    },
+
+STEXI
 @end table
 ETEXI
diff --git a/hmp.c b/hmp.c
index 535613d..39c8965 100644
--- a/hmp.c
+++ b/hmp.c
@@ -2574,3 +2574,15 @@ void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict)
     }
     qapi_free_GuidInfo(info);
 }
+
+void hmp_set_vm_generation_id(Monitor *mon, const QDict *qdict)
+{
+    Error *errp = NULL;
+    const char *guid = qdict_get_str(qdict, "guid");
+
+    qmp_set_vm_generation_id(guid, &errp);
+    if (errp) {
+        hmp_handle_error(mon, &errp);
+        return;
+    }
+}
diff --git a/hmp.h b/hmp.h
index 799fd37..e0ac1e8 100644
--- a/hmp.h
+++ b/hmp.h
@@ -138,5 +138,6 @@ void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict);
 void hmp_info_dump(Monitor *mon, const QDict *qdict);
 void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict);
 void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict);
+void hmp_set_vm_generation_id(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
index e148051..af8b35c 100644
--- a/hw/acpi/vmgenid.c
+++ b/hw/acpi/vmgenid.c
@@ -224,3 +224,15 @@ GuidInfo *qmp_query_vm_generation_id(Error **errp)
     info->guid = qemu_uuid_unparse_strdup(&guid);
     return info;
 }
+
+void qmp_set_vm_generation_id(const char *guid, Error **errp)
+{
+    Object *obj = find_vmgenid_dev(errp);
+
+    if (!obj) {
+        return;
+    }
+
+    object_property_set_str(obj, guid, VMGENID_GUID, errp);
+    return;
+}
diff --git a/qapi-schema.json b/qapi-schema.json
index 384a7f3..ed2657d 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -6051,3 +6051,14 @@
 # Since 2.9
 ##
 { 'command': 'query-vm-generation-id', 'returns': 'GuidInfo' }
+
+##
+# @set-vm-generation-id:
+#
+# Set Virtual Machine Generation ID
+#
+# @guid: new GUID to set as Virtual Machine Generation ID
+#
+# Since 2.9
+##
+{ 'command': 'set-vm-generation-id', 'data': {'guid': 'str'} }
diff --git a/stubs/vmgenid.c b/stubs/vmgenid.c
index 8c448ac..d25d41b 100644
--- a/stubs/vmgenid.c
+++ b/stubs/vmgenid.c
@@ -6,3 +6,9 @@ GuidInfo *qmp_query_vm_generation_id(Error **errp)
     error_setg(errp, "this command is not currently supported");
     return NULL;
 }
+
+void qmp_set_vm_generation_id(const char *guid, Error **errp)
+{
+    error_setg(errp, "this command is not currently supported");
+    return;
+}
-- 
2.7.4

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

* [Qemu-devel] [PATCH v5 08/10] PC: Support dynamic sysbus on pc_i440fx
  2017-02-05  9:11 [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID ben
                   ` (6 preceding siblings ...)
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 07/10] qmp/hmp: add set-vm-generation-id commands ben
@ 2017-02-05  9:12 ` ben
  2017-02-06 16:31   ` Michael S. Tsirkin
  2017-02-07 14:05   ` Igor Mammedov
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 09/10] tests: Move reusable ACPI macros into a new header file ben
                   ` (2 subsequent siblings)
  10 siblings, 2 replies; 70+ messages in thread
From: ben @ 2017-02-05  9:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: lersek, mst, imammedo, Ben Warren

From: Ben Warren <ben@skyportsystems.com>

This allows pc_i440fx-based machines to add new devices such as
VM Generation ID directly to the sysbus.

Signed-off-by: Ben Warren <ben@skyportsystems.com>
---
 hw/i386/pc_piix.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 9f102aa..c8ad99c 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -435,6 +435,7 @@ static void pc_i440fx_machine_options(MachineClass *m)
     m->hot_add_cpu = pc_hot_add_cpu;
     m->default_machine_opts = "firmware=bios-256k.bin";
     m->default_display = "std";
+    m->has_dynamic_sysbus = true;
 }
 
 static void pc_i440fx_2_9_machine_options(MachineClass *m)
-- 
2.7.4

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

* [Qemu-devel] [PATCH v5 09/10] tests: Move reusable ACPI macros into a new header file
  2017-02-05  9:11 [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID ben
                   ` (7 preceding siblings ...)
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 08/10] PC: Support dynamic sysbus on pc_i440fx ben
@ 2017-02-05  9:12 ` ben
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 10/10] tests: Add unit tests for the VM Generation ID feature ben
  2017-02-10 10:12 ` [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID Laszlo Ersek
  10 siblings, 0 replies; 70+ messages in thread
From: ben @ 2017-02-05  9:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: lersek, mst, imammedo, Ben Warren

From: Ben Warren <ben@skyportsystems.com>

Also usable by upcoming VM Generation ID tests

Signed-off-by: Ben Warren <ben@skyportsystems.com>
---
 tests/acpi-utils.h       | 75 ++++++++++++++++++++++++++++++++++++++++++++++++
 tests/bios-tables-test.c | 72 +---------------------------------------------
 2 files changed, 76 insertions(+), 71 deletions(-)
 create mode 100644 tests/acpi-utils.h

diff --git a/tests/acpi-utils.h b/tests/acpi-utils.h
new file mode 100644
index 0000000..d5e5eff
--- /dev/null
+++ b/tests/acpi-utils.h
@@ -0,0 +1,75 @@
+#ifndef TEST_ACPI_UTILS_H
+#define TEST_ACPI_UTILS_H
+
+/* DSDT and SSDTs format */
+typedef struct {
+    AcpiTableHeader header;
+    gchar *aml;            /* aml bytecode from guest */
+    gsize aml_len;
+    gchar *aml_file;
+    gchar *asl;            /* asl code generated from aml */
+    gsize asl_len;
+    gchar *asl_file;
+    bool tmp_files_retain;   /* do not delete the temp asl/aml */
+} QEMU_PACKED AcpiSdtTable;
+
+#define ACPI_READ_FIELD(field, addr)           \
+    do {                                       \
+        switch (sizeof(field)) {               \
+        case 1:                                \
+            field = readb(addr);               \
+            break;                             \
+        case 2:                                \
+            field = readw(addr);               \
+            break;                             \
+        case 4:                                \
+            field = readl(addr);               \
+            break;                             \
+        case 8:                                \
+            field = readq(addr);               \
+            break;                             \
+        default:                               \
+            g_assert(false);                   \
+        }                                      \
+        addr += sizeof(field);                  \
+    } while (0);
+
+#define ACPI_READ_ARRAY_PTR(arr, length, addr)  \
+    do {                                        \
+        int idx;                                \
+        for (idx = 0; idx < length; ++idx) {    \
+            ACPI_READ_FIELD(arr[idx], addr);    \
+        }                                       \
+    } while (0);
+
+#define ACPI_READ_ARRAY(arr, addr)                               \
+    ACPI_READ_ARRAY_PTR(arr, sizeof(arr) / sizeof(arr[0]), addr)
+
+#define ACPI_READ_TABLE_HEADER(table, addr)                      \
+    do {                                                         \
+        ACPI_READ_FIELD((table)->signature, addr);               \
+        ACPI_READ_FIELD((table)->length, addr);                  \
+        ACPI_READ_FIELD((table)->revision, addr);                \
+        ACPI_READ_FIELD((table)->checksum, addr);                \
+        ACPI_READ_ARRAY((table)->oem_id, addr);                  \
+        ACPI_READ_ARRAY((table)->oem_table_id, addr);            \
+        ACPI_READ_FIELD((table)->oem_revision, addr);            \
+        ACPI_READ_ARRAY((table)->asl_compiler_id, addr);         \
+        ACPI_READ_FIELD((table)->asl_compiler_revision, addr);   \
+    } while (0);
+
+#define ACPI_ASSERT_CMP(actual, expected) do { \
+    uint32_t ACPI_ASSERT_CMP_le = cpu_to_le32(actual); \
+    char ACPI_ASSERT_CMP_str[5] = {}; \
+    memcpy(ACPI_ASSERT_CMP_str, &ACPI_ASSERT_CMP_le, 4); \
+    g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \
+} while (0)
+
+#define ACPI_ASSERT_CMP64(actual, expected) do { \
+    uint64_t ACPI_ASSERT_CMP_le = cpu_to_le64(actual); \
+    char ACPI_ASSERT_CMP_str[9] = {}; \
+    memcpy(ACPI_ASSERT_CMP_str, &ACPI_ASSERT_CMP_le, 8); \
+    g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \
+} while (0)
+
+#endif  /* TEST_ACPI_UTILS_H */
diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c
index 5404805..c642f7f 100644
--- a/tests/bios-tables-test.c
+++ b/tests/bios-tables-test.c
@@ -17,6 +17,7 @@
 #include "hw/acpi/acpi-defs.h"
 #include "hw/smbios/smbios.h"
 #include "qemu/bitmap.h"
+#include "acpi-utils.h"
 #include "boot-sector.h"
 
 #define MACHINE_PC "pc"
@@ -24,18 +25,6 @@
 
 #define ACPI_REBUILD_EXPECTED_AML "TEST_ACPI_REBUILD_AML"
 
-/* DSDT and SSDTs format */
-typedef struct {
-    AcpiTableHeader header;
-    gchar *aml;            /* aml bytecode from guest */
-    gsize aml_len;
-    gchar *aml_file;
-    gchar *asl;            /* asl code generated from aml */
-    gsize asl_len;
-    gchar *asl_file;
-    bool tmp_files_retain;   /* do not delete the temp asl/aml */
-} QEMU_PACKED AcpiSdtTable;
-
 typedef struct {
     const char *machine;
     const char *variant;
@@ -53,65 +42,6 @@ typedef struct {
     int required_struct_types_len;
 } test_data;
 
-#define ACPI_READ_FIELD(field, addr)           \
-    do {                                       \
-        switch (sizeof(field)) {               \
-        case 1:                                \
-            field = readb(addr);               \
-            break;                             \
-        case 2:                                \
-            field = readw(addr);               \
-            break;                             \
-        case 4:                                \
-            field = readl(addr);               \
-            break;                             \
-        case 8:                                \
-            field = readq(addr);               \
-            break;                             \
-        default:                               \
-            g_assert(false);                   \
-        }                                      \
-        addr += sizeof(field);                  \
-    } while (0);
-
-#define ACPI_READ_ARRAY_PTR(arr, length, addr)  \
-    do {                                        \
-        int idx;                                \
-        for (idx = 0; idx < length; ++idx) {    \
-            ACPI_READ_FIELD(arr[idx], addr);    \
-        }                                       \
-    } while (0);
-
-#define ACPI_READ_ARRAY(arr, addr)                               \
-    ACPI_READ_ARRAY_PTR(arr, sizeof(arr)/sizeof(arr[0]), addr)
-
-#define ACPI_READ_TABLE_HEADER(table, addr)                      \
-    do {                                                         \
-        ACPI_READ_FIELD((table)->signature, addr);               \
-        ACPI_READ_FIELD((table)->length, addr);                  \
-        ACPI_READ_FIELD((table)->revision, addr);                \
-        ACPI_READ_FIELD((table)->checksum, addr);                \
-        ACPI_READ_ARRAY((table)->oem_id, addr);                  \
-        ACPI_READ_ARRAY((table)->oem_table_id, addr);            \
-        ACPI_READ_FIELD((table)->oem_revision, addr);            \
-        ACPI_READ_ARRAY((table)->asl_compiler_id, addr);         \
-        ACPI_READ_FIELD((table)->asl_compiler_revision, addr);   \
-    } while (0);
-
-#define ACPI_ASSERT_CMP(actual, expected) do { \
-    uint32_t ACPI_ASSERT_CMP_le = cpu_to_le32(actual); \
-    char ACPI_ASSERT_CMP_str[5] = {}; \
-    memcpy(ACPI_ASSERT_CMP_str, &ACPI_ASSERT_CMP_le, 4); \
-    g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \
-} while (0)
-
-#define ACPI_ASSERT_CMP64(actual, expected) do { \
-    uint64_t ACPI_ASSERT_CMP_le = cpu_to_le64(actual); \
-    char ACPI_ASSERT_CMP_str[9] = {}; \
-    memcpy(ACPI_ASSERT_CMP_str, &ACPI_ASSERT_CMP_le, 8); \
-    g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \
-} while (0)
-
 static char disk[] = "tests/acpi-test-disk-XXXXXX";
 static const char *data_dir = "tests/acpi-test-data";
 #ifdef CONFIG_IASL
-- 
2.7.4

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

* [Qemu-devel] [PATCH v5 10/10] tests: Add unit tests for the VM Generation ID feature
  2017-02-05  9:11 [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID ben
                   ` (8 preceding siblings ...)
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 09/10] tests: Move reusable ACPI macros into a new header file ben
@ 2017-02-05  9:12 ` ben
  2017-02-10 10:12 ` [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID Laszlo Ersek
  10 siblings, 0 replies; 70+ messages in thread
From: ben @ 2017-02-05  9:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: lersek, mst, imammedo, Ben Warren

From: Ben Warren <ben@skyportsystems.com>

The following tests are implemented:
* test that a GUID passed in by command line is propagated to the guest.
* test that changing the GUID at runtime via the monitor is reflected in
  the guest.
* test that the "auto" argument to the GUID generates a different, and
  correct GUID as seen by the guest.

  This patch is loosely based on a previous patch from:
  Gal Hammer <ghammer@redhat.com>  and Igor Mammedov <imammedo@redhat.com>

Signed-off-by: Ben Warren <ben@skyportsystems.com>
---
 tests/Makefile.include |   2 +
 tests/vmgenid-test.c   | 184 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 186 insertions(+)
 create mode 100644 tests/vmgenid-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 634394a..ca4b3f7 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -241,6 +241,7 @@ check-qtest-i386-y += tests/usb-hcd-xhci-test$(EXESUF)
 gcov-files-i386-y += hw/usb/hcd-xhci.c
 check-qtest-i386-y += tests/pc-cpu-test$(EXESUF)
 check-qtest-i386-y += tests/q35-test$(EXESUF)
+check-qtest-i386-y += tests/vmgenid-test$(EXESUF)
 gcov-files-i386-y += hw/pci-host/q35.c
 check-qtest-i386-$(CONFIG_VHOST_NET_TEST_i386) += tests/vhost-user-test$(EXESUF)
 ifeq ($(CONFIG_VHOST_NET_TEST_i386),)
@@ -726,6 +727,7 @@ tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contrib/ivshmem-server/ivshmem
 tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o contrib/libvhost-user/libvhost-user.o $(test-util-obj-y)
 tests/test-uuid$(EXESUF): tests/test-uuid.o $(test-util-obj-y)
 tests/test-arm-mptimer$(EXESUF): tests/test-arm-mptimer.o
+tests/vmgenid-test$(EXESUF): tests/vmgenid-test.o
 
 tests/migration/stress$(EXESUF): tests/migration/stress.o
 	$(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ,"LINK","$(TARGET_DIR)$@")
diff --git a/tests/vmgenid-test.c b/tests/vmgenid-test.c
new file mode 100644
index 0000000..0f5ba07
--- /dev/null
+++ b/tests/vmgenid-test.c
@@ -0,0 +1,184 @@
+/*
+ * QTest testcase for VM Generation ID
+ *
+ * Copyright (c) 2016 Red Hat, Inc.
+ * Copyright (c) 2017 Skyport Systems
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <unistd.h>
+#include "qemu/osdep.h"
+#include "qemu/bitmap.h"
+#include "qemu/uuid.h"
+#include "hw/acpi/acpi-defs.h"
+#include "acpi-utils.h"
+#include "libqtest.h"
+
+#define VGID_GUID "324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87"
+
+static uint64_t vgia;
+
+typedef struct {
+    AcpiTableHeader header;
+    gchar name_op;
+    gchar vgia[4];
+    gchar val_op;
+    uint64_t vgia_val;
+} QEMU_PACKED VgidTable;
+
+static uint64_t find_vgia(void)
+{
+    uint32_t off;
+    AcpiRsdpDescriptor rsdp_table;
+    uint32_t rsdt;
+    AcpiRsdtDescriptorRev1 rsdt_table;
+    int tables_nr;
+    uint32_t *tables;
+    AcpiTableHeader ssdt_table;
+    VgidTable vgid_table;
+    int i;
+
+    /* First, find the RSDP */
+    for (off = 0xf0000; off < 0x100000; off += 0x10) {
+        uint8_t sig[] = "RSD PTR ";
+
+        for (i = 0; i < sizeof sig - 1; ++i) {
+            sig[i] = readb(off + i);
+        }
+
+        if (!memcmp(sig, "RSD PTR ", sizeof sig)) {
+            break;
+        }
+    }
+    g_assert_cmphex(off, <, 0x100000);
+
+    /* Parse the RSDP header so we can find the RSDT */
+    ACPI_READ_FIELD(rsdp_table.signature, off);
+    ACPI_ASSERT_CMP64(rsdp_table.signature, "RSD PTR ");
+
+    ACPI_READ_FIELD(rsdp_table.checksum, off);
+    ACPI_READ_ARRAY(rsdp_table.oem_id, off);
+    ACPI_READ_FIELD(rsdp_table.revision, off);
+    ACPI_READ_FIELD(rsdp_table.rsdt_physical_address, off);
+
+    rsdt = rsdp_table.rsdt_physical_address;
+    /* read the header */
+    ACPI_READ_TABLE_HEADER(&rsdt_table, rsdt);
+    ACPI_ASSERT_CMP(rsdt_table.signature, "RSDT");
+
+    /* compute the table entries in rsdt */
+    tables_nr = (rsdt_table.length - sizeof(AcpiRsdtDescriptorRev1)) /
+                sizeof(uint32_t);
+    g_assert_cmpint(tables_nr, >, 0);
+
+    /* get the addresses of the tables pointed by rsdt */
+    tables = g_new0(uint32_t, tables_nr);
+    ACPI_READ_ARRAY_PTR(tables, tables_nr, rsdt);
+
+    for (i = 0; i < tables_nr; i++) {
+        ACPI_READ_TABLE_HEADER(&ssdt_table, tables[i]);
+        if (!strncmp((char *)ssdt_table.oem_table_id, "VMGENID", 7)) {
+            /* the first entry in the table should be VGIA
+             * That's all we need */
+            ACPI_READ_FIELD(vgid_table.name_op, tables[i]);
+            g_assert(vgid_table.name_op == 0x08);  /* name */
+            ACPI_READ_ARRAY(vgid_table.vgia, tables[i]);
+            g_assert(memcmp(vgid_table.vgia, "VGIA", 4) == 0);
+            ACPI_READ_FIELD(vgid_table.val_op, tables[i]);
+            g_assert(vgid_table.val_op == 0x0E);  /* qword */
+            ACPI_READ_FIELD(vgid_table.vgia_val, tables[i]);
+            return vgid_table.vgia_val;
+        }
+    }
+    return 0;
+}
+
+static void vmgenid_read_guid(uint8_t *guid)
+{
+    int i;
+
+    if (vgia == 0) {
+        vgia = find_vgia();
+    }
+    g_assert(vgia);
+
+    /* Read the GUID directly from guest memory */
+    for (i = 0; i < 16; i++) {
+        guid[i] = readb(vgia + i);
+    }
+}
+
+static void vmgenid_test(void)
+{
+    uint8_t measured[16];
+    QemuUUID expected;
+    g_assert(qemu_uuid_parse(VGID_GUID, &expected) == 0);
+    vmgenid_read_guid(measured);
+    g_assert(memcmp(measured, expected.data, sizeof(measured)) == 0);
+}
+
+static void vmgenid_set_guid_test(void)
+{
+    QDict *response;
+    gchar *cmd;
+    uint8_t measured[16];
+    QemuUUID expected;
+    g_assert(qemu_uuid_parse(VGID_GUID, &expected) == 0);
+    /* Change the GUID slightly */
+    expected.data[0] += 1;
+
+    cmd = g_strdup_printf("{ 'execute': 'qom-set', 'arguments': { "
+                   "'path': '/machine/peripheral/testvgid', "
+                   "'property': 'guid', 'value': '%s' } }",
+                   qemu_uuid_unparse_strdup(&expected));
+    response = qmp(cmd);
+    g_assert(qdict_haskey(response, "return"));
+    QDECREF(response);
+
+    vmgenid_read_guid(measured);
+    g_assert(memcmp(measured, expected.data, sizeof(measured)) == 0);
+}
+
+static void vmgenid_set_guid_auto_test(void)
+{
+    QDict *response;
+    QemuUUID measured;
+    QemuUUID expected;
+
+    /* Read the initial value */
+    vmgenid_read_guid(expected.data);
+
+    /* Setting to 'auto' generates a random GUID */
+    response = qmp("{ 'execute': 'qom-set', 'arguments': { "
+                   "'path': '/machine/peripheral/testvgid', "
+                   "'property': 'guid', 'value': 'auto' } }");
+
+    g_assert(qdict_haskey(response, "return"));
+    QDECREF(response);
+
+    vmgenid_read_guid(measured.data);
+    g_assert(memcmp(measured.data, expected.data, sizeof(measured.data)) != 0);
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_start("-machine accel=tcg -device vmgenid,id=testvgid,"
+                "guid=" VGID_GUID);
+    qtest_add_func("/vmgenid/vmgenid", vmgenid_test);
+    qtest_add_func("/vmgenid/vmgenid/set-guid", vmgenid_set_guid_test);
+    qtest_add_func("/vmgenid/vmgenid/set-guid-auto",
+                   vmgenid_set_guid_auto_test);
+    ret = g_test_run();
+
+    qtest_end();
+
+    return ret;
+}
-- 
2.7.4

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

* Re: [Qemu-devel] [PATCH v5 02/10] linker-loader: Add new 'write pointer' command
  2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 02/10] linker-loader: Add new 'write pointer' command ben
@ 2017-02-06 14:56   ` Michael S. Tsirkin
  2017-02-06 17:16     ` Ben Warren
  0 siblings, 1 reply; 70+ messages in thread
From: Michael S. Tsirkin @ 2017-02-06 14:56 UTC (permalink / raw)
  To: ben; +Cc: qemu-devel, lersek, imammedo

On Sun, Feb 05, 2017 at 01:11:57AM -0800, ben@skyportsystems.com wrote:
> From: Ben Warren <ben@skyportsystems.com>
> 
> This adds to the existing 'add pointer' functionality in that it
> instructs the guest (BIOS or UEFI) to not patch memory but to instead
> write the changes back to QEMU via a writeable fw_cfg file.
> 
> Signed-off-by: Ben Warren <ben@skyportsystems.com>
> ---
>  hw/acpi/aml-build.c                  |  2 +-
>  hw/acpi/bios-linker-loader.c         | 35 ++++++++++++++++++++++++-----------
>  hw/acpi/nvdimm.c                     |  2 +-
>  hw/arm/virt-acpi-build.c             |  4 ++--
>  hw/i386/acpi-build.c                 |  8 ++++----
>  include/hw/acpi/bios-linker-loader.h |  3 ++-
>  6 files changed, 34 insertions(+), 20 deletions(-)
> 
> diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
> index 9fc54c9..03b6c6c 100644
> --- a/hw/acpi/aml-build.c
> +++ b/hw/acpi/aml-build.c
> @@ -1626,7 +1626,7 @@ build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets,
>          /* rsdt->table_offset_entry to be filled by Guest linker */
>          bios_linker_loader_add_pointer(linker,
>              ACPI_BUILD_TABLE_FILE, rsdt_entry_offset, rsdt_entry_size,
> -            ACPI_BUILD_TABLE_FILE, ref_tbl_offset);
> +            ACPI_BUILD_TABLE_FILE, ref_tbl_offset, false);
>      }
>      build_header(linker, table_data,
>                   (void *)rsdt, "RSDT", rsdt_len, 1, oem_id, oem_table_id);
> diff --git a/hw/acpi/bios-linker-loader.c b/hw/acpi/bios-linker-loader.c
> index d963ebe..e46bc29 100644
> --- a/hw/acpi/bios-linker-loader.c
> +++ b/hw/acpi/bios-linker-loader.c
> @@ -52,10 +52,13 @@ struct BiosLinkerLoaderEntry {
>          } alloc;
>  
>          /*
> -         * COMMAND_ADD_POINTER - patch the table (originating from
> -         * @dest_file) at @pointer.offset, by adding a pointer to the table
> +         * COMMAND_ADD_POINTER &
> +         * COMMAND_WRITE_POINTER - patch guest memory (originating from
> +         * @dest_file) at @pointer.offset, by adding a pointer to the memory
>           * originating from @src_file. 1,2,4 or 8 byte unsigned
>           * addition is used depending on @pointer.size.
> +         * Instead of patching memory, COMMAND_WRITE_POINTER writes the changes
> +         * to @dest_file in QEMU via fw_cfg DMA.
>           */
>          struct {
>              char dest_file[BIOS_LINKER_LOADER_FILESZ];
> @@ -85,9 +88,10 @@ struct BiosLinkerLoaderEntry {
>  typedef struct BiosLinkerLoaderEntry BiosLinkerLoaderEntry;
>  
>  enum {
> -    BIOS_LINKER_LOADER_COMMAND_ALLOCATE     = 0x1,
> -    BIOS_LINKER_LOADER_COMMAND_ADD_POINTER  = 0x2,
> -    BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM = 0x3,
> +    BIOS_LINKER_LOADER_COMMAND_ALLOCATE          = 0x1,
> +    BIOS_LINKER_LOADER_COMMAND_ADD_POINTER       = 0x2,
> +    BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM      = 0x3,
> +    BIOS_LINKER_LOADER_COMMAND_WRITE_POINTER     = 0x4,
>  };
>  
>  enum {
> @@ -242,13 +246,15 @@ void bios_linker_loader_add_checksum(BIOSLinker *linker, const char *file_name,
>   * @src_offset: location within source file blob to which
>   *              @dest_file+@dst_patched_offset will point to after
>   *              firmware's executed ADD_POINTER command
> + * @write_back: guest should write change contents back to QEMU after patching
>   */
>  void bios_linker_loader_add_pointer(BIOSLinker *linker,
>                                      const char *dest_file,
>                                      uint32_t dst_patched_offset,
>                                      uint8_t dst_patched_size,
>                                      const char *src_file,
> -                                    uint32_t src_offset)
> +                                    uint32_t src_offset,
> +                                    bool write_back)
>  {
>      uint64_t le_src_offset;
>      BiosLinkerLoaderEntry entry;

Frankly I prefer a new bios_linker_loader_write_pointer.


> @@ -257,8 +263,11 @@ void bios_linker_loader_add_pointer(BIOSLinker *linker,
>      const BiosLinkerFileEntry *source_file =
>          bios_linker_find_file(linker, src_file);
>  
> -    assert(dst_patched_offset < dst_file->blob->len);
> -    assert(dst_patched_offset + dst_patched_size <= dst_file->blob->len);
> +    /* dst_file need not exist if writing back */

Why not?

> +    if (!write_back) {
> +        assert(dst_patched_offset < dst_file->blob->len);
> +        assert(dst_patched_offset + dst_patched_size <= dst_file->blob->len);
> +    }
>      assert(src_offset < source_file->blob->len);
>  
>      memset(&entry, 0, sizeof entry);
> @@ -266,15 +275,19 @@ void bios_linker_loader_add_pointer(BIOSLinker *linker,
>              sizeof entry.pointer.dest_file - 1);
>      strncpy(entry.pointer.src_file, src_file,
>              sizeof entry.pointer.src_file - 1);
> -    entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ADD_POINTER);
> +    entry.command = cpu_to_le32(write_back ?
> +                                BIOS_LINKER_LOADER_COMMAND_WRITE_POINTER :
> +                                BIOS_LINKER_LOADER_COMMAND_ADD_POINTER);
>      entry.pointer.offset = cpu_to_le32(dst_patched_offset);
>      entry.pointer.size = dst_patched_size;
>      assert(dst_patched_size == 1 || dst_patched_size == 2 ||
>             dst_patched_size == 4 || dst_patched_size == 8);
>  
>      le_src_offset = cpu_to_le64(src_offset);
> -    memcpy(dst_file->blob->data + dst_patched_offset,
> -           &le_src_offset, dst_patched_size);
> +    if (!write_back) {
> +        memcpy(dst_file->blob->data + dst_patched_offset,
> +               &le_src_offset, dst_patched_size);
> +    }
>  
>      g_array_append_vals(linker->cmd_blob, &entry, sizeof entry);
>  }
> diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c
> index 8e7d6ec..175996e 100644
> --- a/hw/acpi/nvdimm.c
> +++ b/hw/acpi/nvdimm.c
> @@ -1266,7 +1266,7 @@ static void nvdimm_build_ssdt(GArray *table_offsets, GArray *table_data,
>                               sizeof(NvdimmDsmIn), false /* high memory */);
>      bios_linker_loader_add_pointer(linker,
>          ACPI_BUILD_TABLE_FILE, mem_addr_offset, sizeof(uint32_t),
> -        NVDIMM_DSM_MEM_FILE, 0);
> +        NVDIMM_DSM_MEM_FILE, 0, false);
>      build_header(linker, table_data,
>          (void *)(table_data->data + nvdimm_ssdt),
>          "SSDT", table_data->len - nvdimm_ssdt, 1, NULL, "NVDIMM");
> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
> index 07a10ac..a13f40d 100644
> --- a/hw/arm/virt-acpi-build.c
> +++ b/hw/arm/virt-acpi-build.c
> @@ -380,7 +380,7 @@ build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset)
>      /* Address to be filled by Guest linker */
>      bios_linker_loader_add_pointer(linker,
>          ACPI_BUILD_RSDP_FILE, rsdt_pa_offset, rsdt_pa_size,
> -        ACPI_BUILD_TABLE_FILE, rsdt_tbl_offset);
> +        ACPI_BUILD_TABLE_FILE, rsdt_tbl_offset, false);
>  
>      /* Checksum to be filled by Guest linker */
>      bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
> @@ -684,7 +684,7 @@ static void build_fadt(GArray *table_data, BIOSLinker *linker,
>      /* DSDT address to be filled by Guest linker */
>      bios_linker_loader_add_pointer(linker,
>          ACPI_BUILD_TABLE_FILE, dsdt_entry_offset, sizeof(fadt->dsdt),
> -        ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset);
> +        ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset, false);
>  
>      build_header(linker, table_data,
>                   (void *)fadt, "FACP", sizeof(*fadt), 5, NULL, NULL);
> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> index 1c928ab..78a1d84 100644
> --- a/hw/i386/acpi-build.c
> +++ b/hw/i386/acpi-build.c
> @@ -319,13 +319,13 @@ build_fadt(GArray *table_data, BIOSLinker *linker, AcpiPmInfo *pm,
>      /* FACS address to be filled by Guest linker */
>      bios_linker_loader_add_pointer(linker,
>          ACPI_BUILD_TABLE_FILE, fw_ctrl_offset, sizeof(fadt->firmware_ctrl),
> -        ACPI_BUILD_TABLE_FILE, facs_tbl_offset);
> +        ACPI_BUILD_TABLE_FILE, facs_tbl_offset, false);
>  
>      /* DSDT address to be filled by Guest linker */
>      fadt_setup(fadt, pm);
>      bios_linker_loader_add_pointer(linker,
>          ACPI_BUILD_TABLE_FILE, dsdt_entry_offset, sizeof(fadt->dsdt),
> -        ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset);
> +        ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset, false);
>  
>      build_header(linker, table_data,
>                   (void *)fadt, "FACP", sizeof(*fadt), 1, oem_id, oem_table_id);
> @@ -2262,7 +2262,7 @@ build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, GArray *tcpalog)
>      /* log area start address to be filled by Guest linker */
>      bios_linker_loader_add_pointer(linker,
>          ACPI_BUILD_TABLE_FILE, log_addr_offset, log_addr_size,
> -        ACPI_BUILD_TPMLOG_FILE, 0);
> +        ACPI_BUILD_TPMLOG_FILE, 0, false);
>  
>      build_header(linker, table_data,
>                   (void *)tcpa, "TCPA", sizeof(*tcpa), 2, NULL, NULL);
> @@ -2552,7 +2552,7 @@ build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset)
>      /* Address to be filled by Guest linker */
>      bios_linker_loader_add_pointer(linker,
>          ACPI_BUILD_RSDP_FILE, rsdt_pa_offset, rsdt_pa_size,
> -        ACPI_BUILD_TABLE_FILE, rsdt_tbl_offset);
> +        ACPI_BUILD_TABLE_FILE, rsdt_tbl_offset, false);
>  
>      /* Checksum to be filled by Guest linker */
>      bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
> diff --git a/include/hw/acpi/bios-linker-loader.h b/include/hw/acpi/bios-linker-loader.h
> index fa1e5d1..d97e39d 100644
> --- a/include/hw/acpi/bios-linker-loader.h
> +++ b/include/hw/acpi/bios-linker-loader.h
> @@ -24,7 +24,8 @@ void bios_linker_loader_add_pointer(BIOSLinker *linker,
>                                      uint32_t dst_patched_offset,
>                                      uint8_t dst_patched_size,
>                                      const char *src_file,
> -                                    uint32_t src_offset);
> +                                    uint32_t src_offset,
> +                                    bool write_back);
>  
>  void bios_linker_loader_cleanup(BIOSLinker *linker);
>  #endif
> -- 
> 2.7.4

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support ben
@ 2017-02-06 16:15   ` Michael S. Tsirkin
  2017-02-06 17:29     ` Ben Warren
  2017-02-07 13:48   ` Igor Mammedov
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 70+ messages in thread
From: Michael S. Tsirkin @ 2017-02-06 16:15 UTC (permalink / raw)
  To: ben; +Cc: qemu-devel, lersek, imammedo

On Sun, Feb 05, 2017 at 01:12:00AM -0800, ben@skyportsystems.com wrote:
> From: Ben Warren <ben@skyportsystems.com>
> 
> This implements the VM Generation ID feature by passing a 128-bit
> GUID to the guest via a fw_cfg blob.
> Any time the GUID changes, an ACPI notify event is sent to the guest
> 
> The user interface is a simple device with one parameter:
>  - guid (string, must be "auto" or in UUID format
>    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
> 
> Signed-off-by: Ben Warren <ben@skyportsystems.com>


Thanks!
I think it's mostly in a good shape.
Comments inside.


> ---
>  default-configs/i386-softmmu.mak     |   1 +
>  default-configs/x86_64-softmmu.mak   |   1 +
>  hw/acpi/Makefile.objs                |   1 +
>  hw/acpi/vmgenid.c                    | 206 +++++++++++++++++++++++++++++++++++
>  hw/i386/acpi-build.c                 |  10 ++
>  include/hw/acpi/acpi_dev_interface.h |   1 +
>  include/hw/acpi/vmgenid.h            |  37 +++++++
>  7 files changed, 257 insertions(+)
>  create mode 100644 hw/acpi/vmgenid.c
>  create mode 100644 include/hw/acpi/vmgenid.h
> 
> diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
> index 384cefb..1a43542 100644
> --- a/default-configs/i386-softmmu.mak
> +++ b/default-configs/i386-softmmu.mak
> @@ -58,3 +58,4 @@ CONFIG_I82801B11=y
>  CONFIG_SMBIOS=y
>  CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
>  CONFIG_PXB=y
> +CONFIG_ACPI_VMGENID=y
> diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
> index 491a191..aee8b08 100644
> --- a/default-configs/x86_64-softmmu.mak
> +++ b/default-configs/x86_64-softmmu.mak
> @@ -58,3 +58,4 @@ CONFIG_I82801B11=y
>  CONFIG_SMBIOS=y
>  CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
>  CONFIG_PXB=y
> +CONFIG_ACPI_VMGENID=y
> diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
> index 6acf798..11c35bc 100644
> --- a/hw/acpi/Makefile.objs
> +++ b/hw/acpi/Makefile.objs
> @@ -5,6 +5,7 @@ common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
>  common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
>  common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
>  common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
> +common-obj-$(CONFIG_ACPI_VMGENID) += vmgenid.o
>  common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
>  
>  common-obj-y += acpi_interface.o
> diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
> new file mode 100644
> index 0000000..6c9ecfd
> --- /dev/null
> +++ b/hw/acpi/vmgenid.c
> @@ -0,0 +1,206 @@
> +/*
> + *  Virtual Machine Generation ID Device
> + *
> + *  Copyright (C) 2017 Skyport Systems.
> + *
> + *  Author: Ben Warren <ben@skyportsystems.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + *
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qmp-commands.h"
> +#include "hw/acpi/acpi.h"
> +#include "hw/acpi/aml-build.h"
> +#include "hw/acpi/vmgenid.h"
> +#include "hw/nvram/fw_cfg.h"
> +#include "sysemu/sysemu.h"
> +
> +void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker *linker)
> +{
> +    Object *obj;
> +    VmGenIdState *s;
> +    Aml *ssdt, *dev, *scope, *method, *addr, *if_ctx;
> +    uint32_t vgia_offset;
> +
> +    obj = find_vmgenid_dev(NULL);
> +    assert(obj);
> +    s = VMGENID(obj);
> +
> +    /* Fill in the GUID values */
> +    if (guid->len != VMGENID_FW_CFG_SIZE) {
> +        g_array_set_size(guid, VMGENID_FW_CFG_SIZE);
> +    }
> +    g_array_insert_vals(guid, VMGENID_GUID_OFFSET, s->guid.data, 16);

ARRAY_SIZE(s->guid.data);

> +
> +    /* Put this in a separate SSDT table */
> +    ssdt = init_aml_allocator();
> +
> +    /* Reserve space for header */
> +    acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader));
> +
> +    /* Storage for the GUID address */
> +    vgia_offset = table_data->len +
> +        build_append_named_dword(ssdt->buf, "VGIA");
> +    scope = aml_scope("\\_SB");
> +    dev = aml_device("VGEN");
> +    aml_append(dev, aml_name_decl("_HID", aml_string("QEMUVGID")));
> +    aml_append(dev, aml_name_decl("_CID", aml_string("VM_Gen_Counter")));
> +    aml_append(dev, aml_name_decl("_DDN", aml_string("VM_Gen_Counter")));
> +
> +    /* Simple status method to check that address is linked and non-zero */
> +    method = aml_method("_STA", 0, AML_NOTSERIALIZED);
> +    addr = aml_local(0);
> +    aml_append(method, aml_store(aml_int(0xf), addr));
> +    if_ctx = aml_if(aml_equal(aml_name("VGIA"), aml_int(0)));
> +    aml_append(if_ctx, aml_store(aml_int(0), addr));
> +    aml_append(method, if_ctx);
> +    aml_append(method, aml_return(addr));
> +    aml_append(dev, method);
> +
> +    /* the ADDR method returns two 32-bit words representing the lower and
> +     * upper halves * of the physical address of the fw_cfg blob
> +     * (holding the GUID) */

/*
 * multiline comments
 * look like this
 */

> +    method = aml_method("ADDR", 0, AML_NOTSERIALIZED);
> +
> +    addr = aml_local(0);
> +    aml_append(method, aml_store(aml_package(2), addr));
> +
> +    aml_append(method, aml_store(aml_add(aml_name("VGIA"),
> +                                         aml_int(VMGENID_GUID_OFFSET), NULL),
> +                                 aml_index(addr, aml_int(0))));
> +    aml_append(method, aml_store(aml_int(0), aml_index(addr, aml_int(1))));
> +    aml_append(method, aml_return(addr));
> +
> +    aml_append(dev, method);
> +    aml_append(scope, dev);
> +    aml_append(ssdt, scope);
> +
> +    /* attach an ACPI notify */
> +    method = aml_method("\\_GPE._E05", 0, AML_NOTSERIALIZED);
> +    aml_append(method, aml_notify(aml_name("\\_SB.VGEN"), aml_int(0x80)));
> +    aml_append(ssdt, method);
> +
> +    g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len);
> +
> +    /* Allocate guest memory for the Data fw_cfg blob */
> +    bios_linker_loader_alloc(linker, VMGENID_GUID_FW_CFG_FILE, guid, 4096,
> +                             false /* page boundary, high memory */);
> +
> +    /* Patch address of GUID fw_cfg blob into the ADDR fw_cfg blob */

add ... so QEMU can write GUID there

> +    bios_linker_loader_add_pointer(linker,
> +        VMGENID_ADDR_FW_CFG_FILE, 0, sizeof(uint32_t),
> +        VMGENID_GUID_FW_CFG_FILE, 0, true);
> +
> +    /* Patch address of GUID fw_cfg blob into the AML */

add ... so OSPM can retrieve and read it

> +    bios_linker_loader_add_pointer(linker,
> +        ACPI_BUILD_TABLE_FILE, vgia_offset, sizeof(uint32_t),
> +        VMGENID_GUID_FW_CFG_FILE, 0, false);
> +
> +    build_header(linker, table_data,
> +        (void *)(table_data->data + table_data->len - ssdt->buf->len),
> +        "SSDT", ssdt->buf->len, 1, NULL, "VMGENID");
> +    free_aml_allocator();
> +}
> +
> +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid)
> +{
> +    Object *obj = find_vmgenid_dev(NULL);
> +    assert(obj);
> +    VmGenIdState *vms = VMGENID(obj);
> +
> +    /* Create a read-only fw_cfg file for GUID */
> +    fw_cfg_add_file(s, VMGENID_GUID_FW_CFG_FILE, guid->data,
> +                    VMGENID_FW_CFG_SIZE);
> +    /* Create a read-write fw_cfg file for Address */
> +    fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL, NULL,

Seems wrong. What if guest updates the address after command line
set it? You want a callback to copy guid there.


> +                             vms->vgia_le, sizeof(uint32_t), false);

Should be ARRAY_SIZE(vms->vgia_le).

Also, I thought GUID is at an offset from the beginning
in order to trick OVMF, isn't it?


> +}
> +
> +static void vmgenid_update_guest(VmGenIdState *s)
> +{
> +    Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL);
> +    uint32_t vgia;
> +
> +    if (obj) {
> +        /* Write the GUID to guest memory */
> +        memcpy(&vgia, s->vgia_le, sizeof(vgia));
> +        vgia = le32_to_cpu(vgia);
> +        if (vgia) {

add a comment saying 0 means bios did not run yet.

> +            cpu_physical_memory_write(vgia + VMGENID_GUID_OFFSET,
> +                                      s->guid.data, sizeof(s->guid.data));

Avoid this. You want dma.h APIs.

> +            /* Send _GPE.E05 event */
> +            acpi_send_event(DEVICE(obj), ACPI_VMGENID_CHANGE_STATUS);
> +        }
> +    }
> +}
> +
> +static void vmgenid_set_guid(Object *obj, const char *value, Error **errp)
> +{
> +    VmGenIdState *s = VMGENID(obj);
> +
> +    if (!strncmp(value, "auto", 4)) {

I'd use strcmp here.

> +        qemu_uuid_generate(&s->guid);
> +    } else if (qemu_uuid_parse(value, &s->guid) < 0) {
> +        error_setg(errp, "'%s. %s': Failed to parse GUID string: %s",
> +                   object_get_typename(OBJECT(s)), VMGENID_GUID, value);
> +        return;
> +    }
> +    /* QemuUUID has the first three words as big-endian, and expect that any
> +     * GUIDs passed in will always be BE.  The guest, however will expect
> +     * the fields to be little-endian, so store that way internally.

This makes my head spin. It's the actual guid, right? Only place we need it is when
we copy it into guest memory. So swap there -
and do it to a copy so you won't need these comments.

>  Make
> +     * sure to swap back whenever reporting via monitor */

And what code does this swap back?

> +    qemu_uuid_bswap(&s->guid);
> +
> +    /* Send the ACPI notify */
> +    vmgenid_update_guest(s);
> +}
> +
> +/* After restoring an image, we need to update the guest memory and notify
> + * it of a potential change to VM Generation ID */
> +static int vmgenid_post_load(void *opaque, int version_id)
> +{
> +    VmGenIdState *s = opaque;
> +    vmgenid_update_guest(s);
> +    return 0;
> +}
> +
> +static const VMStateDescription vmstate_vmgenid = {
> +    .name = "vmgenid",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .post_load = vmgenid_post_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8_ARRAY(vgia_le, VmGenIdState, sizeof(uint32_t)),
> +        VMSTATE_END_OF_LIST()
> +    },
> +};
> +
> +static void vmgenid_initfn(Object *obj)
> +{
> +    object_property_add_str(obj, VMGENID_GUID, NULL, vmgenid_set_guid, NULL);
> +}
> +
> +static void vmgenid_device_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->vmsd = &vmstate_vmgenid;
> +}
> +
> +static const TypeInfo vmgenid_device_info = {
> +    .name          = VMGENID_DEVICE,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(VmGenIdState),
> +    .instance_init = vmgenid_initfn,
> +    .class_init    = vmgenid_device_class_init,
> +};
> +
> +static void vmgenid_register_types(void)
> +{
> +    type_register_static(&vmgenid_device_info);
> +}
> +
> +type_init(vmgenid_register_types)
> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> index 78a1d84..4c40f76 100644
> --- a/hw/i386/acpi-build.c
> +++ b/hw/i386/acpi-build.c
> @@ -42,6 +42,7 @@
>  #include "hw/acpi/memory_hotplug.h"
>  #include "sysemu/tpm.h"
>  #include "hw/acpi/tpm.h"
> +#include "hw/acpi/vmgenid.h"
>  #include "sysemu/tpm_backend.h"
>  #include "hw/timer/mc146818rtc_regs.h"
>  #include "sysemu/numa.h"
> @@ -2653,6 +2654,11 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
>      acpi_add_table(table_offsets, tables_blob);
>      build_madt(tables_blob, tables->linker, pcms);
>  
> +    if (find_vmgenid_dev(NULL)) {
> +        acpi_add_table(table_offsets, tables_blob);
> +        vmgenid_build_acpi(tables_blob, tables->vmgenid, tables->linker);
> +    }
> +
>      if (misc.has_hpet) {
>          acpi_add_table(table_offsets, tables_blob);
>          build_hpet(tables_blob, tables->linker);
> @@ -2859,6 +2865,10 @@ void acpi_setup(void)
>      fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
>                      tables.tcpalog->data, acpi_data_len(tables.tcpalog));
>  
> +    if (find_vmgenid_dev(NULL)) {
> +        vmgenid_add_fw_cfg(pcms->fw_cfg, tables.vmgenid);
> +    }
> +
>      if (!pcmc->rsdp_in_ram) {
>          /*
>           * Keep for compatibility with old machine types.
> diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h
> index 71d3c48..3c2e4e9 100644
> --- a/include/hw/acpi/acpi_dev_interface.h
> +++ b/include/hw/acpi/acpi_dev_interface.h
> @@ -11,6 +11,7 @@ typedef enum {
>      ACPI_CPU_HOTPLUG_STATUS = 4,
>      ACPI_MEMORY_HOTPLUG_STATUS = 8,
>      ACPI_NVDIMM_HOTPLUG_STATUS = 16,
> +    ACPI_VMGENID_CHANGE_STATUS = 32,
>  } AcpiEventStatusBits;
>  
>  #define TYPE_ACPI_DEVICE_IF "acpi-device-interface"
> diff --git a/include/hw/acpi/vmgenid.h b/include/hw/acpi/vmgenid.h
> new file mode 100644
> index 0000000..b60437a
> --- /dev/null
> +++ b/include/hw/acpi/vmgenid.h
> @@ -0,0 +1,37 @@
> +#ifndef ACPI_VMGENID_H
> +#define ACPI_VMGENID_H
> +
> +#include "hw/acpi/bios-linker-loader.h"
> +#include "hw/sysbus.h"
> +#include "qemu/uuid.h"
> +
> +#define VMGENID_DEVICE           "vmgenid"
> +#define VMGENID_GUID             "guid"
> +#define VMGENID_GUID_FW_CFG_FILE      "etc/vmgenid"

Maybe vmgenid_guid ?

> +#define VMGENID_ADDR_FW_CFG_FILE      "etc/vmgenid_addr"
> +
> +#define VMGENID_FW_CFG_SIZE      4096 /* Occupy a page of memory */
> +#define VMGENID_GUID_OFFSET      40   /* allow space for
> +                                       * OVMF SDT Header Probe Supressor */

ACPI header size is 36 bytes. I'd expect just to use that.
Where does 40 come from? I think it's an 8 bytes alignment requirement.

So do QEMU_ALIGN_UP(sizeof(AcpiTableHeader), 8)

Add a comment explaining that 8.

> +
> +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid);
> +void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker *linker);
> +
> +#define VMGENID(obj) OBJECT_CHECK(VmGenIdState, (obj), VMGENID_DEVICE)
> +
> +typedef struct VmGenIdState {
> +    SysBusDevice parent_obj;
> +    QemuUUID guid;
> +    uint8_t vgia_le[4];

Please give this fields a better name. Is this the address?
Pls add comments, too.

How about we make it 8 byte so it's future proof?
alternatively put it in a ram block instead.

> +} VmGenIdState;
> +
> +static Object *find_vmgenid_dev(Error **errp)
> +{
> +    Object *obj = object_resolve_path_type("", VMGENID_DEVICE, NULL);
> +    if (!obj && errp) {
> +        error_setg(errp, "%s is not found", VMGENID_DEVICE);
> +    }
> +    return obj;
> +}
> +
> +#endif
> -- 
> 2.7.4

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

* Re: [Qemu-devel] [PATCH v5 08/10] PC: Support dynamic sysbus on pc_i440fx
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 08/10] PC: Support dynamic sysbus on pc_i440fx ben
@ 2017-02-06 16:31   ` Michael S. Tsirkin
  2017-02-12 19:55     ` Marcel Apfelbaum
  2017-02-07 14:05   ` Igor Mammedov
  1 sibling, 1 reply; 70+ messages in thread
From: Michael S. Tsirkin @ 2017-02-06 16:31 UTC (permalink / raw)
  To: ben; +Cc: qemu-devel, lersek, imammedo, Marcel Apfelbaum

On Sun, Feb 05, 2017 at 01:12:03AM -0800, ben@skyportsystems.com wrote:
> From: Ben Warren <ben@skyportsystems.com>
> 
> This allows pc_i440fx-based machines to add new devices such as
> VM Generation ID directly to the sysbus.
> 
> Signed-off-by: Ben Warren <ben@skyportsystems.com>

Only point is, we might have to add more flags like
cannot_instantiate_with_device_add_yet
to a bunch of devices.

Marcel, you did a similar thing for q35, can you
take a look here as well pls?

> ---
>  hw/i386/pc_piix.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
> index 9f102aa..c8ad99c 100644
> --- a/hw/i386/pc_piix.c
> +++ b/hw/i386/pc_piix.c
> @@ -435,6 +435,7 @@ static void pc_i440fx_machine_options(MachineClass *m)
>      m->hot_add_cpu = pc_hot_add_cpu;
>      m->default_machine_opts = "firmware=bios-256k.bin";
>      m->default_display = "std";
> +    m->has_dynamic_sysbus = true;
>  }
>  
>  static void pc_i440fx_2_9_machine_options(MachineClass *m)
> -- 
> 2.7.4

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

* Re: [Qemu-devel] [PATCH v5 02/10] linker-loader: Add new 'write pointer' command
  2017-02-06 14:56   ` Michael S. Tsirkin
@ 2017-02-06 17:16     ` Ben Warren
  2017-02-06 17:31       ` Michael S. Tsirkin
  0 siblings, 1 reply; 70+ messages in thread
From: Ben Warren @ 2017-02-06 17:16 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: qemu-devel, Laszlo Ersek, imammedo

[-- Attachment #1: Type: text/plain, Size: 10956 bytes --]


> On Feb 6, 2017, at 6:56 AM, Michael S. Tsirkin <mst@redhat.com> wrote:
> 
> On Sun, Feb 05, 2017 at 01:11:57AM -0800, ben@skyportsystems.com wrote:
>> From: Ben Warren <ben@skyportsystems.com>
>> 
>> This adds to the existing 'add pointer' functionality in that it
>> instructs the guest (BIOS or UEFI) to not patch memory but to instead
>> write the changes back to QEMU via a writeable fw_cfg file.
>> 
>> Signed-off-by: Ben Warren <ben@skyportsystems.com>
>> ---
>> hw/acpi/aml-build.c                  |  2 +-
>> hw/acpi/bios-linker-loader.c         | 35 ++++++++++++++++++++++++-----------
>> hw/acpi/nvdimm.c                     |  2 +-
>> hw/arm/virt-acpi-build.c             |  4 ++--
>> hw/i386/acpi-build.c                 |  8 ++++----
>> include/hw/acpi/bios-linker-loader.h |  3 ++-
>> 6 files changed, 34 insertions(+), 20 deletions(-)
>> 
>> diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
>> index 9fc54c9..03b6c6c 100644
>> --- a/hw/acpi/aml-build.c
>> +++ b/hw/acpi/aml-build.c
>> @@ -1626,7 +1626,7 @@ build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets,
>>         /* rsdt->table_offset_entry to be filled by Guest linker */
>>         bios_linker_loader_add_pointer(linker,
>>             ACPI_BUILD_TABLE_FILE, rsdt_entry_offset, rsdt_entry_size,
>> -            ACPI_BUILD_TABLE_FILE, ref_tbl_offset);
>> +            ACPI_BUILD_TABLE_FILE, ref_tbl_offset, false);
>>     }
>>     build_header(linker, table_data,
>>                  (void *)rsdt, "RSDT", rsdt_len, 1, oem_id, oem_table_id);
>> diff --git a/hw/acpi/bios-linker-loader.c b/hw/acpi/bios-linker-loader.c
>> index d963ebe..e46bc29 100644
>> --- a/hw/acpi/bios-linker-loader.c
>> +++ b/hw/acpi/bios-linker-loader.c
>> @@ -52,10 +52,13 @@ struct BiosLinkerLoaderEntry {
>>         } alloc;
>> 
>>         /*
>> -         * COMMAND_ADD_POINTER - patch the table (originating from
>> -         * @dest_file) at @pointer.offset, by adding a pointer to the table
>> +         * COMMAND_ADD_POINTER &
>> +         * COMMAND_WRITE_POINTER - patch guest memory (originating from
>> +         * @dest_file) at @pointer.offset, by adding a pointer to the memory
>>          * originating from @src_file. 1,2,4 or 8 byte unsigned
>>          * addition is used depending on @pointer.size.
>> +         * Instead of patching memory, COMMAND_WRITE_POINTER writes the changes
>> +         * to @dest_file in QEMU via fw_cfg DMA.
>>          */
>>         struct {
>>             char dest_file[BIOS_LINKER_LOADER_FILESZ];
>> @@ -85,9 +88,10 @@ struct BiosLinkerLoaderEntry {
>> typedef struct BiosLinkerLoaderEntry BiosLinkerLoaderEntry;
>> 
>> enum {
>> -    BIOS_LINKER_LOADER_COMMAND_ALLOCATE     = 0x1,
>> -    BIOS_LINKER_LOADER_COMMAND_ADD_POINTER  = 0x2,
>> -    BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM = 0x3,
>> +    BIOS_LINKER_LOADER_COMMAND_ALLOCATE          = 0x1,
>> +    BIOS_LINKER_LOADER_COMMAND_ADD_POINTER       = 0x2,
>> +    BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM      = 0x3,
>> +    BIOS_LINKER_LOADER_COMMAND_WRITE_POINTER     = 0x4,
>> };
>> 
>> enum {
>> @@ -242,13 +246,15 @@ void bios_linker_loader_add_checksum(BIOSLinker *linker, const char *file_name,
>>  * @src_offset: location within source file blob to which
>>  *              @dest_file+@dst_patched_offset will point to after
>>  *              firmware's executed ADD_POINTER command
>> + * @write_back: guest should write change contents back to QEMU after patching
>>  */
>> void bios_linker_loader_add_pointer(BIOSLinker *linker,
>>                                     const char *dest_file,
>>                                     uint32_t dst_patched_offset,
>>                                     uint8_t dst_patched_size,
>>                                     const char *src_file,
>> -                                    uint32_t src_offset)
>> +                                    uint32_t src_offset,
>> +                                    bool write_back)
>> {
>>     uint64_t le_src_offset;
>>     BiosLinkerLoaderEntry entry;
> 
> Frankly I prefer a new bios_linker_loader_write_pointer.
> 
OK
> 
>> @@ -257,8 +263,11 @@ void bios_linker_loader_add_pointer(BIOSLinker *linker,
>>     const BiosLinkerFileEntry *source_file =
>>         bios_linker_find_file(linker, src_file);
>> 
>> -    assert(dst_patched_offset < dst_file->blob->len);
>> -    assert(dst_patched_offset + dst_patched_size <= dst_file->blob->len);
>> +    /* dst_file need not exist if writing back */
> 
> Why not?
Because WRITE_POINTER can be called without having first called ALLOCATE.  In the Vm Generation ID example, there’s no reason for BIOS to allocate memory for the address fw_cfg, since it’s a construct that only matters to QEMU.  This is something that was requested by Laszlo.
> 
>> +    if (!write_back) {
>> +        assert(dst_patched_offset < dst_file->blob->len);
>> +        assert(dst_patched_offset + dst_patched_size <= dst_file->blob->len);
>> +    }
>>     assert(src_offset < source_file->blob->len);
>> 
>>     memset(&entry, 0, sizeof entry);
>> @@ -266,15 +275,19 @@ void bios_linker_loader_add_pointer(BIOSLinker *linker,
>>             sizeof entry.pointer.dest_file - 1);
>>     strncpy(entry.pointer.src_file, src_file,
>>             sizeof entry.pointer.src_file - 1);
>> -    entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ADD_POINTER);
>> +    entry.command = cpu_to_le32(write_back ?
>> +                                BIOS_LINKER_LOADER_COMMAND_WRITE_POINTER :
>> +                                BIOS_LINKER_LOADER_COMMAND_ADD_POINTER);
>>     entry.pointer.offset = cpu_to_le32(dst_patched_offset);
>>     entry.pointer.size = dst_patched_size;
>>     assert(dst_patched_size == 1 || dst_patched_size == 2 ||
>>            dst_patched_size == 4 || dst_patched_size == 8);
>> 
>>     le_src_offset = cpu_to_le64(src_offset);
>> -    memcpy(dst_file->blob->data + dst_patched_offset,
>> -           &le_src_offset, dst_patched_size);
>> +    if (!write_back) {
>> +        memcpy(dst_file->blob->data + dst_patched_offset,
>> +               &le_src_offset, dst_patched_size);
>> +    }
>> 
>>     g_array_append_vals(linker->cmd_blob, &entry, sizeof entry);
>> }
>> diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c
>> index 8e7d6ec..175996e 100644
>> --- a/hw/acpi/nvdimm.c
>> +++ b/hw/acpi/nvdimm.c
>> @@ -1266,7 +1266,7 @@ static void nvdimm_build_ssdt(GArray *table_offsets, GArray *table_data,
>>                              sizeof(NvdimmDsmIn), false /* high memory */);
>>     bios_linker_loader_add_pointer(linker,
>>         ACPI_BUILD_TABLE_FILE, mem_addr_offset, sizeof(uint32_t),
>> -        NVDIMM_DSM_MEM_FILE, 0);
>> +        NVDIMM_DSM_MEM_FILE, 0, false);
>>     build_header(linker, table_data,
>>         (void *)(table_data->data + nvdimm_ssdt),
>>         "SSDT", table_data->len - nvdimm_ssdt, 1, NULL, "NVDIMM");
>> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
>> index 07a10ac..a13f40d 100644
>> --- a/hw/arm/virt-acpi-build.c
>> +++ b/hw/arm/virt-acpi-build.c
>> @@ -380,7 +380,7 @@ build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset)
>>     /* Address to be filled by Guest linker */
>>     bios_linker_loader_add_pointer(linker,
>>         ACPI_BUILD_RSDP_FILE, rsdt_pa_offset, rsdt_pa_size,
>> -        ACPI_BUILD_TABLE_FILE, rsdt_tbl_offset);
>> +        ACPI_BUILD_TABLE_FILE, rsdt_tbl_offset, false);
>> 
>>     /* Checksum to be filled by Guest linker */
>>     bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
>> @@ -684,7 +684,7 @@ static void build_fadt(GArray *table_data, BIOSLinker *linker,
>>     /* DSDT address to be filled by Guest linker */
>>     bios_linker_loader_add_pointer(linker,
>>         ACPI_BUILD_TABLE_FILE, dsdt_entry_offset, sizeof(fadt->dsdt),
>> -        ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset);
>> +        ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset, false);
>> 
>>     build_header(linker, table_data,
>>                  (void *)fadt, "FACP", sizeof(*fadt), 5, NULL, NULL);
>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>> index 1c928ab..78a1d84 100644
>> --- a/hw/i386/acpi-build.c
>> +++ b/hw/i386/acpi-build.c
>> @@ -319,13 +319,13 @@ build_fadt(GArray *table_data, BIOSLinker *linker, AcpiPmInfo *pm,
>>     /* FACS address to be filled by Guest linker */
>>     bios_linker_loader_add_pointer(linker,
>>         ACPI_BUILD_TABLE_FILE, fw_ctrl_offset, sizeof(fadt->firmware_ctrl),
>> -        ACPI_BUILD_TABLE_FILE, facs_tbl_offset);
>> +        ACPI_BUILD_TABLE_FILE, facs_tbl_offset, false);
>> 
>>     /* DSDT address to be filled by Guest linker */
>>     fadt_setup(fadt, pm);
>>     bios_linker_loader_add_pointer(linker,
>>         ACPI_BUILD_TABLE_FILE, dsdt_entry_offset, sizeof(fadt->dsdt),
>> -        ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset);
>> +        ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset, false);
>> 
>>     build_header(linker, table_data,
>>                  (void *)fadt, "FACP", sizeof(*fadt), 1, oem_id, oem_table_id);
>> @@ -2262,7 +2262,7 @@ build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, GArray *tcpalog)
>>     /* log area start address to be filled by Guest linker */
>>     bios_linker_loader_add_pointer(linker,
>>         ACPI_BUILD_TABLE_FILE, log_addr_offset, log_addr_size,
>> -        ACPI_BUILD_TPMLOG_FILE, 0);
>> +        ACPI_BUILD_TPMLOG_FILE, 0, false);
>> 
>>     build_header(linker, table_data,
>>                  (void *)tcpa, "TCPA", sizeof(*tcpa), 2, NULL, NULL);
>> @@ -2552,7 +2552,7 @@ build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset)
>>     /* Address to be filled by Guest linker */
>>     bios_linker_loader_add_pointer(linker,
>>         ACPI_BUILD_RSDP_FILE, rsdt_pa_offset, rsdt_pa_size,
>> -        ACPI_BUILD_TABLE_FILE, rsdt_tbl_offset);
>> +        ACPI_BUILD_TABLE_FILE, rsdt_tbl_offset, false);
>> 
>>     /* Checksum to be filled by Guest linker */
>>     bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
>> diff --git a/include/hw/acpi/bios-linker-loader.h b/include/hw/acpi/bios-linker-loader.h
>> index fa1e5d1..d97e39d 100644
>> --- a/include/hw/acpi/bios-linker-loader.h
>> +++ b/include/hw/acpi/bios-linker-loader.h
>> @@ -24,7 +24,8 @@ void bios_linker_loader_add_pointer(BIOSLinker *linker,
>>                                     uint32_t dst_patched_offset,
>>                                     uint8_t dst_patched_size,
>>                                     const char *src_file,
>> -                                    uint32_t src_offset);
>> +                                    uint32_t src_offset,
>> +                                    bool write_back);
>> 
>> void bios_linker_loader_cleanup(BIOSLinker *linker);
>> #endif
>> -- 
>> 2.7.4


[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 3583 bytes --]

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-06 16:15   ` Michael S. Tsirkin
@ 2017-02-06 17:29     ` Ben Warren
  2017-02-06 17:41       ` Michael S. Tsirkin
  0 siblings, 1 reply; 70+ messages in thread
From: Ben Warren @ 2017-02-06 17:29 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: qemu-devel, lersek, imammedo

[-- Attachment #1: Type: text/plain, Size: 16576 bytes --]


> On Feb 6, 2017, at 8:15 AM, Michael S. Tsirkin <mst@redhat.com> wrote:
> 
> On Sun, Feb 05, 2017 at 01:12:00AM -0800, ben@skyportsystems.com <mailto:ben@skyportsystems.com> wrote:
>> From: Ben Warren <ben@skyportsystems.com <mailto:ben@skyportsystems.com>>
>> 
>> This implements the VM Generation ID feature by passing a 128-bit
>> GUID to the guest via a fw_cfg blob.
>> Any time the GUID changes, an ACPI notify event is sent to the guest
>> 
>> The user interface is a simple device with one parameter:
>> - guid (string, must be "auto" or in UUID format
>>   xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
>> 
>> Signed-off-by: Ben Warren <ben@skyportsystems.com <mailto:ben@skyportsystems.com>>
> 
> 
> Thanks!
> I think it's mostly in a good shape.
> Comments inside.
> 
Thanks!  Hopefully the next rev has everything you want.
> 
>> ---
>> default-configs/i386-softmmu.mak     |   1 +
>> default-configs/x86_64-softmmu.mak   |   1 +
>> hw/acpi/Makefile.objs                |   1 +
>> hw/acpi/vmgenid.c                    | 206 +++++++++++++++++++++++++++++++++++
>> hw/i386/acpi-build.c                 |  10 ++
>> include/hw/acpi/acpi_dev_interface.h |   1 +
>> include/hw/acpi/vmgenid.h            |  37 +++++++
>> 7 files changed, 257 insertions(+)
>> create mode 100644 hw/acpi/vmgenid.c
>> create mode 100644 include/hw/acpi/vmgenid.h
>> 
>> diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
>> index 384cefb..1a43542 100644
>> --- a/default-configs/i386-softmmu.mak
>> +++ b/default-configs/i386-softmmu.mak
>> @@ -58,3 +58,4 @@ CONFIG_I82801B11=y
>> CONFIG_SMBIOS=y
>> CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
>> CONFIG_PXB=y
>> +CONFIG_ACPI_VMGENID=y
>> diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
>> index 491a191..aee8b08 100644
>> --- a/default-configs/x86_64-softmmu.mak
>> +++ b/default-configs/x86_64-softmmu.mak
>> @@ -58,3 +58,4 @@ CONFIG_I82801B11=y
>> CONFIG_SMBIOS=y
>> CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
>> CONFIG_PXB=y
>> +CONFIG_ACPI_VMGENID=y
>> diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
>> index 6acf798..11c35bc 100644
>> --- a/hw/acpi/Makefile.objs
>> +++ b/hw/acpi/Makefile.objs
>> @@ -5,6 +5,7 @@ common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
>> common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
>> common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
>> common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
>> +common-obj-$(CONFIG_ACPI_VMGENID) += vmgenid.o
>> common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
>> 
>> common-obj-y += acpi_interface.o
>> diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
>> new file mode 100644
>> index 0000000..6c9ecfd
>> --- /dev/null
>> +++ b/hw/acpi/vmgenid.c
>> @@ -0,0 +1,206 @@
>> +/*
>> + *  Virtual Machine Generation ID Device
>> + *
>> + *  Copyright (C) 2017 Skyport Systems.
>> + *
>> + *  Author: Ben Warren <ben@skyportsystems.com>
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
>> + * See the COPYING file in the top-level directory.
>> + *
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "qmp-commands.h"
>> +#include "hw/acpi/acpi.h"
>> +#include "hw/acpi/aml-build.h"
>> +#include "hw/acpi/vmgenid.h"
>> +#include "hw/nvram/fw_cfg.h"
>> +#include "sysemu/sysemu.h"
>> +
>> +void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker *linker)
>> +{
>> +    Object *obj;
>> +    VmGenIdState *s;
>> +    Aml *ssdt, *dev, *scope, *method, *addr, *if_ctx;
>> +    uint32_t vgia_offset;
>> +
>> +    obj = find_vmgenid_dev(NULL);
>> +    assert(obj);
>> +    s = VMGENID(obj);
>> +
>> +    /* Fill in the GUID values */
>> +    if (guid->len != VMGENID_FW_CFG_SIZE) {
>> +        g_array_set_size(guid, VMGENID_FW_CFG_SIZE);
>> +    }
>> +    g_array_insert_vals(guid, VMGENID_GUID_OFFSET, s->guid.data, 16);
> 
> ARRAY_SIZE(s->guid.data);
> 
OK
>> +
>> +    /* Put this in a separate SSDT table */
>> +    ssdt = init_aml_allocator();
>> +
>> +    /* Reserve space for header */
>> +    acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader));
>> +
>> +    /* Storage for the GUID address */
>> +    vgia_offset = table_data->len +
>> +        build_append_named_dword(ssdt->buf, "VGIA");
>> +    scope = aml_scope("\\_SB");
>> +    dev = aml_device("VGEN");
>> +    aml_append(dev, aml_name_decl("_HID", aml_string("QEMUVGID")));
>> +    aml_append(dev, aml_name_decl("_CID", aml_string("VM_Gen_Counter")));
>> +    aml_append(dev, aml_name_decl("_DDN", aml_string("VM_Gen_Counter")));
>> +
>> +    /* Simple status method to check that address is linked and non-zero */
>> +    method = aml_method("_STA", 0, AML_NOTSERIALIZED);
>> +    addr = aml_local(0);
>> +    aml_append(method, aml_store(aml_int(0xf), addr));
>> +    if_ctx = aml_if(aml_equal(aml_name("VGIA"), aml_int(0)));
>> +    aml_append(if_ctx, aml_store(aml_int(0), addr));
>> +    aml_append(method, if_ctx);
>> +    aml_append(method, aml_return(addr));
>> +    aml_append(dev, method);
>> +
>> +    /* the ADDR method returns two 32-bit words representing the lower and
>> +     * upper halves * of the physical address of the fw_cfg blob
>> +     * (holding the GUID) */
> 
> /*
> * multiline comments
> * look like this
> */
> 
OK
>> +    method = aml_method("ADDR", 0, AML_NOTSERIALIZED);
>> +
>> +    addr = aml_local(0);
>> +    aml_append(method, aml_store(aml_package(2), addr));
>> +
>> +    aml_append(method, aml_store(aml_add(aml_name("VGIA"),
>> +                                         aml_int(VMGENID_GUID_OFFSET), NULL),
>> +                                 aml_index(addr, aml_int(0))));
>> +    aml_append(method, aml_store(aml_int(0), aml_index(addr, aml_int(1))));
>> +    aml_append(method, aml_return(addr));
>> +
>> +    aml_append(dev, method);
>> +    aml_append(scope, dev);
>> +    aml_append(ssdt, scope);
>> +
>> +    /* attach an ACPI notify */
>> +    method = aml_method("\\_GPE._E05", 0, AML_NOTSERIALIZED);
>> +    aml_append(method, aml_notify(aml_name("\\_SB.VGEN"), aml_int(0x80)));
>> +    aml_append(ssdt, method);
>> +
>> +    g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len);
>> +
>> +    /* Allocate guest memory for the Data fw_cfg blob */
>> +    bios_linker_loader_alloc(linker, VMGENID_GUID_FW_CFG_FILE, guid, 4096,
>> +                             false /* page boundary, high memory */);
>> +
>> +    /* Patch address of GUID fw_cfg blob into the ADDR fw_cfg blob */
> 
> add ... so QEMU can write GUID there
> 
OK
>> +    bios_linker_loader_add_pointer(linker,
>> +        VMGENID_ADDR_FW_CFG_FILE, 0, sizeof(uint32_t),
>> +        VMGENID_GUID_FW_CFG_FILE, 0, true);
>> +
>> +    /* Patch address of GUID fw_cfg blob into the AML */
> 
> add ... so OSPM can retrieve and read it
> 
OK
>> +    bios_linker_loader_add_pointer(linker,
>> +        ACPI_BUILD_TABLE_FILE, vgia_offset, sizeof(uint32_t),
>> +        VMGENID_GUID_FW_CFG_FILE, 0, false);
>> +
>> +    build_header(linker, table_data,
>> +        (void *)(table_data->data + table_data->len - ssdt->buf->len),
>> +        "SSDT", ssdt->buf->len, 1, NULL, "VMGENID");
>> +    free_aml_allocator();
>> +}
>> +
>> +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid)
>> +{
>> +    Object *obj = find_vmgenid_dev(NULL);
>> +    assert(obj);
>> +    VmGenIdState *vms = VMGENID(obj);
>> +
>> +    /* Create a read-only fw_cfg file for GUID */
>> +    fw_cfg_add_file(s, VMGENID_GUID_FW_CFG_FILE, guid->data,
>> +                    VMGENID_FW_CFG_SIZE);
>> +    /* Create a read-write fw_cfg file for Address */
>> +    fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL, NULL,
> 
> Seems wrong. What if guest updates the address after command line
> set it? You want a callback to copy guid there.
> 
Sure, I can do that.  My understanding was that this is a read callback, but if it also is called upon a write, we should do what you suggest.
> 
>> +                             vms->vgia_le, sizeof(uint32_t), false);
> 
> Should be ARRAY_SIZE(vms->vgia_le).
> 
> Also, I thought GUID is at an offset from the beginning
> in order to trick OVMF, isn't it?
> 
The offset is taken into account in the GUID fw_cfg file.  The writing to guest memory, we add the offset to VGIA.
> 
>> +}
>> +
>> +static void vmgenid_update_guest(VmGenIdState *s)
>> +{
>> +    Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL);
>> +    uint32_t vgia;
>> +
>> +    if (obj) {
>> +        /* Write the GUID to guest memory */
>> +        memcpy(&vgia, s->vgia_le, sizeof(vgia));
>> +        vgia = le32_to_cpu(vgia);
>> +        if (vgia) {
> 
> add a comment saying 0 means bios did not run yet.
OK
> 
>> +            cpu_physical_memory_write(vgia + VMGENID_GUID_OFFSET,
>> +                                      s->guid.data, sizeof(s->guid.data));
> 
> Avoid this. You want dma.h APIs.
I’ll have a look at those.  This function was recommended to me in an earlier patch version.
> 
>> +            /* Send _GPE.E05 event */
>> +            acpi_send_event(DEVICE(obj), ACPI_VMGENID_CHANGE_STATUS);
>> +        }
>> +    }
>> +}
>> +
>> +static void vmgenid_set_guid(Object *obj, const char *value, Error **errp)
>> +{
>> +    VmGenIdState *s = VMGENID(obj);
>> +
>> +    if (!strncmp(value, "auto", 4)) {
> 
> I'd use strcmp here.
OK
> 
>> +        qemu_uuid_generate(&s->guid);
>> +    } else if (qemu_uuid_parse(value, &s->guid) < 0) {
>> +        error_setg(errp, "'%s. %s': Failed to parse GUID string: %s",
>> +                   object_get_typename(OBJECT(s)), VMGENID_GUID, value);
>> +        return;
>> +    }
>> +    /* QemuUUID has the first three words as big-endian, and expect that any
>> +     * GUIDs passed in will always be BE.  The guest, however will expect
>> +     * the fields to be little-endian, so store that way internally.
> 
> This makes my head spin. It's the actual guid, right? Only place we need it is when
> we copy it into guest memory. So swap there -
> and do it to a copy so you won't need these comments.
I understand.  I wanted to only do the swap at one place and decided to do it closest to the user interface, but can do it at the other end instead.
> 
>> Make
>> +     * sure to swap back whenever reporting via monitor */
> 
> And what code does this swap back?
A later patch where the QMP code is added.  But I’ll remove that necessity.
> 
>> +    qemu_uuid_bswap(&s->guid);
>> +
>> +    /* Send the ACPI notify */
>> +    vmgenid_update_guest(s);
>> +}
>> +
>> +/* After restoring an image, we need to update the guest memory and notify
>> + * it of a potential change to VM Generation ID */
>> +static int vmgenid_post_load(void *opaque, int version_id)
>> +{
>> +    VmGenIdState *s = opaque;
>> +    vmgenid_update_guest(s);
>> +    return 0;
>> +}
>> +
>> +static const VMStateDescription vmstate_vmgenid = {
>> +    .name = "vmgenid",
>> +    .version_id = 1,
>> +    .minimum_version_id = 1,
>> +    .post_load = vmgenid_post_load,
>> +    .fields = (VMStateField[]) {
>> +        VMSTATE_UINT8_ARRAY(vgia_le, VmGenIdState, sizeof(uint32_t)),
>> +        VMSTATE_END_OF_LIST()
>> +    },
>> +};
>> +
>> +static void vmgenid_initfn(Object *obj)
>> +{
>> +    object_property_add_str(obj, VMGENID_GUID, NULL, vmgenid_set_guid, NULL);
>> +}
>> +
>> +static void vmgenid_device_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> +    dc->vmsd = &vmstate_vmgenid;
>> +}
>> +
>> +static const TypeInfo vmgenid_device_info = {
>> +    .name          = VMGENID_DEVICE,
>> +    .parent        = TYPE_SYS_BUS_DEVICE,
>> +    .instance_size = sizeof(VmGenIdState),
>> +    .instance_init = vmgenid_initfn,
>> +    .class_init    = vmgenid_device_class_init,
>> +};
>> +
>> +static void vmgenid_register_types(void)
>> +{
>> +    type_register_static(&vmgenid_device_info);
>> +}
>> +
>> +type_init(vmgenid_register_types)
>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>> index 78a1d84..4c40f76 100644
>> --- a/hw/i386/acpi-build.c
>> +++ b/hw/i386/acpi-build.c
>> @@ -42,6 +42,7 @@
>> #include "hw/acpi/memory_hotplug.h"
>> #include "sysemu/tpm.h"
>> #include "hw/acpi/tpm.h"
>> +#include "hw/acpi/vmgenid.h"
>> #include "sysemu/tpm_backend.h"
>> #include "hw/timer/mc146818rtc_regs.h"
>> #include "sysemu/numa.h"
>> @@ -2653,6 +2654,11 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
>>     acpi_add_table(table_offsets, tables_blob);
>>     build_madt(tables_blob, tables->linker, pcms);
>> 
>> +    if (find_vmgenid_dev(NULL)) {
>> +        acpi_add_table(table_offsets, tables_blob);
>> +        vmgenid_build_acpi(tables_blob, tables->vmgenid, tables->linker);
>> +    }
>> +
>>     if (misc.has_hpet) {
>>         acpi_add_table(table_offsets, tables_blob);
>>         build_hpet(tables_blob, tables->linker);
>> @@ -2859,6 +2865,10 @@ void acpi_setup(void)
>>     fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
>>                     tables.tcpalog->data, acpi_data_len(tables.tcpalog));
>> 
>> +    if (find_vmgenid_dev(NULL)) {
>> +        vmgenid_add_fw_cfg(pcms->fw_cfg, tables.vmgenid);
>> +    }
>> +
>>     if (!pcmc->rsdp_in_ram) {
>>         /*
>>          * Keep for compatibility with old machine types.
>> diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h
>> index 71d3c48..3c2e4e9 100644
>> --- a/include/hw/acpi/acpi_dev_interface.h
>> +++ b/include/hw/acpi/acpi_dev_interface.h
>> @@ -11,6 +11,7 @@ typedef enum {
>>     ACPI_CPU_HOTPLUG_STATUS = 4,
>>     ACPI_MEMORY_HOTPLUG_STATUS = 8,
>>     ACPI_NVDIMM_HOTPLUG_STATUS = 16,
>> +    ACPI_VMGENID_CHANGE_STATUS = 32,
>> } AcpiEventStatusBits;
>> 
>> #define TYPE_ACPI_DEVICE_IF "acpi-device-interface"
>> diff --git a/include/hw/acpi/vmgenid.h b/include/hw/acpi/vmgenid.h
>> new file mode 100644
>> index 0000000..b60437a
>> --- /dev/null
>> +++ b/include/hw/acpi/vmgenid.h
>> @@ -0,0 +1,37 @@
>> +#ifndef ACPI_VMGENID_H
>> +#define ACPI_VMGENID_H
>> +
>> +#include "hw/acpi/bios-linker-loader.h"
>> +#include "hw/sysbus.h"
>> +#include "qemu/uuid.h"
>> +
>> +#define VMGENID_DEVICE           "vmgenid"
>> +#define VMGENID_GUID             "guid"
>> +#define VMGENID_GUID_FW_CFG_FILE      "etc/vmgenid"
> 
> Maybe vmgenid_guid ?
Sure.
> 
>> +#define VMGENID_ADDR_FW_CFG_FILE      "etc/vmgenid_addr"
>> +
>> +#define VMGENID_FW_CFG_SIZE      4096 /* Occupy a page of memory */
>> +#define VMGENID_GUID_OFFSET      40   /* allow space for
>> +                                       * OVMF SDT Header Probe Supressor */
> 
> ACPI header size is 36 bytes. I'd expect just to use that.
> Where does 40 come from? I think it's an 8 bytes alignment requirement.
> 
The number 40 was asked for by Laszlo for the OVMF SDT Header Probe Suppressor, which I don’t know anything about.  This GUID isn’t going in an ACPI table, so I’m not sure what you mean here.  We allocate on a page boundary and 40 bytes in should be 8-byte aligned.
> So do QEMU_ALIGN_UP(sizeof(AcpiTableHeader), 8)
> 
> Add a comment explaining that 8.
> 
>> +
>> +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid);
>> +void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker *linker);
>> +
>> +#define VMGENID(obj) OBJECT_CHECK(VmGenIdState, (obj), VMGENID_DEVICE)
>> +
>> +typedef struct VmGenIdState {
>> +    SysBusDevice parent_obj;
>> +    QemuUUID guid;
>> +    uint8_t vgia_le[4];
> 
> Please give this fields a better name. Is this the address?
> Pls add comments, too.
> 
This variable name was suggested by Laszlo.  the ‘a’ in ‘vgia’ refers to address, but I’ll add some comments.
> How about we make it 8 byte so it's future proof?
I can do that, but a previous conversation we had made it clear that guests would never allocate above 4GB so 64 bits wasn’t necessary.
> alternatively put it in a ram block instead.
> 
>> +} VmGenIdState;
>> +
>> +static Object *find_vmgenid_dev(Error **errp)
>> +{
>> +    Object *obj = object_resolve_path_type("", VMGENID_DEVICE, NULL);
>> +    if (!obj && errp) {
>> +        error_setg(errp, "%s is not found", VMGENID_DEVICE);
>> +    }
>> +    return obj;
>> +}
>> +
>> +#endif
>> -- 
>> 2.7.4


[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 3583 bytes --]

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

* Re: [Qemu-devel] [PATCH v5 02/10] linker-loader: Add new 'write pointer' command
  2017-02-06 17:16     ` Ben Warren
@ 2017-02-06 17:31       ` Michael S. Tsirkin
  2017-02-07 12:11         ` Igor Mammedov
  0 siblings, 1 reply; 70+ messages in thread
From: Michael S. Tsirkin @ 2017-02-06 17:31 UTC (permalink / raw)
  To: Ben Warren; +Cc: qemu-devel, Laszlo Ersek, imammedo

On Mon, Feb 06, 2017 at 09:16:25AM -0800, Ben Warren wrote:
> >> @@ -257,8 +263,11 @@ void bios_linker_loader_add_pointer(BIOSLinker *linker,
> >>     const BiosLinkerFileEntry *source_file =
> >>         bios_linker_find_file(linker, src_file);
> >> 
> >> -    assert(dst_patched_offset < dst_file->blob->len);
> >> -    assert(dst_patched_offset + dst_patched_size <= dst_file->blob->len);
> >> +    /* dst_file need not exist if writing back */
> > 
> > Why not?
> Because WRITE_POINTER can be called without having first called
> ALLOCATE.  In the Vm Generation ID example, there’s no reason for BIOS
> to allocate memory for the address fw_cfg, since it’s a construct that
> only matters to QEMU.  This is something that was requested by Laszlo.

Well all other commands require you to first allocate.
How does bios know e.g. which zone to put it in then?

I don't like the asymmetry ... Laszlo?

-- 
MST

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-06 17:29     ` Ben Warren
@ 2017-02-06 17:41       ` Michael S. Tsirkin
  2017-02-06 17:59         ` Ben Warren
  2017-02-07 14:00         ` Igor Mammedov
  0 siblings, 2 replies; 70+ messages in thread
From: Michael S. Tsirkin @ 2017-02-06 17:41 UTC (permalink / raw)
  To: Ben Warren; +Cc: qemu-devel, lersek, imammedo

On Mon, Feb 06, 2017 at 09:29:30AM -0800, Ben Warren wrote:
> 
>     On Feb 6, 2017, at 8:15 AM, Michael S. Tsirkin <mst@redhat.com> wrote:
> 
>     On Sun, Feb 05, 2017 at 01:12:00AM -0800, ben@skyportsystems.com wrote:
> 
>         From: Ben Warren <ben@skyportsystems.com>
> 
>         This implements the VM Generation ID feature by passing a 128-bit
>         GUID to the guest via a fw_cfg blob.
>         Any time the GUID changes, an ACPI notify event is sent to the guest
> 
>         The user interface is a simple device with one parameter:
>         - guid (string, must be "auto" or in UUID format
>           xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
> 
>         Signed-off-by: Ben Warren <ben@skyportsystems.com>
> 
> 
> 
>     Thanks!
>     I think it's mostly in a good shape.
>     Comments inside.
> 
> 
> Thanks!  Hopefully the next rev has everything you want.
> 
> 
> 
>         ---
>         default-configs/i386-softmmu.mak     |   1 +
>         default-configs/x86_64-softmmu.mak   |   1 +
>         hw/acpi/Makefile.objs                |   1 +
>         hw/acpi/vmgenid.c                    | 206
>         +++++++++++++++++++++++++++++++++++
>         hw/i386/acpi-build.c                 |  10 ++
>         include/hw/acpi/acpi_dev_interface.h |   1 +
>         include/hw/acpi/vmgenid.h            |  37 +++++++
>         7 files changed, 257 insertions(+)
>         create mode 100644 hw/acpi/vmgenid.c
>         create mode 100644 include/hw/acpi/vmgenid.h
> 
>         diff --git a/default-configs/i386-softmmu.mak b/default-configs/
>         i386-softmmu.mak
>         index 384cefb..1a43542 100644
>         --- a/default-configs/i386-softmmu.mak
>         +++ b/default-configs/i386-softmmu.mak
>         @@ -58,3 +58,4 @@ CONFIG_I82801B11=y
>         CONFIG_SMBIOS=y
>         CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
>         CONFIG_PXB=y
>         +CONFIG_ACPI_VMGENID=y
>         diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/
>         x86_64-softmmu.mak
>         index 491a191..aee8b08 100644
>         --- a/default-configs/x86_64-softmmu.mak
>         +++ b/default-configs/x86_64-softmmu.mak
>         @@ -58,3 +58,4 @@ CONFIG_I82801B11=y
>         CONFIG_SMBIOS=y
>         CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
>         CONFIG_PXB=y
>         +CONFIG_ACPI_VMGENID=y
>         diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
>         index 6acf798..11c35bc 100644
>         --- a/hw/acpi/Makefile.objs
>         +++ b/hw/acpi/Makefile.objs
>         @@ -5,6 +5,7 @@ common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
>         common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
>         common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
>         common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
>         +common-obj-$(CONFIG_ACPI_VMGENID) += vmgenid.o
>         common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
> 
>         common-obj-y += acpi_interface.o
>         diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
>         new file mode 100644
>         index 0000000..6c9ecfd
>         --- /dev/null
>         +++ b/hw/acpi/vmgenid.c
>         @@ -0,0 +1,206 @@
>         +/*
>         + *  Virtual Machine Generation ID Device
>         + *
>         + *  Copyright (C) 2017 Skyport Systems.
>         + *
>         + *  Author: Ben Warren <ben@skyportsystems.com>
>         + *
>         + * This work is licensed under the terms of the GNU GPL, version 2 or
>         later.
>         + * See the COPYING file in the top-level directory.
>         + *
>         + */
>         +
>         +#include "qemu/osdep.h"
>         +#include "qmp-commands.h"
>         +#include "hw/acpi/acpi.h"
>         +#include "hw/acpi/aml-build.h"
>         +#include "hw/acpi/vmgenid.h"
>         +#include "hw/nvram/fw_cfg.h"
>         +#include "sysemu/sysemu.h"
>         +
>         +void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker
>         *linker)
>         +{
>         +    Object *obj;
>         +    VmGenIdState *s;
>         +    Aml *ssdt, *dev, *scope, *method, *addr, *if_ctx;
>         +    uint32_t vgia_offset;
>         +
>         +    obj = find_vmgenid_dev(NULL);
>         +    assert(obj);
>         +    s = VMGENID(obj);
>         +
>         +    /* Fill in the GUID values */
>         +    if (guid->len != VMGENID_FW_CFG_SIZE) {
>         +        g_array_set_size(guid, VMGENID_FW_CFG_SIZE);
>         +    }
>         +    g_array_insert_vals(guid, VMGENID_GUID_OFFSET, s->guid.data, 16);
> 
> 
>     ARRAY_SIZE(s->guid.data);
> 
> 
> OK
> 
>         +
>         +    /* Put this in a separate SSDT table */
>         +    ssdt = init_aml_allocator();
>         +
>         +    /* Reserve space for header */
>         +    acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader));
>         +
>         +    /* Storage for the GUID address */
>         +    vgia_offset = table_data->len +
>         +        build_append_named_dword(ssdt->buf, "VGIA");
>         +    scope = aml_scope("\\_SB");
>         +    dev = aml_device("VGEN");
>         +    aml_append(dev, aml_name_decl("_HID", aml_string("QEMUVGID")));
>         +    aml_append(dev, aml_name_decl("_CID", aml_string
>         ("VM_Gen_Counter")));
>         +    aml_append(dev, aml_name_decl("_DDN", aml_string
>         ("VM_Gen_Counter")));
>         +
>         +    /* Simple status method to check that address is linked and
>         non-zero */
>         +    method = aml_method("_STA", 0, AML_NOTSERIALIZED);
>         +    addr = aml_local(0);
>         +    aml_append(method, aml_store(aml_int(0xf), addr));
>         +    if_ctx = aml_if(aml_equal(aml_name("VGIA"), aml_int(0)));
>         +    aml_append(if_ctx, aml_store(aml_int(0), addr));
>         +    aml_append(method, if_ctx);
>         +    aml_append(method, aml_return(addr));
>         +    aml_append(dev, method);
>         +
>         +    /* the ADDR method returns two 32-bit words representing the lower
>         and
>         +     * upper halves * of the physical address of the fw_cfg blob
>         +     * (holding the GUID) */
> 
> 
>     /*
>     * multiline comments
>     * look like this
>     */
> 
> 
> OK
> 
>         +    method = aml_method("ADDR", 0, AML_NOTSERIALIZED);
>         +
>         +    addr = aml_local(0);
>         +    aml_append(method, aml_store(aml_package(2), addr));
>         +
>         +    aml_append(method, aml_store(aml_add(aml_name("VGIA"),
>         +                                         aml_int(VMGENID_GUID_OFFSET),
>         NULL),
>         +                                 aml_index(addr, aml_int(0))));
>         +    aml_append(method, aml_store(aml_int(0), aml_index(addr, aml_int
>         (1))));
>         +    aml_append(method, aml_return(addr));
>         +
>         +    aml_append(dev, method);
>         +    aml_append(scope, dev);
>         +    aml_append(ssdt, scope);
>         +
>         +    /* attach an ACPI notify */
>         +    method = aml_method("\\_GPE._E05", 0, AML_NOTSERIALIZED);
>         +    aml_append(method, aml_notify(aml_name("\\_SB.VGEN"), aml_int
>         (0x80)));
>         +    aml_append(ssdt, method);
>         +
>         +    g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len);
>         +
>         +    /* Allocate guest memory for the Data fw_cfg blob */
>         +    bios_linker_loader_alloc(linker, VMGENID_GUID_FW_CFG_FILE, guid,
>         4096,
>         +                             false /* page boundary, high memory */);
>         +
>         +    /* Patch address of GUID fw_cfg blob into the ADDR fw_cfg blob */
> 
> 
>     add ... so QEMU can write GUID there
> 
> 
> OK
> 
>         +    bios_linker_loader_add_pointer(linker,
>         +        VMGENID_ADDR_FW_CFG_FILE, 0, sizeof(uint32_t),
>         +        VMGENID_GUID_FW_CFG_FILE, 0, true);
>         +
>         +    /* Patch address of GUID fw_cfg blob into the AML */
> 
> 
>     add ... so OSPM can retrieve and read it
> 
> 
> OK
> 
>         +    bios_linker_loader_add_pointer(linker,
>         +        ACPI_BUILD_TABLE_FILE, vgia_offset, sizeof(uint32_t),
>         +        VMGENID_GUID_FW_CFG_FILE, 0, false);
>         +
>         +    build_header(linker, table_data,
>         +        (void *)(table_data->data + table_data->len - ssdt->buf->len),
>         +        "SSDT", ssdt->buf->len, 1, NULL, "VMGENID");
>         +    free_aml_allocator();
>         +}
>         +
>         +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid)
>         +{
>         +    Object *obj = find_vmgenid_dev(NULL);
>         +    assert(obj);
>         +    VmGenIdState *vms = VMGENID(obj);
>         +
>         +    /* Create a read-only fw_cfg file for GUID */
>         +    fw_cfg_add_file(s, VMGENID_GUID_FW_CFG_FILE, guid->data,
>         +                    VMGENID_FW_CFG_SIZE);
>         +    /* Create a read-write fw_cfg file for Address */
>         +    fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL, NULL,
> 
> 
>     Seems wrong. What if guest updates the address after command line
>     set it? You want a callback to copy guid there.
> 
> 
> Sure, I can do that.  My understanding was that this is a read callback, but if
> it also is called upon a write, we should do what you suggest.

Hmm you are right. But we really need to call something
on write though - unlike read, it must be called after write.
Otherwise I don't see how it can work if you set gen id before
guest boots.

I guess this means we need yet another callback per file.
FWCfgWriteCallback ?

Can you implement this in hw/nvram/fw_cfg.c?
It's rather straight-forward to do.


> 
> 
>         +                             vms->vgia_le, sizeof(uint32_t), false);
> 
> 
>     Should be ARRAY_SIZE(vms->vgia_le).
> 
>     Also, I thought GUID is at an offset from the beginning
>     in order to trick OVMF, isn't it?
> 
> 
> The offset is taken into account in the GUID fw_cfg file.  The writing to guest
> memory, we add the offset to VGIA.

I keep forgetting it's the address. Really please rename it
using full words.


> 
>         +}
>         +
>         +static void vmgenid_update_guest(VmGenIdState *s)
>         +{
>         +    Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF,
>         NULL);
>         +    uint32_t vgia;
>         +
>         +    if (obj) {
>         +        /* Write the GUID to guest memory */
>         +        memcpy(&vgia, s->vgia_le, sizeof(vgia));
>         +        vgia = le32_to_cpu(vgia);
>         +        if (vgia) {
> 
> 
>     add a comment saying 0 means bios did not run yet.
> 
> OK
> 
> 
> 
>         +            cpu_physical_memory_write(vgia + VMGENID_GUID_OFFSET,
>         +                                      s->guid.data, sizeof(s->
>         guid.data));
> 
> 
>     Avoid this. You want dma.h APIs.
> 
> I’ll have a look at those.  This function was recommended to me in an earlier
> patch version.
> 
> 
> 
>         +            /* Send _GPE.E05 event */
>         +            acpi_send_event(DEVICE(obj), ACPI_VMGENID_CHANGE_STATUS);
>         +        }
>         +    }
>         +}
>         +
>         +static void vmgenid_set_guid(Object *obj, const char *value, Error
>         **errp)
>         +{
>         +    VmGenIdState *s = VMGENID(obj);
>         +
>         +    if (!strncmp(value, "auto", 4)) {
> 
> 
>     I'd use strcmp here.
> 
> OK
> 
> 
> 
>         +        qemu_uuid_generate(&s->guid);
>         +    } else if (qemu_uuid_parse(value, &s->guid) < 0) {
>         +        error_setg(errp, "'%s. %s': Failed to parse GUID string: %s",
>         +                   object_get_typename(OBJECT(s)), VMGENID_GUID,
>         value);
>         +        return;
>         +    }
>         +    /* QemuUUID has the first three words as big-endian, and expect
>         that any
>         +     * GUIDs passed in will always be BE.  The guest, however will
>         expect
>         +     * the fields to be little-endian, so store that way internally.
> 
> 
>     This makes my head spin. It's the actual guid, right? Only place we need it
>     is when
>     we copy it into guest memory. So swap there -
>     and do it to a copy so you won't need these comments.
> 
> I understand.  I wanted to only do the swap at one place and decided to do it
> closest to the user interface, but can do it at the other end instead.
> 
> 
> 
>         Make
>         +     * sure to swap back whenever reporting via monitor */
> 
> 
>     And what code does this swap back?
> 
> A later patch where the QMP code is added.  But I’ll remove that necessity.
> 
> 
> 
>         +    qemu_uuid_bswap(&s->guid);
>         +
>         +    /* Send the ACPI notify */
>         +    vmgenid_update_guest(s);
>         +}
>         +
>         +/* After restoring an image, we need to update the guest memory and
>         notify
>         + * it of a potential change to VM Generation ID */
>         +static int vmgenid_post_load(void *opaque, int version_id)
>         +{
>         +    VmGenIdState *s = opaque;
>         +    vmgenid_update_guest(s);
>         +    return 0;
>         +}
>         +
>         +static const VMStateDescription vmstate_vmgenid = {
>         +    .name = "vmgenid",
>         +    .version_id = 1,
>         +    .minimum_version_id = 1,
>         +    .post_load = vmgenid_post_load,
>         +    .fields = (VMStateField[]) {
>         +        VMSTATE_UINT8_ARRAY(vgia_le, VmGenIdState, sizeof(uint32_t)),
>         +        VMSTATE_END_OF_LIST()
>         +    },
>         +};
>         +
>         +static void vmgenid_initfn(Object *obj)
>         +{
>         +    object_property_add_str(obj, VMGENID_GUID, NULL, vmgenid_set_guid,
>         NULL);
>         +}
>         +
>         +static void vmgenid_device_class_init(ObjectClass *klass, void *data)
>         +{
>         +    DeviceClass *dc = DEVICE_CLASS(klass);
>         +
>         +    dc->vmsd = &vmstate_vmgenid;
>         +}
>         +
>         +static const TypeInfo vmgenid_device_info = {
>         +    .name          = VMGENID_DEVICE,
>         +    .parent        = TYPE_SYS_BUS_DEVICE,
>         +    .instance_size = sizeof(VmGenIdState),
>         +    .instance_init = vmgenid_initfn,
>         +    .class_init    = vmgenid_device_class_init,
>         +};
>         +
>         +static void vmgenid_register_types(void)
>         +{
>         +    type_register_static(&vmgenid_device_info);
>         +}
>         +
>         +type_init(vmgenid_register_types)
>         diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>         index 78a1d84..4c40f76 100644
>         --- a/hw/i386/acpi-build.c
>         +++ b/hw/i386/acpi-build.c
>         @@ -42,6 +42,7 @@
>         #include "hw/acpi/memory_hotplug.h"
>         #include "sysemu/tpm.h"
>         #include "hw/acpi/tpm.h"
>         +#include "hw/acpi/vmgenid.h"
>         #include "sysemu/tpm_backend.h"
>         #include "hw/timer/mc146818rtc_regs.h"
>         #include "sysemu/numa.h"
>         @@ -2653,6 +2654,11 @@ void acpi_build(AcpiBuildTables *tables,
>         MachineState *machine)
>             acpi_add_table(table_offsets, tables_blob);
>             build_madt(tables_blob, tables->linker, pcms);
> 
>         +    if (find_vmgenid_dev(NULL)) {
>         +        acpi_add_table(table_offsets, tables_blob);
>         +        vmgenid_build_acpi(tables_blob, tables->vmgenid, tables->
>         linker);
>         +    }
>         +
>             if (misc.has_hpet) {
>                 acpi_add_table(table_offsets, tables_blob);
>                 build_hpet(tables_blob, tables->linker);
>         @@ -2859,6 +2865,10 @@ void acpi_setup(void)
>             fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
>                             tables.tcpalog->data, acpi_data_len
>         (tables.tcpalog));
> 
>         +    if (find_vmgenid_dev(NULL)) {
>         +        vmgenid_add_fw_cfg(pcms->fw_cfg, tables.vmgenid);
>         +    }
>         +
>             if (!pcmc->rsdp_in_ram) {
>                 /*
>                  * Keep for compatibility with old machine types.
>         diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/
>         acpi_dev_interface.h
>         index 71d3c48..3c2e4e9 100644
>         --- a/include/hw/acpi/acpi_dev_interface.h
>         +++ b/include/hw/acpi/acpi_dev_interface.h
>         @@ -11,6 +11,7 @@ typedef enum {
>             ACPI_CPU_HOTPLUG_STATUS = 4,
>             ACPI_MEMORY_HOTPLUG_STATUS = 8,
>             ACPI_NVDIMM_HOTPLUG_STATUS = 16,
>         +    ACPI_VMGENID_CHANGE_STATUS = 32,
>         } AcpiEventStatusBits;
> 
>         #define TYPE_ACPI_DEVICE_IF "acpi-device-interface"
>         diff --git a/include/hw/acpi/vmgenid.h b/include/hw/acpi/vmgenid.h
>         new file mode 100644
>         index 0000000..b60437a
>         --- /dev/null
>         +++ b/include/hw/acpi/vmgenid.h
>         @@ -0,0 +1,37 @@
>         +#ifndef ACPI_VMGENID_H
>         +#define ACPI_VMGENID_H
>         +
>         +#include "hw/acpi/bios-linker-loader.h"
>         +#include "hw/sysbus.h"
>         +#include "qemu/uuid.h"
>         +
>         +#define VMGENID_DEVICE           "vmgenid"
>         +#define VMGENID_GUID             "guid"
>         +#define VMGENID_GUID_FW_CFG_FILE      "etc/vmgenid"
> 
> 
>     Maybe vmgenid_guid ?
> 
> Sure.
> 
> 
> 
>         +#define VMGENID_ADDR_FW_CFG_FILE      "etc/vmgenid_addr"
>         +
>         +#define VMGENID_FW_CFG_SIZE      4096 /* Occupy a page of memory */
>         +#define VMGENID_GUID_OFFSET      40   /* allow space for
>         +                                       * OVMF SDT Header Probe
>         Supressor */
> 
> 
>     ACPI header size is 36 bytes. I'd expect just to use that.
>     Where does 40 come from? I think it's an 8 bytes alignment requirement.
> 
> 
> The number 40 was asked for by Laszlo for the OVMF SDT Header Probe Suppressor,
> which I don’t know anything about.

I think I do though :)

>  This GUID isn’t going in an ACPI table, so
> I’m not sure what you mean here.  We allocate on a page boundary and 40 bytes
> in should be 8-byte aligned.
> 
>     So do QEMU_ALIGN_UP(sizeof(AcpiTableHeader), 8)
> 
>     Add a comment explaining that 8.

Laszlo could you suggest a comment explaining a bit about what
OVMF does here?

> 
>         +
>         +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid);
>         +void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker
>         *linker);
>         +
>         +#define VMGENID(obj) OBJECT_CHECK(VmGenIdState, (obj), VMGENID_DEVICE)
>         +
>         +typedef struct VmGenIdState {
>         +    SysBusDevice parent_obj;
>         +    QemuUUID guid;
>         +    uint8_t vgia_le[4];
> 
> 
>     Please give this fields a better name. Is this the address?
>     Pls add comments, too.
> 
> 
> This variable name was suggested by Laszlo.  the ‘a’ in ‘vgia’ refers to
> address, but I’ll add some comments.

vmgenid_addr_le?


>     How about we make it 8 byte so it's future proof?
> 
> I can do that, but a previous conversation we had made it clear that guests
> would never allocate above 4GB so 64 bits wasn’t necessary.

Right, it's just very painful to change once we make it 32 bit.

>     alternatively put it in a ram block instead.
> 
> 
>         +} VmGenIdState;
>         +
>         +static Object *find_vmgenid_dev(Error **errp)
>         +{
>         +    Object *obj = object_resolve_path_type("", VMGENID_DEVICE, NULL);
>         +    if (!obj && errp) {
>         +        error_setg(errp, "%s is not found", VMGENID_DEVICE);
>         +    }
>         +    return obj;
>         +}
>         +
>         +#endif
>         -- 
>         2.7.4
> 
> 

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-06 17:41       ` Michael S. Tsirkin
@ 2017-02-06 17:59         ` Ben Warren
  2017-02-06 18:17           ` Michael S. Tsirkin
  2017-02-07 14:00         ` Igor Mammedov
  1 sibling, 1 reply; 70+ messages in thread
From: Ben Warren @ 2017-02-06 17:59 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: qemu-devel, lersek, imammedo

[-- Attachment #1: Type: text/plain, Size: 21147 bytes --]


> On Feb 6, 2017, at 9:41 AM, Michael S. Tsirkin <mst@redhat.com> wrote:
> 
> On Mon, Feb 06, 2017 at 09:29:30AM -0800, Ben Warren wrote:
>> 
>>    On Feb 6, 2017, at 8:15 AM, Michael S. Tsirkin <mst@redhat.com> wrote:
>> 
>>    On Sun, Feb 05, 2017 at 01:12:00AM -0800, ben@skyportsystems.com wrote:
>> 
>>        From: Ben Warren <ben@skyportsystems.com>
>> 
>>        This implements the VM Generation ID feature by passing a 128-bit
>>        GUID to the guest via a fw_cfg blob.
>>        Any time the GUID changes, an ACPI notify event is sent to the guest
>> 
>>        The user interface is a simple device with one parameter:
>>        - guid (string, must be "auto" or in UUID format
>>          xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
>> 
>>        Signed-off-by: Ben Warren <ben@skyportsystems.com>
>> 
>> 
>> 
>>    Thanks!
>>    I think it's mostly in a good shape.
>>    Comments inside.
>> 
>> 
>> Thanks!  Hopefully the next rev has everything you want.
>> 
>> 
>> 
>>        ---
>>        default-configs/i386-softmmu.mak     |   1 +
>>        default-configs/x86_64-softmmu.mak   |   1 +
>>        hw/acpi/Makefile.objs                |   1 +
>>        hw/acpi/vmgenid.c                    | 206
>>        +++++++++++++++++++++++++++++++++++
>>        hw/i386/acpi-build.c                 |  10 ++
>>        include/hw/acpi/acpi_dev_interface.h |   1 +
>>        include/hw/acpi/vmgenid.h            |  37 +++++++
>>        7 files changed, 257 insertions(+)
>>        create mode 100644 hw/acpi/vmgenid.c
>>        create mode 100644 include/hw/acpi/vmgenid.h
>> 
>>        diff --git a/default-configs/i386-softmmu.mak b/default-configs/
>>        i386-softmmu.mak
>>        index 384cefb..1a43542 100644
>>        --- a/default-configs/i386-softmmu.mak
>>        +++ b/default-configs/i386-softmmu.mak
>>        @@ -58,3 +58,4 @@ CONFIG_I82801B11=y
>>        CONFIG_SMBIOS=y
>>        CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
>>        CONFIG_PXB=y
>>        +CONFIG_ACPI_VMGENID=y
>>        diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/
>>        x86_64-softmmu.mak
>>        index 491a191..aee8b08 100644
>>        --- a/default-configs/x86_64-softmmu.mak
>>        +++ b/default-configs/x86_64-softmmu.mak
>>        @@ -58,3 +58,4 @@ CONFIG_I82801B11=y
>>        CONFIG_SMBIOS=y
>>        CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
>>        CONFIG_PXB=y
>>        +CONFIG_ACPI_VMGENID=y
>>        diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
>>        index 6acf798..11c35bc 100644
>>        --- a/hw/acpi/Makefile.objs
>>        +++ b/hw/acpi/Makefile.objs
>>        @@ -5,6 +5,7 @@ common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
>>        common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
>>        common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
>>        common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
>>        +common-obj-$(CONFIG_ACPI_VMGENID) += vmgenid.o
>>        common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
>> 
>>        common-obj-y += acpi_interface.o
>>        diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
>>        new file mode 100644
>>        index 0000000..6c9ecfd
>>        --- /dev/null
>>        +++ b/hw/acpi/vmgenid.c
>>        @@ -0,0 +1,206 @@
>>        +/*
>>        + *  Virtual Machine Generation ID Device
>>        + *
>>        + *  Copyright (C) 2017 Skyport Systems.
>>        + *
>>        + *  Author: Ben Warren <ben@skyportsystems.com>
>>        + *
>>        + * This work is licensed under the terms of the GNU GPL, version 2 or
>>        later.
>>        + * See the COPYING file in the top-level directory.
>>        + *
>>        + */
>>        +
>>        +#include "qemu/osdep.h"
>>        +#include "qmp-commands.h"
>>        +#include "hw/acpi/acpi.h"
>>        +#include "hw/acpi/aml-build.h"
>>        +#include "hw/acpi/vmgenid.h"
>>        +#include "hw/nvram/fw_cfg.h"
>>        +#include "sysemu/sysemu.h"
>>        +
>>        +void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker
>>        *linker)
>>        +{
>>        +    Object *obj;
>>        +    VmGenIdState *s;
>>        +    Aml *ssdt, *dev, *scope, *method, *addr, *if_ctx;
>>        +    uint32_t vgia_offset;
>>        +
>>        +    obj = find_vmgenid_dev(NULL);
>>        +    assert(obj);
>>        +    s = VMGENID(obj);
>>        +
>>        +    /* Fill in the GUID values */
>>        +    if (guid->len != VMGENID_FW_CFG_SIZE) {
>>        +        g_array_set_size(guid, VMGENID_FW_CFG_SIZE);
>>        +    }
>>        +    g_array_insert_vals(guid, VMGENID_GUID_OFFSET, s->guid.data, 16);
>> 
>> 
>>    ARRAY_SIZE(s->guid.data);
>> 
>> 
>> OK
>> 
>>        +
>>        +    /* Put this in a separate SSDT table */
>>        +    ssdt = init_aml_allocator();
>>        +
>>        +    /* Reserve space for header */
>>        +    acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader));
>>        +
>>        +    /* Storage for the GUID address */
>>        +    vgia_offset = table_data->len +
>>        +        build_append_named_dword(ssdt->buf, "VGIA");
>>        +    scope = aml_scope("\\_SB");
>>        +    dev = aml_device("VGEN");
>>        +    aml_append(dev, aml_name_decl("_HID", aml_string("QEMUVGID")));
>>        +    aml_append(dev, aml_name_decl("_CID", aml_string
>>        ("VM_Gen_Counter")));
>>        +    aml_append(dev, aml_name_decl("_DDN", aml_string
>>        ("VM_Gen_Counter")));
>>        +
>>        +    /* Simple status method to check that address is linked and
>>        non-zero */
>>        +    method = aml_method("_STA", 0, AML_NOTSERIALIZED);
>>        +    addr = aml_local(0);
>>        +    aml_append(method, aml_store(aml_int(0xf), addr));
>>        +    if_ctx = aml_if(aml_equal(aml_name("VGIA"), aml_int(0)));
>>        +    aml_append(if_ctx, aml_store(aml_int(0), addr));
>>        +    aml_append(method, if_ctx);
>>        +    aml_append(method, aml_return(addr));
>>        +    aml_append(dev, method);
>>        +
>>        +    /* the ADDR method returns two 32-bit words representing the lower
>>        and
>>        +     * upper halves * of the physical address of the fw_cfg blob
>>        +     * (holding the GUID) */
>> 
>> 
>>    /*
>>    * multiline comments
>>    * look like this
>>    */
>> 
>> 
>> OK
>> 
>>        +    method = aml_method("ADDR", 0, AML_NOTSERIALIZED);
>>        +
>>        +    addr = aml_local(0);
>>        +    aml_append(method, aml_store(aml_package(2), addr));
>>        +
>>        +    aml_append(method, aml_store(aml_add(aml_name("VGIA"),
>>        +                                         aml_int(VMGENID_GUID_OFFSET),
>>        NULL),
>>        +                                 aml_index(addr, aml_int(0))));
>>        +    aml_append(method, aml_store(aml_int(0), aml_index(addr, aml_int
>>        (1))));
>>        +    aml_append(method, aml_return(addr));
>>        +
>>        +    aml_append(dev, method);
>>        +    aml_append(scope, dev);
>>        +    aml_append(ssdt, scope);
>>        +
>>        +    /* attach an ACPI notify */
>>        +    method = aml_method("\\_GPE._E05", 0, AML_NOTSERIALIZED);
>>        +    aml_append(method, aml_notify(aml_name("\\_SB.VGEN"), aml_int
>>        (0x80)));
>>        +    aml_append(ssdt, method);
>>        +
>>        +    g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len);
>>        +
>>        +    /* Allocate guest memory for the Data fw_cfg blob */
>>        +    bios_linker_loader_alloc(linker, VMGENID_GUID_FW_CFG_FILE, guid,
>>        4096,
>>        +                             false /* page boundary, high memory */);
>>        +
>>        +    /* Patch address of GUID fw_cfg blob into the ADDR fw_cfg blob */
>> 
>> 
>>    add ... so QEMU can write GUID there
>> 
>> 
>> OK
>> 
>>        +    bios_linker_loader_add_pointer(linker,
>>        +        VMGENID_ADDR_FW_CFG_FILE, 0, sizeof(uint32_t),
>>        +        VMGENID_GUID_FW_CFG_FILE, 0, true);
>>        +
>>        +    /* Patch address of GUID fw_cfg blob into the AML */
>> 
>> 
>>    add ... so OSPM can retrieve and read it
>> 
>> 
>> OK
>> 
>>        +    bios_linker_loader_add_pointer(linker,
>>        +        ACPI_BUILD_TABLE_FILE, vgia_offset, sizeof(uint32_t),
>>        +        VMGENID_GUID_FW_CFG_FILE, 0, false);
>>        +
>>        +    build_header(linker, table_data,
>>        +        (void *)(table_data->data + table_data->len - ssdt->buf->len),
>>        +        "SSDT", ssdt->buf->len, 1, NULL, "VMGENID");
>>        +    free_aml_allocator();
>>        +}
>>        +
>>        +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid)
>>        +{
>>        +    Object *obj = find_vmgenid_dev(NULL);
>>        +    assert(obj);
>>        +    VmGenIdState *vms = VMGENID(obj);
>>        +
>>        +    /* Create a read-only fw_cfg file for GUID */
>>        +    fw_cfg_add_file(s, VMGENID_GUID_FW_CFG_FILE, guid->data,
>>        +                    VMGENID_FW_CFG_SIZE);
>>        +    /* Create a read-write fw_cfg file for Address */
>>        +    fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL, NULL,
>> 
>> 
>>    Seems wrong. What if guest updates the address after command line
>>    set it? You want a callback to copy guid there.
>> 
>> 
>> Sure, I can do that.  My understanding was that this is a read callback, but if
>> it also is called upon a write, we should do what you suggest.
> 
> Hmm you are right. But we really need to call something
> on write though - unlike read, it must be called after write.
> Otherwise I don't see how it can work if you set gen id before
> guest boots.
> 
> I guess this means we need yet another callback per file.
> FWCfgWriteCallback ?
> 
> Can you implement this in hw/nvram/fw_cfg.c?
> It's rather straight-forward to do.
> 
The reason it works is that we put the initial contents of the GUID (as supplied by command-line) into the GUID fw_cfg in the ‘vmgenid_build_acpi()’ function, which is guaranteed to happen before the guest boots.  The only time QEMU needs to know VGIA is on later updates to the GUID (via monitor) or when restoring.  If you really think this extra complexity is needed, I can do so, but it seems to work very well as-is.
> 
>> 
>> 
>>        +                             vms->vgia_le, sizeof(uint32_t), false);
>> 
>> 
>>    Should be ARRAY_SIZE(vms->vgia_le).
>> 
>>    Also, I thought GUID is at an offset from the beginning
>>    in order to trick OVMF, isn't it?
>> 
>> 
>> The offset is taken into account in the GUID fw_cfg file.  The writing to guest
>> memory, we add the offset to VGIA.
> 
> I keep forgetting it's the address. Really please rename it
> using full words.
> 
Will do.
> 
>> 
>>        +}
>>        +
>>        +static void vmgenid_update_guest(VmGenIdState *s)
>>        +{
>>        +    Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF,
>>        NULL);
>>        +    uint32_t vgia;
>>        +
>>        +    if (obj) {
>>        +        /* Write the GUID to guest memory */
>>        +        memcpy(&vgia, s->vgia_le, sizeof(vgia));
>>        +        vgia = le32_to_cpu(vgia);
>>        +        if (vgia) {
>> 
>> 
>>    add a comment saying 0 means bios did not run yet.
>> 
>> OK
>> 
>> 
>> 
>>        +            cpu_physical_memory_write(vgia + VMGENID_GUID_OFFSET,
>>        +                                      s->guid.data, sizeof(s->
>>        guid.data));
>> 
>> 
>>    Avoid this. You want dma.h APIs.
>> 
>> I’ll have a look at those.  This function was recommended to me in an earlier
>> patch version.
>> 
>> 
>> 
>>        +            /* Send _GPE.E05 event */
>>        +            acpi_send_event(DEVICE(obj), ACPI_VMGENID_CHANGE_STATUS);
>>        +        }
>>        +    }
>>        +}
>>        +
>>        +static void vmgenid_set_guid(Object *obj, const char *value, Error
>>        **errp)
>>        +{
>>        +    VmGenIdState *s = VMGENID(obj);
>>        +
>>        +    if (!strncmp(value, "auto", 4)) {
>> 
>> 
>>    I'd use strcmp here.
>> 
>> OK
>> 
>> 
>> 
>>        +        qemu_uuid_generate(&s->guid);
>>        +    } else if (qemu_uuid_parse(value, &s->guid) < 0) {
>>        +        error_setg(errp, "'%s. %s': Failed to parse GUID string: %s",
>>        +                   object_get_typename(OBJECT(s)), VMGENID_GUID,
>>        value);
>>        +        return;
>>        +    }
>>        +    /* QemuUUID has the first three words as big-endian, and expect
>>        that any
>>        +     * GUIDs passed in will always be BE.  The guest, however will
>>        expect
>>        +     * the fields to be little-endian, so store that way internally.
>> 
>> 
>>    This makes my head spin. It's the actual guid, right? Only place we need it
>>    is when
>>    we copy it into guest memory. So swap there -
>>    and do it to a copy so you won't need these comments.
>> 
>> I understand.  I wanted to only do the swap at one place and decided to do it
>> closest to the user interface, but can do it at the other end instead.
>> 
>> 
>> 
>>        Make
>>        +     * sure to swap back whenever reporting via monitor */
>> 
>> 
>>    And what code does this swap back?
>> 
>> A later patch where the QMP code is added.  But I’ll remove that necessity.
>> 
>> 
>> 
>>        +    qemu_uuid_bswap(&s->guid);
>>        +
>>        +    /* Send the ACPI notify */
>>        +    vmgenid_update_guest(s);
>>        +}
>>        +
>>        +/* After restoring an image, we need to update the guest memory and
>>        notify
>>        + * it of a potential change to VM Generation ID */
>>        +static int vmgenid_post_load(void *opaque, int version_id)
>>        +{
>>        +    VmGenIdState *s = opaque;
>>        +    vmgenid_update_guest(s);
>>        +    return 0;
>>        +}
>>        +
>>        +static const VMStateDescription vmstate_vmgenid = {
>>        +    .name = "vmgenid",
>>        +    .version_id = 1,
>>        +    .minimum_version_id = 1,
>>        +    .post_load = vmgenid_post_load,
>>        +    .fields = (VMStateField[]) {
>>        +        VMSTATE_UINT8_ARRAY(vgia_le, VmGenIdState, sizeof(uint32_t)),
>>        +        VMSTATE_END_OF_LIST()
>>        +    },
>>        +};
>>        +
>>        +static void vmgenid_initfn(Object *obj)
>>        +{
>>        +    object_property_add_str(obj, VMGENID_GUID, NULL, vmgenid_set_guid,
>>        NULL);
>>        +}
>>        +
>>        +static void vmgenid_device_class_init(ObjectClass *klass, void *data)
>>        +{
>>        +    DeviceClass *dc = DEVICE_CLASS(klass);
>>        +
>>        +    dc->vmsd = &vmstate_vmgenid;
>>        +}
>>        +
>>        +static const TypeInfo vmgenid_device_info = {
>>        +    .name          = VMGENID_DEVICE,
>>        +    .parent        = TYPE_SYS_BUS_DEVICE,
>>        +    .instance_size = sizeof(VmGenIdState),
>>        +    .instance_init = vmgenid_initfn,
>>        +    .class_init    = vmgenid_device_class_init,
>>        +};
>>        +
>>        +static void vmgenid_register_types(void)
>>        +{
>>        +    type_register_static(&vmgenid_device_info);
>>        +}
>>        +
>>        +type_init(vmgenid_register_types)
>>        diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>>        index 78a1d84..4c40f76 100644
>>        --- a/hw/i386/acpi-build.c
>>        +++ b/hw/i386/acpi-build.c
>>        @@ -42,6 +42,7 @@
>>        #include "hw/acpi/memory_hotplug.h"
>>        #include "sysemu/tpm.h"
>>        #include "hw/acpi/tpm.h"
>>        +#include "hw/acpi/vmgenid.h"
>>        #include "sysemu/tpm_backend.h"
>>        #include "hw/timer/mc146818rtc_regs.h"
>>        #include "sysemu/numa.h"
>>        @@ -2653,6 +2654,11 @@ void acpi_build(AcpiBuildTables *tables,
>>        MachineState *machine)
>>            acpi_add_table(table_offsets, tables_blob);
>>            build_madt(tables_blob, tables->linker, pcms);
>> 
>>        +    if (find_vmgenid_dev(NULL)) {
>>        +        acpi_add_table(table_offsets, tables_blob);
>>        +        vmgenid_build_acpi(tables_blob, tables->vmgenid, tables->
>>        linker);
>>        +    }
>>        +
>>            if (misc.has_hpet) {
>>                acpi_add_table(table_offsets, tables_blob);
>>                build_hpet(tables_blob, tables->linker);
>>        @@ -2859,6 +2865,10 @@ void acpi_setup(void)
>>            fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
>>                            tables.tcpalog->data, acpi_data_len
>>        (tables.tcpalog));
>> 
>>        +    if (find_vmgenid_dev(NULL)) {
>>        +        vmgenid_add_fw_cfg(pcms->fw_cfg, tables.vmgenid);
>>        +    }
>>        +
>>            if (!pcmc->rsdp_in_ram) {
>>                /*
>>                 * Keep for compatibility with old machine types.
>>        diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/
>>        acpi_dev_interface.h
>>        index 71d3c48..3c2e4e9 100644
>>        --- a/include/hw/acpi/acpi_dev_interface.h
>>        +++ b/include/hw/acpi/acpi_dev_interface.h
>>        @@ -11,6 +11,7 @@ typedef enum {
>>            ACPI_CPU_HOTPLUG_STATUS = 4,
>>            ACPI_MEMORY_HOTPLUG_STATUS = 8,
>>            ACPI_NVDIMM_HOTPLUG_STATUS = 16,
>>        +    ACPI_VMGENID_CHANGE_STATUS = 32,
>>        } AcpiEventStatusBits;
>> 
>>        #define TYPE_ACPI_DEVICE_IF "acpi-device-interface"
>>        diff --git a/include/hw/acpi/vmgenid.h b/include/hw/acpi/vmgenid.h
>>        new file mode 100644
>>        index 0000000..b60437a
>>        --- /dev/null
>>        +++ b/include/hw/acpi/vmgenid.h
>>        @@ -0,0 +1,37 @@
>>        +#ifndef ACPI_VMGENID_H
>>        +#define ACPI_VMGENID_H
>>        +
>>        +#include "hw/acpi/bios-linker-loader.h"
>>        +#include "hw/sysbus.h"
>>        +#include "qemu/uuid.h"
>>        +
>>        +#define VMGENID_DEVICE           "vmgenid"
>>        +#define VMGENID_GUID             "guid"
>>        +#define VMGENID_GUID_FW_CFG_FILE      "etc/vmgenid"
>> 
>> 
>>    Maybe vmgenid_guid ?
>> 
>> Sure.
>> 
>> 
>> 
>>        +#define VMGENID_ADDR_FW_CFG_FILE      "etc/vmgenid_addr"
>>        +
>>        +#define VMGENID_FW_CFG_SIZE      4096 /* Occupy a page of memory */
>>        +#define VMGENID_GUID_OFFSET      40   /* allow space for
>>        +                                       * OVMF SDT Header Probe
>>        Supressor */
>> 
>> 
>>    ACPI header size is 36 bytes. I'd expect just to use that.
>>    Where does 40 come from? I think it's an 8 bytes alignment requirement.
>> 
>> 
>> The number 40 was asked for by Laszlo for the OVMF SDT Header Probe Suppressor,
>> which I don’t know anything about.
> 
> I think I do though :)
> 
>> This GUID isn’t going in an ACPI table, so
>> I’m not sure what you mean here.  We allocate on a page boundary and 40 bytes
>> in should be 8-byte aligned.
>> 
>>    So do QEMU_ALIGN_UP(sizeof(AcpiTableHeader), 8)
>> 
>>    Add a comment explaining that 8.
> 
> Laszlo could you suggest a comment explaining a bit about what
> OVMF does here?
> 
>> 
>>        +
>>        +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid);
>>        +void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker
>>        *linker);
>>        +
>>        +#define VMGENID(obj) OBJECT_CHECK(VmGenIdState, (obj), VMGENID_DEVICE)
>>        +
>>        +typedef struct VmGenIdState {
>>        +    SysBusDevice parent_obj;
>>        +    QemuUUID guid;
>>        +    uint8_t vgia_le[4];
>> 
>> 
>>    Please give this fields a better name. Is this the address?
>>    Pls add comments, too.
>> 
>> 
>> This variable name was suggested by Laszlo.  the ‘a’ in ‘vgia’ refers to
>> address, but I’ll add some comments.
> 
> vmgenid_addr_le?
> 
> 
>>    How about we make it 8 byte so it's future proof?
>> 
>> I can do that, but a previous conversation we had made it clear that guests
>> would never allocate above 4GB so 64 bits wasn’t necessary.
> 
> Right, it's just very painful to change once we make it 32 bit.
> 
OK, make sense.  I’ll wait to hear from Laszlo before continuing.
>>    alternatively put it in a ram block instead.
>> 
>> 
>>        +} VmGenIdState;
>>        +
>>        +static Object *find_vmgenid_dev(Error **errp)
>>        +{
>>        +    Object *obj = object_resolve_path_type("", VMGENID_DEVICE, NULL);
>>        +    if (!obj && errp) {
>>        +        error_setg(errp, "%s is not found", VMGENID_DEVICE);
>>        +    }
>>        +    return obj;
>>        +}
>>        +
>>        +#endif
>>        -- 
>>        2.7.4


[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 3583 bytes --]

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-06 17:59         ` Ben Warren
@ 2017-02-06 18:17           ` Michael S. Tsirkin
  2017-02-06 18:48             ` Ben Warren
  0 siblings, 1 reply; 70+ messages in thread
From: Michael S. Tsirkin @ 2017-02-06 18:17 UTC (permalink / raw)
  To: Ben Warren; +Cc: qemu-devel, lersek, imammedo

On Mon, Feb 06, 2017 at 09:59:55AM -0800, Ben Warren wrote:
>                +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid)
>                +{
>                +    Object *obj = find_vmgenid_dev(NULL);
>                +    assert(obj);
>                +    VmGenIdState *vms = VMGENID(obj);
>                +
>                +    /* Create a read-only fw_cfg file for GUID */
>                +    fw_cfg_add_file(s, VMGENID_GUID_FW_CFG_FILE, guid->data,
>                +                    VMGENID_FW_CFG_SIZE);
>                +    /* Create a read-write fw_cfg file for Address */
>                +    fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL,
>         NULL,
> 
> 
>            Seems wrong. What if guest updates the address after command line
>            set it? You want a callback to copy guid there.
> 
> 
>         Sure, I can do that.  My understanding was that this is a read
>         callback, but if
>         it also is called upon a write, we should do what you suggest.
> 
> 
>     Hmm you are right. But we really need to call something
>     on write though - unlike read, it must be called after write.
>     Otherwise I don't see how it can work if you set gen id before
>     guest boots.
> 
>     I guess this means we need yet another callback per file.
>     FWCfgWriteCallback ?
> 
>     Can you implement this in hw/nvram/fw_cfg.c?
>     It's rather straight-forward to do.
> 
> 
> The reason it works is that we put the initial contents of the GUID (as
> supplied by command-line) into the GUID fw_cfg in the ‘vmgenid_build_acpi()’
> function, which is guaranteed to happen before the guest boots.  The only time
> QEMU needs to know VGIA is on later updates to the GUID (via monitor) or when
> restoring.  If you really think this extra complexity is needed, I can do so,
> but it seems to work very well as-is.

I see. So it's a race condition I think.  It works unless you change the
gen id after bios read the guid from the guid file but before it wrote
out the address.

Or do I miss something?

-- 
MST

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-06 18:17           ` Michael S. Tsirkin
@ 2017-02-06 18:48             ` Ben Warren
  2017-02-06 19:04               ` Michael S. Tsirkin
  0 siblings, 1 reply; 70+ messages in thread
From: Ben Warren @ 2017-02-06 18:48 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: qemu-devel, Laszlo Ersek, imammedo

[-- Attachment #1: Type: text/plain, Size: 2667 bytes --]


> On Feb 6, 2017, at 10:17 AM, Michael S. Tsirkin <mst@redhat.com> wrote:
> 
> On Mon, Feb 06, 2017 at 09:59:55AM -0800, Ben Warren wrote:
>>               +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid)
>>               +{
>>               +    Object *obj = find_vmgenid_dev(NULL);
>>               +    assert(obj);
>>               +    VmGenIdState *vms = VMGENID(obj);
>>               +
>>               +    /* Create a read-only fw_cfg file for GUID */
>>               +    fw_cfg_add_file(s, VMGENID_GUID_FW_CFG_FILE, guid->data,
>>               +                    VMGENID_FW_CFG_SIZE);
>>               +    /* Create a read-write fw_cfg file for Address */
>>               +    fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL,
>>        NULL,
>> 
>> 
>>           Seems wrong. What if guest updates the address after command line
>>           set it? You want a callback to copy guid there.
>> 
>> 
>>        Sure, I can do that.  My understanding was that this is a read
>>        callback, but if
>>        it also is called upon a write, we should do what you suggest.
>> 
>> 
>>    Hmm you are right. But we really need to call something
>>    on write though - unlike read, it must be called after write.
>>    Otherwise I don't see how it can work if you set gen id before
>>    guest boots.
>> 
>>    I guess this means we need yet another callback per file.
>>    FWCfgWriteCallback ?
>> 
>>    Can you implement this in hw/nvram/fw_cfg.c?
>>    It's rather straight-forward to do.
>> 
>> 
>> The reason it works is that we put the initial contents of the GUID (as
>> supplied by command-line) into the GUID fw_cfg in the ‘vmgenid_build_acpi()’
>> function, which is guaranteed to happen before the guest boots.  The only time
>> QEMU needs to know VGIA is on later updates to the GUID (via monitor) or when
>> restoring.  If you really think this extra complexity is needed, I can do so,
>> but it seems to work very well as-is.
> 
> I see. So it's a race condition I think.  It works unless you change the
> gen id after bios read the guid from the guid file but before it wrote
> out the address.
> 
> Or do I miss something?
> 
I don’t think it’s an issue because BIOS is not a consumer of the GUID.  I suppose there’s a window where another GUID could be written via monitor prior to bios writing back, but the change wouldn’t be applied to memory in vmgenid_update_guest() because vgia=0.  That would be solved by a write callback and we could remove the GUID copying from vmgenid_build_acpi().  It’s a very unlikely scenario, though.
> -- 
> MST


[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 3583 bytes --]

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-06 18:48             ` Ben Warren
@ 2017-02-06 19:04               ` Michael S. Tsirkin
  2017-02-06 19:44                 ` Ben Warren
  0 siblings, 1 reply; 70+ messages in thread
From: Michael S. Tsirkin @ 2017-02-06 19:04 UTC (permalink / raw)
  To: Ben Warren; +Cc: qemu-devel, Laszlo Ersek, imammedo

On Mon, Feb 06, 2017 at 10:48:05AM -0800, Ben Warren wrote:
> 
> > On Feb 6, 2017, at 10:17 AM, Michael S. Tsirkin <mst@redhat.com> wrote:
> > 
> > On Mon, Feb 06, 2017 at 09:59:55AM -0800, Ben Warren wrote:
> >>               +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid)
> >>               +{
> >>               +    Object *obj = find_vmgenid_dev(NULL);
> >>               +    assert(obj);
> >>               +    VmGenIdState *vms = VMGENID(obj);
> >>               +
> >>               +    /* Create a read-only fw_cfg file for GUID */
> >>               +    fw_cfg_add_file(s, VMGENID_GUID_FW_CFG_FILE, guid->data,
> >>               +                    VMGENID_FW_CFG_SIZE);
> >>               +    /* Create a read-write fw_cfg file for Address */
> >>               +    fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL,
> >>        NULL,
> >> 
> >> 
> >>           Seems wrong. What if guest updates the address after command line
> >>           set it? You want a callback to copy guid there.
> >> 
> >> 
> >>        Sure, I can do that.  My understanding was that this is a read
> >>        callback, but if
> >>        it also is called upon a write, we should do what you suggest.
> >> 
> >> 
> >>    Hmm you are right. But we really need to call something
> >>    on write though - unlike read, it must be called after write.
> >>    Otherwise I don't see how it can work if you set gen id before
> >>    guest boots.
> >> 
> >>    I guess this means we need yet another callback per file.
> >>    FWCfgWriteCallback ?
> >> 
> >>    Can you implement this in hw/nvram/fw_cfg.c?
> >>    It's rather straight-forward to do.
> >> 
> >> 
> >> The reason it works is that we put the initial contents of the GUID (as
> >> supplied by command-line) into the GUID fw_cfg in the ‘vmgenid_build_acpi()’
> >> function, which is guaranteed to happen before the guest boots.  The only time
> >> QEMU needs to know VGIA is on later updates to the GUID (via monitor) or when
> >> restoring.  If you really think this extra complexity is needed, I can do so,
> >> but it seems to work very well as-is.
> > 
> > I see. So it's a race condition I think.  It works unless you change the
> > gen id after bios read the guid from the guid file but before it wrote
> > out the address.
> > 
> > Or do I miss something?
> > 
> I don’t think it’s an issue because BIOS is not a consumer of the
> GUID.  I suppose there’s a window where another GUID could be written
> via monitor prior to bios writing back, but the change wouldn’t be
> applied to memory in vmgenid_update_guest() because vgia=0.  That
> would be solved by a write callback and we could remove the GUID
> copying from vmgenid_build_acpi().  It’s a very unlikely scenario,
> though.

When people run 100000 VMs and up, every unlikely scenario tends to
trigger.

> > -- 
> > MST
> 

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-06 19:04               ` Michael S. Tsirkin
@ 2017-02-06 19:44                 ` Ben Warren
  0 siblings, 0 replies; 70+ messages in thread
From: Ben Warren @ 2017-02-06 19:44 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: qemu-devel, Laszlo Ersek, imammedo

[-- Attachment #1: Type: text/plain, Size: 3331 bytes --]


> On Feb 6, 2017, at 11:04 AM, Michael S. Tsirkin <mst@redhat.com> wrote:
> 
> On Mon, Feb 06, 2017 at 10:48:05AM -0800, Ben Warren wrote:
>> 
>>> On Feb 6, 2017, at 10:17 AM, Michael S. Tsirkin <mst@redhat.com> wrote:
>>> 
>>> On Mon, Feb 06, 2017 at 09:59:55AM -0800, Ben Warren wrote:
>>>>              +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid)
>>>>              +{
>>>>              +    Object *obj = find_vmgenid_dev(NULL);
>>>>              +    assert(obj);
>>>>              +    VmGenIdState *vms = VMGENID(obj);
>>>>              +
>>>>              +    /* Create a read-only fw_cfg file for GUID */
>>>>              +    fw_cfg_add_file(s, VMGENID_GUID_FW_CFG_FILE, guid->data,
>>>>              +                    VMGENID_FW_CFG_SIZE);
>>>>              +    /* Create a read-write fw_cfg file for Address */
>>>>              +    fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL,
>>>>       NULL,
>>>> 
>>>> 
>>>>          Seems wrong. What if guest updates the address after command line
>>>>          set it? You want a callback to copy guid there.
>>>> 
>>>> 
>>>>       Sure, I can do that.  My understanding was that this is a read
>>>>       callback, but if
>>>>       it also is called upon a write, we should do what you suggest.
>>>> 
>>>> 
>>>>   Hmm you are right. But we really need to call something
>>>>   on write though - unlike read, it must be called after write.
>>>>   Otherwise I don't see how it can work if you set gen id before
>>>>   guest boots.
>>>> 
>>>>   I guess this means we need yet another callback per file.
>>>>   FWCfgWriteCallback ?
>>>> 
>>>>   Can you implement this in hw/nvram/fw_cfg.c?
>>>>   It's rather straight-forward to do.
>>>> 
>>>> 
>>>> The reason it works is that we put the initial contents of the GUID (as
>>>> supplied by command-line) into the GUID fw_cfg in the ‘vmgenid_build_acpi()’
>>>> function, which is guaranteed to happen before the guest boots.  The only time
>>>> QEMU needs to know VGIA is on later updates to the GUID (via monitor) or when
>>>> restoring.  If you really think this extra complexity is needed, I can do so,
>>>> but it seems to work very well as-is.
>>> 
>>> I see. So it's a race condition I think.  It works unless you change the
>>> gen id after bios read the guid from the guid file but before it wrote
>>> out the address.
>>> 
>>> Or do I miss something?
>>> 
>> I don’t think it’s an issue because BIOS is not a consumer of the
>> GUID.  I suppose there’s a window where another GUID could be written
>> via monitor prior to bios writing back, but the change wouldn’t be
>> applied to memory in vmgenid_update_guest() because vgia=0.  That
>> would be solved by a write callback and we could remove the GUID
>> copying from vmgenid_build_acpi().  It’s a very unlikely scenario,
>> though.
> 
> When people run 100000 VMs and up, every unlikely scenario tends to
> trigger.
> 
Right, your point is valid and I don’t want to ever have to debug that type of race.  It turns out that the callback in fw_cfg is tied to select(), not read(), so it is called upon write().  There doesn’t seem to be a need to add a new callback after all.  I’ll go down this path to remove this potential race.
>>> -- 
>>> MST


[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 3583 bytes --]

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

* Re: [Qemu-devel] [PATCH v5 03/10] docs: VM Generation ID device description
  2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 03/10] docs: VM Generation ID device description ben
@ 2017-02-06 20:18   ` Eric Blake
  2017-02-07 20:54   ` Laszlo Ersek
  2017-02-10  0:55   ` Laszlo Ersek
  2 siblings, 0 replies; 70+ messages in thread
From: Eric Blake @ 2017-02-06 20:18 UTC (permalink / raw)
  To: ben, qemu-devel; +Cc: Gal Hammer, imammedo, lersek, mst

[-- Attachment #1: Type: text/plain, Size: 1711 bytes --]

On 02/05/2017 03:11 AM, ben@skyportsystems.com wrote:
> From: Ben Warren <ben@skyportsystems.com>
> 
> This patch is based off an earlier version by
> Gal Hammer (ghammer@redhat.com)
> 
> Requirements section, ASCII diagrams and overall help
> provided by Laszlo Ersek (lersek@redhat.com)
> 
> Signed-off-by: Gal Hammer <ghammer@redhat.com>
> Signed-off-by: Ben Warren <ben@skyportsystems.com>
> ---
>  docs/specs/vmgenid.txt | 239 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 239 insertions(+)
>  create mode 100644 docs/specs/vmgenid.txt
> 

> +

> +
> +Design Details:
> +---------------
> +
> +Requirements R1a through R1e dicate that the memory holding the

s/dicate/dictate/

> +VM Generation ID must be allocated and owned by the guest operating system,

> +
> +GUID Storage Format:
> +--------------------
> +
> +In order to work with OVMF "SDT Header Probe Supressor", the contents of

s/Supressor/Suppressor/

> +the vmgenid fw_cfg blob are not simply a 128-bit GUID.  There is also
> +significant padding in order to align and fill a memory page, as shown in the
> +following diagram:
> +
> ++----------------------------------+
> +| SSDT with OEM Table ID = VMGENID |
> ++----------------------------------+
> +| ...                              |       TOP OF PAGE
> +| VGIA dword object ---------------|-----> +---------------------------+
> +| ...                              |       | fw-allocated array for    |
> +| _STA method referring to VGIA    |       | "etc/vmgenid"        |

Inconsistent whitespace

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

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

* Re: [Qemu-devel] [PATCH v5 02/10] linker-loader: Add new 'write pointer' command
  2017-02-06 17:31       ` Michael S. Tsirkin
@ 2017-02-07 12:11         ` Igor Mammedov
  2017-02-07 20:20           ` Laszlo Ersek
  0 siblings, 1 reply; 70+ messages in thread
From: Igor Mammedov @ 2017-02-07 12:11 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: Ben Warren, qemu-devel, Laszlo Ersek

On Mon, 6 Feb 2017 19:31:24 +0200
"Michael S. Tsirkin" <mst@redhat.com> wrote:

> On Mon, Feb 06, 2017 at 09:16:25AM -0800, Ben Warren wrote:
> > >> @@ -257,8 +263,11 @@ void bios_linker_loader_add_pointer(BIOSLinker *linker,
> > >>     const BiosLinkerFileEntry *source_file =
> > >>         bios_linker_find_file(linker, src_file);
> > >> 
> > >> -    assert(dst_patched_offset < dst_file->blob->len);
> > >> -    assert(dst_patched_offset + dst_patched_size <= dst_file->blob->len);
> > >> +    /* dst_file need not exist if writing back */  
> > > 
> > > Why not?  
> > Because WRITE_POINTER can be called without having first called
> > ALLOCATE.  In the Vm Generation ID example, there’s no reason for BIOS
> > to allocate memory for the address fw_cfg, since it’s a construct that
> > only matters to QEMU.  This is something that was requested by Laszlo.  
> 
> Well all other commands require you to first allocate.
> How does bios know e.g. which zone to put it in then?
There is no need to know which zone to put it in as file
is writeback only, i.e. there is no need to allocate
RAM for file (shadow it) which won't be read by guest side ever
if I got idea right.
Issue in the patch is combining new command with existing API
bios_linker_loader_add_pointer(),
as you suggested new API function + good description what it does
would be better than reusing.


> 
> I don't like the asymmetry ... Laszlo? 

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support ben
  2017-02-06 16:15   ` Michael S. Tsirkin
@ 2017-02-07 13:48   ` Igor Mammedov
  2017-02-07 15:36     ` Michael S. Tsirkin
  2017-02-08 20:19     ` Ben Warren
  2017-02-08  0:48   ` Laszlo Ersek
  2017-02-09  0:37   ` Laszlo Ersek
  3 siblings, 2 replies; 70+ messages in thread
From: Igor Mammedov @ 2017-02-07 13:48 UTC (permalink / raw)
  To: ben; +Cc: qemu-devel, lersek, mst

On Sun,  5 Feb 2017 01:12:00 -0800
ben@skyportsystems.com wrote:

> From: Ben Warren <ben@skyportsystems.com>
> 
> This implements the VM Generation ID feature by passing a 128-bit
> GUID to the guest via a fw_cfg blob.
> Any time the GUID changes, an ACPI notify event is sent to the guest
> 
> The user interface is a simple device with one parameter:
>  - guid (string, must be "auto" or in UUID format
>    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
> 
> Signed-off-by: Ben Warren <ben@skyportsystems.com>
> ---
>  default-configs/i386-softmmu.mak     |   1 +
>  default-configs/x86_64-softmmu.mak   |   1 +
>  hw/acpi/Makefile.objs                |   1 +
>  hw/acpi/vmgenid.c                    | 206 +++++++++++++++++++++++++++++++++++
>  hw/i386/acpi-build.c                 |  10 ++
>  include/hw/acpi/acpi_dev_interface.h |   1 +
>  include/hw/acpi/vmgenid.h            |  37 +++++++
>  7 files changed, 257 insertions(+)
>  create mode 100644 hw/acpi/vmgenid.c
>  create mode 100644 include/hw/acpi/vmgenid.h
> 
> diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
> index 384cefb..1a43542 100644
> --- a/default-configs/i386-softmmu.mak
> +++ b/default-configs/i386-softmmu.mak
> @@ -58,3 +58,4 @@ CONFIG_I82801B11=y
>  CONFIG_SMBIOS=y
>  CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
>  CONFIG_PXB=y
> +CONFIG_ACPI_VMGENID=y
> diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
> index 491a191..aee8b08 100644
> --- a/default-configs/x86_64-softmmu.mak
> +++ b/default-configs/x86_64-softmmu.mak
> @@ -58,3 +58,4 @@ CONFIG_I82801B11=y
>  CONFIG_SMBIOS=y
>  CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
>  CONFIG_PXB=y
> +CONFIG_ACPI_VMGENID=y
> diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
> index 6acf798..11c35bc 100644
> --- a/hw/acpi/Makefile.objs
> +++ b/hw/acpi/Makefile.objs
> @@ -5,6 +5,7 @@ common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
>  common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
>  common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
>  common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
> +common-obj-$(CONFIG_ACPI_VMGENID) += vmgenid.o
>  common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
>  
>  common-obj-y += acpi_interface.o
> diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
> new file mode 100644
> index 0000000..6c9ecfd
> --- /dev/null
> +++ b/hw/acpi/vmgenid.c
> @@ -0,0 +1,206 @@
> +/*
> + *  Virtual Machine Generation ID Device
> + *
> + *  Copyright (C) 2017 Skyport Systems.
> + *
> + *  Author: Ben Warren <ben@skyportsystems.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + *
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qmp-commands.h"
> +#include "hw/acpi/acpi.h"
> +#include "hw/acpi/aml-build.h"
> +#include "hw/acpi/vmgenid.h"
> +#include "hw/nvram/fw_cfg.h"
> +#include "sysemu/sysemu.h"
> +
> +void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker *linker)
> +{
> +    Object *obj;
> +    VmGenIdState *s;
> +    Aml *ssdt, *dev, *scope, *method, *addr, *if_ctx;
> +    uint32_t vgia_offset;
> +
> +    obj = find_vmgenid_dev(NULL);
get obj from caller

> +    assert(obj);
> +    s = VMGENID(obj);
> +
> +    /* Fill in the GUID values */
> +    if (guid->len != VMGENID_FW_CFG_SIZE) {
> +        g_array_set_size(guid, VMGENID_FW_CFG_SIZE);
does it have to be conditional?

> +    }
> +    g_array_insert_vals(guid, VMGENID_GUID_OFFSET, s->guid.data, 16);
> +
> +    /* Put this in a separate SSDT table */
> +    ssdt = init_aml_allocator();
> +
> +    /* Reserve space for header */
> +    acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader));
> +
> +    /* Storage for the GUID address */
> +    vgia_offset = table_data->len +
> +        build_append_named_dword(ssdt->buf, "VGIA");
> +    scope = aml_scope("\\_SB");
> +    dev = aml_device("VGEN");
> +    aml_append(dev, aml_name_decl("_HID", aml_string("QEMUVGID")));
> +    aml_append(dev, aml_name_decl("_CID", aml_string("VM_Gen_Counter")));
> +    aml_append(dev, aml_name_decl("_DDN", aml_string("VM_Gen_Counter")));
> +
> +    /* Simple status method to check that address is linked and non-zero */
> +    method = aml_method("_STA", 0, AML_NOTSERIALIZED);
> +    addr = aml_local(0);
> +    aml_append(method, aml_store(aml_int(0xf), addr));
> +    if_ctx = aml_if(aml_equal(aml_name("VGIA"), aml_int(0)));
> +    aml_append(if_ctx, aml_store(aml_int(0), addr));
> +    aml_append(method, if_ctx);
> +    aml_append(method, aml_return(addr));
> +    aml_append(dev, method);
> +
> +    /* the ADDR method returns two 32-bit words representing the lower and
> +     * upper halves * of the physical address of the fw_cfg blob
> +     * (holding the GUID) */
> +    method = aml_method("ADDR", 0, AML_NOTSERIALIZED);
> +
> +    addr = aml_local(0);
> +    aml_append(method, aml_store(aml_package(2), addr));
> +
> +    aml_append(method, aml_store(aml_add(aml_name("VGIA"),
> +                                         aml_int(VMGENID_GUID_OFFSET), NULL),
> +                                 aml_index(addr, aml_int(0))));
> +    aml_append(method, aml_store(aml_int(0), aml_index(addr, aml_int(1))));
I'd rather have "VGIA" patched wit address to GUID and not the blob start,
see next comment about how.

Also usage aml_index() looks a bit confusing, how about:

pkg = aml_local(0)
aml_store(aml_package(2), pkg)
aml_append(pkg, aml_name("VGIA"))
aml_append(pkg, aml_int(0))

> +    aml_append(method, aml_return(addr));
> +
> +    aml_append(dev, method);
> +    aml_append(scope, dev);
> +    aml_append(ssdt, scope);
> +
> +    /* attach an ACPI notify */
> +    method = aml_method("\\_GPE._E05", 0, AML_NOTSERIALIZED);
> +    aml_append(method, aml_notify(aml_name("\\_SB.VGEN"), aml_int(0x80)));
> +    aml_append(ssdt, method);
> +
> +    g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len);
> +
> +    /* Allocate guest memory for the Data fw_cfg blob */
> +    bios_linker_loader_alloc(linker, VMGENID_GUID_FW_CFG_FILE, guid, 4096,
> +                             false /* page boundary, high memory */);
does it guaranties that blob will be allocated in cacheable page?
(SeaBIOS/OVMF)

> +
> +    /* Patch address of GUID fw_cfg blob into the ADDR fw_cfg blob */
> +    bios_linker_loader_add_pointer(linker,
> +        VMGENID_ADDR_FW_CFG_FILE, 0, sizeof(uint32_t),
> +        VMGENID_GUID_FW_CFG_FILE, 0, true);
> +
> +    /* Patch address of GUID fw_cfg blob into the AML */
> +    bios_linker_loader_add_pointer(linker,
> +        ACPI_BUILD_TABLE_FILE, vgia_offset, sizeof(uint32_t),
> +        VMGENID_GUID_FW_CFG_FILE, 0, false);
see @src_offset argument description,
putting VMGENID_GUID_OFFSET would make patched place point directly to GUID

> +
> +    build_header(linker, table_data,
> +        (void *)(table_data->data + table_data->len - ssdt->buf->len),
> +        "SSDT", ssdt->buf->len, 1, NULL, "VMGENID");
> +    free_aml_allocator();
> +}
> +
> +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid)
> +{
> +    Object *obj = find_vmgenid_dev(NULL);
> +    assert(obj);
> +    VmGenIdState *vms = VMGENID(obj);
> +
> +    /* Create a read-only fw_cfg file for GUID */
> +    fw_cfg_add_file(s, VMGENID_GUID_FW_CFG_FILE, guid->data,
> +                    VMGENID_FW_CFG_SIZE);
> +    /* Create a read-write fw_cfg file for Address */
> +    fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL, NULL,
> +                             vms->vgia_le, sizeof(uint32_t), false);
> +}
> +
> +static void vmgenid_update_guest(VmGenIdState *s)
> +{
> +    Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL);
> +    uint32_t vgia;
> +
> +    if (obj) {
> +        /* Write the GUID to guest memory */
> +        memcpy(&vgia, s->vgia_le, sizeof(vgia));
> +        vgia = le32_to_cpu(vgia);
> +        if (vgia) {
> +            cpu_physical_memory_write(vgia + VMGENID_GUID_OFFSET,
> +                                      s->guid.data, sizeof(s->guid.data));
> +            /* Send _GPE.E05 event */
> +            acpi_send_event(DEVICE(obj), ACPI_VMGENID_CHANGE_STATUS);
> +        }
> +    }
> +}
> +
> +static void vmgenid_set_guid(Object *obj, const char *value, Error **errp)
> +{
> +    VmGenIdState *s = VMGENID(obj);
> +
> +    if (!strncmp(value, "auto", 4)) {
> +        qemu_uuid_generate(&s->guid);
> +    } else if (qemu_uuid_parse(value, &s->guid) < 0) {
> +        error_setg(errp, "'%s. %s': Failed to parse GUID string: %s",
> +                   object_get_typename(OBJECT(s)), VMGENID_GUID, value);
> +        return;
> +    }
> +    /* QemuUUID has the first three words as big-endian, and expect that any
> +     * GUIDs passed in will always be BE.  The guest, however will expect
> +     * the fields to be little-endian, so store that way internally.  Make
> +     * sure to swap back whenever reporting via monitor */
> +    qemu_uuid_bswap(&s->guid);
> +
> +    /* Send the ACPI notify */
> +    vmgenid_update_guest(s);
> +}
> +
> +/* After restoring an image, we need to update the guest memory and notify
> + * it of a potential change to VM Generation ID */
> +static int vmgenid_post_load(void *opaque, int version_id)
> +{
> +    VmGenIdState *s = opaque;
> +    vmgenid_update_guest(s);
> +    return 0;
> +}
> +
> +static const VMStateDescription vmstate_vmgenid = {
> +    .name = "vmgenid",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .post_load = vmgenid_post_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8_ARRAY(vgia_le, VmGenIdState, sizeof(uint32_t)),
file with address could be memory region and migrated automatically,
ex: rsdp_mr + acpi_add_rom_blob + acpi_ram_update

> +        VMSTATE_END_OF_LIST()
> +    },
> +};
> +
> +static void vmgenid_initfn(Object *obj)
> +{
> +    object_property_add_str(obj, VMGENID_GUID, NULL, vmgenid_set_guid, NULL);
> +}
> +
> +static void vmgenid_device_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->vmsd = &vmstate_vmgenid;
> +}
> +
> +static const TypeInfo vmgenid_device_info = {
> +    .name          = VMGENID_DEVICE,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(VmGenIdState),
> +    .instance_init = vmgenid_initfn,
> +    .class_init    = vmgenid_device_class_init,
> +};
> +
> +static void vmgenid_register_types(void)
> +{
> +    type_register_static(&vmgenid_device_info);
> +}
> +
> +type_init(vmgenid_register_types)
> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> index 78a1d84..4c40f76 100644
> --- a/hw/i386/acpi-build.c
> +++ b/hw/i386/acpi-build.c
> @@ -42,6 +42,7 @@
>  #include "hw/acpi/memory_hotplug.h"
>  #include "sysemu/tpm.h"
>  #include "hw/acpi/tpm.h"
> +#include "hw/acpi/vmgenid.h"
>  #include "sysemu/tpm_backend.h"
>  #include "hw/timer/mc146818rtc_regs.h"
>  #include "sysemu/numa.h"
> @@ -2653,6 +2654,11 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
>      acpi_add_table(table_offsets, tables_blob);
>      build_madt(tables_blob, tables->linker, pcms);
>  
> +    if (find_vmgenid_dev(NULL)) {
> +        acpi_add_table(table_offsets, tables_blob);
> +        vmgenid_build_acpi(tables_blob, tables->vmgenid, tables->linker);
pass find_vmgenid_dev(NULL) result as an argument to vmgenid_build_acpi()
so it won't have to do lookup again.

> +    }
> +
>      if (misc.has_hpet) {
>          acpi_add_table(table_offsets, tables_blob);
>          build_hpet(tables_blob, tables->linker);
> @@ -2859,6 +2865,10 @@ void acpi_setup(void)
>      fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
>                      tables.tcpalog->data, acpi_data_len(tables.tcpalog));
>  
> +    if (find_vmgenid_dev(NULL)) {
it's second lookup, cache result of the 1st call and reuse it here

> +        vmgenid_add_fw_cfg(pcms->fw_cfg, tables.vmgenid);
> +    }
> +
>      if (!pcmc->rsdp_in_ram) {
>          /*
>           * Keep for compatibility with old machine types.
> diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h
> index 71d3c48..3c2e4e9 100644
> --- a/include/hw/acpi/acpi_dev_interface.h
> +++ b/include/hw/acpi/acpi_dev_interface.h
> @@ -11,6 +11,7 @@ typedef enum {
>      ACPI_CPU_HOTPLUG_STATUS = 4,
>      ACPI_MEMORY_HOTPLUG_STATUS = 8,
>      ACPI_NVDIMM_HOTPLUG_STATUS = 16,
> +    ACPI_VMGENID_CHANGE_STATUS = 32,
>  } AcpiEventStatusBits;
>  
>  #define TYPE_ACPI_DEVICE_IF "acpi-device-interface"
> diff --git a/include/hw/acpi/vmgenid.h b/include/hw/acpi/vmgenid.h
> new file mode 100644
> index 0000000..b60437a
> --- /dev/null
> +++ b/include/hw/acpi/vmgenid.h
> @@ -0,0 +1,37 @@
> +#ifndef ACPI_VMGENID_H
> +#define ACPI_VMGENID_H
> +
> +#include "hw/acpi/bios-linker-loader.h"
> +#include "hw/sysbus.h"
> +#include "qemu/uuid.h"
> +
> +#define VMGENID_DEVICE           "vmgenid"
> +#define VMGENID_GUID             "guid"
> +#define VMGENID_GUID_FW_CFG_FILE      "etc/vmgenid"
> +#define VMGENID_ADDR_FW_CFG_FILE      "etc/vmgenid_addr"
> +
> +#define VMGENID_FW_CFG_SIZE      4096 /* Occupy a page of memory */
> +#define VMGENID_GUID_OFFSET      40   /* allow space for
> +                                       * OVMF SDT Header Probe Supressor */
> +
> +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid);
> +void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker *linker);
> +
> +#define VMGENID(obj) OBJECT_CHECK(VmGenIdState, (obj), VMGENID_DEVICE)
> +
> +typedef struct VmGenIdState {
> +    SysBusDevice parent_obj;
Could it work with just plain Device parent?
If it works then you can drop patch:
  [PATCH v5 08/10] PC: Support dynamic sysbus on pc_i440fx

> +    QemuUUID guid;
> +    uint8_t vgia_le[4];
> +} VmGenIdState;
> +
> +static Object *find_vmgenid_dev(Error **errp)
> +{
> +    Object *obj = object_resolve_path_type("", VMGENID_DEVICE, NULL);
> +    if (!obj && errp) {
all callers pass NULL as errp, I'd just drop errp altogether.

> +        error_setg(errp, "%s is not found", VMGENID_DEVICE);
> +    }
> +    return obj;
> +}
> +
> +#endif

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

* Re: [Qemu-devel] [PATCH v5 07/10] qmp/hmp: add set-vm-generation-id commands
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 07/10] qmp/hmp: add set-vm-generation-id commands ben
@ 2017-02-07 13:50   ` Igor Mammedov
  2017-02-08 22:01   ` Laszlo Ersek
  1 sibling, 0 replies; 70+ messages in thread
From: Igor Mammedov @ 2017-02-07 13:50 UTC (permalink / raw)
  To: ben; +Cc: qemu-devel, lersek, mst

On Sun,  5 Feb 2017 01:12:02 -0800
ben@skyportsystems.com wrote:

> From: Igor Mammedov <imammedo@redhat.com>
> 
> Add set-vm-generation-id command to set Virtual Machine
> Generation ID counter.
> 
> QMP command example:
>     { "execute": "set-vm-generation-id",
>           "arguments": {
>               "guid": "324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87"
>           }
>     }
> 
> HMP command example:
>     set-vm-generation-id guid=324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87
> 
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> Signed-off-by: Ben Warren <ben@skyportsystems.com>
> ---
>  hmp-commands.hx   | 13 +++++++++++++
>  hmp.c             | 12 ++++++++++++
>  hmp.h             |  1 +
>  hw/acpi/vmgenid.c | 12 ++++++++++++
>  qapi-schema.json  | 11 +++++++++++
>  stubs/vmgenid.c   |  6 ++++++
>  6 files changed, 55 insertions(+)
> 
> diff --git a/hmp-commands.hx b/hmp-commands.hx
> index 8819281..56744aa 100644
> --- a/hmp-commands.hx
> +++ b/hmp-commands.hx
> @@ -1775,5 +1775,18 @@ ETEXI
>      },
>  
>  STEXI
> +@item set-vm-generation-id @var{uuid}
> +Set Virtual Machine Generation ID counter to @var{guid}
> +ETEXI
> +
> +    {
> +        .name       = "set-vm-generation-id",
> +        .args_type  = "guid:s",
> +        .params     = "guid",
> +        .help       = "Set Virtual Machine Generation ID counter",
> +        .cmd = hmp_set_vm_generation_id,
> +    },
> +
> +STEXI
>  @end table
>  ETEXI
> diff --git a/hmp.c b/hmp.c
> index 535613d..39c8965 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -2574,3 +2574,15 @@ void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict)
>      }
>      qapi_free_GuidInfo(info);
>  }
> +
> +void hmp_set_vm_generation_id(Monitor *mon, const QDict *qdict)
> +{
> +    Error *errp = NULL;
> +    const char *guid = qdict_get_str(qdict, "guid");
> +
> +    qmp_set_vm_generation_id(guid, &errp);
> +    if (errp) {
> +        hmp_handle_error(mon, &errp);
> +        return;
> +    }
> +}
> diff --git a/hmp.h b/hmp.h
> index 799fd37..e0ac1e8 100644
> --- a/hmp.h
> +++ b/hmp.h
> @@ -138,5 +138,6 @@ void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict);
>  void hmp_info_dump(Monitor *mon, const QDict *qdict);
>  void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict);
>  void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict);
> +void hmp_set_vm_generation_id(Monitor *mon, const QDict *qdict);
>  
>  #endif
> diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
> index e148051..af8b35c 100644
> --- a/hw/acpi/vmgenid.c
> +++ b/hw/acpi/vmgenid.c
> @@ -224,3 +224,15 @@ GuidInfo *qmp_query_vm_generation_id(Error **errp)
>      info->guid = qemu_uuid_unparse_strdup(&guid);
>      return info;
>  }
> +
> +void qmp_set_vm_generation_id(const char *guid, Error **errp)
> +{
> +    Object *obj = find_vmgenid_dev(errp);
> +
> +    if (!obj) {
move error_set here from find_vmgenid_dev()

> +        return;
> +    }
> +
> +    object_property_set_str(obj, guid, VMGENID_GUID, errp);
> +    return;
> +}
> diff --git a/qapi-schema.json b/qapi-schema.json
> index 384a7f3..ed2657d 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -6051,3 +6051,14 @@
>  # Since 2.9
>  ##
>  { 'command': 'query-vm-generation-id', 'returns': 'GuidInfo' }
> +
> +##
> +# @set-vm-generation-id:
> +#
> +# Set Virtual Machine Generation ID
> +#
> +# @guid: new GUID to set as Virtual Machine Generation ID
> +#
> +# Since 2.9
> +##
> +{ 'command': 'set-vm-generation-id', 'data': {'guid': 'str'} }
> diff --git a/stubs/vmgenid.c b/stubs/vmgenid.c
> index 8c448ac..d25d41b 100644
> --- a/stubs/vmgenid.c
> +++ b/stubs/vmgenid.c
> @@ -6,3 +6,9 @@ GuidInfo *qmp_query_vm_generation_id(Error **errp)
>      error_setg(errp, "this command is not currently supported");
>      return NULL;
>  }
> +
> +void qmp_set_vm_generation_id(const char *guid, Error **errp)
> +{
> +    error_setg(errp, "this command is not currently supported");
> +    return;
> +}

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

* Re: [Qemu-devel] [PATCH v5 01/10] ACPI: Add a function for building named qword entries
  2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 01/10] ACPI: Add a function for building named qword entries ben
@ 2017-02-07 13:51   ` Igor Mammedov
  2017-02-07 20:09     ` Laszlo Ersek
  0 siblings, 1 reply; 70+ messages in thread
From: Igor Mammedov @ 2017-02-07 13:51 UTC (permalink / raw)
  To: ben; +Cc: qemu-devel, lersek, mst

On Sun,  5 Feb 2017 01:11:56 -0800
ben@skyportsystems.com wrote:

> From: Ben Warren <ben@skyportsystems.com>
> 
> This is initially used to patch a 64-bit address into
> the VM Generation ID SSDT
> 
> Signed-off-by: Ben Warren <ben@skyportsystems.com>
> ---
...
> +int
> +build_append_named_qword(GArray *array, const char *name_format, ...)
it ain't used anywhere, I'd just drop this patch.

> +{
> +    int offset;
> +    va_list ap;
> +
> +    build_append_byte(array, 0x08); /* NameOp */
> +    va_start(ap, name_format);
> +    build_append_namestringv(array, name_format, ap);
> +    va_end(ap);
> +
> +    build_append_byte(array, 0x0E); /* QWordPrefix */
> +
> +    offset = array->len;
> +    build_append_int_noprefix(array, 0x0000000000000000, 8);
> +    assert(array->len == offset + 8);
> +
> +    return offset;
> +}
> +
>  static GPtrArray *alloc_list;
>  
>  static Aml *aml_alloc(void)
> diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
> index 559326c..dbf63cf 100644
> --- a/include/hw/acpi/aml-build.h
> +++ b/include/hw/acpi/aml-build.h
> @@ -385,6 +385,10 @@ int
>  build_append_named_dword(GArray *array, const char *name_format, ...)
>  GCC_FMT_ATTR(2, 3);
>  
> +int
> +build_append_named_qword(GArray *array, const char *name_format, ...)
> +GCC_FMT_ATTR(2, 3);
> +
>  void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
>                         uint64_t len, int node, MemoryAffinityFlags flags);
>  

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-06 17:41       ` Michael S. Tsirkin
  2017-02-06 17:59         ` Ben Warren
@ 2017-02-07 14:00         ` Igor Mammedov
  2017-02-07 15:35           ` Michael S. Tsirkin
  1 sibling, 1 reply; 70+ messages in thread
From: Igor Mammedov @ 2017-02-07 14:00 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: Ben Warren, qemu-devel, lersek

On Mon, 6 Feb 2017 19:41:36 +0200
"Michael S. Tsirkin" <mst@redhat.com> wrote:

> On Mon, Feb 06, 2017 at 09:29:30AM -0800, Ben Warren wrote:
> > 
> >     On Feb 6, 2017, at 8:15 AM, Michael S. Tsirkin <mst@redhat.com> wrote:
> > 
> >     On Sun, Feb 05, 2017 at 01:12:00AM -0800, ben@skyportsystems.com wrote:
> > 
> >         From: Ben Warren <ben@skyportsystems.com>
> > 
> >         This implements the VM Generation ID feature by passing a 128-bit
> >         GUID to the guest via a fw_cfg blob.
> >         Any time the GUID changes, an ACPI notify event is sent to the guest
> > 
> >         The user interface is a simple device with one parameter:
> >         - guid (string, must be "auto" or in UUID format
> >           xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
> > 
> >         Signed-off-by: Ben Warren <ben@skyportsystems.com>
> > 
[...]

> > 
> > This variable name was suggested by Laszlo.  the ‘a’ in ‘vgia’ refers to
> > address, but I’ll add some comments.  
> 
> vmgenid_addr_le?
> 
> 
> >     How about we make it 8 byte so it's future proof?
> > 
> > I can do that, but a previous conversation we had made it clear that guests
> > would never allocate above 4GB so 64 bits wasn’t necessary.  
> 
> Right, it's just very painful to change once we make it 32 bit.
I'd keep it 32 bit since it's in variable in global AML context and our
table revision is 1, so per spec OSPM should handle it as 32 number.
Chances of guest survival on boot would depend on AML interpreter tolerance
to AML errors, which for windows usually is 0 and leads to non obvious BSOD.
If we leave DWORD, even XP will be able to boot fine and only report
unknown device.

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

* Re: [Qemu-devel] [PATCH v5 08/10] PC: Support dynamic sysbus on pc_i440fx
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 08/10] PC: Support dynamic sysbus on pc_i440fx ben
  2017-02-06 16:31   ` Michael S. Tsirkin
@ 2017-02-07 14:05   ` Igor Mammedov
  1 sibling, 0 replies; 70+ messages in thread
From: Igor Mammedov @ 2017-02-07 14:05 UTC (permalink / raw)
  To: ben; +Cc: qemu-devel, lersek, mst

On Sun,  5 Feb 2017 01:12:03 -0800
ben@skyportsystems.com wrote:

> From: Ben Warren <ben@skyportsystems.com>
> 
> This allows pc_i440fx-based machines to add new devices such as
> VM Generation ID directly to the sysbus.
> 
> Signed-off-by: Ben Warren <ben@skyportsystems.com>
> ---
>  hw/i386/pc_piix.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
> index 9f102aa..c8ad99c 100644
> --- a/hw/i386/pc_piix.c
> +++ b/hw/i386/pc_piix.c
> @@ -435,6 +435,7 @@ static void pc_i440fx_machine_options(MachineClass *m)
>      m->hot_add_cpu = pc_hot_add_cpu;
>      m->default_machine_opts = "firmware=bios-256k.bin";
>      m->default_display = "std";
> +    m->has_dynamic_sysbus = true;
>  }
>  
>  static void pc_i440fx_2_9_machine_options(MachineClass *m)
since vmgenid device doesn't need any external wiring by board
-device probably would also work if it's inherited from plain Device

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-07 14:00         ` Igor Mammedov
@ 2017-02-07 15:35           ` Michael S. Tsirkin
  2017-02-07 16:04             ` Igor Mammedov
  0 siblings, 1 reply; 70+ messages in thread
From: Michael S. Tsirkin @ 2017-02-07 15:35 UTC (permalink / raw)
  To: Igor Mammedov; +Cc: Ben Warren, qemu-devel, lersek

On Tue, Feb 07, 2017 at 03:00:32PM +0100, Igor Mammedov wrote:
> On Mon, 6 Feb 2017 19:41:36 +0200
> "Michael S. Tsirkin" <mst@redhat.com> wrote:
> 
> > On Mon, Feb 06, 2017 at 09:29:30AM -0800, Ben Warren wrote:
> > > 
> > >     On Feb 6, 2017, at 8:15 AM, Michael S. Tsirkin <mst@redhat.com> wrote:
> > > 
> > >     On Sun, Feb 05, 2017 at 01:12:00AM -0800, ben@skyportsystems.com wrote:
> > > 
> > >         From: Ben Warren <ben@skyportsystems.com>
> > > 
> > >         This implements the VM Generation ID feature by passing a 128-bit
> > >         GUID to the guest via a fw_cfg blob.
> > >         Any time the GUID changes, an ACPI notify event is sent to the guest
> > > 
> > >         The user interface is a simple device with one parameter:
> > >         - guid (string, must be "auto" or in UUID format
> > >           xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
> > > 
> > >         Signed-off-by: Ben Warren <ben@skyportsystems.com>
> > > 
> [...]
> 
> > > 
> > > This variable name was suggested by Laszlo.  the ‘a’ in ‘vgia’ refers to
> > > address, but I’ll add some comments.  
> > 
> > vmgenid_addr_le?
> > 
> > 
> > >     How about we make it 8 byte so it's future proof?
> > > 
> > > I can do that, but a previous conversation we had made it clear that guests
> > > would never allocate above 4GB so 64 bits wasn’t necessary.  
> > 
> > Right, it's just very painful to change once we make it 32 bit.
> I'd keep it 32 bit since it's in variable in global AML context and our
> table revision is 1, so per spec OSPM should handle it as 32 number.
> Chances of guest survival on boot would depend on AML interpreter tolerance
> to AML errors, which for windows usually is 0 and leads to non obvious BSOD.
> If we leave DWORD, even XP will be able to boot fine and only report
> unknown device.

AML reports 2 DWORDS per spec, no issue there. I guess it's exactly for
XP compatibility.

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-07 13:48   ` Igor Mammedov
@ 2017-02-07 15:36     ` Michael S. Tsirkin
  2017-02-08 20:19     ` Ben Warren
  1 sibling, 0 replies; 70+ messages in thread
From: Michael S. Tsirkin @ 2017-02-07 15:36 UTC (permalink / raw)
  To: Igor Mammedov; +Cc: ben, qemu-devel, lersek

On Tue, Feb 07, 2017 at 02:48:22PM +0100, Igor Mammedov wrote:
> On Sun,  5 Feb 2017 01:12:00 -0800
> ben@skyportsystems.com wrote:
> 
> > From: Ben Warren <ben@skyportsystems.com>
> > 
> > This implements the VM Generation ID feature by passing a 128-bit
> > GUID to the guest via a fw_cfg blob.
> > Any time the GUID changes, an ACPI notify event is sent to the guest
> > 
> > The user interface is a simple device with one parameter:
> >  - guid (string, must be "auto" or in UUID format
> >    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
> > 
> > Signed-off-by: Ben Warren <ben@skyportsystems.com>
> > ---
> >  default-configs/i386-softmmu.mak     |   1 +
> >  default-configs/x86_64-softmmu.mak   |   1 +
> >  hw/acpi/Makefile.objs                |   1 +
> >  hw/acpi/vmgenid.c                    | 206 +++++++++++++++++++++++++++++++++++
> >  hw/i386/acpi-build.c                 |  10 ++
> >  include/hw/acpi/acpi_dev_interface.h |   1 +
> >  include/hw/acpi/vmgenid.h            |  37 +++++++
> >  7 files changed, 257 insertions(+)
> >  create mode 100644 hw/acpi/vmgenid.c
> >  create mode 100644 include/hw/acpi/vmgenid.h
> > 
> > diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
> > index 384cefb..1a43542 100644
> > --- a/default-configs/i386-softmmu.mak
> > +++ b/default-configs/i386-softmmu.mak
> > @@ -58,3 +58,4 @@ CONFIG_I82801B11=y
> >  CONFIG_SMBIOS=y
> >  CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
> >  CONFIG_PXB=y
> > +CONFIG_ACPI_VMGENID=y
> > diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
> > index 491a191..aee8b08 100644
> > --- a/default-configs/x86_64-softmmu.mak
> > +++ b/default-configs/x86_64-softmmu.mak
> > @@ -58,3 +58,4 @@ CONFIG_I82801B11=y
> >  CONFIG_SMBIOS=y
> >  CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
> >  CONFIG_PXB=y
> > +CONFIG_ACPI_VMGENID=y
> > diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
> > index 6acf798..11c35bc 100644
> > --- a/hw/acpi/Makefile.objs
> > +++ b/hw/acpi/Makefile.objs
> > @@ -5,6 +5,7 @@ common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
> >  common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
> >  common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
> >  common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
> > +common-obj-$(CONFIG_ACPI_VMGENID) += vmgenid.o
> >  common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
> >  
> >  common-obj-y += acpi_interface.o
> > diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
> > new file mode 100644
> > index 0000000..6c9ecfd
> > --- /dev/null
> > +++ b/hw/acpi/vmgenid.c
> > @@ -0,0 +1,206 @@
> > +/*
> > + *  Virtual Machine Generation ID Device
> > + *
> > + *  Copyright (C) 2017 Skyport Systems.
> > + *
> > + *  Author: Ben Warren <ben@skyportsystems.com>
> > + *
> > + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> > + * See the COPYING file in the top-level directory.
> > + *
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qmp-commands.h"
> > +#include "hw/acpi/acpi.h"
> > +#include "hw/acpi/aml-build.h"
> > +#include "hw/acpi/vmgenid.h"
> > +#include "hw/nvram/fw_cfg.h"
> > +#include "sysemu/sysemu.h"
> > +
> > +void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker *linker)
> > +{
> > +    Object *obj;
> > +    VmGenIdState *s;
> > +    Aml *ssdt, *dev, *scope, *method, *addr, *if_ctx;
> > +    uint32_t vgia_offset;
> > +
> > +    obj = find_vmgenid_dev(NULL);
> get obj from caller
> 
> > +    assert(obj);
> > +    s = VMGENID(obj);
> > +
> > +    /* Fill in the GUID values */
> > +    if (guid->len != VMGENID_FW_CFG_SIZE) {
> > +        g_array_set_size(guid, VMGENID_FW_CFG_SIZE);
> does it have to be conditional?
> 
> > +    }
> > +    g_array_insert_vals(guid, VMGENID_GUID_OFFSET, s->guid.data, 16);
> > +
> > +    /* Put this in a separate SSDT table */
> > +    ssdt = init_aml_allocator();
> > +
> > +    /* Reserve space for header */
> > +    acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader));
> > +
> > +    /* Storage for the GUID address */
> > +    vgia_offset = table_data->len +
> > +        build_append_named_dword(ssdt->buf, "VGIA");
> > +    scope = aml_scope("\\_SB");
> > +    dev = aml_device("VGEN");
> > +    aml_append(dev, aml_name_decl("_HID", aml_string("QEMUVGID")));
> > +    aml_append(dev, aml_name_decl("_CID", aml_string("VM_Gen_Counter")));
> > +    aml_append(dev, aml_name_decl("_DDN", aml_string("VM_Gen_Counter")));
> > +
> > +    /* Simple status method to check that address is linked and non-zero */
> > +    method = aml_method("_STA", 0, AML_NOTSERIALIZED);
> > +    addr = aml_local(0);
> > +    aml_append(method, aml_store(aml_int(0xf), addr));
> > +    if_ctx = aml_if(aml_equal(aml_name("VGIA"), aml_int(0)));
> > +    aml_append(if_ctx, aml_store(aml_int(0), addr));
> > +    aml_append(method, if_ctx);
> > +    aml_append(method, aml_return(addr));
> > +    aml_append(dev, method);
> > +
> > +    /* the ADDR method returns two 32-bit words representing the lower and
> > +     * upper halves * of the physical address of the fw_cfg blob
> > +     * (holding the GUID) */
> > +    method = aml_method("ADDR", 0, AML_NOTSERIALIZED);
> > +
> > +    addr = aml_local(0);
> > +    aml_append(method, aml_store(aml_package(2), addr));
> > +
> > +    aml_append(method, aml_store(aml_add(aml_name("VGIA"),
> > +                                         aml_int(VMGENID_GUID_OFFSET), NULL),
> > +                                 aml_index(addr, aml_int(0))));
> > +    aml_append(method, aml_store(aml_int(0), aml_index(addr, aml_int(1))));
> I'd rather have "VGIA" patched wit address to GUID and not the blob start,
> see next comment about how.
> 
> Also usage aml_index() looks a bit confusing, how about:
> 
> pkg = aml_local(0)
> aml_store(aml_package(2), pkg)
> aml_append(pkg, aml_name("VGIA"))
> aml_append(pkg, aml_int(0))
> 
> > +    aml_append(method, aml_return(addr));
> > +
> > +    aml_append(dev, method);
> > +    aml_append(scope, dev);
> > +    aml_append(ssdt, scope);
> > +
> > +    /* attach an ACPI notify */
> > +    method = aml_method("\\_GPE._E05", 0, AML_NOTSERIALIZED);
> > +    aml_append(method, aml_notify(aml_name("\\_SB.VGEN"), aml_int(0x80)));
> > +    aml_append(ssdt, method);
> > +
> > +    g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len);
> > +
> > +    /* Allocate guest memory for the Data fw_cfg blob */
> > +    bios_linker_loader_alloc(linker, VMGENID_GUID_FW_CFG_FILE, guid, 4096,
> > +                             false /* page boundary, high memory */);
> does it guaranties that blob will be allocated in cacheable page?
> (SeaBIOS/OVMF)

Reserving it from guest. Pretty much, yes.

> > +
> > +    /* Patch address of GUID fw_cfg blob into the ADDR fw_cfg blob */
> > +    bios_linker_loader_add_pointer(linker,
> > +        VMGENID_ADDR_FW_CFG_FILE, 0, sizeof(uint32_t),
> > +        VMGENID_GUID_FW_CFG_FILE, 0, true);
> > +
> > +    /* Patch address of GUID fw_cfg blob into the AML */
> > +    bios_linker_loader_add_pointer(linker,
> > +        ACPI_BUILD_TABLE_FILE, vgia_offset, sizeof(uint32_t),
> > +        VMGENID_GUID_FW_CFG_FILE, 0, false);
> see @src_offset argument description,
> putting VMGENID_GUID_OFFSET would make patched place point directly to GUID
> 
> > +
> > +    build_header(linker, table_data,
> > +        (void *)(table_data->data + table_data->len - ssdt->buf->len),
> > +        "SSDT", ssdt->buf->len, 1, NULL, "VMGENID");
> > +    free_aml_allocator();
> > +}
> > +
> > +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid)
> > +{
> > +    Object *obj = find_vmgenid_dev(NULL);
> > +    assert(obj);
> > +    VmGenIdState *vms = VMGENID(obj);
> > +
> > +    /* Create a read-only fw_cfg file for GUID */
> > +    fw_cfg_add_file(s, VMGENID_GUID_FW_CFG_FILE, guid->data,
> > +                    VMGENID_FW_CFG_SIZE);
> > +    /* Create a read-write fw_cfg file for Address */
> > +    fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL, NULL,
> > +                             vms->vgia_le, sizeof(uint32_t), false);
> > +}
> > +
> > +static void vmgenid_update_guest(VmGenIdState *s)
> > +{
> > +    Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL);
> > +    uint32_t vgia;
> > +
> > +    if (obj) {
> > +        /* Write the GUID to guest memory */
> > +        memcpy(&vgia, s->vgia_le, sizeof(vgia));
> > +        vgia = le32_to_cpu(vgia);
> > +        if (vgia) {
> > +            cpu_physical_memory_write(vgia + VMGENID_GUID_OFFSET,
> > +                                      s->guid.data, sizeof(s->guid.data));
> > +            /* Send _GPE.E05 event */
> > +            acpi_send_event(DEVICE(obj), ACPI_VMGENID_CHANGE_STATUS);
> > +        }
> > +    }
> > +}
> > +
> > +static void vmgenid_set_guid(Object *obj, const char *value, Error **errp)
> > +{
> > +    VmGenIdState *s = VMGENID(obj);
> > +
> > +    if (!strncmp(value, "auto", 4)) {
> > +        qemu_uuid_generate(&s->guid);
> > +    } else if (qemu_uuid_parse(value, &s->guid) < 0) {
> > +        error_setg(errp, "'%s. %s': Failed to parse GUID string: %s",
> > +                   object_get_typename(OBJECT(s)), VMGENID_GUID, value);
> > +        return;
> > +    }
> > +    /* QemuUUID has the first three words as big-endian, and expect that any
> > +     * GUIDs passed in will always be BE.  The guest, however will expect
> > +     * the fields to be little-endian, so store that way internally.  Make
> > +     * sure to swap back whenever reporting via monitor */
> > +    qemu_uuid_bswap(&s->guid);
> > +
> > +    /* Send the ACPI notify */
> > +    vmgenid_update_guest(s);
> > +}
> > +
> > +/* After restoring an image, we need to update the guest memory and notify
> > + * it of a potential change to VM Generation ID */
> > +static int vmgenid_post_load(void *opaque, int version_id)
> > +{
> > +    VmGenIdState *s = opaque;
> > +    vmgenid_update_guest(s);
> > +    return 0;
> > +}
> > +
> > +static const VMStateDescription vmstate_vmgenid = {
> > +    .name = "vmgenid",
> > +    .version_id = 1,
> > +    .minimum_version_id = 1,
> > +    .post_load = vmgenid_post_load,
> > +    .fields = (VMStateField[]) {
> > +        VMSTATE_UINT8_ARRAY(vgia_le, VmGenIdState, sizeof(uint32_t)),
> file with address could be memory region and migrated automatically,
> ex: rsdp_mr + acpi_add_rom_blob + acpi_ram_update
> 
> > +        VMSTATE_END_OF_LIST()
> > +    },
> > +};
> > +
> > +static void vmgenid_initfn(Object *obj)
> > +{
> > +    object_property_add_str(obj, VMGENID_GUID, NULL, vmgenid_set_guid, NULL);
> > +}
> > +
> > +static void vmgenid_device_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +
> > +    dc->vmsd = &vmstate_vmgenid;
> > +}
> > +
> > +static const TypeInfo vmgenid_device_info = {
> > +    .name          = VMGENID_DEVICE,
> > +    .parent        = TYPE_SYS_BUS_DEVICE,
> > +    .instance_size = sizeof(VmGenIdState),
> > +    .instance_init = vmgenid_initfn,
> > +    .class_init    = vmgenid_device_class_init,
> > +};
> > +
> > +static void vmgenid_register_types(void)
> > +{
> > +    type_register_static(&vmgenid_device_info);
> > +}
> > +
> > +type_init(vmgenid_register_types)
> > diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> > index 78a1d84..4c40f76 100644
> > --- a/hw/i386/acpi-build.c
> > +++ b/hw/i386/acpi-build.c
> > @@ -42,6 +42,7 @@
> >  #include "hw/acpi/memory_hotplug.h"
> >  #include "sysemu/tpm.h"
> >  #include "hw/acpi/tpm.h"
> > +#include "hw/acpi/vmgenid.h"
> >  #include "sysemu/tpm_backend.h"
> >  #include "hw/timer/mc146818rtc_regs.h"
> >  #include "sysemu/numa.h"
> > @@ -2653,6 +2654,11 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
> >      acpi_add_table(table_offsets, tables_blob);
> >      build_madt(tables_blob, tables->linker, pcms);
> >  
> > +    if (find_vmgenid_dev(NULL)) {
> > +        acpi_add_table(table_offsets, tables_blob);
> > +        vmgenid_build_acpi(tables_blob, tables->vmgenid, tables->linker);
> pass find_vmgenid_dev(NULL) result as an argument to vmgenid_build_acpi()
> so it won't have to do lookup again.
> 
> > +    }
> > +
> >      if (misc.has_hpet) {
> >          acpi_add_table(table_offsets, tables_blob);
> >          build_hpet(tables_blob, tables->linker);
> > @@ -2859,6 +2865,10 @@ void acpi_setup(void)
> >      fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
> >                      tables.tcpalog->data, acpi_data_len(tables.tcpalog));
> >  
> > +    if (find_vmgenid_dev(NULL)) {
> it's second lookup, cache result of the 1st call and reuse it here
> 
> > +        vmgenid_add_fw_cfg(pcms->fw_cfg, tables.vmgenid);
> > +    }
> > +
> >      if (!pcmc->rsdp_in_ram) {
> >          /*
> >           * Keep for compatibility with old machine types.
> > diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h
> > index 71d3c48..3c2e4e9 100644
> > --- a/include/hw/acpi/acpi_dev_interface.h
> > +++ b/include/hw/acpi/acpi_dev_interface.h
> > @@ -11,6 +11,7 @@ typedef enum {
> >      ACPI_CPU_HOTPLUG_STATUS = 4,
> >      ACPI_MEMORY_HOTPLUG_STATUS = 8,
> >      ACPI_NVDIMM_HOTPLUG_STATUS = 16,
> > +    ACPI_VMGENID_CHANGE_STATUS = 32,
> >  } AcpiEventStatusBits;
> >  
> >  #define TYPE_ACPI_DEVICE_IF "acpi-device-interface"
> > diff --git a/include/hw/acpi/vmgenid.h b/include/hw/acpi/vmgenid.h
> > new file mode 100644
> > index 0000000..b60437a
> > --- /dev/null
> > +++ b/include/hw/acpi/vmgenid.h
> > @@ -0,0 +1,37 @@
> > +#ifndef ACPI_VMGENID_H
> > +#define ACPI_VMGENID_H
> > +
> > +#include "hw/acpi/bios-linker-loader.h"
> > +#include "hw/sysbus.h"
> > +#include "qemu/uuid.h"
> > +
> > +#define VMGENID_DEVICE           "vmgenid"
> > +#define VMGENID_GUID             "guid"
> > +#define VMGENID_GUID_FW_CFG_FILE      "etc/vmgenid"
> > +#define VMGENID_ADDR_FW_CFG_FILE      "etc/vmgenid_addr"
> > +
> > +#define VMGENID_FW_CFG_SIZE      4096 /* Occupy a page of memory */
> > +#define VMGENID_GUID_OFFSET      40   /* allow space for
> > +                                       * OVMF SDT Header Probe Supressor */
> > +
> > +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid);
> > +void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker *linker);
> > +
> > +#define VMGENID(obj) OBJECT_CHECK(VmGenIdState, (obj), VMGENID_DEVICE)
> > +
> > +typedef struct VmGenIdState {
> > +    SysBusDevice parent_obj;
> Could it work with just plain Device parent?
> If it works then you can drop patch:
>   [PATCH v5 08/10] PC: Support dynamic sysbus on pc_i440fx
> 
> > +    QemuUUID guid;
> > +    uint8_t vgia_le[4];
> > +} VmGenIdState;
> > +
> > +static Object *find_vmgenid_dev(Error **errp)
> > +{
> > +    Object *obj = object_resolve_path_type("", VMGENID_DEVICE, NULL);
> > +    if (!obj && errp) {
> all callers pass NULL as errp, I'd just drop errp altogether.
> 
> > +        error_setg(errp, "%s is not found", VMGENID_DEVICE);
> > +    }
> > +    return obj;
> > +}
> > +
> > +#endif

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-07 15:35           ` Michael S. Tsirkin
@ 2017-02-07 16:04             ` Igor Mammedov
  2017-02-07 16:22               ` Michael S. Tsirkin
  0 siblings, 1 reply; 70+ messages in thread
From: Igor Mammedov @ 2017-02-07 16:04 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: Ben Warren, qemu-devel, lersek

On Tue, 7 Feb 2017 17:35:19 +0200
"Michael S. Tsirkin" <mst@redhat.com> wrote:

> On Tue, Feb 07, 2017 at 03:00:32PM +0100, Igor Mammedov wrote:
> > On Mon, 6 Feb 2017 19:41:36 +0200
> > "Michael S. Tsirkin" <mst@redhat.com> wrote:
> > 
> > > On Mon, Feb 06, 2017 at 09:29:30AM -0800, Ben Warren wrote:
> > > > 
> > > >     On Feb 6, 2017, at 8:15 AM, Michael S. Tsirkin <mst@redhat.com> wrote:
> > > > 
> > > >     On Sun, Feb 05, 2017 at 01:12:00AM -0800, ben@skyportsystems.com wrote:
> > > > 
> > > >         From: Ben Warren <ben@skyportsystems.com>
> > > > 
> > > >         This implements the VM Generation ID feature by passing a 128-bit
> > > >         GUID to the guest via a fw_cfg blob.
> > > >         Any time the GUID changes, an ACPI notify event is sent to the guest
> > > > 
> > > >         The user interface is a simple device with one parameter:
> > > >         - guid (string, must be "auto" or in UUID format
> > > >           xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
> > > > 
> > > >         Signed-off-by: Ben Warren <ben@skyportsystems.com>
> > > > 
> > [...]
> > 
> > > > 
> > > > This variable name was suggested by Laszlo.  the ‘a’ in ‘vgia’ refers to
> > > > address, but I’ll add some comments.  
> > > 
> > > vmgenid_addr_le?
> > > 
> > > 
> > > >     How about we make it 8 byte so it's future proof?
> > > > 
> > > > I can do that, but a previous conversation we had made it clear that guests
> > > > would never allocate above 4GB so 64 bits wasn’t necessary.  
> > > 
> > > Right, it's just very painful to change once we make it 32 bit.
> > I'd keep it 32 bit since it's in variable in global AML context and our
> > table revision is 1, so per spec OSPM should handle it as 32 number.
> > Chances of guest survival on boot would depend on AML interpreter tolerance
> > to AML errors, which for windows usually is 0 and leads to non obvious BSOD.
> > If we leave DWORD, even XP will be able to boot fine and only report
> > unknown device.
> 
> AML reports 2 DWORDS per spec, no issue there. I guess it's exactly for
> XP compatibility. 
 
it's only ADDR method thought but we are talking about
Named DWORD vs QWORD VGIA variable which is patched by linker command 
 

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-07 16:04             ` Igor Mammedov
@ 2017-02-07 16:22               ` Michael S. Tsirkin
  0 siblings, 0 replies; 70+ messages in thread
From: Michael S. Tsirkin @ 2017-02-07 16:22 UTC (permalink / raw)
  To: Igor Mammedov; +Cc: Ben Warren, qemu-devel, lersek

On Tue, Feb 07, 2017 at 05:04:56PM +0100, Igor Mammedov wrote:
> On Tue, 7 Feb 2017 17:35:19 +0200
> "Michael S. Tsirkin" <mst@redhat.com> wrote:
> 
> > On Tue, Feb 07, 2017 at 03:00:32PM +0100, Igor Mammedov wrote:
> > > On Mon, 6 Feb 2017 19:41:36 +0200
> > > "Michael S. Tsirkin" <mst@redhat.com> wrote:
> > > 
> > > > On Mon, Feb 06, 2017 at 09:29:30AM -0800, Ben Warren wrote:
> > > > > 
> > > > >     On Feb 6, 2017, at 8:15 AM, Michael S. Tsirkin <mst@redhat.com> wrote:
> > > > > 
> > > > >     On Sun, Feb 05, 2017 at 01:12:00AM -0800, ben@skyportsystems.com wrote:
> > > > > 
> > > > >         From: Ben Warren <ben@skyportsystems.com>
> > > > > 
> > > > >         This implements the VM Generation ID feature by passing a 128-bit
> > > > >         GUID to the guest via a fw_cfg blob.
> > > > >         Any time the GUID changes, an ACPI notify event is sent to the guest
> > > > > 
> > > > >         The user interface is a simple device with one parameter:
> > > > >         - guid (string, must be "auto" or in UUID format
> > > > >           xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
> > > > > 
> > > > >         Signed-off-by: Ben Warren <ben@skyportsystems.com>
> > > > > 
> > > [...]
> > > 
> > > > > 
> > > > > This variable name was suggested by Laszlo.  the ‘a’ in ‘vgia’ refers to
> > > > > address, but I’ll add some comments.  
> > > > 
> > > > vmgenid_addr_le?
> > > > 
> > > > 
> > > > >     How about we make it 8 byte so it's future proof?
> > > > > 
> > > > > I can do that, but a previous conversation we had made it clear that guests
> > > > > would never allocate above 4GB so 64 bits wasn’t necessary.  
> > > > 
> > > > Right, it's just very painful to change once we make it 32 bit.
> > > I'd keep it 32 bit since it's in variable in global AML context and our
> > > table revision is 1, so per spec OSPM should handle it as 32 number.
> > > Chances of guest survival on boot would depend on AML interpreter tolerance
> > > to AML errors, which for windows usually is 0 and leads to non obvious BSOD.
> > > If we leave DWORD, even XP will be able to boot fine and only report
> > > unknown device.
> > 
> > AML reports 2 DWORDS per spec, no issue there. I guess it's exactly for
> > XP compatibility. 
>  
> it's only ADDR method thought but we are talking about
> Named DWORD vs QWORD VGIA variable which is patched by linker command 

Oh sorry. Yes, you want to keep that one a DWORD. Does not affect
the interface. So write 64 bits into fw cfg, but patch 32 bits
into AML.

-- 
MST

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

* Re: [Qemu-devel] [PATCH v5 01/10] ACPI: Add a function for building named qword entries
  2017-02-07 13:51   ` Igor Mammedov
@ 2017-02-07 20:09     ` Laszlo Ersek
  2017-02-08 10:43       ` Igor Mammedov
  0 siblings, 1 reply; 70+ messages in thread
From: Laszlo Ersek @ 2017-02-07 20:09 UTC (permalink / raw)
  To: Igor Mammedov; +Cc: ben, qemu-devel, mst

On 02/07/17 14:51, Igor Mammedov wrote:
> On Sun,  5 Feb 2017 01:11:56 -0800
> ben@skyportsystems.com wrote:
> 
>> From: Ben Warren <ben@skyportsystems.com>
>>
>> This is initially used to patch a 64-bit address into
>> the VM Generation ID SSDT
>>
>> Signed-off-by: Ben Warren <ben@skyportsystems.com>
>> ---
> ...
>> +int
>> +build_append_named_qword(GArray *array, const char *name_format, ...)
> it ain't used anywhere, I'd just drop this patch.

Ben and I discussed this under
- msgid <6E25852D-224A-4BDC-AA83-8DC87DB4D0F0@skyportsystems.com>
  https://www.mail-archive.com/qemu-devel@nongnu.org/msg425496.html
- msgid <a93a6be3-cbed-5afe-7c72-96410fbfce41@redhat.com>
  https://www.mail-archive.com/qemu-devel@nongnu.org/msg425519.html

On 01/26/17 06:35, Ben Warren wrote:
> I propose to still include this patch but touch up the comments as
> requested by Laszlo.  This way it will be in the toolbox for future
> users and has been tested.  [...]

I generally agree that dead code is undesirable, but this function has
surfaced several times until now, and we get to review it every single
time. Ben tested it, I support its inclusion.

OTOH I also pointed it out to Ben

https://www.mail-archive.com/qemu-devel@nongnu.org/msg425218.html

that he should expect disagreement between his reviewers :) Given that
I'm observing this series more from the sidelines and you maintain /
support ACPI gen in QEMU, I certainly defer to you on this.

Thanks
Laszlo


>> +{
>> +    int offset;
>> +    va_list ap;
>> +
>> +    build_append_byte(array, 0x08); /* NameOp */
>> +    va_start(ap, name_format);
>> +    build_append_namestringv(array, name_format, ap);
>> +    va_end(ap);
>> +
>> +    build_append_byte(array, 0x0E); /* QWordPrefix */
>> +
>> +    offset = array->len;
>> +    build_append_int_noprefix(array, 0x0000000000000000, 8);
>> +    assert(array->len == offset + 8);
>> +
>> +    return offset;
>> +}
>> +
>>  static GPtrArray *alloc_list;
>>  
>>  static Aml *aml_alloc(void)
>> diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
>> index 559326c..dbf63cf 100644
>> --- a/include/hw/acpi/aml-build.h
>> +++ b/include/hw/acpi/aml-build.h
>> @@ -385,6 +385,10 @@ int
>>  build_append_named_dword(GArray *array, const char *name_format, ...)
>>  GCC_FMT_ATTR(2, 3);
>>  
>> +int
>> +build_append_named_qword(GArray *array, const char *name_format, ...)
>> +GCC_FMT_ATTR(2, 3);
>> +
>>  void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
>>                         uint64_t len, int node, MemoryAffinityFlags flags);
>>  
> 
> 

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

* Re: [Qemu-devel] [PATCH v5 02/10] linker-loader: Add new 'write pointer' command
  2017-02-07 12:11         ` Igor Mammedov
@ 2017-02-07 20:20           ` Laszlo Ersek
  0 siblings, 0 replies; 70+ messages in thread
From: Laszlo Ersek @ 2017-02-07 20:20 UTC (permalink / raw)
  To: Igor Mammedov, Michael S. Tsirkin; +Cc: qemu-devel, Ben Warren

On 02/07/17 13:11, Igor Mammedov wrote:
> On Mon, 6 Feb 2017 19:31:24 +0200
> "Michael S. Tsirkin" <mst@redhat.com> wrote:
> 
>> On Mon, Feb 06, 2017 at 09:16:25AM -0800, Ben Warren wrote:
>>>>> @@ -257,8 +263,11 @@ void bios_linker_loader_add_pointer(BIOSLinker *linker,
>>>>>     const BiosLinkerFileEntry *source_file =
>>>>>         bios_linker_find_file(linker, src_file);
>>>>>
>>>>> -    assert(dst_patched_offset < dst_file->blob->len);
>>>>> -    assert(dst_patched_offset + dst_patched_size <= dst_file->blob->len);
>>>>> +    /* dst_file need not exist if writing back */  
>>>>
>>>> Why not?  
>>> Because WRITE_POINTER can be called without having first called
>>> ALLOCATE.  In the Vm Generation ID example, there’s no reason for BIOS
>>> to allocate memory for the address fw_cfg, since it’s a construct that
>>> only matters to QEMU.  This is something that was requested by Laszlo.  
>>
>> Well all other commands require you to first allocate.
>> How does bios know e.g. which zone to put it in then?
> There is no need to know which zone to put it in as file
> is writeback only, i.e. there is no need to allocate
> RAM for file (shadow it) which won't be read by guest side ever
> if I got idea right.
> Issue in the patch is combining new command with existing API
> bios_linker_loader_add_pointer(),
> as you suggested new API function + good description what it does
> would be better than reusing.

Agreed on all points (and sorry about the delayed response):

- The writeable fw_cfg file that receives the address from the guest
firmware need not and should not be downloaded by the guest firmware,
into guest memory. Such a blob, in guest memory, is entirely useless to
the guest.

- I also strongly prefer a separate command structure, and function
name, for the new command. (The structure can be shared by a typedef or
another sub-structure, but it should have its own separate struct tag /
type name.)

Thanks!
Laszlo

> 
> 
>>
>> I don't like the asymmetry ... Laszlo? 
> 
> 

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

* Re: [Qemu-devel] [PATCH v5 03/10] docs: VM Generation ID device description
  2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 03/10] docs: VM Generation ID device description ben
  2017-02-06 20:18   ` Eric Blake
@ 2017-02-07 20:54   ` Laszlo Ersek
  2017-02-10  0:55   ` Laszlo Ersek
  2 siblings, 0 replies; 70+ messages in thread
From: Laszlo Ersek @ 2017-02-07 20:54 UTC (permalink / raw)
  To: ben, qemu-devel; +Cc: Gal Hammer, imammedo, mst

On 02/05/17 10:11, ben@skyportsystems.com wrote:
> From: Ben Warren <ben@skyportsystems.com>
> 
> This patch is based off an earlier version by
> Gal Hammer (ghammer@redhat.com)
> 
> Requirements section, ASCII diagrams and overall help
> provided by Laszlo Ersek (lersek@redhat.com)
> 
> Signed-off-by: Gal Hammer <ghammer@redhat.com>
> Signed-off-by: Ben Warren <ben@skyportsystems.com>
> ---
>  docs/specs/vmgenid.txt | 239 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 239 insertions(+)
>  create mode 100644 docs/specs/vmgenid.txt
> 
> diff --git a/docs/specs/vmgenid.txt b/docs/specs/vmgenid.txt
> new file mode 100644
> index 0000000..d36f8bd
> --- /dev/null
> +++ b/docs/specs/vmgenid.txt
> @@ -0,0 +1,239 @@
> +VIRTUAL MACHINE GENERATION ID
> +=============================
> +
> +Copyright (C) 2016 Red Hat, Inc.
> +Copyright (C) 2017 Skyport Systems, Inc.
> +
> +This work is licensed under the terms of the GNU GPL, version 2 or later.
> +See the COPYING file in the top-level directory.
> +
> +===
> +
> +The VM generation ID (vmgenid) device is an emulated device which
> +exposes a 128-bit, cryptographically random, integer value identifier,
> +referred to as a Globally Unique Identifier, or GUID.
> +
> +This allows management applications (e.g. libvirt) to notify the guest
> +operating system when the virtual machine is executed with a different
> +configuration (e.g. snapshot execution or creation from a template).  The
> +guest operating system notices the change, and is then able to react as
> +appropriate by marking its copies of distributed databases as dirty,
> +re-initializing its random number generator etc.
> +
> +
> +Requirements
> +------------
> +
> +These requirements are extracted from the "How to implement virtual machine
> +generation ID support in a virtualization platform" section of the
> +specification, dated August 1, 2012.
> +
> +
> +The document may be found on the web at:
> +  http://go.microsoft.com/fwlink/?LinkId=260709
> +
> +R1a. The generation ID shall live in an 8-byte aligned buffer.
> +
> +R1b. The buffer holding the generation ID shall be in guest RAM, ROM, or device
> +     MMIO range.
> +
> +R1c. The buffer holding the generation ID shall be kept separate from areas
> +     used by the operating system.
> +
> +R1d. The buffer shall not be covered by an AddressRangeMemory or
> +     AddressRangeACPI entry in the E820 or UEFI memory map.
> +
> +R1e. The generation ID shall not live in a page frame that could be mapped with
> +     caching disabled. (In other words, regardless of whether the generation ID
> +     lives in RAM, ROM or MMIO, it shall only be mapped as cacheable.)
> +
> +R2 to R5. [These AML requirements are isolated well enough in the Microsoft
> +          specification for us to simply refer to them here.]
> +
> +R6. The hypervisor shall expose a _HID (hardware identifier) object in the
> +    VMGenId device's scope that is unique to the hypervisor vendor.
> +
> +
> +QEMU Implementation
> +-------------------
> +
> +The above-mentioned specification does not dictate which ACPI descriptor table
> +will contain the VM Generation ID device.  Other implementations (Hyper-V and
> +Xen) put it in the main descriptor table (Differentiated System Description
> +Table or DSDT).  For ease of debugging and implementation, we have decided to
> +put it in its own Secondary System Description Table, or SSDT.
> +
> +The following is a dump of the contents from a running system:
> +
> +# iasl -p ./SSDT -d /sys/firmware/acpi/tables/SSDT
> +
> +Intel ACPI Component Architecture
> +ASL+ Optimizing Compiler version 20150717-64
> +Copyright (c) 2000 - 2015 Intel Corporation
> +
> +Reading ACPI table from file /sys/firmware/acpi/tables/SSDT - Length
> +00000198 (0x0000C6)
> +ACPI: SSDT 0x0000000000000000 0000C6 (v01 BOCHS  VMGENID  00000001 BXPC
> +00000001)
> +Acpi table [SSDT] successfully installed and loaded
> +Pass 1 parse of [SSDT]
> +Pass 2 parse of [SSDT]
> +Parsing Deferred Opcodes (Methods/Buffers/Packages/Regions)
> +
> +Parsing completed
> +Disassembly completed
> +ASL Output:    ./SSDT.dsl - 1631 bytes
> +# cat SSDT.dsl
> +/*
> + * Intel ACPI Component Architecture
> + * AML/ASL+ Disassembler version 20150717-64
> + * Copyright (c) 2000 - 2015 Intel Corporation
> + *
> + * Disassembling to symbolic ASL+ operators
> + *
> + * Disassembly of /sys/firmware/acpi/tables/SSDT, Sun Feb  5 00:19:37 2017
> + *
> + * Original Table Header:
> + *     Signature        "SSDT"
> + *     Length           0x000000CA (202)
> + *     Revision         0x01
> + *     Checksum         0x4B
> + *     OEM ID           "BOCHS "
> + *     OEM Table ID     "VMGENID"
> + *     OEM Revision     0x00000001 (1)
> + *     Compiler ID      "BXPC"
> + *     Compiler Version 0x00000001 (1)
> + */
> +DefinitionBlock ("/sys/firmware/acpi/tables/SSDT.aml", "SSDT", 1, "BOCHS ",
> +"VMGENID", 0x00000001)
> +{
> +    Name (VGIA, 0x07FFF000)
> +    Scope (\_SB)
> +    {
> +        Device (VGEN)
> +        {
> +            Name (_HID, "QEMUVGID")  // _HID: Hardware ID
> +            Name (_CID, "VM_Gen_Counter")  // _CID: Compatible ID
> +            Name (_DDN, "VM_Gen_Counter")  // _DDN: DOS Device Name
> +            Method (_STA, 0, NotSerialized)  // _STA: Status
> +            {
> +                Local0 = 0x0F
> +                If ((VGIA == Zero))
> +                {
> +                    Local0 = Zero
> +                }
> +
> +                Return (Local0)
> +            }
> +
> +            Method (ADDR, 0, NotSerialized)
> +            {
> +                Local0 = Package (0x02) {}
> +                Index (Local0, Zero) = (VGIA + 0x28)
> +                Index (Local0, One) = Zero
> +                Return (Local0)
> +            }
> +        }
> +    }
> +
> +    Method (\_GPE._E05, 0, NotSerialized)  // _Exx: Edge-Triggered GPE
> +    {
> +        Notify (\_SB.VGEN, 0x80) // Status Change
> +    }
> +}
> +
> +
> +Design Details:
> +---------------
> +
> +Requirements R1a through R1e dicate that the memory holding the
> +VM Generation ID must be allocated and owned by the guest operating system,

s/guest operating system/guest firmware/, in my opinion. Do you agree?

> +in this case BIOS or UEFI.  However, to be useful, QEMU must be able to
> +change the contents of the memory at runtime, specifically when starting a
> +backed-up or snapshotted image.  In order to do this, QEMU must know the
> +address that has been allocated.
> +
> +The mechanism chosen for this memory sharing is writeable fw_cfg blobs.
> +These are in-memory data structures that are visible to both QEMU and guests,
> +and are addressable as files.

The expression "in-memory data structures" is misleading; they need not
exist in complete (or any) form in guest RAM.

I recommend "data objects" instead (and maybe reference
"docs/specs/fw_cfg.txt").

Also, "addressable as files" is too generic, we don't have random
access. I'd say "addressable as sequential files" (we have rewind (by
way of select), skip, read, and write).

> +
> +Two fw_cfg blobs are used in this case:
> +
> +/etc/vmgenid      - contains the actual VM Generation ID GUID
> +                  - read-only to the guest
> +/etc/vmgenid_addr - contains the address of the GUID

Please replace "address of the GUID" with "address of the downloaded
vmgenid blob".

> +                  - writeable by the guest
> +
> +
> +QEMU sends the following commands to the guest at startup:
> +
> +1. Allocate memory for vmgenid fw_cfg blob.
> +2. Write the address of vmgenid into the SSDT (VGIA ACPI variable as
> +   shown above in the iasl dump).  Note that this change is not propagated
> +   back to QEMU.
> +3. Write the address of vmgenid back to QEMU's copy of vmgenid_addr
> +   via the fw_cfg DMA interface.

Please drop "QEMU's copy of".

(All fw_cfg blobs are owned by QEMU, and for some of those, it makes
sense for the firmware to have a copy. In this case, the firmware has no
copy, and QEMU's "copy" is the original thing.)

> +
> +After step 3, QEMU is able to update the contents of vmgenid at will.
> +
> +Since BIOS or UEFI does not necessarily run when we wish to change the GUID,
> +the value of VGIA is persisted via the VMState mechanism.
> +
> +As spelled out in the specification, any change to the GUID executes an
> +ACPI notification.  The exact handler to use is not specified, so the vmgenid
> +device uses the first unused one:  \_GPE._E05.
> +
> +
> +Endian-ness Considerations:
> +---------------------------
> +
> +Although not specified in Microsoft's document, it is assumed that the
> +device is expected to use little-endian format.
> +
> +All GUID passed in via command line or monitor are treated as big-endian.
> +GUID values displayed via monitor are shown in big-endian format.
> +
> +
> +GUID Storage Format:
> +--------------------
> +
> +In order to work with OVMF "SDT Header Probe Supressor", the contents of

s/work with/implement an/

> +the vmgenid fw_cfg blob are not simply a 128-bit GUID.  There is also
> +significant padding in order to align and fill a memory page, as shown in the
> +following diagram:
> +
> ++----------------------------------+
> +| SSDT with OEM Table ID = VMGENID |
> ++----------------------------------+
> +| ...                              |       TOP OF PAGE
> +| VGIA dword object ---------------|-----> +---------------------------+
> +| ...                              |       | fw-allocated array for    |
> +| _STA method referring to VGIA    |       | "etc/vmgenid"        |
> +| ...                              |       +---------------------------+
> +| ADDR method referring to VGIA    |       |  0: OVMF SDT Header probe |
> +| ...                              |       |     suppressor            |
> ++----------------------------------+       | 36: padding for 8-byte    |
> +                                           |     alignment             |
> +                                           | 40: GUID                  |
> +                                           | 56: padding to page size  |
> +                                           +---------------------------+
> +                                           END OF PAGE

Hahaha, Laszlo cannot multiply. In my previous review I wrote "48" as
start offset for "padding to page size", which implies an 8-byte
(64-bit) GUID... In fact the GUID takes 128 bits, hence 16 bytes. Good
catch! :)

> +
> +
> +Device Usage:
> +-------------
> +
> +The device has one property, which can be set using the command line
> +argument or the QMP interface:
> +
> + guid - sets the value of the GUID.  A special value "auto" instructs
> +        QEMU to generate a new random GUID.
> +
> +For example:
> +
> + QEMU  -device vmgenid,guid="324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87"
> +
> +Or to change guid in runtime use:
> +
> + set-vm-generation-id guid=124e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87
> + set-vm-generation-id guid=auto
> 

I like this version very much. Please fix up the warts identified by
Eric and myself, and then you can add my

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

for the next version.

(If you change other parts as well, then please don't add my R-b.)

Thank you!
Laszlo

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

* Re: [Qemu-devel] [PATCH v5 04/10] ACPI: Add vmgenid storage entries to the build tables
  2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 04/10] ACPI: Add vmgenid storage entries to the build tables ben
@ 2017-02-07 22:06   ` Laszlo Ersek
  0 siblings, 0 replies; 70+ messages in thread
From: Laszlo Ersek @ 2017-02-07 22:06 UTC (permalink / raw)
  To: ben, qemu-devel; +Cc: imammedo, mst

On 02/05/17 10:11, ben@skyportsystems.com wrote:
> From: Ben Warren <ben@skyportsystems.com>
> 
> This allows them to be centrally initialized and destroyed
> 
> Signed-off-by: Ben Warren <ben@skyportsystems.com>
> ---
>  hw/acpi/aml-build.c         | 2 ++
>  include/hw/acpi/aml-build.h | 1 +
>  2 files changed, 3 insertions(+)

Please replace "storage entries" in the subject line with "blob
storage", and add the following to the commit message:

----
The "AcpiBuildTables.vmgenid" array will be used to construct the
"etc/vmgenid" fw_cfg blob.

Its contents will be linked into fw_cfg after being built on the
pc_machine_done() -> acpi_setup() -> acpi_build() call path, and dropped
without use on the subsequent, guest triggered, acpi_build_update() ->
acpi_build() call path.
----

... This commit message update actually exposes an important flaw in the
implementation (one that entirely escaped me in the previous round!!!),
but as I've now read forward a little bit, into patch 5, I see that
Michael caught it, which is awesome!

So, with the new fw-cfg callback (on which I'll comment under the next
patch), and with the above commit message / subject updates, please add:

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks!
Laszlo

> 
> diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
> index 03b6c6c..0f39eaf 100644
> --- a/hw/acpi/aml-build.c
> +++ b/hw/acpi/aml-build.c
> @@ -1594,6 +1594,7 @@ void acpi_build_tables_init(AcpiBuildTables *tables)
>      tables->rsdp = g_array_new(false, true /* clear */, 1);
>      tables->table_data = g_array_new(false, true /* clear */, 1);
>      tables->tcpalog = g_array_new(false, true /* clear */, 1);
> +    tables->vmgenid = g_array_new(false, true /* clear */, 1);
>      tables->linker = bios_linker_loader_init();
>  }
>  
> @@ -1603,6 +1604,7 @@ void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
>      g_array_free(tables->rsdp, true);
>      g_array_free(tables->table_data, true);
>      g_array_free(tables->tcpalog, mfre);
> +    g_array_free(tables->vmgenid, mfre);
>  }
>  
>  /* Build rsdt table */
> diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
> index dbf63cf..6f4e239 100644
> --- a/include/hw/acpi/aml-build.h
> +++ b/include/hw/acpi/aml-build.h
> @@ -210,6 +210,7 @@ struct AcpiBuildTables {
>      GArray *table_data;
>      GArray *rsdp;
>      GArray *tcpalog;
> +    GArray *vmgenid;
>      BIOSLinker *linker;
>  } AcpiBuildTables;
>  
> 

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support ben
  2017-02-06 16:15   ` Michael S. Tsirkin
  2017-02-07 13:48   ` Igor Mammedov
@ 2017-02-08  0:48   ` Laszlo Ersek
  2017-02-08 11:04     ` Igor Mammedov
                       ` (2 more replies)
  2017-02-09  0:37   ` Laszlo Ersek
  3 siblings, 3 replies; 70+ messages in thread
From: Laszlo Ersek @ 2017-02-08  0:48 UTC (permalink / raw)
  To: ben, imammedo, mst; +Cc: qemu-devel

On 02/05/17 10:12, ben@skyportsystems.com wrote:
> From: Ben Warren <ben@skyportsystems.com>
> 
> This implements the VM Generation ID feature by passing a 128-bit
> GUID to the guest via a fw_cfg blob.
> Any time the GUID changes, an ACPI notify event is sent to the guest
> 
> The user interface is a simple device with one parameter:
>  - guid (string, must be "auto" or in UUID format
>    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
> 
> Signed-off-by: Ben Warren <ben@skyportsystems.com>
> ---
>  default-configs/i386-softmmu.mak     |   1 +
>  default-configs/x86_64-softmmu.mak   |   1 +
>  hw/acpi/Makefile.objs                |   1 +
>  hw/acpi/vmgenid.c                    | 206 +++++++++++++++++++++++++++++++++++
>  hw/i386/acpi-build.c                 |  10 ++
>  include/hw/acpi/acpi_dev_interface.h |   1 +
>  include/hw/acpi/vmgenid.h            |  37 +++++++
>  7 files changed, 257 insertions(+)
>  create mode 100644 hw/acpi/vmgenid.c
>  create mode 100644 include/hw/acpi/vmgenid.h

[snip code]

So, I'm late to the game. I can't possibly comment on all the concerns
that have been raised scattered around the thread, exactly *where* they
have been raised. However, I will try to collect the concerns here.


(1) Byte swapping for the UUID.

The idea of QemuUUID is that wherever it is stored in a non-ephemeral
fashion, it is in BE representation. The guest needs it in LE, so we
should convert it temporarily -- using a local variable -- just before
writing it to guest memory, and then forget about the LE representation
promptly.

As far as I understand, we all agree on this (Michael, Ben, myself -- I
think Igor hasn't commented on this).


(2) Structure of the vmgenid fw_cfg blob, AKA "why that darn offset 40
decimal".

I explained it under points (6) and (7) in the following message:

Message-Id: <c16a03d5-820a-f719-81ea-43858f903395@redhat.com>
URL: https://www.mail-archive.com/qemu-devel@nongnu.org/msg425226.html

The story is that *wherever* an ADD_POINTER command points to -- that
is, at the *exact* target address --, OVMF will look for an ACPI table
header, somewhat heuristically. If it finds a byte pattern that (a) fits
into the remaining blob and (b) passes some superficial ACPI table
header checks, such as length and checksum, then OVMF assumes that the
blob contains an ACPI table there, and passes the address (again, the
exact, relocated, absolute target address of ADD_POINTER) to
EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable().

We want to disable this heuristic for the vmgenid blob. *If* the blob
contained only 16 bytes (for the GUID), then the heuristic would
automatically disable itself, because the ACPI table header (36 bytes)
is larger than 16 bytes, so OVMF wouldn't even look. However, for the
caching and other VMGENID requirements, we need to allocate a full page
with the blob (4KB), hence OVMF *will* look. If we placed the GUID right
at the start of the page, then OVMF would sanity-check it as an ACPI
table header. The check would *most likely* not pass, so things would be
fine in practice, but we can do better than that: just put 40 zero bytes
at the front of the blob.

And this is why the ADD_POINTER command has to point to the beginning of
the blob (i.e., 36 zero bytes), to "suppress the OVMF ACPI SDT header
detection". (The other 4 bytes are for arriving at an address divisible
by 8, which is a VMGENID requirement for the GUID.)

The consequence is that both the ADDR method and QEMU's guest memory
access code have to add 40 manually.


(3) Whether the VGIA named object should be a DWORD or a QWORD in ACPI.
Personally, I'm fine with either, but I see that DWORD is more
compatible with old OSes.

What I really care about though is the new WRITE_POINTER command
structure. That should support 8 bytes as well.

So this is exactly how Michael summarized it ultimately:
- use a DWORD for VGIA in ACPI,
- with a matching 4-byte wide ADD_POINTER command;
- write the address with a 4-byte wide WRITE_POINTER command into
  fw_cfg,
- *but* the WRITE_POINTER command struct should support 8-byte as well,
- and the fw_cfg file that is written (vmgenid_addr) should have size 8
  from the start. (The guest will simply write offsets 0..3 inclusive,
  in LE byte order.)


(4) IIRC Igor asked if sizing the blob to 4KB would guarantee that the
GUID ends up in a cacheable page -- yes (see also Michael's followup).
This size guarantees that the GUID will have a full page to itself, and
its allocated from normal guest RAM, as Reserved memory (SeaBIOS, IIRC)
or EfiACPIMemoryNVS memory (OVMF).

Note that the VMGENID spec says, in ACPI terms, "It must not be in
ranges reported as AddressRangeMemory or AddressRangeACPI", but that's fine:

ACPI speak           UEFI speak            suitable for VMGENID?
------------------   --------------------- ---------------------
AddressRangeMemory   EfiConventionalMemory no
AddressRangeACPI     EfiACPIReclaimMemory  no
AddressRangeNVS      EfiACPIMemoryNVS      yes, used by OVMF
AddressRangeReserved EfiReservedMemoryType yes, used by SeaBIOS


(5) The race and fw_cfg callbacks.

(a) Michael and Ben identified a problem where
- QEMU places the initial GUID in the "vmgenid" fw_cfg blob,
- the guest downloads it,
- the host admin changes the GUID via the monitor,
- and the guest writes the address to "vmgenid_addr" *only* after that.

In other words, the monitor action occurs between the guest's processing
of the ALLOCATE and WRITE_POINTER linker/loader commands.

(b) A similar problem is rebooting the guest.
- The guest starts up fine,
- the OS runs,
- the host admin changes the GUID via the monitor,
- and the guest sees the update fine.
- At this point the guest is rebooted (within the same QEMU instance).

Since the fw_cfg blob is not rebuilt -- more precisely, the blob *is*
rebuilt, but it is then thrown away in acpi_build_update() --, the guest
will see a different GUID from the last value set on the monitor. (And
querying the monitor will actually return that last-set value, which is
no longer known by the guest.)


The suggestion for these problems was to add a callback to "one" of the
fw_cfg files in question.

Let's investigate the writeable "vmgenid_addr" file first. Here the idea
is to rewrite the GUID in guest RAM as soon as the address is known from
the guest, regardless of what GUID the guest placed there originally,
through downloading the "vmgenid" blob.

(i) We have no write callbacks at the moment. Before we removed the data
port based write support in QEMU 2.4, the write callback used to be
invoked when the end of the fw_cfg blob was reached. Since we intend to
pack several addresses in the same writeable fw_cfg blob down the road,
at different offsets, this method wouldn't work; the final offset in the
blob might not be reached at all. (Another thing that wouldn't work is
an 8-byte writeable fw_cfg blob, and a 4-byte WRITE_POINTER command that
only rewrites offsets 0..3 inclusve -- see (3) above.)

So I don't think that a write callback is viable, at least with the
"many addresses at different offsets in the same blob" feature. Unless
we want to register different callbacks (or different callback
arguments) for different offsets. And then a large write could trigger a
series of callbacks, even, if it covers several special offsets. This
looks too complex to me.

(ii) What we do have now is a select callback. Unfortunately, the guest
is not required to select the item and atomically rewrite the blob, in
the same fw_cfg DMA operation. The guest is allowed to do the selection
with the IO port method, and then write the blob separately with DMA.
(This is what OVMF does.) IOW, when we'd get the callback (for the
select), the address would not have been written yet.

So I don't think that a select callback for the writeable "vmgenid_addr"
file is viable either.

(iii) Let's see a select callback for the "vmgenid" blob itself! The
idea is, whenever the guest selects this blob, immediately refresh the
blob from the last set GUID. Then let the guest download the
just-refreshed blob.

The main observation here is that we can *fail* QMP commands. That's
good enough if we can tell *when* to fail them.

Under this idea, we would fail the "set-vm-generation-id" QMP command
with "EAGAIN" if the quest had selected the "vmgenid" blob since machine
reset -- this can be tracked with a latch -- *but* the particular offset
range in the "vmgenid_addr" blob were still zero.

This is exactly the window between the ALLOCATE and WRITE_POINTER
commands where updates from the monitor would be lost. So let's just
tell the management layer to try again later (like 1 second later). By
that time, any sane guest will have written the address into "vmgenid_addr".

Thanks
Laszlo

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

* Re: [Qemu-devel] [PATCH v5 01/10] ACPI: Add a function for building named qword entries
  2017-02-07 20:09     ` Laszlo Ersek
@ 2017-02-08 10:43       ` Igor Mammedov
  2017-02-08 10:53         ` Laszlo Ersek
  0 siblings, 1 reply; 70+ messages in thread
From: Igor Mammedov @ 2017-02-08 10:43 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: ben, qemu-devel, mst

On Tue, 7 Feb 2017 21:09:27 +0100
Laszlo Ersek <lersek@redhat.com> wrote:

> On 02/07/17 14:51, Igor Mammedov wrote:
> > On Sun,  5 Feb 2017 01:11:56 -0800
> > ben@skyportsystems.com wrote:
> >   
> >> From: Ben Warren <ben@skyportsystems.com>
> >>
> >> This is initially used to patch a 64-bit address into
> >> the VM Generation ID SSDT
> >>
> >> Signed-off-by: Ben Warren <ben@skyportsystems.com>
> >> ---  
> > ...  
> >> +int
> >> +build_append_named_qword(GArray *array, const char *name_format, ...)  
> > it ain't used anywhere, I'd just drop this patch.  
> 
> Ben and I discussed this under
> - msgid <6E25852D-224A-4BDC-AA83-8DC87DB4D0F0@skyportsystems.com>
>   https://www.mail-archive.com/qemu-devel@nongnu.org/msg425496.html
> - msgid <a93a6be3-cbed-5afe-7c72-96410fbfce41@redhat.com>
>   https://www.mail-archive.com/qemu-devel@nongnu.org/msg425519.html
> 
> On 01/26/17 06:35, Ben Warren wrote:
> > I propose to still include this patch but touch up the comments as
> > requested by Laszlo.  This way it will be in the toolbox for future
> > users and has been tested.  [...]  
> 
> I generally agree that dead code is undesirable, but this function has
> surfaced several times until now, and we get to review it every single
> time. Ben tested it, I support its inclusion.
> 
> OTOH I also pointed it out to Ben
> 
> https://www.mail-archive.com/qemu-devel@nongnu.org/msg425218.html
> 
> that he should expect disagreement between his reviewers :) Given that
> I'm observing this series more from the sidelines and you maintain /
> support ACPI gen in QEMU, I certainly defer to you on this.
It's not only dead, having patchable QWORD ready for use in QEMU
would tempt someone to use it and that would lead to XP BSOD
if it slips screening at review time. I'd delay this patch until
we announce that ACPI 1.0 (XP based) guest no more supported by
new QEMU.

Anyway I won't object to merging this if you insist and give it your RB.


> Thanks
> Laszlo
> 
> 
> >> +{
> >> +    int offset;
> >> +    va_list ap;
> >> +
> >> +    build_append_byte(array, 0x08); /* NameOp */
> >> +    va_start(ap, name_format);
> >> +    build_append_namestringv(array, name_format, ap);
> >> +    va_end(ap);
> >> +
> >> +    build_append_byte(array, 0x0E); /* QWordPrefix */
> >> +
> >> +    offset = array->len;
> >> +    build_append_int_noprefix(array, 0x0000000000000000, 8);
> >> +    assert(array->len == offset + 8);
> >> +
> >> +    return offset;
> >> +}
> >> +
> >>  static GPtrArray *alloc_list;
> >>  
> >>  static Aml *aml_alloc(void)
> >> diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
> >> index 559326c..dbf63cf 100644
> >> --- a/include/hw/acpi/aml-build.h
> >> +++ b/include/hw/acpi/aml-build.h
> >> @@ -385,6 +385,10 @@ int
> >>  build_append_named_dword(GArray *array, const char *name_format, ...)
> >>  GCC_FMT_ATTR(2, 3);
> >>  
> >> +int
> >> +build_append_named_qword(GArray *array, const char *name_format, ...)
> >> +GCC_FMT_ATTR(2, 3);
> >> +
> >>  void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
> >>                         uint64_t len, int node, MemoryAffinityFlags flags);
> >>    
> > 
> >   
> 

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

* Re: [Qemu-devel] [PATCH v5 01/10] ACPI: Add a function for building named qword entries
  2017-02-08 10:43       ` Igor Mammedov
@ 2017-02-08 10:53         ` Laszlo Ersek
  2017-02-08 20:24           ` Ben Warren
  0 siblings, 1 reply; 70+ messages in thread
From: Laszlo Ersek @ 2017-02-08 10:53 UTC (permalink / raw)
  To: Igor Mammedov; +Cc: ben, qemu-devel, mst

On 02/08/17 11:43, Igor Mammedov wrote:
> On Tue, 7 Feb 2017 21:09:27 +0100
> Laszlo Ersek <lersek@redhat.com> wrote:
> 
>> On 02/07/17 14:51, Igor Mammedov wrote:
>>> On Sun,  5 Feb 2017 01:11:56 -0800
>>> ben@skyportsystems.com wrote:
>>>   
>>>> From: Ben Warren <ben@skyportsystems.com>
>>>>
>>>> This is initially used to patch a 64-bit address into
>>>> the VM Generation ID SSDT
>>>>
>>>> Signed-off-by: Ben Warren <ben@skyportsystems.com>
>>>> ---  
>>> ...  
>>>> +int
>>>> +build_append_named_qword(GArray *array, const char *name_format, ...)  
>>> it ain't used anywhere, I'd just drop this patch.  
>>
>> Ben and I discussed this under
>> - msgid <6E25852D-224A-4BDC-AA83-8DC87DB4D0F0@skyportsystems.com>
>>   https://www.mail-archive.com/qemu-devel@nongnu.org/msg425496.html
>> - msgid <a93a6be3-cbed-5afe-7c72-96410fbfce41@redhat.com>
>>   https://www.mail-archive.com/qemu-devel@nongnu.org/msg425519.html
>>
>> On 01/26/17 06:35, Ben Warren wrote:
>>> I propose to still include this patch but touch up the comments as
>>> requested by Laszlo.  This way it will be in the toolbox for future
>>> users and has been tested.  [...]  
>>
>> I generally agree that dead code is undesirable, but this function has
>> surfaced several times until now, and we get to review it every single
>> time. Ben tested it, I support its inclusion.
>>
>> OTOH I also pointed it out to Ben
>>
>> https://www.mail-archive.com/qemu-devel@nongnu.org/msg425218.html
>>
>> that he should expect disagreement between his reviewers :) Given that
>> I'm observing this series more from the sidelines and you maintain /
>> support ACPI gen in QEMU, I certainly defer to you on this.
> It's not only dead, having patchable QWORD ready for use in QEMU
> would tempt someone to use it and that would lead to XP BSOD
> if it slips screening at review time.

Good point.

> I'd delay this patch until
> we announce that ACPI 1.0 (XP based) guest no more supported by
> new QEMU.
> 
> Anyway I won't object to merging this if you insist and give it your RB.

No, you are entirely right. As long as we consider Windows XP guests
first class citizens (i.e., we even reject the idea of additional
command line options), then keeping QWORD "out of sight" is safer.

Follow up question: when are we going to drop Windows XP? Do we have a
plan? :) It's quite a struggle to support both ends of the spectrum with
the same machine types and options (decades-old DOS and Windows XP vs.
supercomputer-class NUMA setups). I think this limits development.

(Just curious; I'm not suggesting to drop Windows XP "soon".)

Thanks!
Laszlo


>>
>>
>>>> +{
>>>> +    int offset;
>>>> +    va_list ap;
>>>> +
>>>> +    build_append_byte(array, 0x08); /* NameOp */
>>>> +    va_start(ap, name_format);
>>>> +    build_append_namestringv(array, name_format, ap);
>>>> +    va_end(ap);
>>>> +
>>>> +    build_append_byte(array, 0x0E); /* QWordPrefix */
>>>> +
>>>> +    offset = array->len;
>>>> +    build_append_int_noprefix(array, 0x0000000000000000, 8);
>>>> +    assert(array->len == offset + 8);
>>>> +
>>>> +    return offset;
>>>> +}
>>>> +
>>>>  static GPtrArray *alloc_list;
>>>>  
>>>>  static Aml *aml_alloc(void)
>>>> diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
>>>> index 559326c..dbf63cf 100644
>>>> --- a/include/hw/acpi/aml-build.h
>>>> +++ b/include/hw/acpi/aml-build.h
>>>> @@ -385,6 +385,10 @@ int
>>>>  build_append_named_dword(GArray *array, const char *name_format, ...)
>>>>  GCC_FMT_ATTR(2, 3);
>>>>  
>>>> +int
>>>> +build_append_named_qword(GArray *array, const char *name_format, ...)
>>>> +GCC_FMT_ATTR(2, 3);
>>>> +
>>>>  void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
>>>>                         uint64_t len, int node, MemoryAffinityFlags flags);
>>>>    
>>>
>>>   
>>
> 

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-08  0:48   ` Laszlo Ersek
@ 2017-02-08 11:04     ` Igor Mammedov
  2017-02-08 11:17       ` Laszlo Ersek
  2017-02-08 22:34     ` Ben Warren
  2017-02-09 17:23     ` Igor Mammedov
  2 siblings, 1 reply; 70+ messages in thread
From: Igor Mammedov @ 2017-02-08 11:04 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: ben, mst, qemu-devel

On Wed, 8 Feb 2017 01:48:42 +0100
Laszlo Ersek <lersek@redhat.com> wrote:

> On 02/05/17 10:12, ben@skyportsystems.com wrote:
> > From: Ben Warren <ben@skyportsystems.com>
> > 
> > This implements the VM Generation ID feature by passing a 128-bit
> > GUID to the guest via a fw_cfg blob.
> > Any time the GUID changes, an ACPI notify event is sent to the guest
> > 
> > The user interface is a simple device with one parameter:
> >  - guid (string, must be "auto" or in UUID format
> >    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
> > 
> > Signed-off-by: Ben Warren <ben@skyportsystems.com>
> > ---
> >  default-configs/i386-softmmu.mak     |   1 +
> >  default-configs/x86_64-softmmu.mak   |   1 +
> >  hw/acpi/Makefile.objs                |   1 +
> >  hw/acpi/vmgenid.c                    | 206 +++++++++++++++++++++++++++++++++++
> >  hw/i386/acpi-build.c                 |  10 ++
> >  include/hw/acpi/acpi_dev_interface.h |   1 +
> >  include/hw/acpi/vmgenid.h            |  37 +++++++
> >  7 files changed, 257 insertions(+)
> >  create mode 100644 hw/acpi/vmgenid.c
> >  create mode 100644 include/hw/acpi/vmgenid.h  
> 
> [snip code]
> 
> So, I'm late to the game. I can't possibly comment on all the concerns
> that have been raised scattered around the thread, exactly *where* they
> have been raised. However, I will try to collect the concerns here.
> 
> 
> (1) Byte swapping for the UUID.
> 
> The idea of QemuUUID is that wherever it is stored in a non-ephemeral
> fashion, it is in BE representation. The guest needs it in LE, so we
> should convert it temporarily -- using a local variable -- just before
> writing it to guest memory, and then forget about the LE representation
> promptly.
> 
> As far as I understand, we all agree on this (Michael, Ben, myself -- I
> think Igor hasn't commented on this).
> 
> 
> (2) Structure of the vmgenid fw_cfg blob, AKA "why that darn offset 40
> decimal".
> 
> I explained it under points (6) and (7) in the following message:
> 
> Message-Id: <c16a03d5-820a-f719-81ea-43858f903395@redhat.com>
> URL: https://www.mail-archive.com/qemu-devel@nongnu.org/msg425226.html
> 
> The story is that *wherever* an ADD_POINTER command points to -- that
> is, at the *exact* target address --, OVMF will look for an ACPI table
> header, somewhat heuristically. If it finds a byte pattern that (a) fits
> into the remaining blob and (b) passes some superficial ACPI table
> header checks, such as length and checksum, then OVMF assumes that the
> blob contains an ACPI table there, and passes the address (again, the
> exact, relocated, absolute target address of ADD_POINTER) to
> EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable().
> 
> We want to disable this heuristic for the vmgenid blob. *If* the blob
> contained only 16 bytes (for the GUID), then the heuristic would
> automatically disable itself, because the ACPI table header (36 bytes)
> is larger than 16 bytes, so OVMF wouldn't even look. However, for the
> caching and other VMGENID requirements, we need to allocate a full page
> with the blob (4KB), hence OVMF *will* look. If we placed the GUID right
> at the start of the page, then OVMF would sanity-check it as an ACPI
> table header. The check would *most likely* not pass, so things would be
> fine in practice, but we can do better than that: just put 40 zero bytes
> at the front of the blob.
> 
> And this is why the ADD_POINTER command has to point to the beginning of
> the blob (i.e., 36 zero bytes), to "suppress the OVMF ACPI SDT header
> detection". (The other 4 bytes are for arriving at an address divisible
> by 8, which is a VMGENID requirement for the GUID.)
that's deserves a comment in code/doc as it's non obvious to someone
who is not familiar with OVMF.


> The consequence is that both the ADDR method and QEMU's guest memory
> access code have to add 40 manually.
> 
> 
> (3) Whether the VGIA named object should be a DWORD or a QWORD in ACPI.
> Personally, I'm fine with either, but I see that DWORD is more
> compatible with old OSes.
It's not only old OSes, but newer ones as well (32 bit and to some degree 64-bit).
We should not put QWORD objects in global scope until we switch
DSDT rev to 2.0 or higher AND ready to drop support for ACPI 1.0 guests.
DSDT rev is important for 64-bit guests as well as OSPM chooses
supported integer length based on it.

> 
> What I really care about though is the new WRITE_POINTER command
> structure. That should support 8 bytes as well.
> 
> So this is exactly how Michael summarized it ultimately:
> - use a DWORD for VGIA in ACPI,
> - with a matching 4-byte wide ADD_POINTER command;
> - write the address with a 4-byte wide WRITE_POINTER command into
>   fw_cfg,
> - *but* the WRITE_POINTER command struct should support 8-byte as well,
> - and the fw_cfg file that is written (vmgenid_addr) should have size 8
>   from the start. (The guest will simply write offsets 0..3 inclusive,
>   in LE byte order.)
ACK above summary.

 
> (4) IIRC Igor asked if sizing the blob to 4KB would guarantee that the
> GUID ends up in a cacheable page -- yes (see also Michael's followup).
> This size guarantees that the GUID will have a full page to itself, and
> its allocated from normal guest RAM, as Reserved memory (SeaBIOS, IIRC)
> or EfiACPIMemoryNVS memory (OVMF).
> 
> Note that the VMGENID spec says, in ACPI terms, "It must not be in
> ranges reported as AddressRangeMemory or AddressRangeACPI", but that's fine:
> 
> ACPI speak           UEFI speak            suitable for VMGENID?
> ------------------   --------------------- ---------------------
> AddressRangeMemory   EfiConventionalMemory no
> AddressRangeACPI     EfiACPIReclaimMemory  no
> AddressRangeNVS      EfiACPIMemoryNVS      yes, used by OVMF
> AddressRangeReserved EfiReservedMemoryType yes, used by SeaBIOS
> 
> 
> (5) The race and fw_cfg callbacks.
> 
> (a) Michael and Ben identified a problem where
> - QEMU places the initial GUID in the "vmgenid" fw_cfg blob,
> - the guest downloads it,
> - the host admin changes the GUID via the monitor,
> - and the guest writes the address to "vmgenid_addr" *only* after that.
> 
> In other words, the monitor action occurs between the guest's processing
> of the ALLOCATE and WRITE_POINTER linker/loader commands.
> 
> (b) A similar problem is rebooting the guest.
> - The guest starts up fine,
> - the OS runs,
> - the host admin changes the GUID via the monitor,
> - and the guest sees the update fine.
> - At this point the guest is rebooted (within the same QEMU instance).
> 
> Since the fw_cfg blob is not rebuilt -- more precisely, the blob *is*
> rebuilt, but it is then thrown away in acpi_build_update() --, the guest
> will see a different GUID from the last value set on the monitor. (And
> querying the monitor will actually return that last-set value, which is
> no longer known by the guest.)
> 
> 
> The suggestion for these problems was to add a callback to "one" of the
> fw_cfg files in question.
> 
> Let's investigate the writeable "vmgenid_addr" file first. Here the idea
> is to rewrite the GUID in guest RAM as soon as the address is known from
> the guest, regardless of what GUID the guest placed there originally,
> through downloading the "vmgenid" blob.
> 
> (i) We have no write callbacks at the moment. Before we removed the data
> port based write support in QEMU 2.4, the write callback used to be
> invoked when the end of the fw_cfg blob was reached. Since we intend to
> pack several addresses in the same writeable fw_cfg blob down the road,
> at different offsets, this method wouldn't work; the final offset in the
> blob might not be reached at all. (Another thing that wouldn't work is
> an 8-byte writeable fw_cfg blob, and a 4-byte WRITE_POINTER command that
> only rewrites offsets 0..3 inclusve -- see (3) above.)
> 
> So I don't think that a write callback is viable, at least with the
> "many addresses at different offsets in the same blob" feature. Unless
> we want to register different callbacks (or different callback
> arguments) for different offsets. And then a large write could trigger a
> series of callbacks, even, if it covers several special offsets. This
> looks too complex to me.
> 
> (ii) What we do have now is a select callback. Unfortunately, the guest
> is not required to select the item and atomically rewrite the blob, in
> the same fw_cfg DMA operation. The guest is allowed to do the selection
> with the IO port method, and then write the blob separately with DMA.
> (This is what OVMF does.) IOW, when we'd get the callback (for the
> select), the address would not have been written yet.
> 
> So I don't think that a select callback for the writeable "vmgenid_addr"
> file is viable either.
> 
> (iii) Let's see a select callback for the "vmgenid" blob itself! The
> idea is, whenever the guest selects this blob, immediately refresh the
> blob from the last set GUID. Then let the guest download the
> just-refreshed blob.
> 
> The main observation here is that we can *fail* QMP commands. That's
> good enough if we can tell *when* to fail them.
> 
> Under this idea, we would fail the "set-vm-generation-id" QMP command
> with "EAGAIN" if the quest had selected the "vmgenid" blob since machine
> reset -- this can be tracked with a latch -- *but* the particular offset
> range in the "vmgenid_addr" blob were still zero.
> 
> This is exactly the window between the ALLOCATE and WRITE_POINTER
> commands where updates from the monitor would be lost. So let's just
> tell the management layer to try again later (like 1 second later). By
> that time, any sane guest will have written the address into "vmgenid_addr".
> 
> Thanks
> Laszlo

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-08 11:04     ` Igor Mammedov
@ 2017-02-08 11:17       ` Laszlo Ersek
  2017-02-08 12:00         ` Igor Mammedov
  0 siblings, 1 reply; 70+ messages in thread
From: Laszlo Ersek @ 2017-02-08 11:17 UTC (permalink / raw)
  To: Igor Mammedov; +Cc: ben, mst, qemu-devel

On 02/08/17 12:04, Igor Mammedov wrote:
> On Wed, 8 Feb 2017 01:48:42 +0100
> Laszlo Ersek <lersek@redhat.com> wrote:

[snip]

>> (2) Structure of the vmgenid fw_cfg blob, AKA "why that darn offset 40
>> decimal".
>>
>> I explained it under points (6) and (7) in the following message:
>>
>> Message-Id: <c16a03d5-820a-f719-81ea-43858f903395@redhat.com>
>> URL: https://www.mail-archive.com/qemu-devel@nongnu.org/msg425226.html
>>
>> The story is that *wherever* an ADD_POINTER command points to -- that
>> is, at the *exact* target address --, OVMF will look for an ACPI table
>> header, somewhat heuristically. If it finds a byte pattern that (a) fits
>> into the remaining blob and (b) passes some superficial ACPI table
>> header checks, such as length and checksum, then OVMF assumes that the
>> blob contains an ACPI table there, and passes the address (again, the
>> exact, relocated, absolute target address of ADD_POINTER) to
>> EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable().
>>
>> We want to disable this heuristic for the vmgenid blob. *If* the blob
>> contained only 16 bytes (for the GUID), then the heuristic would
>> automatically disable itself, because the ACPI table header (36 bytes)
>> is larger than 16 bytes, so OVMF wouldn't even look. However, for the
>> caching and other VMGENID requirements, we need to allocate a full page
>> with the blob (4KB), hence OVMF *will* look. If we placed the GUID right
>> at the start of the page, then OVMF would sanity-check it as an ACPI
>> table header. The check would *most likely* not pass, so things would be
>> fine in practice, but we can do better than that: just put 40 zero bytes
>> at the front of the blob.
>>
>> And this is why the ADD_POINTER command has to point to the beginning of
>> the blob (i.e., 36 zero bytes), to "suppress the OVMF ACPI SDT header
>> detection". (The other 4 bytes are for arriving at an address divisible
>> by 8, which is a VMGENID requirement for the GUID.)
> that's deserves a comment in code/doc as it's non obvious to someone
> who is not familiar with OVMF.

It is mentioned in the document "docs/specs/vmgenid.txt", added in patch 3.

I didn't want to push for more details there, but if you think it's
helpful or even required, then Ben should please simply add a

Rationale for padding at the front (OVMF SDT Header probe suppressor)
---------------------------------------------------------------------

subsection under the

GUID Storage Format
-------------------

section, and just dump the above into it.

Maybe tone down the over-use of *bold*. :)

> 
> 
>> The consequence is that both the ADDR method and QEMU's guest memory
>> access code have to add 40 manually.
>>
>>
>> (3) Whether the VGIA named object should be a DWORD or a QWORD in ACPI.
>> Personally, I'm fine with either, but I see that DWORD is more
>> compatible with old OSes.
> It's not only old OSes, but newer ones as well (32 bit and to some degree 64-bit).
> We should not put QWORD objects in global scope until we switch
> DSDT rev to 2.0 or higher AND ready to drop support for ACPI 1.0 guests.
> DSDT rev is important for 64-bit guests as well as OSPM chooses
> supported integer length based on it.

Good point. DWORD is fine with me.

[snipping the rest, nothing for me to add there, it seems]

Thanks!
Laszlo

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-08 11:17       ` Laszlo Ersek
@ 2017-02-08 12:00         ` Igor Mammedov
  0 siblings, 0 replies; 70+ messages in thread
From: Igor Mammedov @ 2017-02-08 12:00 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: ben, mst, qemu-devel

On Wed, 8 Feb 2017 12:17:54 +0100
Laszlo Ersek <lersek@redhat.com> wrote:

> On 02/08/17 12:04, Igor Mammedov wrote:
> > On Wed, 8 Feb 2017 01:48:42 +0100
> > Laszlo Ersek <lersek@redhat.com> wrote:  
> 
> [snip]
> 
> >> (2) Structure of the vmgenid fw_cfg blob, AKA "why that darn offset 40
> >> decimal".
> >>
> >> I explained it under points (6) and (7) in the following message:
> >>
> >> Message-Id: <c16a03d5-820a-f719-81ea-43858f903395@redhat.com>
> >> URL: https://www.mail-archive.com/qemu-devel@nongnu.org/msg425226.html
> >>
> >> The story is that *wherever* an ADD_POINTER command points to -- that
> >> is, at the *exact* target address --, OVMF will look for an ACPI table
> >> header, somewhat heuristically. If it finds a byte pattern that (a) fits
> >> into the remaining blob and (b) passes some superficial ACPI table
> >> header checks, such as length and checksum, then OVMF assumes that the
> >> blob contains an ACPI table there, and passes the address (again, the
> >> exact, relocated, absolute target address of ADD_POINTER) to
> >> EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable().
> >>
> >> We want to disable this heuristic for the vmgenid blob. *If* the blob
> >> contained only 16 bytes (for the GUID), then the heuristic would
> >> automatically disable itself, because the ACPI table header (36 bytes)
> >> is larger than 16 bytes, so OVMF wouldn't even look. However, for the
> >> caching and other VMGENID requirements, we need to allocate a full page
> >> with the blob (4KB), hence OVMF *will* look. If we placed the GUID right
> >> at the start of the page, then OVMF would sanity-check it as an ACPI
> >> table header. The check would *most likely* not pass, so things would be
> >> fine in practice, but we can do better than that: just put 40 zero bytes
> >> at the front of the blob.
> >>
> >> And this is why the ADD_POINTER command has to point to the beginning of
> >> the blob (i.e., 36 zero bytes), to "suppress the OVMF ACPI SDT header
> >> detection". (The other 4 bytes are for arriving at an address divisible
> >> by 8, which is a VMGENID requirement for the GUID.)  
> > that's deserves a comment in code/doc as it's non obvious to someone
> > who is not familiar with OVMF.  
> 
> It is mentioned in the document "docs/specs/vmgenid.txt", added in patch 3.
> 
> I didn't want to push for more details there, but if you think it's
> helpful or even required, then Ben should please simply add a
> 
> Rationale for padding at the front (OVMF SDT Header probe suppressor)
> ---------------------------------------------------------------------
> 
> subsection under the
> 
> GUID Storage Format
> -------------------
> 
> section, and just dump the above into it.
> 
> Maybe tone down the over-use of *bold*. :)
+ comment/reference to doc in the code where this 'suppressor' is used,
otherwise it would be easy to forget why pointer points to the blob start
instead of directly to GUID.

> 
> Thanks!
> Laszlo
> 
> 

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-07 13:48   ` Igor Mammedov
  2017-02-07 15:36     ` Michael S. Tsirkin
@ 2017-02-08 20:19     ` Ben Warren
  2017-02-09  9:59       ` Igor Mammedov
  1 sibling, 1 reply; 70+ messages in thread
From: Ben Warren @ 2017-02-08 20:19 UTC (permalink / raw)
  To: Igor Mammedov; +Cc: qemu-devel, lersek, mst

[-- Attachment #1: Type: text/plain, Size: 15321 bytes --]

Thanks for reviewing Igor.

> On Feb 7, 2017, at 5:48 AM, Igor Mammedov <imammedo@redhat.com> wrote:
> 
> On Sun,  5 Feb 2017 01:12:00 -0800
> ben@skyportsystems.com <mailto:ben@skyportsystems.com> wrote:
> 
>> From: Ben Warren <ben@skyportsystems.com>
>> 
>> This implements the VM Generation ID feature by passing a 128-bit
>> GUID to the guest via a fw_cfg blob.
>> Any time the GUID changes, an ACPI notify event is sent to the guest
>> 
>> The user interface is a simple device with one parameter:
>> - guid (string, must be "auto" or in UUID format
>>   xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
>> 
>> Signed-off-by: Ben Warren <ben@skyportsystems.com>
>> ---
>> default-configs/i386-softmmu.mak     |   1 +
>> default-configs/x86_64-softmmu.mak   |   1 +
>> hw/acpi/Makefile.objs                |   1 +
>> hw/acpi/vmgenid.c                    | 206 +++++++++++++++++++++++++++++++++++
>> hw/i386/acpi-build.c                 |  10 ++
>> include/hw/acpi/acpi_dev_interface.h |   1 +
>> include/hw/acpi/vmgenid.h            |  37 +++++++
>> 7 files changed, 257 insertions(+)
>> create mode 100644 hw/acpi/vmgenid.c
>> create mode 100644 include/hw/acpi/vmgenid.h
>> 
>> diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
>> index 384cefb..1a43542 100644
>> --- a/default-configs/i386-softmmu.mak
>> +++ b/default-configs/i386-softmmu.mak
>> @@ -58,3 +58,4 @@ CONFIG_I82801B11=y
>> CONFIG_SMBIOS=y
>> CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
>> CONFIG_PXB=y
>> +CONFIG_ACPI_VMGENID=y
>> diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
>> index 491a191..aee8b08 100644
>> --- a/default-configs/x86_64-softmmu.mak
>> +++ b/default-configs/x86_64-softmmu.mak
>> @@ -58,3 +58,4 @@ CONFIG_I82801B11=y
>> CONFIG_SMBIOS=y
>> CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
>> CONFIG_PXB=y
>> +CONFIG_ACPI_VMGENID=y
>> diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
>> index 6acf798..11c35bc 100644
>> --- a/hw/acpi/Makefile.objs
>> +++ b/hw/acpi/Makefile.objs
>> @@ -5,6 +5,7 @@ common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
>> common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
>> common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
>> common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
>> +common-obj-$(CONFIG_ACPI_VMGENID) += vmgenid.o
>> common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
>> 
>> common-obj-y += acpi_interface.o
>> diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
>> new file mode 100644
>> index 0000000..6c9ecfd
>> --- /dev/null
>> +++ b/hw/acpi/vmgenid.c
>> @@ -0,0 +1,206 @@
>> +/*
>> + *  Virtual Machine Generation ID Device
>> + *
>> + *  Copyright (C) 2017 Skyport Systems.
>> + *
>> + *  Author: Ben Warren <ben@skyportsystems.com>
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
>> + * See the COPYING file in the top-level directory.
>> + *
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "qmp-commands.h"
>> +#include "hw/acpi/acpi.h"
>> +#include "hw/acpi/aml-build.h"
>> +#include "hw/acpi/vmgenid.h"
>> +#include "hw/nvram/fw_cfg.h"
>> +#include "sysemu/sysemu.h"
>> +
>> +void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker *linker)
>> +{
>> +    Object *obj;
>> +    VmGenIdState *s;
>> +    Aml *ssdt, *dev, *scope, *method, *addr, *if_ctx;
>> +    uint32_t vgia_offset;
>> +
>> +    obj = find_vmgenid_dev(NULL);
> get obj from caller
> 
>> +    assert(obj);
>> +    s = VMGENID(obj);
>> +
>> +    /* Fill in the GUID values */
>> +    if (guid->len != VMGENID_FW_CFG_SIZE) {
>> +        g_array_set_size(guid, VMGENID_FW_CFG_SIZE);
> does it have to be conditional?
> 
No, I guess not.
>> +    }
>> +    g_array_insert_vals(guid, VMGENID_GUID_OFFSET, s->guid.data, 16);
>> +
>> +    /* Put this in a separate SSDT table */
>> +    ssdt = init_aml_allocator();
>> +
>> +    /* Reserve space for header */
>> +    acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader));
>> +
>> +    /* Storage for the GUID address */
>> +    vgia_offset = table_data->len +
>> +        build_append_named_dword(ssdt->buf, "VGIA");
>> +    scope = aml_scope("\\_SB");
>> +    dev = aml_device("VGEN");
>> +    aml_append(dev, aml_name_decl("_HID", aml_string("QEMUVGID")));
>> +    aml_append(dev, aml_name_decl("_CID", aml_string("VM_Gen_Counter")));
>> +    aml_append(dev, aml_name_decl("_DDN", aml_string("VM_Gen_Counter")));
>> +
>> +    /* Simple status method to check that address is linked and non-zero */
>> +    method = aml_method("_STA", 0, AML_NOTSERIALIZED);
>> +    addr = aml_local(0);
>> +    aml_append(method, aml_store(aml_int(0xf), addr));
>> +    if_ctx = aml_if(aml_equal(aml_name("VGIA"), aml_int(0)));
>> +    aml_append(if_ctx, aml_store(aml_int(0), addr));
>> +    aml_append(method, if_ctx);
>> +    aml_append(method, aml_return(addr));
>> +    aml_append(dev, method);
>> +
>> +    /* the ADDR method returns two 32-bit words representing the lower and
>> +     * upper halves * of the physical address of the fw_cfg blob
>> +     * (holding the GUID) */
>> +    method = aml_method("ADDR", 0, AML_NOTSERIALIZED);
>> +
>> +    addr = aml_local(0);
>> +    aml_append(method, aml_store(aml_package(2), addr));
>> +
>> +    aml_append(method, aml_store(aml_add(aml_name("VGIA"),
>> +                                         aml_int(VMGENID_GUID_OFFSET), NULL),
>> +                                 aml_index(addr, aml_int(0))));
>> +    aml_append(method, aml_store(aml_int(0), aml_index(addr, aml_int(1))));
> I'd rather have "VGIA" patched wit address to GUID and not the blob start,
> see next comment about how.
> 
> Also usage aml_index() looks a bit confusing, how about:
> 
> pkg = aml_local(0)
> aml_store(aml_package(2), pkg)
> aml_append(pkg, aml_name("VGIA"))
> aml_append(pkg, aml_int(0))
> 
I’ll try that, it does look simpler.  I thought I tried this and couldn’t get it to work, but will try again.
>> +    aml_append(method, aml_return(addr));
>> +
>> +    aml_append(dev, method);
>> +    aml_append(scope, dev);
>> +    aml_append(ssdt, scope);
>> +
>> +    /* attach an ACPI notify */
>> +    method = aml_method("\\_GPE._E05", 0, AML_NOTSERIALIZED);
>> +    aml_append(method, aml_notify(aml_name("\\_SB.VGEN"), aml_int(0x80)));
>> +    aml_append(ssdt, method);
>> +
>> +    g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len);
>> +
>> +    /* Allocate guest memory for the Data fw_cfg blob */
>> +    bios_linker_loader_alloc(linker, VMGENID_GUID_FW_CFG_FILE, guid, 4096,
>> +                             false /* page boundary, high memory */);
> does it guaranties that blob will be allocated in cacheable page?
> (SeaBIOS/OVMF)
> 
>> +
>> +    /* Patch address of GUID fw_cfg blob into the ADDR fw_cfg blob */
>> +    bios_linker_loader_add_pointer(linker,
>> +        VMGENID_ADDR_FW_CFG_FILE, 0, sizeof(uint32_t),
>> +        VMGENID_GUID_FW_CFG_FILE, 0, true);
>> +
>> +    /* Patch address of GUID fw_cfg blob into the AML */
>> +    bios_linker_loader_add_pointer(linker,
>> +        ACPI_BUILD_TABLE_FILE, vgia_offset, sizeof(uint32_t),
>> +        VMGENID_GUID_FW_CFG_FILE, 0, false);
> see @src_offset argument description,
> putting VMGENID_GUID_OFFSET would make patched place point directly to GUID
> 
>> +
>> +    build_header(linker, table_data,
>> +        (void *)(table_data->data + table_data->len - ssdt->buf->len),
>> +        "SSDT", ssdt->buf->len, 1, NULL, "VMGENID");
>> +    free_aml_allocator();
>> +}
>> +
>> +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid)
>> +{
>> +    Object *obj = find_vmgenid_dev(NULL);
>> +    assert(obj);
>> +    VmGenIdState *vms = VMGENID(obj);
>> +
>> +    /* Create a read-only fw_cfg file for GUID */
>> +    fw_cfg_add_file(s, VMGENID_GUID_FW_CFG_FILE, guid->data,
>> +                    VMGENID_FW_CFG_SIZE);
>> +    /* Create a read-write fw_cfg file for Address */
>> +    fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL, NULL,
>> +                             vms->vgia_le, sizeof(uint32_t), false);
>> +}
>> +
>> +static void vmgenid_update_guest(VmGenIdState *s)
>> +{
>> +    Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL);
>> +    uint32_t vgia;
>> +
>> +    if (obj) {
>> +        /* Write the GUID to guest memory */
>> +        memcpy(&vgia, s->vgia_le, sizeof(vgia));
>> +        vgia = le32_to_cpu(vgia);
>> +        if (vgia) {
>> +            cpu_physical_memory_write(vgia + VMGENID_GUID_OFFSET,
>> +                                      s->guid.data, sizeof(s->guid.data));
>> +            /* Send _GPE.E05 event */
>> +            acpi_send_event(DEVICE(obj), ACPI_VMGENID_CHANGE_STATUS);
>> +        }
>> +    }
>> +}
>> +
>> +static void vmgenid_set_guid(Object *obj, const char *value, Error **errp)
>> +{
>> +    VmGenIdState *s = VMGENID(obj);
>> +
>> +    if (!strncmp(value, "auto", 4)) {
>> +        qemu_uuid_generate(&s->guid);
>> +    } else if (qemu_uuid_parse(value, &s->guid) < 0) {
>> +        error_setg(errp, "'%s. %s': Failed to parse GUID string: %s",
>> +                   object_get_typename(OBJECT(s)), VMGENID_GUID, value);
>> +        return;
>> +    }
>> +    /* QemuUUID has the first three words as big-endian, and expect that any
>> +     * GUIDs passed in will always be BE.  The guest, however will expect
>> +     * the fields to be little-endian, so store that way internally.  Make
>> +     * sure to swap back whenever reporting via monitor */
>> +    qemu_uuid_bswap(&s->guid);
>> +
>> +    /* Send the ACPI notify */
>> +    vmgenid_update_guest(s);
>> +}
>> +
>> +/* After restoring an image, we need to update the guest memory and notify
>> + * it of a potential change to VM Generation ID */
>> +static int vmgenid_post_load(void *opaque, int version_id)
>> +{
>> +    VmGenIdState *s = opaque;
>> +    vmgenid_update_guest(s);
>> +    return 0;
>> +}
>> +
>> +static const VMStateDescription vmstate_vmgenid = {
>> +    .name = "vmgenid",
>> +    .version_id = 1,
>> +    .minimum_version_id = 1,
>> +    .post_load = vmgenid_post_load,
>> +    .fields = (VMStateField[]) {
>> +        VMSTATE_UINT8_ARRAY(vgia_le, VmGenIdState, sizeof(uint32_t)),
> file with address could be memory region and migrated automatically,
> ex: rsdp_mr + acpi_add_rom_blob + acpi_ram_update
> 
I don’t follow.  Can you please elaborate?
>> +        VMSTATE_END_OF_LIST()
>> +    },
>> +};
>> +
>> +static void vmgenid_initfn(Object *obj)
>> +{
>> +    object_property_add_str(obj, VMGENID_GUID, NULL, vmgenid_set_guid, NULL);
>> +}
>> +
>> +static void vmgenid_device_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> +    dc->vmsd = &vmstate_vmgenid;
>> +}
>> +
>> +static const TypeInfo vmgenid_device_info = {
>> +    .name          = VMGENID_DEVICE,
>> +    .parent        = TYPE_SYS_BUS_DEVICE,
>> +    .instance_size = sizeof(VmGenIdState),
>> +    .instance_init = vmgenid_initfn,
>> +    .class_init    = vmgenid_device_class_init,
>> +};
>> +
>> +static void vmgenid_register_types(void)
>> +{
>> +    type_register_static(&vmgenid_device_info);
>> +}
>> +
>> +type_init(vmgenid_register_types)
>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>> index 78a1d84..4c40f76 100644
>> --- a/hw/i386/acpi-build.c
>> +++ b/hw/i386/acpi-build.c
>> @@ -42,6 +42,7 @@
>> #include "hw/acpi/memory_hotplug.h"
>> #include "sysemu/tpm.h"
>> #include "hw/acpi/tpm.h"
>> +#include "hw/acpi/vmgenid.h"
>> #include "sysemu/tpm_backend.h"
>> #include "hw/timer/mc146818rtc_regs.h"
>> #include "sysemu/numa.h"
>> @@ -2653,6 +2654,11 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
>>     acpi_add_table(table_offsets, tables_blob);
>>     build_madt(tables_blob, tables->linker, pcms);
>> 
>> +    if (find_vmgenid_dev(NULL)) {
>> +        acpi_add_table(table_offsets, tables_blob);
>> +        vmgenid_build_acpi(tables_blob, tables->vmgenid, tables->linker);
> pass find_vmgenid_dev(NULL) result as an argument to vmgenid_build_acpi()
> so it won't have to do lookup again.
> 
OK
>> +    }
>> +
>>     if (misc.has_hpet) {
>>         acpi_add_table(table_offsets, tables_blob);
>>         build_hpet(tables_blob, tables->linker);
>> @@ -2859,6 +2865,10 @@ void acpi_setup(void)
>>     fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
>>                     tables.tcpalog->data, acpi_data_len(tables.tcpalog));
>> 
>> +    if (find_vmgenid_dev(NULL)) {
> it's second lookup, cache result of the 1st call and reuse it here
> 
OK
>> +        vmgenid_add_fw_cfg(pcms->fw_cfg, tables.vmgenid);
>> +    }
>> +
>>     if (!pcmc->rsdp_in_ram) {
>>         /*
>>          * Keep for compatibility with old machine types.
>> diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h
>> index 71d3c48..3c2e4e9 100644
>> --- a/include/hw/acpi/acpi_dev_interface.h
>> +++ b/include/hw/acpi/acpi_dev_interface.h
>> @@ -11,6 +11,7 @@ typedef enum {
>>     ACPI_CPU_HOTPLUG_STATUS = 4,
>>     ACPI_MEMORY_HOTPLUG_STATUS = 8,
>>     ACPI_NVDIMM_HOTPLUG_STATUS = 16,
>> +    ACPI_VMGENID_CHANGE_STATUS = 32,
>> } AcpiEventStatusBits;
>> 
>> #define TYPE_ACPI_DEVICE_IF "acpi-device-interface"
>> diff --git a/include/hw/acpi/vmgenid.h b/include/hw/acpi/vmgenid.h
>> new file mode 100644
>> index 0000000..b60437a
>> --- /dev/null
>> +++ b/include/hw/acpi/vmgenid.h
>> @@ -0,0 +1,37 @@
>> +#ifndef ACPI_VMGENID_H
>> +#define ACPI_VMGENID_H
>> +
>> +#include "hw/acpi/bios-linker-loader.h"
>> +#include "hw/sysbus.h"
>> +#include "qemu/uuid.h"
>> +
>> +#define VMGENID_DEVICE           "vmgenid"
>> +#define VMGENID_GUID             "guid"
>> +#define VMGENID_GUID_FW_CFG_FILE      "etc/vmgenid"
>> +#define VMGENID_ADDR_FW_CFG_FILE      "etc/vmgenid_addr"
>> +
>> +#define VMGENID_FW_CFG_SIZE      4096 /* Occupy a page of memory */
>> +#define VMGENID_GUID_OFFSET      40   /* allow space for
>> +                                       * OVMF SDT Header Probe Supressor */
>> +
>> +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid);
>> +void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker *linker);
>> +
>> +#define VMGENID(obj) OBJECT_CHECK(VmGenIdState, (obj), VMGENID_DEVICE)
>> +
>> +typedef struct VmGenIdState {
>> +    SysBusDevice parent_obj;
> Could it work with just plain Device parent?
> If it works then you can drop patch:
>  [PATCH v5 08/10] PC: Support dynamic sysbus on pc_i440fx
> 
Huh, I was sure I tried that originally and couldn’t make it work, but it turns out it does.  Definitely better.
>> +    QemuUUID guid;
>> +    uint8_t vgia_le[4];
>> +} VmGenIdState;
>> +
>> +static Object *find_vmgenid_dev(Error **errp)
>> +{
>> +    Object *obj = object_resolve_path_type("", VMGENID_DEVICE, NULL);
>> +    if (!obj && errp) {
> all callers pass NULL as errp, I'd just drop errp altogether.
> 
OK
>> +        error_setg(errp, "%s is not found", VMGENID_DEVICE);
>> +    }
>> +    return obj;
>> +}
>> +
>> +#endif


[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 3583 bytes --]

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

* Re: [Qemu-devel] [PATCH v5 01/10] ACPI: Add a function for building named qword entries
  2017-02-08 10:53         ` Laszlo Ersek
@ 2017-02-08 20:24           ` Ben Warren
  0 siblings, 0 replies; 70+ messages in thread
From: Ben Warren @ 2017-02-08 20:24 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: Igor Mammedov, qemu-devel, mst

[-- Attachment #1: Type: text/plain, Size: 4201 bytes --]


> On Feb 8, 2017, at 2:53 AM, Laszlo Ersek <lersek@redhat.com> wrote:
> 
> On 02/08/17 11:43, Igor Mammedov wrote:
>> On Tue, 7 Feb 2017 21:09:27 +0100
>> Laszlo Ersek <lersek@redhat.com> wrote:
>> 
>>> On 02/07/17 14:51, Igor Mammedov wrote:
>>>> On Sun,  5 Feb 2017 01:11:56 -0800
>>>> ben@skyportsystems.com wrote:
>>>> 
>>>>> From: Ben Warren <ben@skyportsystems.com>
>>>>> 
>>>>> This is initially used to patch a 64-bit address into
>>>>> the VM Generation ID SSDT
>>>>> 
>>>>> Signed-off-by: Ben Warren <ben@skyportsystems.com>
>>>>> ---  
>>>> ...  
>>>>> +int
>>>>> +build_append_named_qword(GArray *array, const char *name_format, ...)  
>>>> it ain't used anywhere, I'd just drop this patch.  
>>> 
>>> Ben and I discussed this under
>>> - msgid <6E25852D-224A-4BDC-AA83-8DC87DB4D0F0@skyportsystems.com>
>>>  https://www.mail-archive.com/qemu-devel@nongnu.org/msg425496.html
>>> - msgid <a93a6be3-cbed-5afe-7c72-96410fbfce41@redhat.com>
>>>  https://www.mail-archive.com/qemu-devel@nongnu.org/msg425519.html
>>> 
>>> On 01/26/17 06:35, Ben Warren wrote:
>>>> I propose to still include this patch but touch up the comments as
>>>> requested by Laszlo.  This way it will be in the toolbox for future
>>>> users and has been tested.  [...]  
>>> 
>>> I generally agree that dead code is undesirable, but this function has
>>> surfaced several times until now, and we get to review it every single
>>> time. Ben tested it, I support its inclusion.
>>> 
>>> OTOH I also pointed it out to Ben
>>> 
>>> https://www.mail-archive.com/qemu-devel@nongnu.org/msg425218.html
>>> 
>>> that he should expect disagreement between his reviewers :) Given that
>>> I'm observing this series more from the sidelines and you maintain /
>>> support ACPI gen in QEMU, I certainly defer to you on this.
>> It's not only dead, having patchable QWORD ready for use in QEMU
>> would tempt someone to use it and that would lead to XP BSOD
>> if it slips screening at review time.
> 
> Good point.
> 
>> I'd delay this patch until
>> we announce that ACPI 1.0 (XP based) guest no more supported by
>> new QEMU.
>> 
>> Anyway I won't object to merging this if you insist and give it your RB.
> 
> No, you are entirely right. As long as we consider Windows XP guests
> first class citizens (i.e., we even reject the idea of additional
> command line options), then keeping QWORD "out of sight" is safer.
> 
> Follow up question: when are we going to drop Windows XP? Do we have a
> plan? :) It's quite a struggle to support both ends of the spectrum with
> the same machine types and options (decades-old DOS and Windows XP vs.
> supercomputer-class NUMA setups). I think this limits development.
> 
> (Just curious; I'm not suggesting to drop Windows XP "soon".)
> 
> Thanks!
> Laszlo
> 
OK, I’ll drop this patch from the set.  I guess it will always be around if we want to resurrect.
> 
>>> 
>>> 
>>>>> +{
>>>>> +    int offset;
>>>>> +    va_list ap;
>>>>> +
>>>>> +    build_append_byte(array, 0x08); /* NameOp */
>>>>> +    va_start(ap, name_format);
>>>>> +    build_append_namestringv(array, name_format, ap);
>>>>> +    va_end(ap);
>>>>> +
>>>>> +    build_append_byte(array, 0x0E); /* QWordPrefix */
>>>>> +
>>>>> +    offset = array->len;
>>>>> +    build_append_int_noprefix(array, 0x0000000000000000, 8);
>>>>> +    assert(array->len == offset + 8);
>>>>> +
>>>>> +    return offset;
>>>>> +}
>>>>> +
>>>>> static GPtrArray *alloc_list;
>>>>> 
>>>>> static Aml *aml_alloc(void)
>>>>> diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
>>>>> index 559326c..dbf63cf 100644
>>>>> --- a/include/hw/acpi/aml-build.h
>>>>> +++ b/include/hw/acpi/aml-build.h
>>>>> @@ -385,6 +385,10 @@ int
>>>>> build_append_named_dword(GArray *array, const char *name_format, ...)
>>>>> GCC_FMT_ATTR(2, 3);
>>>>> 
>>>>> +int
>>>>> +build_append_named_qword(GArray *array, const char *name_format, ...)
>>>>> +GCC_FMT_ATTR(2, 3);
>>>>> +
>>>>> void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
>>>>>                        uint64_t len, int node, MemoryAffinityFlags flags);


[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 3583 bytes --]

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

* Re: [Qemu-devel] [PATCH v5 07/10] qmp/hmp: add set-vm-generation-id commands
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 07/10] qmp/hmp: add set-vm-generation-id commands ben
  2017-02-07 13:50   ` Igor Mammedov
@ 2017-02-08 22:01   ` Laszlo Ersek
  1 sibling, 0 replies; 70+ messages in thread
From: Laszlo Ersek @ 2017-02-08 22:01 UTC (permalink / raw)
  To: ben, qemu-devel; +Cc: imammedo, mst

On 02/05/17 10:12, ben@skyportsystems.com wrote:
> From: Igor Mammedov <imammedo@redhat.com>
> 
> Add set-vm-generation-id command to set Virtual Machine
> Generation ID counter.
> 
> QMP command example:
>     { "execute": "set-vm-generation-id",
>           "arguments": {
>               "guid": "324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87"
>           }
>     }
> 
> HMP command example:
>     set-vm-generation-id guid=324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87
> 
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> Signed-off-by: Ben Warren <ben@skyportsystems.com>
> ---
>  hmp-commands.hx   | 13 +++++++++++++
>  hmp.c             | 12 ++++++++++++
>  hmp.h             |  1 +
>  hw/acpi/vmgenid.c | 12 ++++++++++++
>  qapi-schema.json  | 11 +++++++++++
>  stubs/vmgenid.c   |  6 ++++++
>  6 files changed, 55 insertions(+)
> 
> diff --git a/hmp-commands.hx b/hmp-commands.hx
> index 8819281..56744aa 100644
> --- a/hmp-commands.hx
> +++ b/hmp-commands.hx
> @@ -1775,5 +1775,18 @@ ETEXI
>      },
>  
>  STEXI
> +@item set-vm-generation-id @var{uuid}
> +Set Virtual Machine Generation ID counter to @var{guid}
> +ETEXI
> +
> +    {
> +        .name       = "set-vm-generation-id",
> +        .args_type  = "guid:s",
> +        .params     = "guid",
> +        .help       = "Set Virtual Machine Generation ID counter",
> +        .cmd = hmp_set_vm_generation_id,
> +    },
> +
> +STEXI
>  @end table
>  ETEXI
> diff --git a/hmp.c b/hmp.c
> index 535613d..39c8965 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -2574,3 +2574,15 @@ void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict)
>      }
>      qapi_free_GuidInfo(info);
>  }
> +
> +void hmp_set_vm_generation_id(Monitor *mon, const QDict *qdict)
> +{
> +    Error *errp = NULL;
> +    const char *guid = qdict_get_str(qdict, "guid");
> +
> +    qmp_set_vm_generation_id(guid, &errp);
> +    if (errp) {
> +        hmp_handle_error(mon, &errp);
> +        return;

This return statement is superfluous.

> +    }
> +}
> diff --git a/hmp.h b/hmp.h
> index 799fd37..e0ac1e8 100644
> --- a/hmp.h
> +++ b/hmp.h
> @@ -138,5 +138,6 @@ void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict);
>  void hmp_info_dump(Monitor *mon, const QDict *qdict);
>  void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict);
>  void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict);
> +void hmp_set_vm_generation_id(Monitor *mon, const QDict *qdict);
>  
>  #endif
> diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
> index e148051..af8b35c 100644
> --- a/hw/acpi/vmgenid.c
> +++ b/hw/acpi/vmgenid.c
> @@ -224,3 +224,15 @@ GuidInfo *qmp_query_vm_generation_id(Error **errp)
>      info->guid = qemu_uuid_unparse_strdup(&guid);
>      return info;
>  }
> +
> +void qmp_set_vm_generation_id(const char *guid, Error **errp)
> +{
> +    Object *obj = find_vmgenid_dev(errp);
> +
> +    if (!obj) {
> +        return;
> +    }
> +
> +    object_property_set_str(obj, guid, VMGENID_GUID, errp);
> +    return;

This too.

> +}
> diff --git a/qapi-schema.json b/qapi-schema.json
> index 384a7f3..ed2657d 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -6051,3 +6051,14 @@
>  # Since 2.9
>  ##
>  { 'command': 'query-vm-generation-id', 'returns': 'GuidInfo' }
> +
> +##
> +# @set-vm-generation-id:
> +#
> +# Set Virtual Machine Generation ID
> +#
> +# @guid: new GUID to set as Virtual Machine Generation ID
> +#
> +# Since 2.9
> +##
> +{ 'command': 'set-vm-generation-id', 'data': {'guid': 'str'} }
> diff --git a/stubs/vmgenid.c b/stubs/vmgenid.c
> index 8c448ac..d25d41b 100644
> --- a/stubs/vmgenid.c
> +++ b/stubs/vmgenid.c
> @@ -6,3 +6,9 @@ GuidInfo *qmp_query_vm_generation_id(Error **errp)
>      error_setg(errp, "this command is not currently supported");
>      return NULL;
>  }
> +
> +void qmp_set_vm_generation_id(const char *guid, Error **errp)
> +{
> +    error_setg(errp, "this command is not currently supported");
> +    return;

And this.

Thanks,
Laszlo

> +}
> 

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-08  0:48   ` Laszlo Ersek
  2017-02-08 11:04     ` Igor Mammedov
@ 2017-02-08 22:34     ` Ben Warren
  2017-02-08 23:43       ` Laszlo Ersek
  2017-02-09 17:23     ` Igor Mammedov
  2 siblings, 1 reply; 70+ messages in thread
From: Ben Warren @ 2017-02-08 22:34 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: Igor Mammedov, Michael S. Tsirkin, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 11720 bytes --]


> On Feb 7, 2017, at 4:48 PM, Laszlo Ersek <lersek@redhat.com> wrote:
> 
> On 02/05/17 10:12, ben@skyportsystems.com <mailto:ben@skyportsystems.com> wrote:
>> From: Ben Warren <ben@skyportsystems.com>
>> 
>> This implements the VM Generation ID feature by passing a 128-bit
>> GUID to the guest via a fw_cfg blob.
>> Any time the GUID changes, an ACPI notify event is sent to the guest
>> 
>> The user interface is a simple device with one parameter:
>> - guid (string, must be "auto" or in UUID format
>>   xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
>> 
>> Signed-off-by: Ben Warren <ben@skyportsystems.com>
>> ---
>> default-configs/i386-softmmu.mak     |   1 +
>> default-configs/x86_64-softmmu.mak   |   1 +
>> hw/acpi/Makefile.objs                |   1 +
>> hw/acpi/vmgenid.c                    | 206 +++++++++++++++++++++++++++++++++++
>> hw/i386/acpi-build.c                 |  10 ++
>> include/hw/acpi/acpi_dev_interface.h |   1 +
>> include/hw/acpi/vmgenid.h            |  37 +++++++
>> 7 files changed, 257 insertions(+)
>> create mode 100644 hw/acpi/vmgenid.c
>> create mode 100644 include/hw/acpi/vmgenid.h
> 
> [snip code]
> 
> So, I'm late to the game. I can't possibly comment on all the concerns
> that have been raised scattered around the thread, exactly *where* they
> have been raised. However, I will try to collect the concerns here.
> 
> 
> (1) Byte swapping for the UUID.
> 
> The idea of QemuUUID is that wherever it is stored in a non-ephemeral
> fashion, it is in BE representation. The guest needs it in LE, so we
> should convert it temporarily -- using a local variable -- just before
> writing it to guest memory, and then forget about the LE representation
> promptly.
> 
> As far as I understand, we all agree on this (Michael, Ben, myself -- I
> think Igor hasn't commented on this).
> 
> 
Sure, will rework.
> (2) Structure of the vmgenid fw_cfg blob, AKA "why that darn offset 40
> decimal".
> 
> I explained it under points (6) and (7) in the following message:
> 
> Message-Id: <c16a03d5-820a-f719-81ea-43858f903395@redhat.com <mailto:c16a03d5-820a-f719-81ea-43858f903395@redhat.com>>
> URL: https://www.mail-archive.com/qemu-devel@nongnu.org/msg425226.html <https://www.mail-archive.com/qemu-devel@nongnu.org/msg425226.html>
> 
> The story is that *wherever* an ADD_POINTER command points to -- that
> is, at the *exact* target address --, OVMF will look for an ACPI table
> header, somewhat heuristically. If it finds a byte pattern that (a) fits
> into the remaining blob and (b) passes some superficial ACPI table
> header checks, such as length and checksum, then OVMF assumes that the
> blob contains an ACPI table there, and passes the address (again, the
> exact, relocated, absolute target address of ADD_POINTER) to
> EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable().
> 
> We want to disable this heuristic for the vmgenid blob. *If* the blob
> contained only 16 bytes (for the GUID), then the heuristic would
> automatically disable itself, because the ACPI table header (36 bytes)
> is larger than 16 bytes, so OVMF wouldn't even look. However, for the
> caching and other VMGENID requirements, we need to allocate a full page
> with the blob (4KB), hence OVMF *will* look. If we placed the GUID right
> at the start of the page, then OVMF would sanity-check it as an ACPI
> table header. The check would *most likely* not pass, so things would be
> fine in practice, but we can do better than that: just put 40 zero bytes
> at the front of the blob.
> 
> And this is why the ADD_POINTER command has to point to the beginning of
> the blob (i.e., 36 zero bytes), to "suppress the OVMF ACPI SDT header
> detection". (The other 4 bytes are for arriving at an address divisible
> by 8, which is a VMGENID requirement for the GUID.)
> 
> The consequence is that both the ADDR method and QEMU's guest memory
> access code have to add 40 manually.
> 
Igor has recommended that I have the add_pointer() call that patches AML have an offset of 40 from the start of the source file, which will result in the VGIA AML variable pointing to the GUID, not offset by 40.  I assume this isn’t a problem for you, but please confirm.
> 
> (3) Whether the VGIA named object should be a DWORD or a QWORD in ACPI.
> Personally, I'm fine with either, but I see that DWORD is more
> compatible with old OSes.
> 
> What I really care about though is the new WRITE_POINTER command
> structure. That should support 8 bytes as well.
> 
> So this is exactly how Michael summarized it ultimately:
> - use a DWORD for VGIA in ACPI,
> - with a matching 4-byte wide ADD_POINTER command;
> - write the address with a 4-byte wide WRITE_POINTER command into
>  fw_cfg,
> - *but* the WRITE_POINTER command struct should support 8-byte as well,
> - and the fw_cfg file that is written (vmgenid_addr) should have size 8
>  from the start. (The guest will simply write offsets 0..3 inclusive,
>  in LE byte order.)
> 
This is an easy change, WRITE_POINTER already supports 8-byte writes.
> 
> (4) IIRC Igor asked if sizing the blob to 4KB would guarantee that the
> GUID ends up in a cacheable page -- yes (see also Michael's followup).
> This size guarantees that the GUID will have a full page to itself, and
> its allocated from normal guest RAM, as Reserved memory (SeaBIOS, IIRC)
> or EfiACPIMemoryNVS memory (OVMF).
> 
> Note that the VMGENID spec says, in ACPI terms, "It must not be in
> ranges reported as AddressRangeMemory or AddressRangeACPI", but that's fine:
> 
> ACPI speak           UEFI speak            suitable for VMGENID?
> ------------------   --------------------- ---------------------
> AddressRangeMemory   EfiConventionalMemory no
> AddressRangeACPI     EfiACPIReclaimMemory  no
> AddressRangeNVS      EfiACPIMemoryNVS      yes, used by OVMF
> AddressRangeReserved EfiReservedMemoryType yes, used by SeaBIOS
> 
> 
> (5) The race and fw_cfg callbacks.
> 
> (a) Michael and Ben identified a problem where
> - QEMU places the initial GUID in the "vmgenid" fw_cfg blob,
> - the guest downloads it,
> - the host admin changes the GUID via the monitor,
> - and the guest writes the address to "vmgenid_addr" *only* after that.
> 
> In other words, the monitor action occurs between the guest's processing
> of the ALLOCATE and WRITE_POINTER linker/loader commands.
> 
> (b) A similar problem is rebooting the guest.
> - The guest starts up fine,
> - the OS runs,
> - the host admin changes the GUID via the monitor,
> - and the guest sees the update fine.
> - At this point the guest is rebooted (within the same QEMU instance).
> 
> Since the fw_cfg blob is not rebuilt -- more precisely, the blob *is*
> rebuilt, but it is then thrown away in acpi_build_update() --, the guest
> will see a different GUID from the last value set on the monitor. (And
> querying the monitor will actually return that last-set value, which is
> no longer known by the guest.)
> 
> 
> The suggestion for these problems was to add a callback to "one" of the
> fw_cfg files in question.
> 
> Let's investigate the writeable "vmgenid_addr" file first. Here the idea
> is to rewrite the GUID in guest RAM as soon as the address is known from
> the guest, regardless of what GUID the guest placed there originally,
> through downloading the "vmgenid" blob.
> 
> (i) We have no write callbacks at the moment. Before we removed the data
> port based write support in QEMU 2.4, the write callback used to be
> invoked when the end of the fw_cfg blob was reached. Since we intend to
> pack several addresses in the same writeable fw_cfg blob down the road,
> at different offsets, this method wouldn't work; the final offset in the
> blob might not be reached at all. (Another thing that wouldn't work is
> an 8-byte writeable fw_cfg blob, and a 4-byte WRITE_POINTER command that
> only rewrites offsets 0..3 inclusve -- see (3) above.)
> 
> So I don't think that a write callback is viable, at least with the
> "many addresses at different offsets in the same blob" feature. Unless
> we want to register different callbacks (or different callback
> arguments) for different offsets. And then a large write could trigger a
> series of callbacks, even, if it covers several special offsets. This
> looks too complex to me.
> 
> (ii) What we do have now is a select callback. Unfortunately, the guest
> is not required to select the item and atomically rewrite the blob, in
> the same fw_cfg DMA operation. The guest is allowed to do the selection
> with the IO port method, and then write the blob separately with DMA.
> (This is what OVMF does.) IOW, when we'd get the callback (for the
> select), the address would not have been written yet.
> 
> So I don't think that a select callback for the writeable "vmgenid_addr"
> file is viable either.
> 
> (iii) Let's see a select callback for the "vmgenid" blob itself! The
> idea is, whenever the guest selects this blob, immediately refresh the
> blob from the last set GUID. Then let the guest download the
> just-refreshed blob.
> 
I like this approach, and have it working.  I assume by “refresh the blob” you mean making a call to fw_cfg_modify_file().  If that is the case, I need to modify the function fw_cfg_modify_bytes_read() because of the following commented-out problem lines (656:657 in fw_cfg.c):

    /* return the old data to the function caller, avoid memory leak */
    ptr = s->entries[arch][key].data;
    s->entries[arch][key].data = data;
    s->entries[arch][key].len = len;
//    s->entries[arch][key].callback_opaque = NULL;
//    s->entries[arch][key].allow_write = false;

As you can see, this function modifies not only a fw_cfg object’s data, but also its metadata, wiping out the callback parameter and forcing it to read-only.  I don’t know the history of this function, so want to tread lightly.  The second parameter doesn’t impact me, since this fw_cfg object is read-only, but the callback parameter one does.

> The main observation here is that we can *fail* QMP commands. That's
> good enough if we can tell *when* to fail them.
> 
> Under this idea, we would fail the "set-vm-generation-id" QMP command
> with "EAGAIN" if the quest had selected the "vmgenid" blob since machine
> reset -- this can be tracked with a latch -- *but* the particular offset
> range in the "vmgenid_addr" blob were still zero.
> 
> This is exactly the window between the ALLOCATE and WRITE_POINTER
> commands where updates from the monitor would be lost. So let's just
> tell the management layer to try again later (like 1 second later). By
> that time, any sane guest will have written the address into "vmgenid_addr”.
> 
This seems sane.  I’ll just return EAGAIN if vmgenid_addr is zero, meaning the guest is not fully synchronized yet so don’t accept input.

One other more radical idea I had was to just remove the monitor GUID modification capability completely.  The VM Generation ID needs to change only in the following situations:
- new VM (command line processed)
- start from snapshot (command line processed, VGIA restored from VmState.
- VM recovered from backup (like a new VM, command line processed).
- VM imported, copied or cloned (like a new VM, command line processed).
- failed over from a disaster recovery environment.  Here I’m not sure. It’s possible I suppose that one would have a DR VM in hot standby, but would want to change its VM Generation ID in order to force Windows to re-synchronize Active Directory, crypto seeds etc.  Here the monitor might be necessary.

> Thanks
> Laszlo


[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 3583 bytes --]

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-08 22:34     ` Ben Warren
@ 2017-02-08 23:43       ` Laszlo Ersek
  0 siblings, 0 replies; 70+ messages in thread
From: Laszlo Ersek @ 2017-02-08 23:43 UTC (permalink / raw)
  To: Ben Warren; +Cc: Igor Mammedov, Michael S. Tsirkin, qemu-devel

On 02/08/17 23:34, Ben Warren wrote:
> 
>> On Feb 7, 2017, at 4:48 PM, Laszlo Ersek <lersek@redhat.com
>> <mailto:lersek@redhat.com>> wrote:
>>
>> On 02/05/17 10:12, ben@skyportsystems.com
>> <mailto:ben@skyportsystems.com> wrote:
>>> From: Ben Warren <ben@skyportsystems.com <mailto:ben@skyportsystems.com>>
>>>
>>> This implements the VM Generation ID feature by passing a 128-bit
>>> GUID to the guest via a fw_cfg blob.
>>> Any time the GUID changes, an ACPI notify event is sent to the guest
>>>
>>> The user interface is a simple device with one parameter:
>>> - guid (string, must be "auto" or in UUID format
>>>   xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
>>>
>>> Signed-off-by: Ben Warren <ben@skyportsystems.com
>>> <mailto:ben@skyportsystems.com>>
>>> ---
>>> default-configs/i386-softmmu.mak     |   1 +
>>> default-configs/x86_64-softmmu.mak   |   1 +
>>> hw/acpi/Makefile.objs                |   1 +
>>> hw/acpi/vmgenid.c                    | 206
>>> +++++++++++++++++++++++++++++++++++
>>> hw/i386/acpi-build.c                 |  10 ++
>>> include/hw/acpi/acpi_dev_interface.h |   1 +
>>> include/hw/acpi/vmgenid.h            |  37 +++++++
>>> 7 files changed, 257 insertions(+)
>>> create mode 100644 hw/acpi/vmgenid.c
>>> create mode 100644 include/hw/acpi/vmgenid.h
>>
>> [snip code]
>>
>> So, I'm late to the game. I can't possibly comment on all the concerns
>> that have been raised scattered around the thread, exactly *where* they
>> have been raised. However, I will try to collect the concerns here.
>>
>>
>> (1) Byte swapping for the UUID.
>>
>> The idea of QemuUUID is that wherever it is stored in a non-ephemeral
>> fashion, it is in BE representation. The guest needs it in LE, so we
>> should convert it temporarily -- using a local variable -- just before
>> writing it to guest memory, and then forget about the LE representation
>> promptly.
>>
>> As far as I understand, we all agree on this (Michael, Ben, myself -- I
>> think Igor hasn't commented on this).
>>
>>
> Sure, will rework.
>> (2) Structure of the vmgenid fw_cfg blob, AKA "why that darn offset 40
>> decimal".
>>
>> I explained it under points (6) and (7) in the following message:
>>
>> Message-Id: <c16a03d5-820a-f719-81ea-43858f903395@redhat.com
>> <mailto:c16a03d5-820a-f719-81ea-43858f903395@redhat.com>>
>> URL: https://www.mail-archive.com/qemu-devel@nongnu.org/msg425226.html
>>
>> The story is that *wherever* an ADD_POINTER command points to -- that
>> is, at the *exact* target address --, OVMF will look for an ACPI table
>> header, somewhat heuristically. If it finds a byte pattern that (a) fits
>> into the remaining blob and (b) passes some superficial ACPI table
>> header checks, such as length and checksum, then OVMF assumes that the
>> blob contains an ACPI table there, and passes the address (again, the
>> exact, relocated, absolute target address of ADD_POINTER) to
>> EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable().
>>
>> We want to disable this heuristic for the vmgenid blob. *If* the blob
>> contained only 16 bytes (for the GUID), then the heuristic would
>> automatically disable itself, because the ACPI table header (36 bytes)
>> is larger than 16 bytes, so OVMF wouldn't even look. However, for the
>> caching and other VMGENID requirements, we need to allocate a full page
>> with the blob (4KB), hence OVMF *will* look. If we placed the GUID right
>> at the start of the page, then OVMF would sanity-check it as an ACPI
>> table header. The check would *most likely* not pass, so things would be
>> fine in practice, but we can do better than that: just put 40 zero bytes
>> at the front of the blob.
>>
>> And this is why the ADD_POINTER command has to point to the beginning of
>> the blob (i.e., 36 zero bytes), to "suppress the OVMF ACPI SDT header
>> detection". (The other 4 bytes are for arriving at an address divisible
>> by 8, which is a VMGENID requirement for the GUID.)
>>
>> The consequence is that both the ADDR method and QEMU's guest memory
>> access code have to add 40 manually.
>>
> Igor has recommended that I have the add_pointer() call that patches AML
> have an offset of 40 from the start of the source file, which will
> result in the VGIA AML variable pointing to the GUID, not offset by 40.
>  I assume this isn’t a problem for you, but please confirm.

No, that would be a problem. The explanation as to why is right above.

Please process the rest of this sub-thread; Igor has agreed that my
request makes sense, he'd just like to see the reasoning behind it
documented:

http://lists.nongnu.org/archive/html/qemu-devel/2017-02/msg01640.html

To which I suggested that you please capture the above argument in a new
subsection in the docs file:

http://lists.nongnu.org/archive/html/qemu-devel/2017-02/msg01642.html

To which Igor replied that we should reference that documentation from
the exact spot in the code, where 40 decimal is added:

http://lists.nongnu.org/archive/html/qemu-devel/2017-02/msg01647.html

That's apparently our agreement on this. :)

>>
>> (3) Whether the VGIA named object should be a DWORD or a QWORD in ACPI.
>> Personally, I'm fine with either, but I see that DWORD is more
>> compatible with old OSes.
>>
>> What I really care about though is the new WRITE_POINTER command
>> structure. That should support 8 bytes as well.
>>
>> So this is exactly how Michael summarized it ultimately:
>> - use a DWORD for VGIA in ACPI,
>> - with a matching 4-byte wide ADD_POINTER command;
>> - write the address with a 4-byte wide WRITE_POINTER command into
>>  fw_cfg,
>> - *but* the WRITE_POINTER command struct should support 8-byte as well,
>> - and the fw_cfg file that is written (vmgenid_addr) should have size 8
>>  from the start. (The guest will simply write offsets 0..3 inclusive,
>>  in LE byte order.)
>>
> This is an easy change, WRITE_POINTER already supports 8-byte writes.
>>
>> (4) IIRC Igor asked if sizing the blob to 4KB would guarantee that the
>> GUID ends up in a cacheable page -- yes (see also Michael's followup).
>> This size guarantees that the GUID will have a full page to itself, and
>> its allocated from normal guest RAM, as Reserved memory (SeaBIOS, IIRC)
>> or EfiACPIMemoryNVS memory (OVMF).
>>
>> Note that the VMGENID spec says, in ACPI terms, "It must not be in
>> ranges reported as AddressRangeMemory or AddressRangeACPI", but that's
>> fine:
>>
>> ACPI speak           UEFI speak            suitable for VMGENID?
>> ------------------   --------------------- ---------------------
>> AddressRangeMemory   EfiConventionalMemory no
>> AddressRangeACPI     EfiACPIReclaimMemory  no
>> AddressRangeNVS      EfiACPIMemoryNVS      yes, used by OVMF
>> AddressRangeReserved EfiReservedMemoryType yes, used by SeaBIOS
>>
>>
>> (5) The race and fw_cfg callbacks.
>>
>> (a) Michael and Ben identified a problem where
>> - QEMU places the initial GUID in the "vmgenid" fw_cfg blob,
>> - the guest downloads it,
>> - the host admin changes the GUID via the monitor,
>> - and the guest writes the address to "vmgenid_addr" *only* after that.
>>
>> In other words, the monitor action occurs between the guest's processing
>> of the ALLOCATE and WRITE_POINTER linker/loader commands.
>>
>> (b) A similar problem is rebooting the guest.
>> - The guest starts up fine,
>> - the OS runs,
>> - the host admin changes the GUID via the monitor,
>> - and the guest sees the update fine.
>> - At this point the guest is rebooted (within the same QEMU instance).
>>
>> Since the fw_cfg blob is not rebuilt -- more precisely, the blob *is*
>> rebuilt, but it is then thrown away in acpi_build_update() --, the guest
>> will see a different GUID from the last value set on the monitor. (And
>> querying the monitor will actually return that last-set value, which is
>> no longer known by the guest.)
>>
>>
>> The suggestion for these problems was to add a callback to "one" of the
>> fw_cfg files in question.
>>
>> Let's investigate the writeable "vmgenid_addr" file first. Here the idea
>> is to rewrite the GUID in guest RAM as soon as the address is known from
>> the guest, regardless of what GUID the guest placed there originally,
>> through downloading the "vmgenid" blob.
>>
>> (i) We have no write callbacks at the moment. Before we removed the data
>> port based write support in QEMU 2.4, the write callback used to be
>> invoked when the end of the fw_cfg blob was reached. Since we intend to
>> pack several addresses in the same writeable fw_cfg blob down the road,
>> at different offsets, this method wouldn't work; the final offset in the
>> blob might not be reached at all. (Another thing that wouldn't work is
>> an 8-byte writeable fw_cfg blob, and a 4-byte WRITE_POINTER command that
>> only rewrites offsets 0..3 inclusve -- see (3) above.)
>>
>> So I don't think that a write callback is viable, at least with the
>> "many addresses at different offsets in the same blob" feature. Unless
>> we want to register different callbacks (or different callback
>> arguments) for different offsets. And then a large write could trigger a
>> series of callbacks, even, if it covers several special offsets. This
>> looks too complex to me.
>>
>> (ii) What we do have now is a select callback. Unfortunately, the guest
>> is not required to select the item and atomically rewrite the blob, in
>> the same fw_cfg DMA operation. The guest is allowed to do the selection
>> with the IO port method, and then write the blob separately with DMA.
>> (This is what OVMF does.) IOW, when we'd get the callback (for the
>> select), the address would not have been written yet.
>>
>> So I don't think that a select callback for the writeable "vmgenid_addr"
>> file is viable either.
>>
>> (iii) Let's see a select callback for the "vmgenid" blob itself! The
>> idea is, whenever the guest selects this blob, immediately refresh the
>> blob from the last set GUID. Then let the guest download the
>> just-refreshed blob.
>>
> I like this approach, and have it working.

Cool! :)

> I assume by “refresh the
> blob” you mean making a call to fw_cfg_modify_file().  If that is the
> case, I need to modify the function fw_cfg_modify_bytes_read() because
> of the following commented-out problem lines (656:657 in fw_cfg.c):
> 
>     /* return the old data to the function caller, avoid memory leak */
>     ptr = s->entries[arch][key].data;
>     s->entries[arch][key].data = data;
>     s->entries[arch][key].len = len;
> //    s->entries[arch][key].callback_opaque = NULL;
> //    s->entries[arch][key].allow_write = false;
> 
> As you can see, this function modifies not only a fw_cfg object’s data,
> but also its metadata, wiping out the callback parameter and forcing it
> to read-only.  I don’t know the history of this function, so want to
> tread lightly.  The second parameter doesn’t impact me, since this
> fw_cfg object is read-only, but the callback parameter one does.

It is justified to tread lightly :), because you really don't need to
call fw_cfg_modify_file().

Instead, in vmgenid_add_fw_cfg(), please do this:

diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
index af8b35cebbe7..3860e9717e12 100644
--- a/hw/acpi/vmgenid.c
+++ b/hw/acpi/vmgenid.c
@@ -111,6 +111,8 @@ void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid)
     assert(obj);
     VmGenIdState *vms = VMGENID(obj);

+    vms->guid_blob = guid->data;
+
     /* Create a read-only fw_cfg file for GUID */
     fw_cfg_add_file(s, VMGENID_GUID_FW_CFG_FILE, guid->data,
                     VMGENID_FW_CFG_SIZE);

and then, whenever necessary, you can poke the GUID right into
"vms->guid_blob" (i.e., the fw_cfg data), at the appropriate offset
(40). No reallocation / metadata changes are necessary.

However, this means that you have to extend vmgenid_post_load() *too*,
with the same fw_cfg blob update. (You don't have to migrate the blob,
it is a whole bunch of zeroes with a GUID in the middle that has to be
refreshed on the target host anyway.)

> 
>> The main observation here is that we can *fail* QMP commands. That's
>> good enough if we can tell *when* to fail them.
>>
>> Under this idea, we would fail the "set-vm-generation-id" QMP command
>> with "EAGAIN" if the quest had selected the "vmgenid" blob since machine
>> reset -- this can be tracked with a latch -- *but* the particular offset
>> range in the "vmgenid_addr" blob were still zero.
>>
>> This is exactly the window between the ALLOCATE and WRITE_POINTER
>> commands where updates from the monitor would be lost. So let's just
>> tell the management layer to try again later (like 1 second later). By
>> that time, any sane guest will have written the address into
>> "vmgenid_addr”.
>>
> This seems sane.  I’ll just return EAGAIN if vmgenid_addr is zero,
> meaning the guest is not fully synchronized yet so don’t accept input.

Right, it means that the guest is temporarily in a state where it cannot
accept a new GUID.

Regarding the error structure -- we have structured errors! --, please
don't use error_setg(), nor error_setg_errno(). "EAGAIN" above was just
an example. Both of the aforementioned functions format an
ERROR_CLASS_GENERIC_ERROR, which is not really useful for libvirt if
libvirt wants to treat this condition specially.

Instead, we have another error class that looks appropriate:
ERROR_CLASS_DEVICE_NOT_ACTIVE. If you grep the source for it, you'll
find two independent users, which is (IMO) license to use it for our
purposes as well.

    error_set(errp, ERROR_CLASS_DEVICE_NOT_ACTIVE,
              "<format-string>", arguments ...);

See also "@DeviceNotActive" under "@QapiErrorClass" in "qapi/common.json".

If you grep the libvirt source code for "DeviceNotActive", there are
several hits (with custom error handling) in "src/qemu/qemu_monitor_json.c".

> 
> One other more radical idea I had was to just remove the monitor GUID
> modification capability completely.

You are going to laugh, but this was actually what I was about to
suggest while writing the email you've just replied to :)

I could not figure out *why* the management layer would want to change
the VMGUID for an already running domain. Generate a random one at
startup, or at incoming migration (hence, on the command line!), which
also covers restart from snapshot I guess, is fully justified, but why
mess with it otherwise? Where does this requirement come from?

In the docs patch, you mention Hyper-V and Xen as other VMMs that
support vmgenid. I didn't look into Hyper-V, but googling Xen, it looked
like they had a similar management interface (for runtime). At that
point I said to myself, "okay, so this is for 'feature parity' for all I
know", and deleted like three paragraphs :)

>  The VM Generation ID needs to
> change only in the following situations:
> - new VM (command line processed)
> - start from snapshot (command line processed, VGIA restored from VmState.

(this is also "incoming migration")

> - VM recovered from backup (like a new VM, command line processed).
> - VM imported, copied or cloned (like a new VM, command line processed).
> - failed over from a disaster recovery environment.  Here I’m not sure.
> It’s possible I suppose that one would have a DR VM in hot standby, but
> would want to change its VM Generation ID in order to force Windows to
> re-synchronize Active Directory, crypto seeds etc.  Here the monitor
> might be necessary.

Well, I really don't know. I guess we can follow approach (iii), just to
be safe.

Thanks!
Laszlo

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support ben
                     ` (2 preceding siblings ...)
  2017-02-08  0:48   ` Laszlo Ersek
@ 2017-02-09  0:37   ` Laszlo Ersek
  3 siblings, 0 replies; 70+ messages in thread
From: Laszlo Ersek @ 2017-02-09  0:37 UTC (permalink / raw)
  To: ben, qemu-devel; +Cc: imammedo, mst

On 02/05/17 10:12, ben@skyportsystems.com wrote:
> From: Ben Warren <ben@skyportsystems.com>
> 
> This implements the VM Generation ID feature by passing a 128-bit
> GUID to the guest via a fw_cfg blob.
> Any time the GUID changes, an ACPI notify event is sent to the guest
> 
> The user interface is a simple device with one parameter:
>  - guid (string, must be "auto" or in UUID format
>    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
> 
> Signed-off-by: Ben Warren <ben@skyportsystems.com>
> ---
>  default-configs/i386-softmmu.mak     |   1 +
>  default-configs/x86_64-softmmu.mak   |   1 +
>  hw/acpi/Makefile.objs                |   1 +
>  hw/acpi/vmgenid.c                    | 206 +++++++++++++++++++++++++++++++++++
>  hw/i386/acpi-build.c                 |  10 ++
>  include/hw/acpi/acpi_dev_interface.h |   1 +
>  include/hw/acpi/vmgenid.h            |  37 +++++++
>  7 files changed, 257 insertions(+)
>  create mode 100644 hw/acpi/vmgenid.c
>  create mode 100644 include/hw/acpi/vmgenid.h

[snip]


> +static void vmgenid_device_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->vmsd = &vmstate_vmgenid;
> +}

I think in this function, you should set up a dc->realize member as
well. And, in that dc->realize member, you should call
qemu_register_reset().

Because, as it stands now, the "vgia_le" field is not cleared on reset.
It should be; when the guest is rebooted, we should forget any address
returned by its firmware.

In this reset callback, you should also clear the (new) latch that
tracks whether the "vmgenid" blob was selected since reset. (The latch
is for approach (iii) against the race.)

Thanks,
Laszlo

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-08 20:19     ` Ben Warren
@ 2017-02-09  9:59       ` Igor Mammedov
  0 siblings, 0 replies; 70+ messages in thread
From: Igor Mammedov @ 2017-02-09  9:59 UTC (permalink / raw)
  To: Ben Warren; +Cc: qemu-devel, lersek, mst

On Wed, 8 Feb 2017 12:19:24 -0800
Ben Warren <ben@skyportsystems.com> wrote:

> Thanks for reviewing Igor.
> 
> > On Feb 7, 2017, at 5:48 AM, Igor Mammedov <imammedo@redhat.com> wrote:
> > 
> > On Sun,  5 Feb 2017 01:12:00 -0800
> > ben@skyportsystems.com <mailto:ben@skyportsystems.com> wrote:
> > 
> >> From: Ben Warren <ben@skyportsystems.com>
> >> 
> >> This implements the VM Generation ID feature by passing a 128-bit
> >> GUID to the guest via a fw_cfg blob.
> >> Any time the GUID changes, an ACPI notify event is sent to the guest
> >> 
> >> The user interface is a simple device with one parameter:
> >> - guid (string, must be "auto" or in UUID format
> >>   xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
> >> 
> >> Signed-off-by: Ben Warren <ben@skyportsystems.com>
> >> ---
> >> default-configs/i386-softmmu.mak     |   1 +
> >> default-configs/x86_64-softmmu.mak   |   1 +
> >> hw/acpi/Makefile.objs                |   1 +
> >> hw/acpi/vmgenid.c                    | 206 +++++++++++++++++++++++++++++++++++
> >> hw/i386/acpi-build.c                 |  10 ++
> >> include/hw/acpi/acpi_dev_interface.h |   1 +
> >> include/hw/acpi/vmgenid.h            |  37 +++++++
> >> 7 files changed, 257 insertions(+)
> >> create mode 100644 hw/acpi/vmgenid.c
> >> create mode 100644 include/hw/acpi/vmgenid.h
> >> 
> >> diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
> >> index 384cefb..1a43542 100644
> >> --- a/default-configs/i386-softmmu.mak
> >> +++ b/default-configs/i386-softmmu.mak
> >> @@ -58,3 +58,4 @@ CONFIG_I82801B11=y
> >> CONFIG_SMBIOS=y
> >> CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
> >> CONFIG_PXB=y
> >> +CONFIG_ACPI_VMGENID=y
> >> diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
> >> index 491a191..aee8b08 100644
> >> --- a/default-configs/x86_64-softmmu.mak
> >> +++ b/default-configs/x86_64-softmmu.mak
> >> @@ -58,3 +58,4 @@ CONFIG_I82801B11=y
> >> CONFIG_SMBIOS=y
> >> CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
> >> CONFIG_PXB=y
> >> +CONFIG_ACPI_VMGENID=y
> >> diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
> >> index 6acf798..11c35bc 100644
> >> --- a/hw/acpi/Makefile.objs
> >> +++ b/hw/acpi/Makefile.objs
> >> @@ -5,6 +5,7 @@ common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
> >> common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
> >> common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
> >> common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
> >> +common-obj-$(CONFIG_ACPI_VMGENID) += vmgenid.o
> >> common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
> >> 
> >> common-obj-y += acpi_interface.o
> >> diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
> >> new file mode 100644
> >> index 0000000..6c9ecfd
> >> --- /dev/null
> >> +++ b/hw/acpi/vmgenid.c
> >> @@ -0,0 +1,206 @@
> >> +/*
> >> + *  Virtual Machine Generation ID Device
> >> + *
> >> + *  Copyright (C) 2017 Skyport Systems.
> >> + *
> >> + *  Author: Ben Warren <ben@skyportsystems.com>
> >> + *
> >> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> >> + * See the COPYING file in the top-level directory.
> >> + *
> >> + */
> >> +
> >> +#include "qemu/osdep.h"
> >> +#include "qmp-commands.h"
> >> +#include "hw/acpi/acpi.h"
> >> +#include "hw/acpi/aml-build.h"
> >> +#include "hw/acpi/vmgenid.h"
> >> +#include "hw/nvram/fw_cfg.h"
> >> +#include "sysemu/sysemu.h"
> >> +
> >> +void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker *linker)
> >> +{
> >> +    Object *obj;
> >> +    VmGenIdState *s;
> >> +    Aml *ssdt, *dev, *scope, *method, *addr, *if_ctx;
> >> +    uint32_t vgia_offset;
> >> +
> >> +    obj = find_vmgenid_dev(NULL);
> > get obj from caller
> > 
> >> +    assert(obj);
> >> +    s = VMGENID(obj);
> >> +
> >> +    /* Fill in the GUID values */
> >> +    if (guid->len != VMGENID_FW_CFG_SIZE) {
> >> +        g_array_set_size(guid, VMGENID_FW_CFG_SIZE);
> > does it have to be conditional?
> > 
> No, I guess not.
> >> +    }
> >> +    g_array_insert_vals(guid, VMGENID_GUID_OFFSET, s->guid.data, 16);
> >> +
> >> +    /* Put this in a separate SSDT table */
> >> +    ssdt = init_aml_allocator();
> >> +
> >> +    /* Reserve space for header */
> >> +    acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader));
> >> +
> >> +    /* Storage for the GUID address */
> >> +    vgia_offset = table_data->len +
> >> +        build_append_named_dword(ssdt->buf, "VGIA");
> >> +    scope = aml_scope("\\_SB");
> >> +    dev = aml_device("VGEN");
> >> +    aml_append(dev, aml_name_decl("_HID", aml_string("QEMUVGID")));
> >> +    aml_append(dev, aml_name_decl("_CID", aml_string("VM_Gen_Counter")));
> >> +    aml_append(dev, aml_name_decl("_DDN", aml_string("VM_Gen_Counter")));
> >> +
> >> +    /* Simple status method to check that address is linked and non-zero */
> >> +    method = aml_method("_STA", 0, AML_NOTSERIALIZED);
> >> +    addr = aml_local(0);
> >> +    aml_append(method, aml_store(aml_int(0xf), addr));
> >> +    if_ctx = aml_if(aml_equal(aml_name("VGIA"), aml_int(0)));
> >> +    aml_append(if_ctx, aml_store(aml_int(0), addr));
> >> +    aml_append(method, if_ctx);
> >> +    aml_append(method, aml_return(addr));
> >> +    aml_append(dev, method);
> >> +
> >> +    /* the ADDR method returns two 32-bit words representing the lower and
> >> +     * upper halves * of the physical address of the fw_cfg blob
> >> +     * (holding the GUID) */
> >> +    method = aml_method("ADDR", 0, AML_NOTSERIALIZED);
> >> +
> >> +    addr = aml_local(0);
> >> +    aml_append(method, aml_store(aml_package(2), addr));
> >> +
> >> +    aml_append(method, aml_store(aml_add(aml_name("VGIA"),
> >> +                                         aml_int(VMGENID_GUID_OFFSET), NULL),
> >> +                                 aml_index(addr, aml_int(0))));
> >> +    aml_append(method, aml_store(aml_int(0), aml_index(addr, aml_int(1))));
> > I'd rather have "VGIA" patched wit address to GUID and not the blob start,
> > see next comment about how.
> > 
> > Also usage aml_index() looks a bit confusing, how about:
> > 
> > pkg = aml_local(0)
> > aml_store(aml_package(2), pkg)
> > aml_append(pkg, aml_name("VGIA"))
> > aml_append(pkg, aml_int(0))
> > 
> I’ll try that, it does look simpler.  I thought I tried this and couldn’t get it to work, but will try again.
> >> +    aml_append(method, aml_return(addr));
> >> +
> >> +    aml_append(dev, method);
> >> +    aml_append(scope, dev);
> >> +    aml_append(ssdt, scope);
> >> +
> >> +    /* attach an ACPI notify */
> >> +    method = aml_method("\\_GPE._E05", 0, AML_NOTSERIALIZED);
> >> +    aml_append(method, aml_notify(aml_name("\\_SB.VGEN"), aml_int(0x80)));
> >> +    aml_append(ssdt, method);
> >> +
> >> +    g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len);
> >> +
> >> +    /* Allocate guest memory for the Data fw_cfg blob */
> >> +    bios_linker_loader_alloc(linker, VMGENID_GUID_FW_CFG_FILE, guid, 4096,
> >> +                             false /* page boundary, high memory */);
> > does it guaranties that blob will be allocated in cacheable page?
> > (SeaBIOS/OVMF)
> > 
> >> +
> >> +    /* Patch address of GUID fw_cfg blob into the ADDR fw_cfg blob */
> >> +    bios_linker_loader_add_pointer(linker,
> >> +        VMGENID_ADDR_FW_CFG_FILE, 0, sizeof(uint32_t),
> >> +        VMGENID_GUID_FW_CFG_FILE, 0, true);
> >> +
> >> +    /* Patch address of GUID fw_cfg blob into the AML */
> >> +    bios_linker_loader_add_pointer(linker,
> >> +        ACPI_BUILD_TABLE_FILE, vgia_offset, sizeof(uint32_t),
> >> +        VMGENID_GUID_FW_CFG_FILE, 0, false);
> > see @src_offset argument description,
> > putting VMGENID_GUID_OFFSET would make patched place point directly to GUID
> > 
> >> +
> >> +    build_header(linker, table_data,
> >> +        (void *)(table_data->data + table_data->len - ssdt->buf->len),
> >> +        "SSDT", ssdt->buf->len, 1, NULL, "VMGENID");
> >> +    free_aml_allocator();
> >> +}
> >> +
> >> +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid)
> >> +{
> >> +    Object *obj = find_vmgenid_dev(NULL);
> >> +    assert(obj);
> >> +    VmGenIdState *vms = VMGENID(obj);
> >> +
> >> +    /* Create a read-only fw_cfg file for GUID */
> >> +    fw_cfg_add_file(s, VMGENID_GUID_FW_CFG_FILE, guid->data,
> >> +                    VMGENID_FW_CFG_SIZE);
> >> +    /* Create a read-write fw_cfg file for Address */
> >> +    fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL, NULL,
> >> +                             vms->vgia_le, sizeof(uint32_t), false);
> >> +}
> >> +
> >> +static void vmgenid_update_guest(VmGenIdState *s)
> >> +{
> >> +    Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL);
> >> +    uint32_t vgia;
> >> +
> >> +    if (obj) {
> >> +        /* Write the GUID to guest memory */
> >> +        memcpy(&vgia, s->vgia_le, sizeof(vgia));
> >> +        vgia = le32_to_cpu(vgia);
> >> +        if (vgia) {
> >> +            cpu_physical_memory_write(vgia + VMGENID_GUID_OFFSET,
> >> +                                      s->guid.data, sizeof(s->guid.data));
> >> +            /* Send _GPE.E05 event */
> >> +            acpi_send_event(DEVICE(obj), ACPI_VMGENID_CHANGE_STATUS);
> >> +        }
> >> +    }
> >> +}
> >> +
> >> +static void vmgenid_set_guid(Object *obj, const char *value, Error **errp)
> >> +{
> >> +    VmGenIdState *s = VMGENID(obj);
> >> +
> >> +    if (!strncmp(value, "auto", 4)) {
> >> +        qemu_uuid_generate(&s->guid);
> >> +    } else if (qemu_uuid_parse(value, &s->guid) < 0) {
> >> +        error_setg(errp, "'%s. %s': Failed to parse GUID string: %s",
> >> +                   object_get_typename(OBJECT(s)), VMGENID_GUID, value);
> >> +        return;
> >> +    }
> >> +    /* QemuUUID has the first three words as big-endian, and expect that any
> >> +     * GUIDs passed in will always be BE.  The guest, however will expect
> >> +     * the fields to be little-endian, so store that way internally.  Make
> >> +     * sure to swap back whenever reporting via monitor */
> >> +    qemu_uuid_bswap(&s->guid);
> >> +
> >> +    /* Send the ACPI notify */
> >> +    vmgenid_update_guest(s);
> >> +}
> >> +
> >> +/* After restoring an image, we need to update the guest memory and notify
> >> + * it of a potential change to VM Generation ID */
> >> +static int vmgenid_post_load(void *opaque, int version_id)
> >> +{
> >> +    VmGenIdState *s = opaque;
> >> +    vmgenid_update_guest(s);
> >> +    return 0;
> >> +}
> >> +
> >> +static const VMStateDescription vmstate_vmgenid = {
> >> +    .name = "vmgenid",
> >> +    .version_id = 1,
> >> +    .minimum_version_id = 1,
> >> +    .post_load = vmgenid_post_load,
> >> +    .fields = (VMStateField[]) {
> >> +        VMSTATE_UINT8_ARRAY(vgia_le, VmGenIdState, sizeof(uint32_t)),
> > file with address could be memory region and migrated automatically,
> > ex: rsdp_mr + acpi_add_rom_blob + acpi_ram_update
> > 
> I don’t follow.  Can you please elaborate?
acpi_add_rom_blob() allocates memory that is automatically migrated
without need for explicit VMSTATE_FOO magic.

rsdp_mr is an example that uses this approach.

> >> +        VMSTATE_END_OF_LIST()
> >> +    },
> >> +};
> >> +
> >> +static void vmgenid_initfn(Object *obj)
> >> +{
> >> +    object_property_add_str(obj, VMGENID_GUID, NULL, vmgenid_set_guid, NULL);
> >> +}
> >> +
> >> +static void vmgenid_device_class_init(ObjectClass *klass, void *data)
> >> +{
> >> +    DeviceClass *dc = DEVICE_CLASS(klass);
> >> +
> >> +    dc->vmsd = &vmstate_vmgenid;
> >> +}
> >> +
> >> +static const TypeInfo vmgenid_device_info = {
> >> +    .name          = VMGENID_DEVICE,
> >> +    .parent        = TYPE_SYS_BUS_DEVICE,
> >> +    .instance_size = sizeof(VmGenIdState),
> >> +    .instance_init = vmgenid_initfn,
> >> +    .class_init    = vmgenid_device_class_init,
> >> +};
> >> +
> >> +static void vmgenid_register_types(void)
> >> +{
> >> +    type_register_static(&vmgenid_device_info);
> >> +}
> >> +
> >> +type_init(vmgenid_register_types)
> >> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> >> index 78a1d84..4c40f76 100644
> >> --- a/hw/i386/acpi-build.c
> >> +++ b/hw/i386/acpi-build.c
> >> @@ -42,6 +42,7 @@
> >> #include "hw/acpi/memory_hotplug.h"
> >> #include "sysemu/tpm.h"
> >> #include "hw/acpi/tpm.h"
> >> +#include "hw/acpi/vmgenid.h"
> >> #include "sysemu/tpm_backend.h"
> >> #include "hw/timer/mc146818rtc_regs.h"
> >> #include "sysemu/numa.h"
> >> @@ -2653,6 +2654,11 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
> >>     acpi_add_table(table_offsets, tables_blob);
> >>     build_madt(tables_blob, tables->linker, pcms);
> >> 
> >> +    if (find_vmgenid_dev(NULL)) {
> >> +        acpi_add_table(table_offsets, tables_blob);
> >> +        vmgenid_build_acpi(tables_blob, tables->vmgenid, tables->linker);
> > pass find_vmgenid_dev(NULL) result as an argument to vmgenid_build_acpi()
> > so it won't have to do lookup again.
> > 
> OK
> >> +    }
> >> +
> >>     if (misc.has_hpet) {
> >>         acpi_add_table(table_offsets, tables_blob);
> >>         build_hpet(tables_blob, tables->linker);
> >> @@ -2859,6 +2865,10 @@ void acpi_setup(void)
> >>     fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
> >>                     tables.tcpalog->data, acpi_data_len(tables.tcpalog));
> >> 
> >> +    if (find_vmgenid_dev(NULL)) {
> > it's second lookup, cache result of the 1st call and reuse it here
> > 
> OK
> >> +        vmgenid_add_fw_cfg(pcms->fw_cfg, tables.vmgenid);
> >> +    }
> >> +
> >>     if (!pcmc->rsdp_in_ram) {
> >>         /*
> >>          * Keep for compatibility with old machine types.
> >> diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h
> >> index 71d3c48..3c2e4e9 100644
> >> --- a/include/hw/acpi/acpi_dev_interface.h
> >> +++ b/include/hw/acpi/acpi_dev_interface.h
> >> @@ -11,6 +11,7 @@ typedef enum {
> >>     ACPI_CPU_HOTPLUG_STATUS = 4,
> >>     ACPI_MEMORY_HOTPLUG_STATUS = 8,
> >>     ACPI_NVDIMM_HOTPLUG_STATUS = 16,
> >> +    ACPI_VMGENID_CHANGE_STATUS = 32,
> >> } AcpiEventStatusBits;
> >> 
> >> #define TYPE_ACPI_DEVICE_IF "acpi-device-interface"
> >> diff --git a/include/hw/acpi/vmgenid.h b/include/hw/acpi/vmgenid.h
> >> new file mode 100644
> >> index 0000000..b60437a
> >> --- /dev/null
> >> +++ b/include/hw/acpi/vmgenid.h
> >> @@ -0,0 +1,37 @@
> >> +#ifndef ACPI_VMGENID_H
> >> +#define ACPI_VMGENID_H
> >> +
> >> +#include "hw/acpi/bios-linker-loader.h"
> >> +#include "hw/sysbus.h"
> >> +#include "qemu/uuid.h"
> >> +
> >> +#define VMGENID_DEVICE           "vmgenid"
> >> +#define VMGENID_GUID             "guid"
> >> +#define VMGENID_GUID_FW_CFG_FILE      "etc/vmgenid"
> >> +#define VMGENID_ADDR_FW_CFG_FILE      "etc/vmgenid_addr"
> >> +
> >> +#define VMGENID_FW_CFG_SIZE      4096 /* Occupy a page of memory */
> >> +#define VMGENID_GUID_OFFSET      40   /* allow space for
> >> +                                       * OVMF SDT Header Probe Supressor */
> >> +
> >> +void vmgenid_add_fw_cfg(FWCfgState *s, GArray *guid);
> >> +void vmgenid_build_acpi(GArray *table_data, GArray *guid, BIOSLinker *linker);
> >> +
> >> +#define VMGENID(obj) OBJECT_CHECK(VmGenIdState, (obj), VMGENID_DEVICE)
> >> +
> >> +typedef struct VmGenIdState {
> >> +    SysBusDevice parent_obj;
> > Could it work with just plain Device parent?
> > If it works then you can drop patch:
> >  [PATCH v5 08/10] PC: Support dynamic sysbus on pc_i440fx
> > 
> Huh, I was sure I tried that originally and couldn’t make it work, but it turns out it does.  Definitely better.
> >> +    QemuUUID guid;
> >> +    uint8_t vgia_le[4];
> >> +} VmGenIdState;
> >> +
> >> +static Object *find_vmgenid_dev(Error **errp)
> >> +{
> >> +    Object *obj = object_resolve_path_type("", VMGENID_DEVICE, NULL);
> >> +    if (!obj && errp) {
> > all callers pass NULL as errp, I'd just drop errp altogether.
> > 
> OK
> >> +        error_setg(errp, "%s is not found", VMGENID_DEVICE);
> >> +    }
> >> +    return obj;
> >> +}
> >> +
> >> +#endif
> 

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-08  0:48   ` Laszlo Ersek
  2017-02-08 11:04     ` Igor Mammedov
  2017-02-08 22:34     ` Ben Warren
@ 2017-02-09 17:23     ` Igor Mammedov
  2017-02-09 18:21       ` Michael S. Tsirkin
  2017-02-09 19:27       ` Laszlo Ersek
  2 siblings, 2 replies; 70+ messages in thread
From: Igor Mammedov @ 2017-02-09 17:23 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: ben, mst, qemu-devel

On Wed, 8 Feb 2017 01:48:42 +0100
Laszlo Ersek <lersek@redhat.com> wrote:

> On 02/05/17 10:12, ben@skyportsystems.com wrote:
> > From: Ben Warren <ben@skyportsystems.com>
[...]

> (2) Structure of the vmgenid fw_cfg blob, AKA "why that darn offset 40
> decimal".
> 
> I explained it under points (6) and (7) in the following message:
> 
> Message-Id: <c16a03d5-820a-f719-81ea-43858f903395@redhat.com>
> URL: https://www.mail-archive.com/qemu-devel@nongnu.org/msg425226.html
> 
> The story is that *wherever* an ADD_POINTER command points to -- that
> is, at the *exact* target address --, OVMF will look for an ACPI table
> header, somewhat heuristically. If it finds a byte pattern that (a) fits
> into the remaining blob and (b) passes some superficial ACPI table
> header checks, such as length and checksum, then OVMF assumes that the
> blob contains an ACPI table there, and passes the address (again, the
> exact, relocated, absolute target address of ADD_POINTER) to
> EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable().
> 
> We want to disable this heuristic for the vmgenid blob. *If* the blob
> contained only 16 bytes (for the GUID), then the heuristic would
> automatically disable itself, because the ACPI table header (36 bytes)
> is larger than 16 bytes, so OVMF wouldn't even look. However, for the
> caching and other VMGENID requirements, we need to allocate a full page
> with the blob (4KB), hence OVMF *will* look. If we placed the GUID right
> at the start of the page, then OVMF would sanity-check it as an ACPI
> table header. The check would *most likely* not pass, so things would be
> fine in practice, but we can do better than that: just put 40 zero bytes
> at the front of the blob.
> 
> And this is why the ADD_POINTER command has to point to the beginning of
> the blob (i.e., 36 zero bytes), to "suppress the OVMF ACPI SDT header
> detection". (The other 4 bytes are for arriving at an address divisible
> by 8, which is a VMGENID requirement for the GUID.)
> 
> The consequence is that both the ADDR method and QEMU's guest memory
> access code have to add 40 manually.
The longer I look "suppress the OVMF ACPI SDT header detection",
the less I like approach.

It looks somewhat backwards where a firmware forces QEMU
to use non obvious offsets to workaround OVMF ACPI table detection
heuristics.
Can we add and use explicit flag to mark blobs as ACPI tables,
so that OVMF won't have to guess whether to hand off table
as ACPI to UEFI stack or just keep it to yourself?


[...]
> Thanks
> Laszlo
> 

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-09 17:23     ` Igor Mammedov
@ 2017-02-09 18:21       ` Michael S. Tsirkin
  2017-02-09 19:27       ` Laszlo Ersek
  1 sibling, 0 replies; 70+ messages in thread
From: Michael S. Tsirkin @ 2017-02-09 18:21 UTC (permalink / raw)
  To: Igor Mammedov; +Cc: Laszlo Ersek, ben, qemu-devel

On Thu, Feb 09, 2017 at 06:23:16PM +0100, Igor Mammedov wrote:
> On Wed, 8 Feb 2017 01:48:42 +0100
> Laszlo Ersek <lersek@redhat.com> wrote:
> 
> > On 02/05/17 10:12, ben@skyportsystems.com wrote:
> > > From: Ben Warren <ben@skyportsystems.com>
> [...]
> 
> > (2) Structure of the vmgenid fw_cfg blob, AKA "why that darn offset 40
> > decimal".
> > 
> > I explained it under points (6) and (7) in the following message:
> > 
> > Message-Id: <c16a03d5-820a-f719-81ea-43858f903395@redhat.com>
> > URL: https://www.mail-archive.com/qemu-devel@nongnu.org/msg425226.html
> > 
> > The story is that *wherever* an ADD_POINTER command points to -- that
> > is, at the *exact* target address --, OVMF will look for an ACPI table
> > header, somewhat heuristically. If it finds a byte pattern that (a) fits
> > into the remaining blob and (b) passes some superficial ACPI table
> > header checks, such as length and checksum, then OVMF assumes that the
> > blob contains an ACPI table there, and passes the address (again, the
> > exact, relocated, absolute target address of ADD_POINTER) to
> > EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable().
> > 
> > We want to disable this heuristic for the vmgenid blob. *If* the blob
> > contained only 16 bytes (for the GUID), then the heuristic would
> > automatically disable itself, because the ACPI table header (36 bytes)
> > is larger than 16 bytes, so OVMF wouldn't even look. However, for the
> > caching and other VMGENID requirements, we need to allocate a full page
> > with the blob (4KB), hence OVMF *will* look. If we placed the GUID right
> > at the start of the page, then OVMF would sanity-check it as an ACPI
> > table header. The check would *most likely* not pass, so things would be
> > fine in practice, but we can do better than that: just put 40 zero bytes
> > at the front of the blob.
> > 
> > And this is why the ADD_POINTER command has to point to the beginning of
> > the blob (i.e., 36 zero bytes), to "suppress the OVMF ACPI SDT header
> > detection". (The other 4 bytes are for arriving at an address divisible
> > by 8, which is a VMGENID requirement for the GUID.)
> > 
> > The consequence is that both the ADDR method and QEMU's guest memory
> > access code have to add 40 manually.
> The longer I look "suppress the OVMF ACPI SDT header detection",
> the less I like approach.
> 
> It looks somewhat backwards where a firmware forces QEMU
> to use non obvious offsets to workaround OVMF ACPI table detection
> heuristics.
> Can we add and use explicit flag to mark blobs as ACPI tables,
> so that OVMF won't have to guess whether to hand off table
> as ACPI to UEFI stack or just keep it to yourself?

Seems like the minor enough hack.

At this stage I'm inclined to say let's merge with the current approach,
and we can do a patch on top if we have the time.

> 
> [...]
> > Thanks
> > Laszlo
> > 

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-09 17:23     ` Igor Mammedov
  2017-02-09 18:21       ` Michael S. Tsirkin
@ 2017-02-09 19:27       ` Laszlo Ersek
  2017-02-09 20:02         ` Ben Warren
  1 sibling, 1 reply; 70+ messages in thread
From: Laszlo Ersek @ 2017-02-09 19:27 UTC (permalink / raw)
  To: Igor Mammedov; +Cc: ben, mst, qemu-devel

On 02/09/17 18:23, Igor Mammedov wrote:
> On Wed, 8 Feb 2017 01:48:42 +0100
> Laszlo Ersek <lersek@redhat.com> wrote:
> 
>> On 02/05/17 10:12, ben@skyportsystems.com wrote:
>>> From: Ben Warren <ben@skyportsystems.com>
> [...]
> 
>> (2) Structure of the vmgenid fw_cfg blob, AKA "why that darn offset 40
>> decimal".
>>
>> I explained it under points (6) and (7) in the following message:
>>
>> Message-Id: <c16a03d5-820a-f719-81ea-43858f903395@redhat.com>
>> URL: https://www.mail-archive.com/qemu-devel@nongnu.org/msg425226.html
>>
>> The story is that *wherever* an ADD_POINTER command points to -- that
>> is, at the *exact* target address --, OVMF will look for an ACPI table
>> header, somewhat heuristically. If it finds a byte pattern that (a) fits
>> into the remaining blob and (b) passes some superficial ACPI table
>> header checks, such as length and checksum, then OVMF assumes that the
>> blob contains an ACPI table there, and passes the address (again, the
>> exact, relocated, absolute target address of ADD_POINTER) to
>> EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable().
>>
>> We want to disable this heuristic for the vmgenid blob. *If* the blob
>> contained only 16 bytes (for the GUID), then the heuristic would
>> automatically disable itself, because the ACPI table header (36 bytes)
>> is larger than 16 bytes, so OVMF wouldn't even look. However, for the
>> caching and other VMGENID requirements, we need to allocate a full page
>> with the blob (4KB), hence OVMF *will* look. If we placed the GUID right
>> at the start of the page, then OVMF would sanity-check it as an ACPI
>> table header. The check would *most likely* not pass, so things would be
>> fine in practice, but we can do better than that: just put 40 zero bytes
>> at the front of the blob.
>>
>> And this is why the ADD_POINTER command has to point to the beginning of
>> the blob (i.e., 36 zero bytes), to "suppress the OVMF ACPI SDT header
>> detection". (The other 4 bytes are for arriving at an address divisible
>> by 8, which is a VMGENID requirement for the GUID.)
>>
>> The consequence is that both the ADDR method and QEMU's guest memory
>> access code have to add 40 manually.
> The longer I look "suppress the OVMF ACPI SDT header detection",
> the less I like approach.
> 
> It looks somewhat backwards where a firmware forces QEMU
> to use non obvious offsets to workaround OVMF ACPI table detection
> heuristics.

This is for historical reasons -- when the linker/loader commands were
invented, it wasn't considered that in UEFI, ACPI tables cannot just be
linked together in-place, instead they'd have to be passed to
EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() one by one, for copying. The
commands didn't provide dedicated means for identifying individual
tables in blobs. Hence the heuristics built upon ADD_POINTER.

And once you have heuristics, you want to suppress them occasionally, if
you can find a way.

> Can we add and use explicit flag to mark blobs as ACPI tables,
> so that OVMF won't have to guess whether to hand off table
> as ACPI to UEFI stack or just keep it to yourself?

The ADD_POINTER-based heuristics cannot be turned off for ACPI table
identification, because a single fw_cfg blob can (and does) contain
multiple ACPI tables, and OVMF needs to figure out, somehow, where each
of those tables start. Blob-level hints won't help with this.

The following could be an improvement though: a blob-level hint (perhaps
in the ALLOCATE command) that the blob contains *no* ACPI tables. In
this case, OVMF could turn off the table recognition heuristics for
those ADD_POINTER commands that point into such blobs. (Plus mark the
blob for permanent preservation at once, and not only when an
ADD_POINTER "probe" into the blob fails.)

OVMF currently ignores the Zone field in the ALLOCATE command, so that
could be extended / abused for such a hint, without breaking
compatibility with OVMF. (Not sure about SeaBIOS.)

Otherwise, a new allocation command will be necessary. (Which should
embed the current ALLOCATE command structure fully, at some offset.)

Thanks
Laszlo

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-09 19:27       ` Laszlo Ersek
@ 2017-02-09 20:02         ` Ben Warren
  2017-02-09 20:24           ` Laszlo Ersek
  0 siblings, 1 reply; 70+ messages in thread
From: Ben Warren @ 2017-02-09 20:02 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: Igor Mammedov, mst, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 4925 bytes --]


> On Feb 9, 2017, at 11:27 AM, Laszlo Ersek <lersek@redhat.com> wrote:
> 
> On 02/09/17 18:23, Igor Mammedov wrote:
>> On Wed, 8 Feb 2017 01:48:42 +0100
>> Laszlo Ersek <lersek@redhat.com> wrote:
>> 
>>> On 02/05/17 10:12, ben@skyportsystems.com wrote:
>>>> From: Ben Warren <ben@skyportsystems.com>
>> [...]
>> 
>>> (2) Structure of the vmgenid fw_cfg blob, AKA "why that darn offset 40
>>> decimal".
>>> 
>>> I explained it under points (6) and (7) in the following message:
>>> 
>>> Message-Id: <c16a03d5-820a-f719-81ea-43858f903395@redhat.com>
>>> URL: https://www.mail-archive.com/qemu-devel@nongnu.org/msg425226.html
>>> 
>>> The story is that *wherever* an ADD_POINTER command points to -- that
>>> is, at the *exact* target address --, OVMF will look for an ACPI table
>>> header, somewhat heuristically. If it finds a byte pattern that (a) fits
>>> into the remaining blob and (b) passes some superficial ACPI table
>>> header checks, such as length and checksum, then OVMF assumes that the
>>> blob contains an ACPI table there, and passes the address (again, the
>>> exact, relocated, absolute target address of ADD_POINTER) to
>>> EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable().
>>> 
>>> We want to disable this heuristic for the vmgenid blob. *If* the blob
>>> contained only 16 bytes (for the GUID), then the heuristic would
>>> automatically disable itself, because the ACPI table header (36 bytes)
>>> is larger than 16 bytes, so OVMF wouldn't even look. However, for the
>>> caching and other VMGENID requirements, we need to allocate a full page
>>> with the blob (4KB), hence OVMF *will* look. If we placed the GUID right
>>> at the start of the page, then OVMF would sanity-check it as an ACPI
>>> table header. The check would *most likely* not pass, so things would be
>>> fine in practice, but we can do better than that: just put 40 zero bytes
>>> at the front of the blob.
>>> 
>>> And this is why the ADD_POINTER command has to point to the beginning of
>>> the blob (i.e., 36 zero bytes), to "suppress the OVMF ACPI SDT header
>>> detection". (The other 4 bytes are for arriving at an address divisible
>>> by 8, which is a VMGENID requirement for the GUID.)
>>> 
>>> The consequence is that both the ADDR method and QEMU's guest memory
>>> access code have to add 40 manually.
>> The longer I look "suppress the OVMF ACPI SDT header detection",
>> the less I like approach.
>> 
>> It looks somewhat backwards where a firmware forces QEMU
>> to use non obvious offsets to workaround OVMF ACPI table detection
>> heuristics.
> 
> This is for historical reasons -- when the linker/loader commands were
> invented, it wasn't considered that in UEFI, ACPI tables cannot just be
> linked together in-place, instead they'd have to be passed to
> EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() one by one, for copying. The
> commands didn't provide dedicated means for identifying individual
> tables in blobs. Hence the heuristics built upon ADD_POINTER.
> 
> And once you have heuristics, you want to suppress them occasionally, if
> you can find a way.
> 
>> Can we add and use explicit flag to mark blobs as ACPI tables,
>> so that OVMF won't have to guess whether to hand off table
>> as ACPI to UEFI stack or just keep it to yourself?
> 
> The ADD_POINTER-based heuristics cannot be turned off for ACPI table
> identification, because a single fw_cfg blob can (and does) contain
> multiple ACPI tables, and OVMF needs to figure out, somehow, where each
> of those tables start. Blob-level hints won't help with this.
> 
> The following could be an improvement though: a blob-level hint (perhaps
> in the ALLOCATE command) that the blob contains *no* ACPI tables. In
> this case, OVMF could turn off the table recognition heuristics for
> those ADD_POINTER commands that point into such blobs. (Plus mark the
> blob for permanent preservation at once, and not only when an
> ADD_POINTER "probe" into the blob fails.)
> 
> OVMF currently ignores the Zone field in the ALLOCATE command, so that
> could be extended / abused for such a hint, without breaking
> compatibility with OVMF. (Not sure about SeaBIOS.)
> 
Overloading the ALLOCATE command in theory could be done with a simple change to SeaBIOS.  Here’s where the zone is handled:

    switch (entry->alloc_zone) {
        case ROMFILE_LOADER_ALLOC_ZONE_HIGH:
            zone = &ZoneHigh;
            break;
        case ROMFILE_LOADER_ALLOC_ZONE_FSEG:
            zone = &ZoneFSeg;
            break;
        default:
            goto err;
    }
 
ZONE_HIGH = 1, and ZONE_FSEG = 2 and alloc_zone is 8 bits.  Stealing the MSB and masking it off would be dirty, but could work.


> Otherwise, a new allocation command will be necessary. (Which should
> embed the current ALLOCATE command structure fully, at some offset.)
> 
> Thanks
> Laszlo


[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 3583 bytes --]

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-09 20:02         ` Ben Warren
@ 2017-02-09 20:24           ` Laszlo Ersek
  2017-02-09 20:39             ` Ben Warren
  0 siblings, 1 reply; 70+ messages in thread
From: Laszlo Ersek @ 2017-02-09 20:24 UTC (permalink / raw)
  To: Ben Warren; +Cc: Igor Mammedov, mst, qemu-devel

On 02/09/17 21:02, Ben Warren wrote:
> 
>> On Feb 9, 2017, at 11:27 AM, Laszlo Ersek <lersek@redhat.com
>> <mailto:lersek@redhat.com>> wrote:
>>
>> On 02/09/17 18:23, Igor Mammedov wrote:
>>> On Wed, 8 Feb 2017 01:48:42 +0100
>>> Laszlo Ersek <lersek@redhat.com <mailto:lersek@redhat.com>> wrote:
>>>
>>>> On 02/05/17 10:12, ben@skyportsystems.com
>>>> <mailto:ben@skyportsystems.com> wrote:
>>>>> From: Ben Warren <ben@skyportsystems.com
>>>>> <mailto:ben@skyportsystems.com>>
>>> [...]
>>>
>>>> (2) Structure of the vmgenid fw_cfg blob, AKA "why that darn offset 40
>>>> decimal".
>>>>
>>>> I explained it under points (6) and (7) in the following message:
>>>>
>>>> Message-Id: <c16a03d5-820a-f719-81ea-43858f903395@redhat.com
>>>> <mailto:c16a03d5-820a-f719-81ea-43858f903395@redhat.com>>
>>>> URL: https://www.mail-archive.com/qemu-devel@nongnu.org/msg425226.html
>>>>
>>>> The story is that *wherever* an ADD_POINTER command points to -- that
>>>> is, at the *exact* target address --, OVMF will look for an ACPI table
>>>> header, somewhat heuristically. If it finds a byte pattern that (a) fits
>>>> into the remaining blob and (b) passes some superficial ACPI table
>>>> header checks, such as length and checksum, then OVMF assumes that the
>>>> blob contains an ACPI table there, and passes the address (again, the
>>>> exact, relocated, absolute target address of ADD_POINTER) to
>>>> EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable().
>>>>
>>>> We want to disable this heuristic for the vmgenid blob. *If* the blob
>>>> contained only 16 bytes (for the GUID), then the heuristic would
>>>> automatically disable itself, because the ACPI table header (36 bytes)
>>>> is larger than 16 bytes, so OVMF wouldn't even look. However, for the
>>>> caching and other VMGENID requirements, we need to allocate a full page
>>>> with the blob (4KB), hence OVMF *will* look. If we placed the GUID right
>>>> at the start of the page, then OVMF would sanity-check it as an ACPI
>>>> table header. The check would *most likely* not pass, so things would be
>>>> fine in practice, but we can do better than that: just put 40 zero bytes
>>>> at the front of the blob.
>>>>
>>>> And this is why the ADD_POINTER command has to point to the beginning of
>>>> the blob (i.e., 36 zero bytes), to "suppress the OVMF ACPI SDT header
>>>> detection". (The other 4 bytes are for arriving at an address divisible
>>>> by 8, which is a VMGENID requirement for the GUID.)
>>>>
>>>> The consequence is that both the ADDR method and QEMU's guest memory
>>>> access code have to add 40 manually.
>>> The longer I look "suppress the OVMF ACPI SDT header detection",
>>> the less I like approach.
>>>
>>> It looks somewhat backwards where a firmware forces QEMU
>>> to use non obvious offsets to workaround OVMF ACPI table detection
>>> heuristics.
>>
>> This is for historical reasons -- when the linker/loader commands were
>> invented, it wasn't considered that in UEFI, ACPI tables cannot just be
>> linked together in-place, instead they'd have to be passed to
>> EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() one by one, for copying. The
>> commands didn't provide dedicated means for identifying individual
>> tables in blobs. Hence the heuristics built upon ADD_POINTER.
>>
>> And once you have heuristics, you want to suppress them occasionally, if
>> you can find a way.
>>
>>> Can we add and use explicit flag to mark blobs as ACPI tables,
>>> so that OVMF won't have to guess whether to hand off table
>>> as ACPI to UEFI stack or just keep it to yourself?
>>
>> The ADD_POINTER-based heuristics cannot be turned off for ACPI table
>> identification, because a single fw_cfg blob can (and does) contain
>> multiple ACPI tables, and OVMF needs to figure out, somehow, where each
>> of those tables start. Blob-level hints won't help with this.
>>
>> The following could be an improvement though: a blob-level hint (perhaps
>> in the ALLOCATE command) that the blob contains *no* ACPI tables. In
>> this case, OVMF could turn off the table recognition heuristics for
>> those ADD_POINTER commands that point into such blobs. (Plus mark the
>> blob for permanent preservation at once, and not only when an
>> ADD_POINTER "probe" into the blob fails.)
>>
>> OVMF currently ignores the Zone field in the ALLOCATE command, so that
>> could be extended / abused for such a hint, without breaking
>> compatibility with OVMF. (Not sure about SeaBIOS.)
>>
> Overloading the ALLOCATE command in theory could be done with a simple
> change to SeaBIOS.  Here’s where the zone is handled:
> 
>     switch (entry->alloc_zone) {
>         case ROMFILE_LOADER_ALLOC_ZONE_HIGH:
>             zone = &ZoneHigh;
>             break;
>         case ROMFILE_LOADER_ALLOC_ZONE_FSEG:
>             zone = &ZoneFSeg;
>             break;
>         default:
>             goto err;
>     }
>  
> ZONE_HIGH = 1, and ZONE_FSEG = 2 and alloc_zone is 8 bits.  Stealing the
> MSB and masking it off would be dirty, but could work.

Even assuming that we don't horribly break cross-version compatibility
with tricks like this, the problem is that such changes only look simple
and easy in isolation. They add up, and their testing impact is not small.

This week I've been working practically every waking moment -- I wanted
to provide quick and detailed feedback (as far as OVMF was concerned)
under both this series and on the topic of DSDT / X_DSDT /
multiply-pointed-to tables. I'm also "racing you" to create a good
quality OVMF series for WRITE_POINTER (including replay at S3 resume),
so that as soon you post v6, we can test it together with OVMF too.
(Last night I thought I had WRITE_POINTER ready, and started testing it
against your v5, but then I suddenly thought of device reset and S3...
Sigh.)

We can certainly file RFEs for stuff like the above (maybe in RHBZ,
maybe in Launchpad), but the scope creep is already significant for
VMGENID (it's noone's fault, VMGENID has tentacles into everything).
Igor's suggestion is good, it aims to decrease technical debt, but I'm
grasping at cycles -- review is very time consuming (albeit just as
necessary). Also, for QEMU, the 2.9 soft freeze is around the corner...

Best I can recommend now is filing an RFE for this.

Thanks
Laszlo

>> Otherwise, a new allocation command will be necessary. (Which should
>> embed the current ALLOCATE command structure fully, at some offset.)
>>
>> Thanks
>> Laszlo
> 

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-09 20:24           ` Laszlo Ersek
@ 2017-02-09 20:39             ` Ben Warren
  2017-02-10  8:54               ` Igor Mammedov
  0 siblings, 1 reply; 70+ messages in thread
From: Ben Warren @ 2017-02-09 20:39 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: Igor Mammedov, mst, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 6934 bytes --]


> On Feb 9, 2017, at 12:24 PM, Laszlo Ersek <lersek@redhat.com> wrote:
> 
> On 02/09/17 21:02, Ben Warren wrote:
>> 
>>> On Feb 9, 2017, at 11:27 AM, Laszlo Ersek <lersek@redhat.com
>>> <mailto:lersek@redhat.com>> wrote:
>>> 
>>> On 02/09/17 18:23, Igor Mammedov wrote:
>>>> On Wed, 8 Feb 2017 01:48:42 +0100
>>>> Laszlo Ersek <lersek@redhat.com <mailto:lersek@redhat.com>> wrote:
>>>> 
>>>>> On 02/05/17 10:12, ben@skyportsystems.com
>>>>> <mailto:ben@skyportsystems.com> wrote:
>>>>>> From: Ben Warren <ben@skyportsystems.com
>>>>>> <mailto:ben@skyportsystems.com>>
>>>> [...]
>>>> 
>>>>> (2) Structure of the vmgenid fw_cfg blob, AKA "why that darn offset 40
>>>>> decimal".
>>>>> 
>>>>> I explained it under points (6) and (7) in the following message:
>>>>> 
>>>>> Message-Id: <c16a03d5-820a-f719-81ea-43858f903395@redhat.com
>>>>> <mailto:c16a03d5-820a-f719-81ea-43858f903395@redhat.com>>
>>>>> URL: https://www.mail-archive.com/qemu-devel@nongnu.org/msg425226.html
>>>>> 
>>>>> The story is that *wherever* an ADD_POINTER command points to -- that
>>>>> is, at the *exact* target address --, OVMF will look for an ACPI table
>>>>> header, somewhat heuristically. If it finds a byte pattern that (a) fits
>>>>> into the remaining blob and (b) passes some superficial ACPI table
>>>>> header checks, such as length and checksum, then OVMF assumes that the
>>>>> blob contains an ACPI table there, and passes the address (again, the
>>>>> exact, relocated, absolute target address of ADD_POINTER) to
>>>>> EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable().
>>>>> 
>>>>> We want to disable this heuristic for the vmgenid blob. *If* the blob
>>>>> contained only 16 bytes (for the GUID), then the heuristic would
>>>>> automatically disable itself, because the ACPI table header (36 bytes)
>>>>> is larger than 16 bytes, so OVMF wouldn't even look. However, for the
>>>>> caching and other VMGENID requirements, we need to allocate a full page
>>>>> with the blob (4KB), hence OVMF *will* look. If we placed the GUID right
>>>>> at the start of the page, then OVMF would sanity-check it as an ACPI
>>>>> table header. The check would *most likely* not pass, so things would be
>>>>> fine in practice, but we can do better than that: just put 40 zero bytes
>>>>> at the front of the blob.
>>>>> 
>>>>> And this is why the ADD_POINTER command has to point to the beginning of
>>>>> the blob (i.e., 36 zero bytes), to "suppress the OVMF ACPI SDT header
>>>>> detection". (The other 4 bytes are for arriving at an address divisible
>>>>> by 8, which is a VMGENID requirement for the GUID.)
>>>>> 
>>>>> The consequence is that both the ADDR method and QEMU's guest memory
>>>>> access code have to add 40 manually.
>>>> The longer I look "suppress the OVMF ACPI SDT header detection",
>>>> the less I like approach.
>>>> 
>>>> It looks somewhat backwards where a firmware forces QEMU
>>>> to use non obvious offsets to workaround OVMF ACPI table detection
>>>> heuristics.
>>> 
>>> This is for historical reasons -- when the linker/loader commands were
>>> invented, it wasn't considered that in UEFI, ACPI tables cannot just be
>>> linked together in-place, instead they'd have to be passed to
>>> EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() one by one, for copying. The
>>> commands didn't provide dedicated means for identifying individual
>>> tables in blobs. Hence the heuristics built upon ADD_POINTER.
>>> 
>>> And once you have heuristics, you want to suppress them occasionally, if
>>> you can find a way.
>>> 
>>>> Can we add and use explicit flag to mark blobs as ACPI tables,
>>>> so that OVMF won't have to guess whether to hand off table
>>>> as ACPI to UEFI stack or just keep it to yourself?
>>> 
>>> The ADD_POINTER-based heuristics cannot be turned off for ACPI table
>>> identification, because a single fw_cfg blob can (and does) contain
>>> multiple ACPI tables, and OVMF needs to figure out, somehow, where each
>>> of those tables start. Blob-level hints won't help with this.
>>> 
>>> The following could be an improvement though: a blob-level hint (perhaps
>>> in the ALLOCATE command) that the blob contains *no* ACPI tables. In
>>> this case, OVMF could turn off the table recognition heuristics for
>>> those ADD_POINTER commands that point into such blobs. (Plus mark the
>>> blob for permanent preservation at once, and not only when an
>>> ADD_POINTER "probe" into the blob fails.)
>>> 
>>> OVMF currently ignores the Zone field in the ALLOCATE command, so that
>>> could be extended / abused for such a hint, without breaking
>>> compatibility with OVMF. (Not sure about SeaBIOS.)
>>> 
>> Overloading the ALLOCATE command in theory could be done with a simple
>> change to SeaBIOS.  Here’s where the zone is handled:
>> 
>>    switch (entry->alloc_zone) {
>>        case ROMFILE_LOADER_ALLOC_ZONE_HIGH:
>>            zone = &ZoneHigh;
>>            break;
>>        case ROMFILE_LOADER_ALLOC_ZONE_FSEG:
>>            zone = &ZoneFSeg;
>>            break;
>>        default:
>>            goto err;
>>    }
>> 
>> ZONE_HIGH = 1, and ZONE_FSEG = 2 and alloc_zone is 8 bits.  Stealing the
>> MSB and masking it off would be dirty, but could work.
> 
> Even assuming that we don't horribly break cross-version compatibility
> with tricks like this, the problem is that such changes only look simple
> and easy in isolation. They add up, and their testing impact is not small.
> 
> This week I've been working practically every waking moment -- I wanted
> to provide quick and detailed feedback (as far as OVMF was concerned)
> under both this series and on the topic of DSDT / X_DSDT /
> multiply-pointed-to tables. I'm also "racing you" to create a good
> quality OVMF series for WRITE_POINTER (including replay at S3 resume),
> so that as soon you post v6, we can test it together with OVMF too.
> (Last night I thought I had WRITE_POINTER ready, and started testing it
> against your v5, but then I suddenly thought of device reset and S3...
> Sigh.)
> 
> We can certainly file RFEs for stuff like the above (maybe in RHBZ,
> maybe in Launchpad), but the scope creep is already significant for
> VMGENID (it's noone's fault, VMGENID has tentacles into everything).
> Igor's suggestion is good, it aims to decrease technical debt, but I'm
> grasping at cycles -- review is very time consuming (albeit just as
> necessary). Also, for QEMU, the 2.9 soft freeze is around the corner…

OK, well I’m fine with things as they are.  I’ll try to get v6 out tomorrow.  This optimization can wait until later.

> Best I can recommend now is filing an RFE for this.
> 
> Thanks
> Laszlo
> 
>>> Otherwise, a new allocation command will be necessary. (Which should
>>> embed the current ALLOCATE command structure fully, at some offset.)
>>> 
>>> Thanks
>>> Laszlo
>> 
> 


[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 3583 bytes --]

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

* Re: [Qemu-devel] [PATCH v5 03/10] docs: VM Generation ID device description
  2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 03/10] docs: VM Generation ID device description ben
  2017-02-06 20:18   ` Eric Blake
  2017-02-07 20:54   ` Laszlo Ersek
@ 2017-02-10  0:55   ` Laszlo Ersek
  2 siblings, 0 replies; 70+ messages in thread
From: Laszlo Ersek @ 2017-02-10  0:55 UTC (permalink / raw)
  To: ben, qemu-devel; +Cc: Gal Hammer, imammedo, mst

On 02/05/17 10:11, ben@skyportsystems.com wrote:

> +Or to change guid in runtime use:
> +
> + set-vm-generation-id guid=124e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87
> + set-vm-generation-id guid=auto
> 

Please drop the "guid=" prefix from the examples; the HMP command
doesn't need it / chokes on it. It only takes "auto" or a UUID.

Thanks
Laszlo

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

* Re: [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support
  2017-02-09 20:39             ` Ben Warren
@ 2017-02-10  8:54               ` Igor Mammedov
  0 siblings, 0 replies; 70+ messages in thread
From: Igor Mammedov @ 2017-02-10  8:54 UTC (permalink / raw)
  To: Ben Warren; +Cc: Laszlo Ersek, qemu-devel, mst

On Thu, 9 Feb 2017 12:39:30 -0800
Ben Warren <ben@skyportsystems.com> wrote:

> > On Feb 9, 2017, at 12:24 PM, Laszlo Ersek <lersek@redhat.com> wrote:
> > 
> > On 02/09/17 21:02, Ben Warren wrote:  
> >>   
> >>> On Feb 9, 2017, at 11:27 AM, Laszlo Ersek <lersek@redhat.com
> >>> <mailto:lersek@redhat.com>> wrote:
> >>> 
> >>> On 02/09/17 18:23, Igor Mammedov wrote:  
> >>>> On Wed, 8 Feb 2017 01:48:42 +0100
> >>>> Laszlo Ersek <lersek@redhat.com <mailto:lersek@redhat.com>> wrote:
> >>>>   
> >>>>> On 02/05/17 10:12, ben@skyportsystems.com
> >>>>> <mailto:ben@skyportsystems.com> wrote:  
> >>>>>> From: Ben Warren <ben@skyportsystems.com
> >>>>>> <mailto:ben@skyportsystems.com>>  
> >>>> [...]
> >>>>   
> >>>>> (2) Structure of the vmgenid fw_cfg blob, AKA "why that darn offset 40
> >>>>> decimal".
> >>>>> 
> >>>>> I explained it under points (6) and (7) in the following message:
> >>>>> 
> >>>>> Message-Id: <c16a03d5-820a-f719-81ea-43858f903395@redhat.com
> >>>>> <mailto:c16a03d5-820a-f719-81ea-43858f903395@redhat.com>>
> >>>>> URL: https://www.mail-archive.com/qemu-devel@nongnu.org/msg425226.html
> >>>>> 
> >>>>> The story is that *wherever* an ADD_POINTER command points to -- that
> >>>>> is, at the *exact* target address --, OVMF will look for an ACPI table
> >>>>> header, somewhat heuristically. If it finds a byte pattern that (a) fits
> >>>>> into the remaining blob and (b) passes some superficial ACPI table
> >>>>> header checks, such as length and checksum, then OVMF assumes that the
> >>>>> blob contains an ACPI table there, and passes the address (again, the
> >>>>> exact, relocated, absolute target address of ADD_POINTER) to
> >>>>> EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable().
> >>>>> 
> >>>>> We want to disable this heuristic for the vmgenid blob. *If* the blob
> >>>>> contained only 16 bytes (for the GUID), then the heuristic would
> >>>>> automatically disable itself, because the ACPI table header (36 bytes)
> >>>>> is larger than 16 bytes, so OVMF wouldn't even look. However, for the
> >>>>> caching and other VMGENID requirements, we need to allocate a full page
> >>>>> with the blob (4KB), hence OVMF *will* look. If we placed the GUID right
> >>>>> at the start of the page, then OVMF would sanity-check it as an ACPI
> >>>>> table header. The check would *most likely* not pass, so things would be
> >>>>> fine in practice, but we can do better than that: just put 40 zero bytes
> >>>>> at the front of the blob.
> >>>>> 
> >>>>> And this is why the ADD_POINTER command has to point to the beginning of
> >>>>> the blob (i.e., 36 zero bytes), to "suppress the OVMF ACPI SDT header
> >>>>> detection". (The other 4 bytes are for arriving at an address divisible
> >>>>> by 8, which is a VMGENID requirement for the GUID.)
> >>>>> 
> >>>>> The consequence is that both the ADDR method and QEMU's guest memory
> >>>>> access code have to add 40 manually.  
> >>>> The longer I look "suppress the OVMF ACPI SDT header detection",
> >>>> the less I like approach.
> >>>> 
> >>>> It looks somewhat backwards where a firmware forces QEMU
> >>>> to use non obvious offsets to workaround OVMF ACPI table detection
> >>>> heuristics.  
> >>> 
> >>> This is for historical reasons -- when the linker/loader commands were
> >>> invented, it wasn't considered that in UEFI, ACPI tables cannot just be
> >>> linked together in-place, instead they'd have to be passed to
> >>> EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() one by one, for copying. The
> >>> commands didn't provide dedicated means for identifying individual
> >>> tables in blobs. Hence the heuristics built upon ADD_POINTER.
> >>> 
> >>> And once you have heuristics, you want to suppress them occasionally, if
> >>> you can find a way.
> >>>   
> >>>> Can we add and use explicit flag to mark blobs as ACPI tables,
> >>>> so that OVMF won't have to guess whether to hand off table
> >>>> as ACPI to UEFI stack or just keep it to yourself?  
> >>> 
> >>> The ADD_POINTER-based heuristics cannot be turned off for ACPI table
> >>> identification, because a single fw_cfg blob can (and does) contain
> >>> multiple ACPI tables, and OVMF needs to figure out, somehow, where each
> >>> of those tables start. Blob-level hints won't help with this.
> >>> 
> >>> The following could be an improvement though: a blob-level hint (perhaps
> >>> in the ALLOCATE command) that the blob contains *no* ACPI tables. In
> >>> this case, OVMF could turn off the table recognition heuristics for
> >>> those ADD_POINTER commands that point into such blobs. (Plus mark the
> >>> blob for permanent preservation at once, and not only when an
> >>> ADD_POINTER "probe" into the blob fails.)
> >>> 
> >>> OVMF currently ignores the Zone field in the ALLOCATE command, so that
> >>> could be extended / abused for such a hint, without breaking
> >>> compatibility with OVMF. (Not sure about SeaBIOS.)
> >>>   
> >> Overloading the ALLOCATE command in theory could be done with a simple
> >> change to SeaBIOS.  Here’s where the zone is handled:
> >> 
> >>    switch (entry->alloc_zone) {
> >>        case ROMFILE_LOADER_ALLOC_ZONE_HIGH:
> >>            zone = &ZoneHigh;
> >>            break;
> >>        case ROMFILE_LOADER_ALLOC_ZONE_FSEG:
> >>            zone = &ZoneFSeg;
> >>            break;
> >>        default:
> >>            goto err;
> >>    }
> >> 
> >> ZONE_HIGH = 1, and ZONE_FSEG = 2 and alloc_zone is 8 bits.  Stealing the
> >> MSB and masking it off would be dirty, but could work.  
> > 
> > Even assuming that we don't horribly break cross-version compatibility
> > with tricks like this, the problem is that such changes only look simple
> > and easy in isolation. They add up, and their testing impact is not small.
> > 
> > This week I've been working practically every waking moment -- I wanted
> > to provide quick and detailed feedback (as far as OVMF was concerned)
> > under both this series and on the topic of DSDT / X_DSDT /
> > multiply-pointed-to tables. I'm also "racing you" to create a good
> > quality OVMF series for WRITE_POINTER (including replay at S3 resume),
> > so that as soon you post v6, we can test it together with OVMF too.
> > (Last night I thought I had WRITE_POINTER ready, and started testing it
> > against your v5, but then I suddenly thought of device reset and S3...
> > Sigh.)
> > 
> > We can certainly file RFEs for stuff like the above (maybe in RHBZ,
> > maybe in Launchpad), but the scope creep is already significant for
> > VMGENID (it's noone's fault, VMGENID has tentacles into everything).
> > Igor's suggestion is good, it aims to decrease technical debt, but I'm
> > grasping at cycles -- review is very time consuming (albeit just as
> > necessary). Also, for QEMU, the 2.9 soft freeze is around the corner…  
> 
> OK, well I’m fine with things as they are.  I’ll try to get v6 out tomorrow.  This optimization can wait until later.
Agreed,
let forget about this for now, we can later revisit this issue.

(vmgeid is probably not the only one that needs it,
TPM comes in mind and maybe there are other blobs.)

> 
> > Best I can recommend now is filing an RFE for this.
> > 
> > Thanks
> > Laszlo
> >   
> >>> Otherwise, a new allocation command will be necessary. (Which should
> >>> embed the current ALLOCATE command structure fully, at some offset.)
> >>> 
> >>> Thanks
> >>> Laszlo  
> >>   
> >   
> 

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

* Re: [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID
  2017-02-05  9:11 [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID ben
                   ` (9 preceding siblings ...)
  2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 10/10] tests: Add unit tests for the VM Generation ID feature ben
@ 2017-02-10 10:12 ` Laszlo Ersek
  2017-02-10 10:28   ` Igor Mammedov
  2017-02-10 15:31   ` Michael S. Tsirkin
  10 siblings, 2 replies; 70+ messages in thread
From: Laszlo Ersek @ 2017-02-10 10:12 UTC (permalink / raw)
  To: ben, qemu-devel; +Cc: imammedo, mst

On 02/05/17 10:11, ben@skyportsystems.com wrote:
> From: Ben Warren <ben@skyportsystems.com>
> 
> This patch set adds support for passing a GUID to Windows guests.  It is a
> re-implementation of previous patch sets written by Igor Mammedov et al, but
> this time passing the GUID data as a fw_cfg blob.
> 
> This patch set has dependencies on new guest functionality, in particular the
> support for a new linker-loader command and the ability to write back data
> to QEMU over a DMA link.  Work is in flight in both SeaBIOS and OVMF to support this.
> 
> v4->v5:
>     - Added significantly more detail to the documentation.
>     - Replaced the previously-implemented linker-loader command with a new one:
>       "write pointer".  This allows writing the guest address of a fw_cfg blob back
>       to an arbitrary offset in a writeable fw_cfg file visible to QEMU.  This will
>       require support in SeaBIOS and OVMF (ongoing).
>     - Fixed endianness issues throughout.
>     - Several styling cleanups.

Low importance question, but I'll ask it anyway:

Can we somehow make the realization of "-device vmgenid" fail, if the PC
machine type in use is 2.6 or earlier? Because, those machine types do
not have DMA enabled for fw_cfg. Hence the WRITE_POINTER commands cannot
be effectively executed by firmware (the underlying virtual hardware is
not enabled).

For example, if a user adds VMGENID to a 2.5 machine type, and migrates
the VM, then on the target host,

  vmgenid_post_load()
    vmgenid_update_guest()

will not be effective, because (back on the source host) the guest had
no way to write the address of the downloaded "etc/vmgenid" blob to
"etc/vmgenid_addr".

I don't think it's a big deal, but perhaps we can be user-friendly a
bit. Things that crossed my mind (different levels of ugliness):

- in the realize function for vmgenid (which I've proposed anyway, for
registering the reset handler), we could look up the fw_cfg object, and
see if its "dma-enabled" property is on or off. Possible problem: not
sure if such cross-device checks are allowed in realize methods, and if
there are any ordering issues for this. (I.e., when vmgenid's realize
checks, has the property been set for fw_cfg?)

- or else, add another boolean property to vmgenid, one that parallels
"dma-enabled" of "fw-cfg" precisely, in HW_COMPAT*. Then simply fail
realize() when this property is false.

There are probably better ways...

Anyway, it's not a big deal, I think this can be addressed incrementally
(or not at all, perhaps). I don't want to delay the series with it, just
throwing it out there.

BTW, I tested the OVMF patches against v5, and it looks good. I
cross-referenced the firmware log with acpidump in the guest, plus I
used dump-guest-memory and the "crash" utility to check the memory
contents for the guest, before/after setting the GUID with the monitor
command.

I'd like to verify S3 too, but for that I'd like to use v6 (which I hope
clears "vgia_le" on reset).

Thanks,
Laszlo

> 
> v3->v4:
>     - Rebased to top of tree.
>     - Re-added document patch that was accidentally dropped from the last revision.
>     - Added VMState functionality so that VGIA is restored properly.
>     - Added Unit tests
> v2->v3:
>     - Added second writeable fw_cfg for storing the VM Generaiton ID
>       address.  This uses a new linker-loader command for instructing the
>       guest to write back the allocated address.  A patch for SeaBIOS has been
>       submitted (https://www.seabios.org/pipermail/seabios/2017-January/011079.html)
>       and the resulting binary will need to be pulled into QEMU once accepted.
>     - Setting VM Generation ID by command line or qmp/hmp now accepts an "auto"
>       value, whereby QEMU generates a random GUID.
>     - Incorporated review comments from v2 mainly around code styling and AML syntax
>     - Changed to use the E05 ACPI event instead of E00
> v1->v2:
>     - Removed "changed" boolean parameter as it is unneeded
>     - Added ACPI Notify logic
>     - Style changes to pass checkpatch.pl
>     - Added support for dynamic sysbus to pc_piix boards
> 
> 
> Ben Warren (8):
>   ACPI: Add a function for building named qword entries
>   linker-loader: Add new 'write pointer' command
>   docs: VM Generation ID device description
>   ACPI: Add vmgenid storage entries to the build tables
>   ACPI: Add Virtual Machine Generation ID support
>   PC: Support dynamic sysbus on pc_i440fx
>   tests: Move reusable ACPI macros into a new header file
>   tests: Add unit tests for the VM Generation ID feature
> 
> Igor Mammedov (2):
>   qmp/hmp: add query-vm-generation-id and 'info vm-generation-id'
>     commands
>   qmp/hmp: add set-vm-generation-id commands
> 
>  default-configs/i386-softmmu.mak     |   1 +
>  default-configs/x86_64-softmmu.mak   |   1 +
>  docs/specs/vmgenid.txt               | 239 +++++++++++++++++++++++++++++++++++
>  hmp-commands-info.hx                 |  13 ++
>  hmp-commands.hx                      |  13 ++
>  hmp.c                                |  21 +++
>  hmp.h                                |   2 +
>  hw/acpi/Makefile.objs                |   1 +
>  hw/acpi/aml-build.c                  |  39 +++++-
>  hw/acpi/bios-linker-loader.c         |  35 +++--
>  hw/acpi/nvdimm.c                     |   2 +-
>  hw/acpi/vmgenid.c                    | 238 ++++++++++++++++++++++++++++++++++
>  hw/arm/virt-acpi-build.c             |   4 +-
>  hw/i386/acpi-build.c                 |  18 ++-
>  hw/i386/pc_piix.c                    |   1 +
>  include/hw/acpi/acpi_dev_interface.h |   1 +
>  include/hw/acpi/aml-build.h          |   5 +
>  include/hw/acpi/bios-linker-loader.h |   3 +-
>  include/hw/acpi/vmgenid.h            |  37 ++++++
>  qapi-schema.json                     |  31 +++++
>  stubs/Makefile.objs                  |   1 +
>  stubs/vmgenid.c                      |  14 ++
>  tests/Makefile.include               |   2 +
>  tests/acpi-utils.h                   |  75 +++++++++++
>  tests/bios-tables-test.c             |  72 +----------
>  tests/vmgenid-test.c                 | 184 +++++++++++++++++++++++++++
>  26 files changed, 962 insertions(+), 91 deletions(-)
>  create mode 100644 docs/specs/vmgenid.txt
>  create mode 100644 hw/acpi/vmgenid.c
>  create mode 100644 include/hw/acpi/vmgenid.h
>  create mode 100644 stubs/vmgenid.c
>  create mode 100644 tests/acpi-utils.h
>  create mode 100644 tests/vmgenid-test.c
> 

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

* Re: [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID
  2017-02-10 10:12 ` [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID Laszlo Ersek
@ 2017-02-10 10:28   ` Igor Mammedov
  2017-02-10 15:31   ` Michael S. Tsirkin
  1 sibling, 0 replies; 70+ messages in thread
From: Igor Mammedov @ 2017-02-10 10:28 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: ben, qemu-devel, mst

On Fri, 10 Feb 2017 11:12:13 +0100
Laszlo Ersek <lersek@redhat.com> wrote:

> On 02/05/17 10:11, ben@skyportsystems.com wrote:
> > From: Ben Warren <ben@skyportsystems.com>
> > 
> > This patch set adds support for passing a GUID to Windows guests.  It is a
> > re-implementation of previous patch sets written by Igor Mammedov et al, but
> > this time passing the GUID data as a fw_cfg blob.
> > 
> > This patch set has dependencies on new guest functionality, in particular the
> > support for a new linker-loader command and the ability to write back data
> > to QEMU over a DMA link.  Work is in flight in both SeaBIOS and OVMF to support this.
> > 
> > v4->v5:
> >     - Added significantly more detail to the documentation.
> >     - Replaced the previously-implemented linker-loader command with a new one:
> >       "write pointer".  This allows writing the guest address of a fw_cfg blob back
> >       to an arbitrary offset in a writeable fw_cfg file visible to QEMU.  This will
> >       require support in SeaBIOS and OVMF (ongoing).
> >     - Fixed endianness issues throughout.
> >     - Several styling cleanups.  
> 
> Low importance question, but I'll ask it anyway:
> 
> Can we somehow make the realization of "-device vmgenid" fail, if the PC
> machine type in use is 2.6 or earlier? Because, those machine types do
> not have DMA enabled for fw_cfg. Hence the WRITE_POINTER commands cannot
> be effectively executed by firmware (the underlying virtual hardware is
> not enabled).
> 
> For example, if a user adds VMGENID to a 2.5 machine type, and migrates
> the VM, then on the target host,
> 
>   vmgenid_post_load()
>     vmgenid_update_guest()
> 
> will not be effective, because (back on the source host) the guest had
> no way to write the address of the downloaded "etc/vmgenid" blob to
> "etc/vmgenid_addr".
> 
> I don't think it's a big deal, but perhaps we can be user-friendly a
> bit. Things that crossed my mind (different levels of ugliness):
> 
> - in the realize function for vmgenid (which I've proposed anyway, for
> registering the reset handler), we could look up the fw_cfg object, and
> see if its "dma-enabled" property is on or off. Possible problem: not
> sure if such cross-device checks are allowed in realize methods, and if
> there are any ordering issues for this. (I.e., when vmgenid's realize
> checks, has the property been set for fw_cfg?)
> 
> - or else, add another boolean property to vmgenid, one that parallels
> "dma-enabled" of "fw-cfg" precisely, in HW_COMPAT*. Then simply fail
> realize() when this property is false.
we usually shouldn't poke from realize to outside world so
I'd go compat property way.


> There are probably better ways...
> 
> Anyway, it's not a big deal, I think this can be addressed incrementally
> (or not at all, perhaps). I don't want to delay the series with it, just
> throwing it out there.
> 
> BTW, I tested the OVMF patches against v5, and it looks good. I
> cross-referenced the firmware log with acpidump in the guest, plus I
> used dump-guest-memory and the "crash" utility to check the memory
> contents for the guest, before/after setting the GUID with the monitor
> command.
> 
> I'd like to verify S3 too, but for that I'd like to use v6 (which I hope
> clears "vgia_le" on reset).
> 
> Thanks,
> Laszlo
> 
> > 
> > v3->v4:
> >     - Rebased to top of tree.
> >     - Re-added document patch that was accidentally dropped from the last revision.
> >     - Added VMState functionality so that VGIA is restored properly.
> >     - Added Unit tests
> > v2->v3:
> >     - Added second writeable fw_cfg for storing the VM Generaiton ID
> >       address.  This uses a new linker-loader command for instructing the
> >       guest to write back the allocated address.  A patch for SeaBIOS has been
> >       submitted (https://www.seabios.org/pipermail/seabios/2017-January/011079.html)
> >       and the resulting binary will need to be pulled into QEMU once accepted.
> >     - Setting VM Generation ID by command line or qmp/hmp now accepts an "auto"
> >       value, whereby QEMU generates a random GUID.
> >     - Incorporated review comments from v2 mainly around code styling and AML syntax
> >     - Changed to use the E05 ACPI event instead of E00
> > v1->v2:
> >     - Removed "changed" boolean parameter as it is unneeded
> >     - Added ACPI Notify logic
> >     - Style changes to pass checkpatch.pl
> >     - Added support for dynamic sysbus to pc_piix boards
> > 
> > 
> > Ben Warren (8):
> >   ACPI: Add a function for building named qword entries
> >   linker-loader: Add new 'write pointer' command
> >   docs: VM Generation ID device description
> >   ACPI: Add vmgenid storage entries to the build tables
> >   ACPI: Add Virtual Machine Generation ID support
> >   PC: Support dynamic sysbus on pc_i440fx
> >   tests: Move reusable ACPI macros into a new header file
> >   tests: Add unit tests for the VM Generation ID feature
> > 
> > Igor Mammedov (2):
> >   qmp/hmp: add query-vm-generation-id and 'info vm-generation-id'
> >     commands
> >   qmp/hmp: add set-vm-generation-id commands
> > 
> >  default-configs/i386-softmmu.mak     |   1 +
> >  default-configs/x86_64-softmmu.mak   |   1 +
> >  docs/specs/vmgenid.txt               | 239 +++++++++++++++++++++++++++++++++++
> >  hmp-commands-info.hx                 |  13 ++
> >  hmp-commands.hx                      |  13 ++
> >  hmp.c                                |  21 +++
> >  hmp.h                                |   2 +
> >  hw/acpi/Makefile.objs                |   1 +
> >  hw/acpi/aml-build.c                  |  39 +++++-
> >  hw/acpi/bios-linker-loader.c         |  35 +++--
> >  hw/acpi/nvdimm.c                     |   2 +-
> >  hw/acpi/vmgenid.c                    | 238 ++++++++++++++++++++++++++++++++++
> >  hw/arm/virt-acpi-build.c             |   4 +-
> >  hw/i386/acpi-build.c                 |  18 ++-
> >  hw/i386/pc_piix.c                    |   1 +
> >  include/hw/acpi/acpi_dev_interface.h |   1 +
> >  include/hw/acpi/aml-build.h          |   5 +
> >  include/hw/acpi/bios-linker-loader.h |   3 +-
> >  include/hw/acpi/vmgenid.h            |  37 ++++++
> >  qapi-schema.json                     |  31 +++++
> >  stubs/Makefile.objs                  |   1 +
> >  stubs/vmgenid.c                      |  14 ++
> >  tests/Makefile.include               |   2 +
> >  tests/acpi-utils.h                   |  75 +++++++++++
> >  tests/bios-tables-test.c             |  72 +----------
> >  tests/vmgenid-test.c                 | 184 +++++++++++++++++++++++++++
> >  26 files changed, 962 insertions(+), 91 deletions(-)
> >  create mode 100644 docs/specs/vmgenid.txt
> >  create mode 100644 hw/acpi/vmgenid.c
> >  create mode 100644 include/hw/acpi/vmgenid.h
> >  create mode 100644 stubs/vmgenid.c
> >  create mode 100644 tests/acpi-utils.h
> >  create mode 100644 tests/vmgenid-test.c
> >   
> 

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

* Re: [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID
  2017-02-10 10:12 ` [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID Laszlo Ersek
  2017-02-10 10:28   ` Igor Mammedov
@ 2017-02-10 15:31   ` Michael S. Tsirkin
  2017-02-10 16:16     ` Igor Mammedov
  1 sibling, 1 reply; 70+ messages in thread
From: Michael S. Tsirkin @ 2017-02-10 15:31 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: ben, qemu-devel, imammedo

On Fri, Feb 10, 2017 at 11:12:13AM +0100, Laszlo Ersek wrote:
> On 02/05/17 10:11, ben@skyportsystems.com wrote:
> > From: Ben Warren <ben@skyportsystems.com>
> > 
> > This patch set adds support for passing a GUID to Windows guests.  It is a
> > re-implementation of previous patch sets written by Igor Mammedov et al, but
> > this time passing the GUID data as a fw_cfg blob.
> > 
> > This patch set has dependencies on new guest functionality, in particular the
> > support for a new linker-loader command and the ability to write back data
> > to QEMU over a DMA link.  Work is in flight in both SeaBIOS and OVMF to support this.
> > 
> > v4->v5:
> >     - Added significantly more detail to the documentation.
> >     - Replaced the previously-implemented linker-loader command with a new one:
> >       "write pointer".  This allows writing the guest address of a fw_cfg blob back
> >       to an arbitrary offset in a writeable fw_cfg file visible to QEMU.  This will
> >       require support in SeaBIOS and OVMF (ongoing).
> >     - Fixed endianness issues throughout.
> >     - Several styling cleanups.
> 
> Low importance question, but I'll ask it anyway:
> 
> Can we somehow make the realization of "-device vmgenid" fail, if the PC
> machine type in use is 2.6 or earlier? Because, those machine types do
> not have DMA enabled for fw_cfg. Hence the WRITE_POINTER commands cannot
> be effectively executed by firmware (the underlying virtual hardware is
> not enabled).
> 
> For example, if a user adds VMGENID to a 2.5 machine type, and migrates
> the VM, then on the target host,
> 
>   vmgenid_post_load()
>     vmgenid_update_guest()
> 
> will not be effective, because (back on the source host) the guest had
> no way to write the address of the downloaded "etc/vmgenid" blob to
> "etc/vmgenid_addr".
> 
> I don't think it's a big deal, but perhaps we can be user-friendly a
> bit.

The most user-friendly thing would be to DWIM and enable DMA.
But that would be hard to implement so probably not
worth the trouble.

> Things that crossed my mind (different levels of ugliness):
> 
> - in the realize function for vmgenid (which I've proposed anyway, for
> registering the reset handler), we could look up the fw_cfg object, and
> see if its "dma-enabled" property is on or off. Possible problem: not
> sure if such cross-device checks are allowed in realize methods, and if
> there are any ordering issues for this. (I.e., when vmgenid's realize
> checks, has the property been set for fw_cfg?)
> 
> - or else, add another boolean property to vmgenid, one that parallels
> "dma-enabled" of "fw-cfg" precisely, in HW_COMPAT*. Then simply fail
> realize() when this property is false.

That's probably the easiest way. x-fw-cfg-dma-enabled.
Won't delay merging because of this, can be done with
patch on top.

> There are probably better ways...
> 
> Anyway, it's not a big deal, I think this can be addressed incrementally
> (or not at all, perhaps). I don't want to delay the series with it, just
> throwing it out there.

Yes, pls do not delay because of this.

> BTW, I tested the OVMF patches against v5, and it looks good. I
> cross-referenced the firmware log with acpidump in the guest, plus I
> used dump-guest-memory and the "crash" utility to check the memory
> contents for the guest, before/after setting the GUID with the monitor
> command.
> 
> I'd like to verify S3 too, but for that I'd like to use v6 (which I hope
> clears "vgia_le" on reset).
> 
> Thanks,
> Laszlo
> 
> > 
> > v3->v4:
> >     - Rebased to top of tree.
> >     - Re-added document patch that was accidentally dropped from the last revision.
> >     - Added VMState functionality so that VGIA is restored properly.
> >     - Added Unit tests
> > v2->v3:
> >     - Added second writeable fw_cfg for storing the VM Generaiton ID
> >       address.  This uses a new linker-loader command for instructing the
> >       guest to write back the allocated address.  A patch for SeaBIOS has been
> >       submitted (https://www.seabios.org/pipermail/seabios/2017-January/011079.html)
> >       and the resulting binary will need to be pulled into QEMU once accepted.
> >     - Setting VM Generation ID by command line or qmp/hmp now accepts an "auto"
> >       value, whereby QEMU generates a random GUID.
> >     - Incorporated review comments from v2 mainly around code styling and AML syntax
> >     - Changed to use the E05 ACPI event instead of E00
> > v1->v2:
> >     - Removed "changed" boolean parameter as it is unneeded
> >     - Added ACPI Notify logic
> >     - Style changes to pass checkpatch.pl
> >     - Added support for dynamic sysbus to pc_piix boards
> > 
> > 
> > Ben Warren (8):
> >   ACPI: Add a function for building named qword entries
> >   linker-loader: Add new 'write pointer' command
> >   docs: VM Generation ID device description
> >   ACPI: Add vmgenid storage entries to the build tables
> >   ACPI: Add Virtual Machine Generation ID support
> >   PC: Support dynamic sysbus on pc_i440fx
> >   tests: Move reusable ACPI macros into a new header file
> >   tests: Add unit tests for the VM Generation ID feature
> > 
> > Igor Mammedov (2):
> >   qmp/hmp: add query-vm-generation-id and 'info vm-generation-id'
> >     commands
> >   qmp/hmp: add set-vm-generation-id commands
> > 
> >  default-configs/i386-softmmu.mak     |   1 +
> >  default-configs/x86_64-softmmu.mak   |   1 +
> >  docs/specs/vmgenid.txt               | 239 +++++++++++++++++++++++++++++++++++
> >  hmp-commands-info.hx                 |  13 ++
> >  hmp-commands.hx                      |  13 ++
> >  hmp.c                                |  21 +++
> >  hmp.h                                |   2 +
> >  hw/acpi/Makefile.objs                |   1 +
> >  hw/acpi/aml-build.c                  |  39 +++++-
> >  hw/acpi/bios-linker-loader.c         |  35 +++--
> >  hw/acpi/nvdimm.c                     |   2 +-
> >  hw/acpi/vmgenid.c                    | 238 ++++++++++++++++++++++++++++++++++
> >  hw/arm/virt-acpi-build.c             |   4 +-
> >  hw/i386/acpi-build.c                 |  18 ++-
> >  hw/i386/pc_piix.c                    |   1 +
> >  include/hw/acpi/acpi_dev_interface.h |   1 +
> >  include/hw/acpi/aml-build.h          |   5 +
> >  include/hw/acpi/bios-linker-loader.h |   3 +-
> >  include/hw/acpi/vmgenid.h            |  37 ++++++
> >  qapi-schema.json                     |  31 +++++
> >  stubs/Makefile.objs                  |   1 +
> >  stubs/vmgenid.c                      |  14 ++
> >  tests/Makefile.include               |   2 +
> >  tests/acpi-utils.h                   |  75 +++++++++++
> >  tests/bios-tables-test.c             |  72 +----------
> >  tests/vmgenid-test.c                 | 184 +++++++++++++++++++++++++++
> >  26 files changed, 962 insertions(+), 91 deletions(-)
> >  create mode 100644 docs/specs/vmgenid.txt
> >  create mode 100644 hw/acpi/vmgenid.c
> >  create mode 100644 include/hw/acpi/vmgenid.h
> >  create mode 100644 stubs/vmgenid.c
> >  create mode 100644 tests/acpi-utils.h
> >  create mode 100644 tests/vmgenid-test.c
> > 

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

* Re: [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID
  2017-02-10 15:31   ` Michael S. Tsirkin
@ 2017-02-10 16:16     ` Igor Mammedov
  2017-02-10 18:18       ` Andrew Jones
  0 siblings, 1 reply; 70+ messages in thread
From: Igor Mammedov @ 2017-02-10 16:16 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Laszlo Ersek, qemu-devel, ben, Peter Maydell, Andreas Färber

On Fri, 10 Feb 2017 17:31:33 +0200
"Michael S. Tsirkin" <mst@redhat.com> wrote:

> On Fri, Feb 10, 2017 at 11:12:13AM +0100, Laszlo Ersek wrote:
> > On 02/05/17 10:11, ben@skyportsystems.com wrote:  
> > > From: Ben Warren <ben@skyportsystems.com>
[...]

> > 
> > - or else, add another boolean property to vmgenid, one that parallels
> > "dma-enabled" of "fw-cfg" precisely, in HW_COMPAT*. Then simply fail
> > realize() when this property is false.  
> 
> That's probably the easiest way. x-fw-cfg-dma-enabled.
> Won't delay merging because of this, can be done with
> patch on top.
(not related to this series)

I've thought that there still were no consensus on x-foo prefix,
not to mention that x- might be legitimate prefix for some properties.

Maybe we should add a flag to property like INTERNAL_PROPERTY
and then set it explicitly on for internal stuff.

That way we could cleanly exclude internal properties from
 -device foo,help and make sure that user won't set them from CLI.
I'd even volunteer to add this API to Object

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

* Re: [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID
  2017-02-10 16:16     ` Igor Mammedov
@ 2017-02-10 18:18       ` Andrew Jones
  2017-02-10 18:27         ` Andreas Färber
  0 siblings, 1 reply; 70+ messages in thread
From: Andrew Jones @ 2017-02-10 18:18 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Michael S. Tsirkin, Peter Maydell, Laszlo Ersek, qemu-devel, ben,
	Andreas Färber

On Fri, Feb 10, 2017 at 05:16:59PM +0100, Igor Mammedov wrote:
> On Fri, 10 Feb 2017 17:31:33 +0200
> "Michael S. Tsirkin" <mst@redhat.com> wrote:
> 
> > On Fri, Feb 10, 2017 at 11:12:13AM +0100, Laszlo Ersek wrote:
> > > On 02/05/17 10:11, ben@skyportsystems.com wrote:  
> > > > From: Ben Warren <ben@skyportsystems.com>
> [...]
> 
> > > 
> > > - or else, add another boolean property to vmgenid, one that parallels
> > > "dma-enabled" of "fw-cfg" precisely, in HW_COMPAT*. Then simply fail
> > > realize() when this property is false.  
> > 
> > That's probably the easiest way. x-fw-cfg-dma-enabled.
> > Won't delay merging because of this, can be done with
> > patch on top.
> (not related to this series)
> 
> I've thought that there still were no consensus on x-foo prefix,
> not to mention that x- might be legitimate prefix for some properties.
> 
> Maybe we should add a flag to property like INTERNAL_PROPERTY
> and then set it explicitly on for internal stuff.
> 
> That way we could cleanly exclude internal properties from
>  -device foo,help and make sure that user won't set them from CLI.
> I'd even volunteer to add this API to Object

Yes, please. I know of a property or two where it would be nice to
have that flag.

Thanks,
drew

> 
> 

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

* Re: [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID
  2017-02-10 18:18       ` Andrew Jones
@ 2017-02-10 18:27         ` Andreas Färber
  2017-02-13 11:00           ` Igor Mammedov
  0 siblings, 1 reply; 70+ messages in thread
From: Andreas Färber @ 2017-02-10 18:27 UTC (permalink / raw)
  To: Andrew Jones, Igor Mammedov
  Cc: Michael S. Tsirkin, Peter Maydell, Laszlo Ersek, qemu-devel, ben

Am 10.02.2017 um 19:18 schrieb Andrew Jones:
> On Fri, Feb 10, 2017 at 05:16:59PM +0100, Igor Mammedov wrote:
>> On Fri, 10 Feb 2017 17:31:33 +0200
>> "Michael S. Tsirkin" <mst@redhat.com> wrote:
>>
>>> On Fri, Feb 10, 2017 at 11:12:13AM +0100, Laszlo Ersek wrote:
>>>> On 02/05/17 10:11, ben@skyportsystems.com wrote:  
>>>>> From: Ben Warren <ben@skyportsystems.com>
>> [...]
>>
>>>>
>>>> - or else, add another boolean property to vmgenid, one that parallels
>>>> "dma-enabled" of "fw-cfg" precisely, in HW_COMPAT*. Then simply fail
>>>> realize() when this property is false.  
>>>
>>> That's probably the easiest way. x-fw-cfg-dma-enabled.
>>> Won't delay merging because of this, can be done with
>>> patch on top.
>> (not related to this series)
>>
>> I've thought that there still were no consensus on x-foo prefix,
>> not to mention that x- might be legitimate prefix for some properties.
>>
>> Maybe we should add a flag to property like INTERNAL_PROPERTY
>> and then set it explicitly on for internal stuff.
>>
>> That way we could cleanly exclude internal properties from
>>  -device foo,help and make sure that user won't set them from CLI.
>> I'd even volunteer to add this API to Object
> 
> Yes, please. I know of a property or two where it would be nice to
> have that flag.

Apart from documentation, what effect would such a flag have?

With QOM I don't really see "internal" as being a thing: Besides -device
and the likes, we expose qom-set operation and -global option, and I
don't think it makes sense to restrict the latter two. For -device,
"realized" is a property I would classify as non-user maybe.

Regards,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

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

* Re: [Qemu-devel] [PATCH v5 08/10] PC: Support dynamic sysbus on pc_i440fx
  2017-02-06 16:31   ` Michael S. Tsirkin
@ 2017-02-12 19:55     ` Marcel Apfelbaum
  2017-02-13  0:32       ` Ben Warren
  0 siblings, 1 reply; 70+ messages in thread
From: Marcel Apfelbaum @ 2017-02-12 19:55 UTC (permalink / raw)
  To: Michael S. Tsirkin, ben; +Cc: imammedo, lersek, qemu-devel, Marcel Apfelbaum

On 02/06/2017 06:31 PM, Michael S. Tsirkin wrote:
> On Sun, Feb 05, 2017 at 01:12:03AM -0800, ben@skyportsystems.com wrote:
>> From: Ben Warren <ben@skyportsystems.com>
>>
>> This allows pc_i440fx-based machines to add new devices such as
>> VM Generation ID directly to the sysbus.
>>
>> Signed-off-by: Ben Warren <ben@skyportsystems.com>
>

Hi,

> Only point is, we might have to add more flags like
> cannot_instantiate_with_device_add_yet
> to a bunch of devices.
>
> Marcel, you did a similar thing for q35, can you
> take a look here as well pls?
>

The change is a must because the new vmgenid device
is a sysbus device and QEMU will not allow it without
marking explicitly that i440fx supports sysbus device.

As you already mentioned, we need to make sure that
all sysbus devices that can be added to the PC machines
are marked with "cannot_instantiate_with_device_add_yet".

Sadly I see no easy way, but going manually over each one...

Thanks,
Marcel

>> ---
>>  hw/i386/pc_piix.c | 1 +
>>  1 file changed, 1 insertion(+)
>>
>> diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
>> index 9f102aa..c8ad99c 100644
>> --- a/hw/i386/pc_piix.c
>> +++ b/hw/i386/pc_piix.c
>> @@ -435,6 +435,7 @@ static void pc_i440fx_machine_options(MachineClass *m)
>>      m->hot_add_cpu = pc_hot_add_cpu;
>>      m->default_machine_opts = "firmware=bios-256k.bin";
>>      m->default_display = "std";
>> +    m->has_dynamic_sysbus = true;
>>  }
>>
>>  static void pc_i440fx_2_9_machine_options(MachineClass *m)
>> --
>> 2.7.4
>

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

* Re: [Qemu-devel] [PATCH v5 08/10] PC: Support dynamic sysbus on pc_i440fx
  2017-02-12 19:55     ` Marcel Apfelbaum
@ 2017-02-13  0:32       ` Ben Warren
  0 siblings, 0 replies; 70+ messages in thread
From: Ben Warren @ 2017-02-13  0:32 UTC (permalink / raw)
  To: marcel; +Cc: Michael S. Tsirkin, imammedo, lersek, qemu-devel, Marcel Apfelbaum

[-- Attachment #1: Type: text/plain, Size: 1986 bytes --]

Hi
> On Feb 12, 2017, at 11:55 AM, Marcel Apfelbaum <marcel.apfelbaum@gmail.com> wrote:
> 
> On 02/06/2017 06:31 PM, Michael S. Tsirkin wrote:
>> On Sun, Feb 05, 2017 at 01:12:03AM -0800, ben@skyportsystems.com wrote:
>>> From: Ben Warren <ben@skyportsystems.com>
>>> 
>>> This allows pc_i440fx-based machines to add new devices such as
>>> VM Generation ID directly to the sysbus.
>>> 
>>> Signed-off-by: Ben Warren <ben@skyportsystems.com>
>> 
> 
> Hi,
> 
>> Only point is, we might have to add more flags like
>> cannot_instantiate_with_device_add_yet
>> to a bunch of devices.
>> 
>> Marcel, you did a similar thing for q35, can you
>> take a look here as well pls?
>> 
> 
> The change is a must because the new vmgenid device
> is a sysbus device and QEMU will not allow it without
> marking explicitly that i440fx supports sysbus device.
> 
As recommended by Igor, I was able to make the vmgenid work with DeviceClass as parent (i.e. not on sysbus), so this work can be deferred until it’s really needed.  The next patch set (hopefully posted tonight) will drop this patch.
> As you already mentioned, we need to make sure that
> all sysbus devices that can be added to the PC machines
> are marked with "cannot_instantiate_with_device_add_yet".
> 
> Sadly I see no easy way, but going manually over each one...
> 
> Thanks,
> Marcel
> 
—Ben
>>> ---
>>> hw/i386/pc_piix.c | 1 +
>>> 1 file changed, 1 insertion(+)
>>> 
>>> diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
>>> index 9f102aa..c8ad99c 100644
>>> --- a/hw/i386/pc_piix.c
>>> +++ b/hw/i386/pc_piix.c
>>> @@ -435,6 +435,7 @@ static void pc_i440fx_machine_options(MachineClass *m)
>>>     m->hot_add_cpu = pc_hot_add_cpu;
>>>     m->default_machine_opts = "firmware=bios-256k.bin";
>>>     m->default_display = "std";
>>> +    m->has_dynamic_sysbus = true;
>>> }
>>> 
>>> static void pc_i440fx_2_9_machine_options(MachineClass *m)
>>> --
>>> 2.7.4
>> 
> 


[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 3583 bytes --]

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

* Re: [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID
  2017-02-10 18:27         ` Andreas Färber
@ 2017-02-13 11:00           ` Igor Mammedov
  2017-02-13 13:00             ` Michael S. Tsirkin
  0 siblings, 1 reply; 70+ messages in thread
From: Igor Mammedov @ 2017-02-13 11:00 UTC (permalink / raw)
  To: Andreas Färber
  Cc: Andrew Jones, Michael S. Tsirkin, Peter Maydell, Laszlo Ersek,
	qemu-devel, ben, Daniel P. Berrange, Eric Blake

On Fri, 10 Feb 2017 19:27:21 +0100
Andreas Färber <afaerber@suse.de> wrote:

> Am 10.02.2017 um 19:18 schrieb Andrew Jones:
> > On Fri, Feb 10, 2017 at 05:16:59PM +0100, Igor Mammedov wrote:  
> >> On Fri, 10 Feb 2017 17:31:33 +0200
> >> "Michael S. Tsirkin" <mst@redhat.com> wrote:
> >>  
> >>> On Fri, Feb 10, 2017 at 11:12:13AM +0100, Laszlo Ersek wrote:  
> >>>> On 02/05/17 10:11, ben@skyportsystems.com wrote:    
> >>>>> From: Ben Warren <ben@skyportsystems.com>  
> >> [...]
> >>  
> >>>>
> >>>> - or else, add another boolean property to vmgenid, one that parallels
> >>>> "dma-enabled" of "fw-cfg" precisely, in HW_COMPAT*. Then simply fail
> >>>> realize() when this property is false.    
> >>>
> >>> That's probably the easiest way. x-fw-cfg-dma-enabled.
> >>> Won't delay merging because of this, can be done with
> >>> patch on top.  
> >> (not related to this series)
> >>
> >> I've thought that there still were no consensus on x-foo prefix,
> >> not to mention that x- might be legitimate prefix for some properties.
> >>
> >> Maybe we should add a flag to property like INTERNAL_PROPERTY
> >> and then set it explicitly on for internal stuff.
> >>
> >> That way we could cleanly exclude internal properties from
> >>  -device foo,help and make sure that user won't set them from CLI.
> >> I'd even volunteer to add this API to Object  
> > 
> > Yes, please. I know of a property or two where it would be nice to
> > have that flag.  
> 
> Apart from documentation, what effect would such a flag have?
> 
> With QOM I don't really see "internal" as being a thing: Besides -device
> and the likes, we expose qom-set operation and -global option, and I
> don't think it makes sense to restrict the latter two. For -device,
> "realized" is a property I would classify as non-user maybe.
I'd propose to start with this flag hiding/forbiding usage of
property in following interfaces:

  * -device
  * -device foo,help
  * device_add

With docs mentioning that usage of hidden properties with
 -globals/qom-set isn't recommended.
  
> 
> Regards,
> Andreas
> 

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

* Re: [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID
  2017-02-13 11:00           ` Igor Mammedov
@ 2017-02-13 13:00             ` Michael S. Tsirkin
  2017-02-13 13:40               ` Igor Mammedov
  0 siblings, 1 reply; 70+ messages in thread
From: Michael S. Tsirkin @ 2017-02-13 13:00 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Andreas Färber, Andrew Jones, Peter Maydell, Laszlo Ersek,
	qemu-devel, ben, Daniel P. Berrange, Eric Blake

On Mon, Feb 13, 2017 at 12:00:36PM +0100, Igor Mammedov wrote:
> On Fri, 10 Feb 2017 19:27:21 +0100
> Andreas Färber <afaerber@suse.de> wrote:
> 
> > Am 10.02.2017 um 19:18 schrieb Andrew Jones:
> > > On Fri, Feb 10, 2017 at 05:16:59PM +0100, Igor Mammedov wrote:  
> > >> On Fri, 10 Feb 2017 17:31:33 +0200
> > >> "Michael S. Tsirkin" <mst@redhat.com> wrote:
> > >>  
> > >>> On Fri, Feb 10, 2017 at 11:12:13AM +0100, Laszlo Ersek wrote:  
> > >>>> On 02/05/17 10:11, ben@skyportsystems.com wrote:    
> > >>>>> From: Ben Warren <ben@skyportsystems.com>  
> > >> [...]
> > >>  
> > >>>>
> > >>>> - or else, add another boolean property to vmgenid, one that parallels
> > >>>> "dma-enabled" of "fw-cfg" precisely, in HW_COMPAT*. Then simply fail
> > >>>> realize() when this property is false.    
> > >>>
> > >>> That's probably the easiest way. x-fw-cfg-dma-enabled.
> > >>> Won't delay merging because of this, can be done with
> > >>> patch on top.  
> > >> (not related to this series)
> > >>
> > >> I've thought that there still were no consensus on x-foo prefix,
> > >> not to mention that x- might be legitimate prefix for some properties.
> > >>
> > >> Maybe we should add a flag to property like INTERNAL_PROPERTY
> > >> and then set it explicitly on for internal stuff.
> > >>
> > >> That way we could cleanly exclude internal properties from
> > >>  -device foo,help and make sure that user won't set them from CLI.
> > >> I'd even volunteer to add this API to Object  
> > > 
> > > Yes, please. I know of a property or two where it would be nice to
> > > have that flag.  
> > 
> > Apart from documentation, what effect would such a flag have?
> > 
> > With QOM I don't really see "internal" as being a thing: Besides -device
> > and the likes, we expose qom-set operation and -global option, and I
> > don't think it makes sense to restrict the latter two. For -device,
> > "realized" is a property I would classify as non-user maybe.
> I'd propose to start with this flag hiding/forbiding usage of
> property in following interfaces:
> 
>   * -device
>   * -device foo,help
>   * device_add
> 
> With docs mentioning that usage of hidden properties with
>  -globals/qom-set isn't recommended.

I'm not sure I agree. These properties can be useful e.g. for debugging,
the only issue is we don't guarantee to support them across QEMU
releases. If you won't want something exposed to users, don't make it a
property at all.

Producing a warning when a property starting with x- is set
might not be a bad idea.

> > 
> > Regards,
> > Andreas
> > 

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

* Re: [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID
  2017-02-13 13:00             ` Michael S. Tsirkin
@ 2017-02-13 13:40               ` Igor Mammedov
  0 siblings, 0 replies; 70+ messages in thread
From: Igor Mammedov @ 2017-02-13 13:40 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Peter Maydell, Andrew Jones, ben, qemu-devel, Laszlo Ersek,
	Andreas Färber, Paolo Bonzini

On Mon, 13 Feb 2017 15:00:22 +0200
"Michael S. Tsirkin" <mst@redhat.com> wrote:

> On Mon, Feb 13, 2017 at 12:00:36PM +0100, Igor Mammedov wrote:
> > On Fri, 10 Feb 2017 19:27:21 +0100
> > Andreas Färber <afaerber@suse.de> wrote:
> >   
> > > Am 10.02.2017 um 19:18 schrieb Andrew Jones:  
> > > > On Fri, Feb 10, 2017 at 05:16:59PM +0100, Igor Mammedov wrote:    
> > > >> On Fri, 10 Feb 2017 17:31:33 +0200
> > > >> "Michael S. Tsirkin" <mst@redhat.com> wrote:
> > > >>    
> > > >>> On Fri, Feb 10, 2017 at 11:12:13AM +0100, Laszlo Ersek wrote:    
> > > >>>> On 02/05/17 10:11, ben@skyportsystems.com wrote:      
> > > >>>>> From: Ben Warren <ben@skyportsystems.com>    
> > > >> [...]
> > > >>    
> > > >>>>
> > > >>>> - or else, add another boolean property to vmgenid, one that parallels
> > > >>>> "dma-enabled" of "fw-cfg" precisely, in HW_COMPAT*. Then simply fail
> > > >>>> realize() when this property is false.      
> > > >>>
> > > >>> That's probably the easiest way. x-fw-cfg-dma-enabled.
> > > >>> Won't delay merging because of this, can be done with
> > > >>> patch on top.    
> > > >> (not related to this series)
> > > >>
> > > >> I've thought that there still were no consensus on x-foo prefix,
> > > >> not to mention that x- might be legitimate prefix for some properties.
*1

> > > >>
> > > >> Maybe we should add a flag to property like INTERNAL_PROPERTY
> > > >> and then set it explicitly on for internal stuff.
> > > >>
> > > >> That way we could cleanly exclude internal properties from
> > > >>  -device foo,help and make sure that user won't set them from CLI.
> > > >> I'd even volunteer to add this API to Object    
> > > > 
> > > > Yes, please. I know of a property or two where it would be nice to
> > > > have that flag.    
> > > 
> > > Apart from documentation, what effect would such a flag have?
> > > 
> > > With QOM I don't really see "internal" as being a thing: Besides -device
> > > and the likes, we expose qom-set operation and -global option, and I
> > > don't think it makes sense to restrict the latter two. For -device,
> > > "realized" is a property I would classify as non-user maybe.  
> > I'd propose to start with this flag hiding/forbiding usage of
> > property in following interfaces:
> > 
> >   * -device
> >   * -device foo,help
> >   * device_add
> > 
> > With docs mentioning that usage of hidden properties with
> >  -globals/qom-set isn't recommended.  
> 
> I'm not sure I agree. These properties can be useful e.g. for debugging,
> the only issue is we don't guarantee to support them across QEMU
> releases. If you won't want something exposed to users, don't make it a
> property at all.
Property approach is cleaner especially in cases where
it's used to tie together generic with target-specific code
+ automatically makes feature introspect-able via qom-get
(I've used it for debugging to poke into object properties
without need for gdb).
Replacing property with direct function call makes one
to create stubs (I've seen Paolo working on removing stubs)
for targets that do not implement it or uglifying headers with
target specific ifdefs.

> Producing a warning when a property starting with x- is set
> might not be a bad idea.
I don't like x- prefix for above [1] and
we already have a bunch of properties that shouldn't be
user settable that makes x- convention inconsistent.
so how about following:
   * -device foo,help:
       * hide non user flagged properties or
       *less preferable mark them as non stable/supportable
   * issue warning in case such property is used
     with -device/device_add
   * since it's warning we could probably put it in -globals as well
     so user would notice probable misuse
  

> > > 
> > > Regards,
> > > Andreas
> > >   
> 

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

end of thread, other threads:[~2017-02-13 13:40 UTC | newest]

Thread overview: 70+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-05  9:11 [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID ben
2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 01/10] ACPI: Add a function for building named qword entries ben
2017-02-07 13:51   ` Igor Mammedov
2017-02-07 20:09     ` Laszlo Ersek
2017-02-08 10:43       ` Igor Mammedov
2017-02-08 10:53         ` Laszlo Ersek
2017-02-08 20:24           ` Ben Warren
2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 02/10] linker-loader: Add new 'write pointer' command ben
2017-02-06 14:56   ` Michael S. Tsirkin
2017-02-06 17:16     ` Ben Warren
2017-02-06 17:31       ` Michael S. Tsirkin
2017-02-07 12:11         ` Igor Mammedov
2017-02-07 20:20           ` Laszlo Ersek
2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 03/10] docs: VM Generation ID device description ben
2017-02-06 20:18   ` Eric Blake
2017-02-07 20:54   ` Laszlo Ersek
2017-02-10  0:55   ` Laszlo Ersek
2017-02-05  9:11 ` [Qemu-devel] [PATCH v5 04/10] ACPI: Add vmgenid storage entries to the build tables ben
2017-02-07 22:06   ` Laszlo Ersek
2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 05/10] ACPI: Add Virtual Machine Generation ID support ben
2017-02-06 16:15   ` Michael S. Tsirkin
2017-02-06 17:29     ` Ben Warren
2017-02-06 17:41       ` Michael S. Tsirkin
2017-02-06 17:59         ` Ben Warren
2017-02-06 18:17           ` Michael S. Tsirkin
2017-02-06 18:48             ` Ben Warren
2017-02-06 19:04               ` Michael S. Tsirkin
2017-02-06 19:44                 ` Ben Warren
2017-02-07 14:00         ` Igor Mammedov
2017-02-07 15:35           ` Michael S. Tsirkin
2017-02-07 16:04             ` Igor Mammedov
2017-02-07 16:22               ` Michael S. Tsirkin
2017-02-07 13:48   ` Igor Mammedov
2017-02-07 15:36     ` Michael S. Tsirkin
2017-02-08 20:19     ` Ben Warren
2017-02-09  9:59       ` Igor Mammedov
2017-02-08  0:48   ` Laszlo Ersek
2017-02-08 11:04     ` Igor Mammedov
2017-02-08 11:17       ` Laszlo Ersek
2017-02-08 12:00         ` Igor Mammedov
2017-02-08 22:34     ` Ben Warren
2017-02-08 23:43       ` Laszlo Ersek
2017-02-09 17:23     ` Igor Mammedov
2017-02-09 18:21       ` Michael S. Tsirkin
2017-02-09 19:27       ` Laszlo Ersek
2017-02-09 20:02         ` Ben Warren
2017-02-09 20:24           ` Laszlo Ersek
2017-02-09 20:39             ` Ben Warren
2017-02-10  8:54               ` Igor Mammedov
2017-02-09  0:37   ` Laszlo Ersek
2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 06/10] qmp/hmp: add query-vm-generation-id and 'info vm-generation-id' commands ben
2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 07/10] qmp/hmp: add set-vm-generation-id commands ben
2017-02-07 13:50   ` Igor Mammedov
2017-02-08 22:01   ` Laszlo Ersek
2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 08/10] PC: Support dynamic sysbus on pc_i440fx ben
2017-02-06 16:31   ` Michael S. Tsirkin
2017-02-12 19:55     ` Marcel Apfelbaum
2017-02-13  0:32       ` Ben Warren
2017-02-07 14:05   ` Igor Mammedov
2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 09/10] tests: Move reusable ACPI macros into a new header file ben
2017-02-05  9:12 ` [Qemu-devel] [PATCH v5 10/10] tests: Add unit tests for the VM Generation ID feature ben
2017-02-10 10:12 ` [Qemu-devel] [PATCH v5 00/10] Add support for VM Generation ID Laszlo Ersek
2017-02-10 10:28   ` Igor Mammedov
2017-02-10 15:31   ` Michael S. Tsirkin
2017-02-10 16:16     ` Igor Mammedov
2017-02-10 18:18       ` Andrew Jones
2017-02-10 18:27         ` Andreas Färber
2017-02-13 11:00           ` Igor Mammedov
2017-02-13 13:00             ` Michael S. Tsirkin
2017-02-13 13:40               ` Igor Mammedov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.