All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI
@ 2016-12-01 17:06 Laszlo Ersek
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 1/7] fw-cfg: support writeable blobs Laszlo Ersek
                   ` (8 more replies)
  0 siblings, 9 replies; 46+ messages in thread
From: Laszlo Ersek @ 2016-12-01 17:06 UTC (permalink / raw)
  To: qemu devel list
  Cc: Gabriel L. Somlo, Michael S. Tsirkin, Eduardo Habkost,
	Gerd Hoffmann, Igor Mammedov, Michael Walle, Paolo Bonzini,
	Peter Maydell, Shannon Zhao, qemu-arm

* This is version 4 of the series; the last version was at
  <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03582.html>.

  This version is practically a rewrite from scratch, seeking to address
  the v3 feedback. Here's what the individual patches do:

  - Patch #1 rebases and extends Michael's "writeable fw_cfg blobs"
    patch from Feb/March 2016. The changes relative to the original
    patch are documented in the commit message (the code changes are
    minimal).

  - Patches #2 and #3 turn the FW_CFG_FILE_SLOTS constant into a device
    property, and expose the desired number of fw_cfg file slots to
    board code. This is meant to address a concern raised by Paolo in
    the v2 review
    <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03125.html>,
    namely that we're about to run out of FW_CFG_FILE_SLOTS.

  - Patch #4 introduces the "pc-q35-2.9" and "pc-i440fx-2.9" machine
    types, which are allowed to take advantage of the new default for
    fw_cfg file slots (0x20 rather than 0x10).

  - Patch #5 introduces SMI feature negotiation via fw_cfg, with the
    following new files:

    - etc/smi/host-features
    - etc/smi/guest-features
    - etc/smi/features-ok

    This is supposed to follow Michael's recommendation re: imitating
    virtio
    <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03218.html>.

    The guest-features file is freely writeable by the guest (no write
    callbacks in fw_cfg), and the feature validation & lockdown occurs
    when the guest selects the features-ok file (for reading).

    Board code is allowed to choose the host feature bitmap to
    advertise.

    This patch doesn't add any specific SMI features yet.

  - Patch #6 adds the ICH9_LPC_SMI_F_BROADCAST feature.

  - Patch #7 introduces the PCMachineClass.get_smi_host_features method,
    and implements it for "pc-q35-2.9" and later. The idea is to tie the
    SMI host features to machine types, and let the machine types
    calculate their host features with code (i.e., not just a constant).

    In this patch, the "pc-q35-2.9" machine type exposes the
    ICH9_LPC_SMI_F_BROADCAST feature iff (smp_cpus == max_cpus), that
    is, when VCPU hotplug is not possible. (Also from Paolo's v3
    feedback, in
    <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg04919.html>.)

* I've written the OVMF side patches too and tested them together
  (including gdb / debug messages for "white box" testing).

* Note that this version depends on the following PULL req from Michael:

  [Qemu-devel] [PULL 0/5] virtio, vhost, pc: fixes
  http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg05503.html

  In particular on the following patch:
  "loader: fix handling of custom address spaces when adding ROM blobs"

Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Eduardo Habkost <ehabkost@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Michael Walle <michael@walle.cc>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Shannon Zhao <zhaoshenglong@huawei.com>
Cc: qemu-arm@nongnu.org

Thanks
Laszlo

Laszlo Ersek (6):
  fw-cfg: turn FW_CFG_FILE_SLOTS into a device property
  fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma()
  hw/i386/pc: introduce 2.9 machine types with 0x20 fw_cfg file slots
  hw/isa/lpc_ich9: add SMI feature negotiation via fw_cfg
  hw/isa/lpc_ich9: add broadcast SMI feature
  hw/i386/pc_q35: advertise broadcast SMI if VCPU hotplug is turned off

Michael S. Tsirkin (1):
  fw-cfg: support writeable blobs

 docs/specs/fw_cfg.txt          |  36 +++++++++---
 hw/lm32/lm32_hwsetup.h         |   2 +-
 include/hw/compat.h            |  11 ++++
 include/hw/i386/ich9.h         |  15 ++++-
 include/hw/i386/pc.h           |   4 ++
 include/hw/loader.h            |   7 ++-
 include/hw/nvram/fw_cfg.h      |   5 +-
 include/hw/nvram/fw_cfg_keys.h |   7 ++-
 hw/arm/virt-acpi-build.c       |   2 +-
 hw/core/loader.c               |  18 +++---
 hw/i386/acpi-build.c           |   4 +-
 hw/i386/pc.c                   |   3 +-
 hw/i386/pc_piix.c              |  16 +++++-
 hw/i386/pc_q35.c               |  37 ++++++++++++-
 hw/isa/lpc_ich9.c              |  92 +++++++++++++++++++++++++++++-
 hw/nvram/fw_cfg.c              | 123 +++++++++++++++++++++++++++++++++++------
 16 files changed, 326 insertions(+), 56 deletions(-)

-- 
2.9.2

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

* [Qemu-devel] [PATCH v4 1/7] fw-cfg: support writeable blobs
  2016-12-01 17:06 [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI Laszlo Ersek
@ 2016-12-01 17:06 ` Laszlo Ersek
  2016-12-20 15:58   ` Marcel Apfelbaum
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 2/7] fw-cfg: turn FW_CFG_FILE_SLOTS into a device property Laszlo Ersek
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 46+ messages in thread
From: Laszlo Ersek @ 2016-12-01 17:06 UTC (permalink / raw)
  To: qemu devel list
  Cc: Gabriel L. Somlo, Michael S. Tsirkin, Gerd Hoffmann,
	Igor Mammedov, Michael Walle, Paolo Bonzini, Peter Maydell,
	Shannon Zhao, qemu-arm

From: "Michael S. Tsirkin" <mst@redhat.com>

Useful to send guest data back to QEMU.

Changes from Laszlo Ersek <lersek@redhat.com>:
- rebase the patch from Michael Tsirkin's original postings at [1] and [2]
  to the following patches:
  - loader: Allow a custom AddressSpace when loading ROMs
  - loader: Add AddressSpace loading support to uImages
  - loader: fix handling of custom address spaces when adding ROM blobs
- reject such writes immediately that would exceed the end of the array,
  rather than performing a partial write before setting the error bit: see
  the (len != dma.length) condition
- document the write interface

[1] http://lists.nongnu.org/archive/html/qemu-devel/2016-02/msg04968.html
[2] http://lists.nongnu.org/archive/html/qemu-devel/2016-03/msg02735.html

Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Michael Walle <michael@walle.cc>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Shannon Zhao <zhaoshenglong@huawei.com>
Cc: qemu-arm@nongnu.org
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 docs/specs/fw_cfg.txt     | 32 +++++++++++++++++++++++++-------
 hw/lm32/lm32_hwsetup.h    |  2 +-
 include/hw/loader.h       |  7 ++++---
 include/hw/nvram/fw_cfg.h |  3 ++-
 hw/arm/virt-acpi-build.c  |  2 +-
 hw/core/loader.c          | 18 +++++++++++-------
 hw/i386/acpi-build.c      |  4 ++--
 hw/nvram/fw_cfg.c         | 37 +++++++++++++++++++++++++++++--------
 8 files changed, 75 insertions(+), 30 deletions(-)

diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
index 7a5f8c7824ce..a19e2adbe1c6 100644
--- a/docs/specs/fw_cfg.txt
+++ b/docs/specs/fw_cfg.txt
@@ -31,21 +31,25 @@ register. In other words, configuration write mode is enabled when
 the selector value is between 0x4000-0x7fff or 0xc000-0xffff.
 
 NOTE: As of QEMU v2.4, writes to the fw_cfg data register are no
       longer supported, and will be ignored (treated as no-ops)!
 
+NOTE: As of QEMU v2.9, writes are reinstated, but only through the DMA
+      interface (see below). Furthermore, writeability of any specific item is
+      governed independently of Bit14 in the selector key value.
+
 Bit15 of the selector register indicates whether the configuration
 setting is architecture specific. A value of 0 means the item is a
 generic configuration item. A value of 1 means the item is specific
 to a particular architecture. In other words, generic configuration
 items are accessed with a selector value between 0x0000-0x7fff, and
 architecture specific configuration items are accessed with a selector
 value between 0x8000-0xffff.
 
 == Data Register ==
 
-* Read/Write (writes ignored as of QEMU v2.4)
+* Read/Write (writes ignored as of QEMU v2.4, but see the DMA interface)
 * Location: platform dependent (IOport [*] or MMIO)
 * Width: 8-bit (if IOport), 8/16/32/64-bit (if MMIO)
 * Endianness: string-preserving
 
 [*] On platforms where the data register is exposed as an IOport, its
@@ -132,23 +136,25 @@ struct FWCfgFile {		/* an individual file entry, 64 bytes total */
     char name[56];		/* fw_cfg item name, NUL-terminated ascii */
 };
 
 === All Other Data Items ===
 
-Please consult the QEMU source for the most up-to-date and authoritative
-list of selector keys and their respective items' purpose and format.
+Please consult the QEMU source for the most up-to-date and authoritative list
+of selector keys and their respective items' purpose, format and writeability.
 
 === Ranges ===
 
 Theoretically, there may be up to 0x4000 generic firmware configuration
 items, and up to 0x4000 architecturally specific ones.
 
 Selector Reg.    Range Usage
 ---------------  -----------
-0x0000 - 0x3fff  Generic (0x0000 - 0x3fff, RO)
+0x0000 - 0x3fff  Generic (0x0000 - 0x3fff, generally RO, possibly RW through
+                          the DMA interface in QEMU v2.9+)
 0x4000 - 0x7fff  Generic (0x0000 - 0x3fff, RW, ignored in QEMU v2.4+)
-0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, RO)
+0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW
+                                 through the DMA interface in QEMU v2.9+)
 0xc000 - 0xffff  Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
 
 In practice, the number of allowed firmware configuration items is given
 by the value of FW_CFG_MAX_ENTRY (see fw_cfg.h).
 
@@ -180,21 +186,31 @@ address is the "control" field.
 The "control" field has the following bits:
  - Bit 0: Error
  - Bit 1: Read
  - Bit 2: Skip
  - Bit 3: Select. The upper 16 bits are the selected index.
+ - Bit 4: Write
 
 When an operation is triggered, if the "control" field has bit 3 set, the
 upper 16 bits are interpreted as an index of a firmware configuration item.
 This has the same effect as writing the selector register.
 
 If the "control" field has bit 1 set, a read operation will be performed.
 "length" bytes for the current selector and offset will be copied into the
 physical RAM address specified by the "address" field.
 
-If the "control" field has bit 2 set (and not bit 1), a skip operation will be
-performed. The offset for the current selector will be advanced "length" bytes.
+If the "control" field has bit 4 set (and not bit 1), a write operation will be
+performed. "length" bytes will be copied from the physical RAM address
+specified by the "address" field to the current selector and offset. QEMU
+prevents starting or finishing the write beyond the end of the item associated
+with the current selector (i.e., the item cannot be resized). Truncated writes
+are dropped entirely. Writes to read-only items are also rejected. All of these
+write errors set bit 0 (the error bit) in the "control" field.
+
+If the "control" field has bit 2 set (and neither bit 1 nor bit 4), a skip
+operation will be performed. The offset for the current selector will be
+advanced "length" bytes.
 
 To check the result, read the "control" field:
    error bit set        ->  something went wrong.
    all bits cleared     ->  transfer finished successfully.
    otherwise            ->  transfer still in progress (doesn't happen
@@ -232,5 +248,7 @@ For historical reasons, "opt/ovmf/" is reserved for OVMF firmware.
 
 Prefix "opt/org.qemu/" is reserved for QEMU itself.
 
 Use of names not beginning with "opt/" is potentially dangerous and
 entirely unsupported.  QEMU will warn if you try.
+
+All externally provided fw_cfg items are read-only to the guest.
diff --git a/hw/lm32/lm32_hwsetup.h b/hw/lm32/lm32_hwsetup.h
index 23e18784dffd..a01f6bc5dfeb 100644
--- a/hw/lm32/lm32_hwsetup.h
+++ b/hw/lm32/lm32_hwsetup.h
@@ -73,11 +73,11 @@ static inline void hwsetup_free(HWSetup *hw)
 
 static inline void hwsetup_create_rom(HWSetup *hw,
         hwaddr base)
 {
     rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE,
-                 TARGET_PAGE_SIZE, base, NULL, NULL, NULL, NULL);
+                 TARGET_PAGE_SIZE, base, NULL, NULL, NULL, NULL, true);
 }
 
 static inline void hwsetup_add_u8(HWSetup *hw, uint8_t u)
 {
     stb_p(hw->ptr, u);
diff --git a/include/hw/loader.h b/include/hw/loader.h
index 0c864cfd6046..0dbd8d6bf37a 100644
--- a/include/hw/loader.h
+++ b/include/hw/loader.h
@@ -178,11 +178,12 @@ int rom_add_file(const char *file, const char *fw_dir,
                  bool option_rom, MemoryRegion *mr, AddressSpace *as);
 MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
                            size_t max_len, hwaddr addr,
                            const char *fw_file_name,
                            FWCfgReadCallback fw_callback,
-                           void *callback_opaque, AddressSpace *as);
+                           void *callback_opaque, AddressSpace *as,
+                           bool read_only);
 int rom_add_elf_program(const char *name, void *data, size_t datasize,
                         size_t romsize, hwaddr addr, AddressSpace *as);
 int rom_check_and_register_reset(void);
 void rom_set_fw(FWCfgState *f);
 void rom_set_order_override(int order);
@@ -192,19 +193,19 @@ void *rom_ptr(hwaddr addr);
 void hmp_info_roms(Monitor *mon, const QDict *qdict);
 
 #define rom_add_file_fixed(_f, _a, _i)          \
     rom_add_file(_f, NULL, _a, _i, false, NULL, NULL)
 #define rom_add_blob_fixed(_f, _b, _l, _a)      \
-    rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL, NULL)
+    rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL, NULL, true)
 #define rom_add_file_mr(_f, _mr, _i)            \
     rom_add_file(_f, NULL, 0, _i, false, _mr, NULL)
 #define rom_add_file_as(_f, _as, _i)            \
     rom_add_file(_f, NULL, 0, _i, false, NULL, _as)
 #define rom_add_file_fixed_as(_f, _a, _i, _as)          \
     rom_add_file(_f, NULL, _a, _i, false, NULL, _as)
 #define rom_add_blob_fixed_as(_f, _b, _l, _a, _as)      \
-    rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL, _as)
+    rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL, _as, true)
 
 #define PC_ROM_MIN_VGA     0xc0000
 #define PC_ROM_MIN_OPTION  0xc8000
 #define PC_ROM_MAX         0xe0000
 #define PC_ROM_ALIGN       0x800
diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
index 5c27a1f0d50b..b980cbaebf43 100644
--- a/include/hw/nvram/fw_cfg.h
+++ b/include/hw/nvram/fw_cfg.h
@@ -134,10 +134,11 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data,
  * @filename: name of new fw_cfg file item
  * @callback: callback function
  * @callback_opaque: argument to be passed into callback function
  * @data: pointer to start of item data
  * @len: size of item data
+ * @read_only: is file read only
  *
  * Add a new NAMED fw_cfg item as a raw "blob" of the given size. The data
  * referenced by the starting pointer is only linked, NOT copied, into the
  * data structure of the fw_cfg device.
  * The next available (unused) selector key starting at FW_CFG_FILE_FIRST
@@ -149,11 +150,11 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data,
  * the fw_cfg control register, or passed to QEMU in FWCfgDmaAccess.control
  * with FW_CFG_DMA_CTL_SELECT).
  */
 void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
                               FWCfgReadCallback callback, void *callback_opaque,
-                              void *data, size_t len);
+                              void *data, size_t len, bool read_only);
 
 /**
  * fw_cfg_modify_file:
  * @s: fw_cfg device being modified
  * @filename: name of new fw_cfg file item
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index d4160dfa7d34..542fb67239db 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -807,11 +807,11 @@ static void virt_acpi_build_reset(void *build_opaque)
 static MemoryRegion *acpi_add_rom_blob(AcpiBuildState *build_state,
                                        GArray *blob, const char *name,
                                        uint64_t max_size)
 {
     return rom_add_blob(name, blob->data, acpi_data_len(blob), max_size, -1,
-                        name, virt_acpi_build_update, build_state, NULL);
+                        name, virt_acpi_build_update, build_state, NULL, true);
 }
 
 static const VMStateDescription vmstate_virt_acpi_build = {
     .name = "virt_acpi_build",
     .version_id = 1,
diff --git a/hw/core/loader.c b/hw/core/loader.c
index 45742494e6fd..ee5abd6eb7f4 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -851,20 +851,20 @@ static void fw_cfg_resized(const char *id, uint64_t length, void *host)
     if (fw_cfg) {
         fw_cfg_modify_file(fw_cfg, id + strlen("/rom@"), host, length);
     }
 }
 
-static void *rom_set_mr(Rom *rom, Object *owner, const char *name)
+static void *rom_set_mr(Rom *rom, Object *owner, const char *name, bool ro)
 {
     void *data;
 
     rom->mr = g_malloc(sizeof(*rom->mr));
     memory_region_init_resizeable_ram(rom->mr, owner, name,
                                       rom->datasize, rom->romsize,
                                       fw_cfg_resized,
                                       &error_fatal);
-    memory_region_set_readonly(rom->mr, true);
+    memory_region_set_readonly(rom->mr, ro);
     vmstate_register_ram_global(rom->mr);
 
     data = memory_region_get_ram_ptr(rom->mr);
     memcpy(data, rom->data, rom->datasize);
 
@@ -940,11 +940,11 @@ int rom_add_file(const char *file, const char *fw_dir,
         snprintf(fw_file_name, sizeof(fw_file_name), "%s/%s", rom->fw_dir,
                  basename);
         snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
 
         if ((!option_rom || mc->option_rom_has_mr) && mc->rom_file_has_mr) {
-            data = rom_set_mr(rom, OBJECT(fw_cfg), devpath);
+            data = rom_set_mr(rom, OBJECT(fw_cfg), devpath, true);
         } else {
             data = rom->data;
         }
 
         fw_cfg_add_file(fw_cfg, fw_file_name, data, rom->romsize);
@@ -977,11 +977,11 @@ err:
 }
 
 MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
                    size_t max_len, hwaddr addr, const char *fw_file_name,
                    FWCfgReadCallback fw_callback, void *callback_opaque,
-                   AddressSpace *as)
+                   AddressSpace *as, bool read_only)
 {
     MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
     Rom *rom;
     MemoryRegion *mr = NULL;
 
@@ -996,22 +996,26 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
     rom_insert(rom);
     if (fw_file_name && fw_cfg) {
         char devpath[100];
         void *data;
 
-        snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
+        if (read_only) {
+            snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
+        } else {
+            snprintf(devpath, sizeof(devpath), "/ram@%s", fw_file_name);
+        }
 
         if (mc->rom_file_has_mr) {
-            data = rom_set_mr(rom, OBJECT(fw_cfg), devpath);
+            data = rom_set_mr(rom, OBJECT(fw_cfg), devpath, read_only);
             mr = rom->mr;
         } else {
             data = rom->data;
         }
 
         fw_cfg_add_file_callback(fw_cfg, fw_file_name,
                                  fw_callback, callback_opaque,
-                                 data, rom->datasize);
+                                 data, rom->datasize, read_only);
     }
     return mr;
 }
 
 /* This function is specific for elf program because we don't need to allocate
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 9708cdc463df..965cb4cd4c51 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -2934,11 +2934,11 @@ static void acpi_build_reset(void *build_opaque)
 static MemoryRegion *acpi_add_rom_blob(AcpiBuildState *build_state,
                                        GArray *blob, const char *name,
                                        uint64_t max_size)
 {
     return rom_add_blob(name, blob->data, acpi_data_len(blob), max_size, -1,
-                        name, acpi_build_update, build_state, NULL);
+                        name, acpi_build_update, build_state, NULL, true);
 }
 
 static const VMStateDescription vmstate_acpi_build = {
     .name = "acpi_build",
     .version_id = 1,
@@ -3000,11 +3000,11 @@ void acpi_setup(void)
         uint32_t rsdp_size = acpi_data_len(tables.rsdp);
 
         build_state->rsdp = g_memdup(tables.rsdp->data, rsdp_size);
         fw_cfg_add_file_callback(pcms->fw_cfg, ACPI_BUILD_RSDP_FILE,
                                  acpi_build_update, build_state,
-                                 build_state->rsdp, rsdp_size);
+                                 build_state->rsdp, rsdp_size, true);
         build_state->rsdp_mr = NULL;
     } else {
         build_state->rsdp = NULL;
         build_state->rsdp_mr = acpi_add_rom_blob(build_state, tables.rsdp,
                                                   ACPI_BUILD_RSDP_FILE, 0);
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 3ebecb22606a..e0145c11a19b 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -52,15 +52,17 @@
 /* FW_CFG_DMA_CONTROL bits */
 #define FW_CFG_DMA_CTL_ERROR   0x01
 #define FW_CFG_DMA_CTL_READ    0x02
 #define FW_CFG_DMA_CTL_SKIP    0x04
 #define FW_CFG_DMA_CTL_SELECT  0x08
+#define FW_CFG_DMA_CTL_WRITE   0x10
 
 #define FW_CFG_DMA_SIGNATURE 0x51454d5520434647ULL /* "QEMU CFG" */
 
 typedef struct FWCfgEntry {
     uint32_t len;
+    bool allow_write;
     uint8_t *data;
     void *callback_opaque;
     FWCfgReadCallback read_callback;
 } FWCfgEntry;
 
@@ -324,11 +326,11 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
 {
     dma_addr_t len;
     FWCfgDmaAccess dma;
     int arch;
     FWCfgEntry *e;
-    int read;
+    int read = 0, write = 0;
     dma_addr_t dma_addr;
 
     /* Reset the address before the next access */
     dma_addr = s->dma_addr;
     s->dma_addr = 0;
@@ -351,12 +353,17 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
     e = (s->cur_entry == FW_CFG_INVALID) ? NULL :
         &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
 
     if (dma.control & FW_CFG_DMA_CTL_READ) {
         read = 1;
+        write = 0;
+    } else if (dma.control & FW_CFG_DMA_CTL_WRITE) {
+        read = 0;
+        write = 1;
     } else if (dma.control & FW_CFG_DMA_CTL_SKIP) {
         read = 0;
+        write = 0;
     } else {
         dma.length = 0;
     }
 
     dma.control = 0;
@@ -372,11 +379,13 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
             if (read) {
                 if (dma_memory_set(s->dma_as, dma.address, 0, len)) {
                     dma.control |= FW_CFG_DMA_CTL_ERROR;
                 }
             }
-
+            if (write) {
+                dma.control |= FW_CFG_DMA_CTL_ERROR;
+            }
         } else {
             if (dma.length <= (e->len - s->cur_offset)) {
                 len = dma.length;
             } else {
                 len = (e->len - s->cur_offset);
@@ -389,10 +398,18 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
                 if (dma_memory_write(s->dma_as, dma.address,
                                     &e->data[s->cur_offset], len)) {
                     dma.control |= FW_CFG_DMA_CTL_ERROR;
                 }
             }
+            if (write) {
+                if (!e->allow_write ||
+                    len != dma.length ||
+                    dma_memory_read(s->dma_as, dma.address,
+                                    &e->data[s->cur_offset], len)) {
+                    dma.control |= FW_CFG_DMA_CTL_ERROR;
+                }
+            }
 
             s->cur_offset += len;
         }
 
         dma.address += len;
@@ -584,11 +601,12 @@ static const VMStateDescription vmstate_fw_cfg = {
 };
 
 static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key,
                                            FWCfgReadCallback callback,
                                            void *callback_opaque,
-                                           void *data, size_t len)
+                                           void *data, size_t len,
+                                           bool read_only)
 {
     int arch = !!(key & FW_CFG_ARCH_LOCAL);
 
     key &= FW_CFG_ENTRY_MASK;
 
@@ -597,10 +615,11 @@ static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key,
 
     s->entries[arch][key].data = data;
     s->entries[arch][key].len = (uint32_t)len;
     s->entries[arch][key].read_callback = callback;
     s->entries[arch][key].callback_opaque = callback_opaque;
+    s->entries[arch][key].allow_write = !read_only;
 }
 
 static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key,
                                               void *data, size_t len)
 {
@@ -614,17 +633,18 @@ static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key,
     /* 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;
 
     return ptr;
 }
 
 void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len)
 {
-    fw_cfg_add_bytes_read_callback(s, key, NULL, NULL, data, len);
+    fw_cfg_add_bytes_read_callback(s, key, NULL, NULL, data, len, true);
 }
 
 void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value)
 {
     size_t sz = strlen(value) + 1;
@@ -747,11 +767,11 @@ static int get_fw_cfg_order(FWCfgState *s, const char *name)
     return FW_CFG_ORDER_OVERRIDE_LAST;
 }
 
 void fw_cfg_add_file_callback(FWCfgState *s,  const char *filename,
                               FWCfgReadCallback callback, void *callback_opaque,
-                              void *data, size_t len)
+                              void *data, size_t len, bool read_only)
 {
     int i, index, count;
     size_t dsize;
     MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
     int order = 0;
@@ -809,11 +829,12 @@ void fw_cfg_add_file_callback(FWCfgState *s,  const char *filename,
             exit(1);
         }
     }
 
     fw_cfg_add_bytes_read_callback(s, FW_CFG_FILE_FIRST + index,
-                                   callback, callback_opaque, data, len);
+                                   callback, callback_opaque, data, len,
+                                   read_only);
 
     s->files->f[index].size   = cpu_to_be32(len);
     s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index);
     s->entry_order[index] = order;
     trace_fw_cfg_add_file(s, index, s->files->f[index].name, len);
@@ -822,11 +843,11 @@ void fw_cfg_add_file_callback(FWCfgState *s,  const char *filename,
 }
 
 void fw_cfg_add_file(FWCfgState *s,  const char *filename,
                      void *data, size_t len)
 {
-    fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len);
+    fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len, true);
 }
 
 void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
                         void *data, size_t len)
 {
@@ -845,11 +866,11 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
             s->files->f[i].size   = cpu_to_be32(len);
             return ptr;
         }
     }
     /* add new one */
-    fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len);
+    fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len, true);
     return NULL;
 }
 
 static void fw_cfg_machine_reset(void *opaque)
 {
-- 
2.9.2

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

* [Qemu-devel] [PATCH v4 2/7] fw-cfg: turn FW_CFG_FILE_SLOTS into a device property
  2016-12-01 17:06 [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI Laszlo Ersek
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 1/7] fw-cfg: support writeable blobs Laszlo Ersek
@ 2016-12-01 17:06 ` Laszlo Ersek
  2016-12-02 11:10   ` Gerd Hoffmann
                     ` (2 more replies)
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 3/7] fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma() Laszlo Ersek
                   ` (6 subsequent siblings)
  8 siblings, 3 replies; 46+ messages in thread
From: Laszlo Ersek @ 2016-12-01 17:06 UTC (permalink / raw)
  To: qemu devel list
  Cc: Gabriel L. Somlo, Michael S. Tsirkin, Gerd Hoffmann,
	Igor Mammedov, Paolo Bonzini

We'd like to raise the value of FW_CFG_FILE_SLOTS. Doing it naively could
lead to problems with backward migration: a more recent QEMU (running an
older machine type) would allow the guest, in fw_cfg_select(), to select a
high key value that is unavailable in the same machine type implemented by
the older (target) QEMU. On the target host, fw_cfg_data_read() for
example could dereference nonexistent entries.

As first step, size the FWCfgState.entries[*] and FWCfgState.entry_order
arrays dynamically. All three array sizes will be influenced by the new
field (and device property) FWCfgState.file_slots.

Make the following changes:

- Replace the FW_CFG_FILE_SLOTS macro with FW_CFG_FILE_SLOTS_TRAD
  (traditional count of fw_cfg file slots) in the header file. The value
  remains 0x10.

- Replace all uses of FW_CFG_FILE_SLOTS with a helper function called
  fw_cfg_file_slots(), returning the new property.

- Eliminate the macro FW_CFG_MAX_ENTRY, and replace all its uses with a
  helper function called fw_cfg_max_entry().

- In the MMIO- and IO-mapped realize functions both, allocate all three
  arrays dynamically, based on the new property.

- The new property defaults to 0x20; however at the moment we forcibly set
  it to FW_CFG_FILE_SLOTS_TRAD on all code paths available to board code
  (namely in the fw_cfg_init_io_dma() and fw_cfg_init_mem_wide() helper
  functions). This is going to be customized in the following patches.

Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---

Notes:
    I know that upstream doesn't care about backward migration, but some
    downstreams might.

 docs/specs/fw_cfg.txt          |  2 +-
 include/hw/nvram/fw_cfg_keys.h |  3 +-
 hw/nvram/fw_cfg.c              | 85 ++++++++++++++++++++++++++++++++++++++----
 3 files changed, 79 insertions(+), 11 deletions(-)

diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
index a19e2adbe1c6..84e2978706f5 100644
--- a/docs/specs/fw_cfg.txt
+++ b/docs/specs/fw_cfg.txt
@@ -154,11 +154,11 @@ Selector Reg.    Range Usage
 0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW
                                  through the DMA interface in QEMU v2.9+)
 0xc000 - 0xffff  Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
 
 In practice, the number of allowed firmware configuration items is given
-by the value of FW_CFG_MAX_ENTRY (see fw_cfg.h).
+by the value (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS_TRAD) (see fw_cfg.h).
 
 = Guest-side DMA Interface =
 
 If bit 1 of the feature bitmap is set, the DMA interface is present. This does
 not replace the existing fw_cfg interface, it is an add-on. This interface
diff --git a/include/hw/nvram/fw_cfg_keys.h b/include/hw/nvram/fw_cfg_keys.h
index 0f3e871884c0..627589793671 100644
--- a/include/hw/nvram/fw_cfg_keys.h
+++ b/include/hw/nvram/fw_cfg_keys.h
@@ -27,12 +27,11 @@
 #define FW_CFG_SETUP_SIZE       0x17
 #define FW_CFG_SETUP_DATA       0x18
 #define FW_CFG_FILE_DIR         0x19
 
 #define FW_CFG_FILE_FIRST       0x20
-#define FW_CFG_FILE_SLOTS       0x10
-#define FW_CFG_MAX_ENTRY        (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS)
+#define FW_CFG_FILE_SLOTS_TRAD  0x10
 
 #define FW_CFG_WRITE_CHANNEL    0x4000
 #define FW_CFG_ARCH_LOCAL       0x8000
 #define FW_CFG_ENTRY_MASK       (~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL))
 
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index e0145c11a19b..2e1441c09750 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -31,10 +31,13 @@
 #include "hw/sysbus.h"
 #include "trace.h"
 #include "qemu/error-report.h"
 #include "qemu/config-file.h"
 #include "qemu/cutils.h"
+#include "qapi/error.h"
+
+#define FW_CFG_FILE_SLOTS_DFLT 0x20
 
 #define FW_CFG_NAME "fw_cfg"
 #define FW_CFG_PATH "/machine/" FW_CFG_NAME
 
 #define TYPE_FW_CFG     "fw_cfg"
@@ -69,12 +72,13 @@ typedef struct FWCfgEntry {
 struct FWCfgState {
     /*< private >*/
     SysBusDevice parent_obj;
     /*< public >*/
 
-    FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
-    int entry_order[FW_CFG_MAX_ENTRY];
+    uint32_t file_slots;
+    FWCfgEntry *entries[2];
+    int *entry_order;
     FWCfgFiles *files;
     uint16_t cur_entry;
     uint32_t cur_offset;
     Notifier machine_ready;
 
@@ -255,17 +259,27 @@ static void fw_cfg_reboot(FWCfgState *s)
 static void fw_cfg_write(FWCfgState *s, uint8_t value)
 {
     /* nothing, write support removed in QEMU v2.4+ */
 }
 
+static inline uint32_t fw_cfg_file_slots(const FWCfgState *s)
+{
+    return s->file_slots;
+}
+
+static inline uint32_t fw_cfg_max_entry(const FWCfgState *s)
+{
+    return FW_CFG_FILE_FIRST + fw_cfg_file_slots(s);
+}
+
 static int fw_cfg_select(FWCfgState *s, uint16_t key)
 {
     int arch, ret;
     FWCfgEntry *e;
 
     s->cur_offset = 0;
-    if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
+    if ((key & FW_CFG_ENTRY_MASK) >= fw_cfg_max_entry(s)) {
         s->cur_entry = FW_CFG_INVALID;
         ret = 0;
     } else {
         s->cur_entry = key;
         ret = 1;
@@ -608,11 +622,11 @@ static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key,
 {
     int arch = !!(key & FW_CFG_ARCH_LOCAL);
 
     key &= FW_CFG_ENTRY_MASK;
 
-    assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
+    assert(key < fw_cfg_max_entry(s) && len < UINT32_MAX);
     assert(s->entries[arch][key].data == NULL); /* avoid key conflict */
 
     s->entries[arch][key].data = data;
     s->entries[arch][key].len = (uint32_t)len;
     s->entries[arch][key].read_callback = callback;
@@ -626,11 +640,11 @@ static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key,
     void *ptr;
     int arch = !!(key & FW_CFG_ARCH_LOCAL);
 
     key &= FW_CFG_ENTRY_MASK;
 
-    assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
+    assert(key < fw_cfg_max_entry(s) && len < UINT32_MAX);
 
     /* 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;
@@ -775,17 +789,17 @@ void fw_cfg_add_file_callback(FWCfgState *s,  const char *filename,
     size_t dsize;
     MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
     int order = 0;
 
     if (!s->files) {
-        dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * FW_CFG_FILE_SLOTS;
+        dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * fw_cfg_file_slots(s);
         s->files = g_malloc0(dsize);
         fw_cfg_add_bytes(s, FW_CFG_FILE_DIR, s->files, dsize);
     }
 
     count = be32_to_cpu(s->files->count);
-    assert(count < FW_CFG_FILE_SLOTS);
+    assert(count < fw_cfg_file_slots(s));
 
     /* Find the insertion point. */
     if (mc->legacy_fw_cfg_order) {
         /*
          * Sort by order. For files with the same order, we keep them
@@ -855,11 +869,11 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
     void *ptr = NULL;
 
     assert(s->files);
 
     index = be32_to_cpu(s->files->count);
-    assert(index < FW_CFG_FILE_SLOTS);
+    assert(index < fw_cfg_file_slots(s));
 
     for (i = 0; i < index; i++) {
         if (strcmp(filename, s->files->f[i].name) == 0) {
             ptr = fw_cfg_modify_bytes_read(s, FW_CFG_FILE_FIRST + i,
                                            data, len);
@@ -926,10 +940,16 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
     qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase);
     if (!dma_requested) {
         qdev_prop_set_bit(dev, "dma_enabled", false);
     }
 
+    /* Once we expose the "file_slots" property to callers of
+     * fw_cfg_init_io_dma(), the following setting should become conditional on
+     * the input parameter being lower than the current value of the property.
+     */
+    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
+
     fw_cfg_init1(dev);
     s = FW_CFG(dev);
 
     if (s->dma_enabled) {
         /* 64 bits for the address field */
@@ -963,10 +983,17 @@ FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
     qdev_prop_set_uint32(dev, "data_width", data_width);
     if (!dma_requested) {
         qdev_prop_set_bit(dev, "dma_enabled", false);
     }
 
+    /* Once we expose the "file_slots" property to callers of
+     * fw_cfg_init_mem_wide(), the following setting should become conditional
+     * on the input parameter being lower than the current value of the
+     * property. Refer to fw_cfg_init_io_dma().
+     */
+    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
+
     fw_cfg_init1(dev);
 
     sbd = SYS_BUS_DEVICE(dev);
     sysbus_mmio_map(sbd, 0, ctl_addr);
     sysbus_mmio_map(sbd, 1, data_addr);
@@ -1012,23 +1039,56 @@ static const TypeInfo fw_cfg_info = {
     .abstract      = true,
     .instance_size = sizeof(FWCfgState),
     .class_init    = fw_cfg_class_init,
 };
 
+static void fw_cfg_file_slots_allocate(FWCfgState *s, Error **errp)
+{
+    uint16_t file_slots_max;
+
+    if (fw_cfg_file_slots(s) < FW_CFG_FILE_SLOTS_TRAD) {
+        error_setg(errp, "\"file_slots\" must be at least 0x%x",
+                   FW_CFG_FILE_SLOTS_TRAD);
+        return;
+    }
+
+    /* (UINT16_MAX & FW_CFG_ENTRY_MASK) is the highest inclusive selector value
+     * that we permit. The actual (exclusive) value coming from the
+     * configuration is (FW_CFG_FILE_FIRST + fw_cfg_file_slots(s)). */
+    file_slots_max = (UINT16_MAX & FW_CFG_ENTRY_MASK) - FW_CFG_FILE_FIRST + 1;
+    if (fw_cfg_file_slots(s) > file_slots_max) {
+        error_setg(errp, "\"file_slots\" must not exceed 0x%" PRIx16,
+                   file_slots_max);
+        return;
+    }
+
+    s->entries[0] = g_new0(FWCfgEntry, fw_cfg_max_entry(s));
+    s->entries[1] = g_new0(FWCfgEntry, fw_cfg_max_entry(s));
+    s->entry_order = g_new0(int, fw_cfg_max_entry(s));
+}
 
 static Property fw_cfg_io_properties[] = {
     DEFINE_PROP_UINT32("iobase", FWCfgIoState, iobase, -1),
     DEFINE_PROP_UINT32("dma_iobase", FWCfgIoState, dma_iobase, -1),
     DEFINE_PROP_BOOL("dma_enabled", FWCfgIoState, parent_obj.dma_enabled,
                      true),
+    DEFINE_PROP_UINT32("file_slots", FWCfgIoState, parent_obj.file_slots,
+                       FW_CFG_FILE_SLOTS_DFLT),
     DEFINE_PROP_END_OF_LIST(),
 };
 
 static void fw_cfg_io_realize(DeviceState *dev, Error **errp)
 {
     FWCfgIoState *s = FW_CFG_IO(dev);
     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    Error *local_err = NULL;
+
+    fw_cfg_file_slots_allocate(FW_CFG(s), &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
 
     /* when using port i/o, the 8-bit data register ALWAYS overlaps
      * with half of the 16-bit control register. Hence, the total size
      * of the i/o region used is FW_CFG_CTL_SIZE */
     memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops,
@@ -1061,18 +1121,27 @@ static const TypeInfo fw_cfg_io_info = {
 
 static Property fw_cfg_mem_properties[] = {
     DEFINE_PROP_UINT32("data_width", FWCfgMemState, data_width, -1),
     DEFINE_PROP_BOOL("dma_enabled", FWCfgMemState, parent_obj.dma_enabled,
                      true),
+    DEFINE_PROP_UINT32("file_slots", FWCfgMemState, parent_obj.file_slots,
+                       FW_CFG_FILE_SLOTS_DFLT),
     DEFINE_PROP_END_OF_LIST(),
 };
 
 static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
 {
     FWCfgMemState *s = FW_CFG_MEM(dev);
     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
     const MemoryRegionOps *data_ops = &fw_cfg_data_mem_ops;
+    Error *local_err = NULL;
+
+    fw_cfg_file_slots_allocate(FW_CFG(s), &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
 
     memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops,
                           FW_CFG(s), "fwcfg.ctl", FW_CFG_CTL_SIZE);
     sysbus_init_mmio(sbd, &s->ctl_iomem);
 
-- 
2.9.2

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

* [Qemu-devel] [PATCH v4 3/7] fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma()
  2016-12-01 17:06 [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI Laszlo Ersek
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 1/7] fw-cfg: support writeable blobs Laszlo Ersek
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 2/7] fw-cfg: turn FW_CFG_FILE_SLOTS into a device property Laszlo Ersek
@ 2016-12-01 17:06 ` Laszlo Ersek
  2016-12-06 11:49   ` Igor Mammedov
  2017-01-10 15:02   ` [Qemu-devel] " Michael S. Tsirkin
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 4/7] hw/i386/pc: introduce 2.9 machine types with 0x20 fw_cfg file slots Laszlo Ersek
                   ` (5 subsequent siblings)
  8 siblings, 2 replies; 46+ messages in thread
From: Laszlo Ersek @ 2016-12-01 17:06 UTC (permalink / raw)
  To: qemu devel list
  Cc: Gabriel L. Somlo, Michael S. Tsirkin, Gerd Hoffmann,
	Igor Mammedov, Paolo Bonzini

Accordingly, generalize the "file_slots" minimum calculation in
fw_cfg_init_io_dma(), and move the constant FW_CFG_FILE_SLOTS_TRAD
argument to the callers of fw_cfg_init_io_dma().

Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 docs/specs/fw_cfg.txt     |  4 ++--
 include/hw/nvram/fw_cfg.h |  2 +-
 hw/i386/pc.c              |  3 ++-
 hw/nvram/fw_cfg.c         | 13 ++++++-------
 4 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
index 84e2978706f5..4a6888b511f4 100644
--- a/docs/specs/fw_cfg.txt
+++ b/docs/specs/fw_cfg.txt
@@ -153,12 +153,12 @@ Selector Reg.    Range Usage
 0x4000 - 0x7fff  Generic (0x0000 - 0x3fff, RW, ignored in QEMU v2.4+)
 0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW
                                  through the DMA interface in QEMU v2.9+)
 0xc000 - 0xffff  Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
 
-In practice, the number of allowed firmware configuration items is given
-by the value (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS_TRAD) (see fw_cfg.h).
+In practice, the number of allowed firmware configuration items depends on the
+machine type.
 
 = Guest-side DMA Interface =
 
 If bit 1 of the feature bitmap is set, the DMA interface is present. This does
 not replace the existing fw_cfg interface, it is an add-on. This interface
diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
index b980cbaebf43..e9a6b6aa968c 100644
--- a/include/hw/nvram/fw_cfg.h
+++ b/include/hw/nvram/fw_cfg.h
@@ -173,11 +173,11 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
  */
 void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data,
                          size_t len);
 
 FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
-                                AddressSpace *dma_as);
+                                AddressSpace *dma_as, uint32_t file_slots);
 FWCfgState *fw_cfg_init_io(uint32_t iobase);
 FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr);
 FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
                                  hwaddr data_addr, uint32_t data_width,
                                  hwaddr dma_addr, AddressSpace *dma_as);
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index a9e64a88e5e7..5d929d8fc887 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -741,11 +741,12 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms)
 {
     FWCfgState *fw_cfg;
     uint64_t *numa_fw_cfg;
     int i, j;
 
-    fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as);
+    fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as,
+                                FW_CFG_FILE_SLOTS_TRAD);
     fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus);
 
     /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
      *
      * For machine types prior to 1.8, SeaBIOS needs FW_CFG_MAX_CPUS for
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 2e1441c09750..c33c76ab93b1 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -926,11 +926,11 @@ static void fw_cfg_init1(DeviceState *dev)
     s->machine_ready.notify = fw_cfg_machine_ready;
     qemu_add_machine_init_done_notifier(&s->machine_ready);
 }
 
 FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
-                                AddressSpace *dma_as)
+                                AddressSpace *dma_as, uint32_t file_slots)
 {
     DeviceState *dev;
     FWCfgState *s;
     uint32_t version = FW_CFG_VERSION;
     bool dma_requested = dma_iobase && dma_as;
@@ -940,15 +940,14 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
     qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase);
     if (!dma_requested) {
         qdev_prop_set_bit(dev, "dma_enabled", false);
     }
 
-    /* Once we expose the "file_slots" property to callers of
-     * fw_cfg_init_io_dma(), the following setting should become conditional on
-     * the input parameter being lower than the current value of the property.
-     */
-    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
+    if (file_slots < object_property_get_int(OBJECT(dev), "file_slots",
+                                             &error_abort)) {
+        qdev_prop_set_uint32(dev, "file_slots", file_slots);
+    }
 
     fw_cfg_init1(dev);
     s = FW_CFG(dev);
 
     if (s->dma_enabled) {
@@ -964,11 +963,11 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
     return s;
 }
 
 FWCfgState *fw_cfg_init_io(uint32_t iobase)
 {
-    return fw_cfg_init_io_dma(iobase, 0, NULL);
+    return fw_cfg_init_io_dma(iobase, 0, NULL, FW_CFG_FILE_SLOTS_TRAD);
 }
 
 FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
                                  hwaddr data_addr, uint32_t data_width,
                                  hwaddr dma_addr, AddressSpace *dma_as)
-- 
2.9.2

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

* [Qemu-devel] [PATCH v4 4/7] hw/i386/pc: introduce 2.9 machine types with 0x20 fw_cfg file slots
  2016-12-01 17:06 [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI Laszlo Ersek
                   ` (2 preceding siblings ...)
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 3/7] fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma() Laszlo Ersek
@ 2016-12-01 17:06 ` Laszlo Ersek
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 5/7] hw/isa/lpc_ich9: add SMI feature negotiation via fw_cfg Laszlo Ersek
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 46+ messages in thread
From: Laszlo Ersek @ 2016-12-01 17:06 UTC (permalink / raw)
  To: qemu devel list
  Cc: Michael S. Tsirkin, Eduardo Habkost, Gerd Hoffmann,
	Igor Mammedov, Paolo Bonzini

Add "file_slots" compat properties for 2.8 and earlier machine types.

Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Eduardo Habkost <ehabkost@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 include/hw/compat.h            | 11 +++++++++++
 include/hw/i386/pc.h           |  3 +++
 include/hw/nvram/fw_cfg_keys.h |  6 ++++--
 hw/i386/pc.c                   |  2 +-
 hw/i386/pc_piix.c              | 16 +++++++++++++---
 hw/i386/pc_q35.c               | 13 +++++++++++--
 hw/nvram/fw_cfg.c              |  2 --
 7 files changed, 43 insertions(+), 10 deletions(-)

diff --git a/include/hw/compat.h b/include/hw/compat.h
index 0f06e113bee2..4eca87dc9c85 100644
--- a/include/hw/compat.h
+++ b/include/hw/compat.h
@@ -1,8 +1,19 @@
 #ifndef HW_COMPAT_H
 #define HW_COMPAT_H
 
+#define HW_COMPAT_2_8 \
+    {\
+        .driver   = "fw_cfg_mem",\
+        .property = "file_slots",\
+        .value    = stringify(0x10),\
+    },{\
+        .driver   = "fw_cfg_io",\
+        .property = "file_slots",\
+        .value    = stringify(0x10),\
+    },
+
 #define HW_COMPAT_2_7 \
     {\
         .driver   = "virtio-pci",\
         .property = "page-per-vq",\
         .value    = "on",\
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 4b7413055989..430735e501dd 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -365,11 +365,14 @@ void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
 
 int e820_add_entry(uint64_t, uint64_t, uint32_t);
 int e820_get_num_entries(void);
 bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
 
+#define PC_COMPAT_2_9 \
+
 #define PC_COMPAT_2_8 \
+    HW_COMPAT_2_8 \
 
 #define PC_COMPAT_2_7 \
     HW_COMPAT_2_7 \
     {\
         .driver   = TYPE_X86_CPU,\
diff --git a/include/hw/nvram/fw_cfg_keys.h b/include/hw/nvram/fw_cfg_keys.h
index 627589793671..335a0df79f23 100644
--- a/include/hw/nvram/fw_cfg_keys.h
+++ b/include/hw/nvram/fw_cfg_keys.h
@@ -26,12 +26,14 @@
 #define FW_CFG_SETUP_ADDR       0x16
 #define FW_CFG_SETUP_SIZE       0x17
 #define FW_CFG_SETUP_DATA       0x18
 #define FW_CFG_FILE_DIR         0x19
 
-#define FW_CFG_FILE_FIRST       0x20
-#define FW_CFG_FILE_SLOTS_TRAD  0x10
+#define FW_CFG_FILE_FIRST       0x20 /* never change this */
+#define FW_CFG_FILE_SLOTS_TRAD  0x10 /* never change this */
+#define FW_CFG_FILE_SLOTS_DFLT  0x20 /* update HW_COMPAT_xxx in sync */
+
 
 #define FW_CFG_WRITE_CHANNEL    0x4000
 #define FW_CFG_ARCH_LOCAL       0x8000
 #define FW_CFG_ENTRY_MASK       (~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL))
 
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 5d929d8fc887..af51e8372db5 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -742,11 +742,11 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms)
     FWCfgState *fw_cfg;
     uint64_t *numa_fw_cfg;
     int i, j;
 
     fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as,
-                                FW_CFG_FILE_SLOTS_TRAD);
+                                FW_CFG_FILE_SLOTS_DFLT);
     fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus);
 
     /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
      *
      * For machine types prior to 1.8, SeaBIOS needs FW_CFG_MAX_CPUS for
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index a54a468c0ab3..2b67cf85371a 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -435,26 +435,36 @@ 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";
 }
 
-static void pc_i440fx_2_8_machine_options(MachineClass *m)
+static void pc_i440fx_2_9_machine_options(MachineClass *m)
 {
     pc_i440fx_machine_options(m);
     m->alias = "pc";
     m->is_default = 1;
 }
 
+DEFINE_I440FX_MACHINE(v2_9, "pc-i440fx-2.9", NULL,
+                      pc_i440fx_2_9_machine_options);
+
+
+static void pc_i440fx_2_8_machine_options(MachineClass *m)
+{
+    pc_i440fx_2_9_machine_options(m);
+    m->alias = NULL;
+    m->is_default = 0;
+    SET_MACHINE_COMPAT(m, PC_COMPAT_2_8);
+}
+
 DEFINE_I440FX_MACHINE(v2_8, "pc-i440fx-2.8", NULL,
                       pc_i440fx_2_8_machine_options);
 
 
 static void pc_i440fx_2_7_machine_options(MachineClass *m)
 {
     pc_i440fx_2_8_machine_options(m);
-    m->is_default = 0;
-    m->alias = NULL;
     SET_MACHINE_COMPAT(m, PC_COMPAT_2_7);
 }
 
 DEFINE_I440FX_MACHINE(v2_7, "pc-i440fx-2.7", NULL,
                       pc_i440fx_2_7_machine_options);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index b40d19ee00da..7fa40e7cbe0e 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -292,23 +292,32 @@ static void pc_q35_machine_options(MachineClass *m)
     m->no_floppy = 1;
     m->has_dynamic_sysbus = true;
     m->max_cpus = 288;
 }
 
-static void pc_q35_2_8_machine_options(MachineClass *m)
+static void pc_q35_2_9_machine_options(MachineClass *m)
 {
     pc_q35_machine_options(m);
     m->alias = "q35";
 }
 
+DEFINE_Q35_MACHINE(v2_9, "pc-q35-2.9", NULL,
+                   pc_q35_2_9_machine_options);
+
+static void pc_q35_2_8_machine_options(MachineClass *m)
+{
+    pc_q35_2_9_machine_options(m);
+    m->alias = NULL;
+    SET_MACHINE_COMPAT(m, PC_COMPAT_2_8);
+}
+
 DEFINE_Q35_MACHINE(v2_8, "pc-q35-2.8", NULL,
                    pc_q35_2_8_machine_options);
 
 static void pc_q35_2_7_machine_options(MachineClass *m)
 {
     pc_q35_2_8_machine_options(m);
-    m->alias = NULL;
     m->max_cpus = 255;
     SET_MACHINE_COMPAT(m, PC_COMPAT_2_7);
 }
 
 DEFINE_Q35_MACHINE(v2_7, "pc-q35-2.7", NULL,
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index c33c76ab93b1..feb4760830db 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -33,12 +33,10 @@
 #include "qemu/error-report.h"
 #include "qemu/config-file.h"
 #include "qemu/cutils.h"
 #include "qapi/error.h"
 
-#define FW_CFG_FILE_SLOTS_DFLT 0x20
-
 #define FW_CFG_NAME "fw_cfg"
 #define FW_CFG_PATH "/machine/" FW_CFG_NAME
 
 #define TYPE_FW_CFG     "fw_cfg"
 #define TYPE_FW_CFG_IO  "fw_cfg_io"
-- 
2.9.2

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

* [Qemu-devel] [PATCH v4 5/7] hw/isa/lpc_ich9: add SMI feature negotiation via fw_cfg
  2016-12-01 17:06 [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI Laszlo Ersek
                   ` (3 preceding siblings ...)
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 4/7] hw/i386/pc: introduce 2.9 machine types with 0x20 fw_cfg file slots Laszlo Ersek
@ 2016-12-01 17:06 ` Laszlo Ersek
  2016-12-02 11:54   ` Igor Mammedov
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 6/7] hw/isa/lpc_ich9: add broadcast SMI feature Laszlo Ersek
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 46+ messages in thread
From: Laszlo Ersek @ 2016-12-01 17:06 UTC (permalink / raw)
  To: qemu devel list
  Cc: Michael S. Tsirkin, Gerd Hoffmann, Igor Mammedov, Paolo Bonzini

Introduce the following fw_cfg files:

- "etc/smi/host-features": a little endian uint64_t feature bitmap,
  presenting the features known by the host to the guest. Read-only for
  the guest.

  The content of this file is calculated by QEMU at startup (the
  calculation will be added later). The same machine type is supposed to
  expose the same SMI features regardless of QEMU version, hence this file
  is not migrated.

- "etc/smi/guest-features": a little endian uint64_t feature bitmap,
  representing the features the guest would like to request. Read-write
  for the guest.

  The guest can freely (re)write this file, it has no direct consequence.
  Initial value is zero. A nonzero value causes the SMI-related fw_cfg
  files and fields that are under guest influence to be migrated.

- "etc/smi/features-ok": contains a uint8_t value, and it is read-only for
  the guest. When the guest selects the associated fw_cfg key, the guest
  features are validated against the host features. In case of error, the
  negotiation doesn't proceed, and the features-ok file remains zero. In
  case of success, the features-ok file becomes (uint8_t)1, and the
  negotiated features are locked down internally (to which no further
  changes are possible until reset).

  The initial value is zero.  A nonzero value causes the SMI-related
  fw_cfg files and fields that are under guest influence to be migrated.

The C-language fields backing the host-features and guest-features files
are uint8_t arrays. This is because they carry guest-side representation
(our choice is little endian), while VMSTATE_UINT64() assumes / implies
host-side endianness for any uint64_t fields. If we migrate a guest
between hosts with different endiannesses (which is possible with TCG),
then the host-side value is preserved, and the host-side representation is
translated. This would be visible to the guest through fw_cfg, unless we
used plain byte arrays. So we do.

Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 include/hw/i386/ich9.h | 12 +++++++-
 hw/i386/pc_q35.c       |  2 +-
 hw/isa/lpc_ich9.c      | 83 +++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 94 insertions(+), 3 deletions(-)

diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h
index 5fd7e97d2347..33142eb37252 100644
--- a/include/hw/i386/ich9.h
+++ b/include/hw/i386/ich9.h
@@ -15,11 +15,12 @@
 #include "hw/pci/pci_bus.h"
 
 void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
 int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx);
 PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin);
-void ich9_lpc_pm_init(PCIDevice *pci_lpc, bool smm_enabled);
+void ich9_lpc_pm_init(PCIDevice *pci_lpc, bool smm_enabled,
+                      uint64_t smi_host_features);
 I2CBus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
 
 void ich9_generate_smi(void);
 void ich9_generate_nmi(void);
 
@@ -62,10 +63,19 @@ typedef struct ICH9LPCState {
      * register contents and IO memory region
      */
     uint8_t rst_cnt;
     MemoryRegion rst_cnt_mem;
 
+    /* SMI feature negotiation via fw_cfg */
+    uint8_t smi_host_features[8];     /* guest-visible, read-only, little
+                                       * endian uint64_t */
+    uint8_t smi_guest_features[8];    /* guest-visible, read-write, little
+                                       * endian uint64_t */
+    uint8_t smi_features_ok;          /* guest-visible, read-only; selecting it
+                                       * triggers feature lockdown */
+    uint64_t smi_negotiated_features; /* guest-invisible, host endian */
+
     /* isa bus */
     ISABus *isa_bus;
     MemoryRegion rcrb_mem; /* root complex register block */
     Notifier machine_ready;
 
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 7fa40e7cbe0e..eb0953bb6b16 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -228,11 +228,11 @@ static void pc_q35_init(MachineState *machine)
     /* init basic PC hardware */
     pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, !mc->no_floppy,
                          (pcms->vmport != ON_OFF_AUTO_ON), 0xff0104);
 
     /* connect pm stuff to lpc */
-    ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms));
+    ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms), 0);
 
     /* ahci and SATA device, for q35 1 ahci controller is built-in */
     ahci = pci_create_simple_multifunction(host_bus,
                                            PCI_DEVFN(ICH9_SATA1_DEV,
                                                      ICH9_SATA1_FUNC),
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index 10d1ee8b9310..ee1fa553bfee 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -46,10 +46,12 @@
 #include "hw/acpi/ich9.h"
 #include "hw/pci/pci_bus.h"
 #include "exec/address-spaces.h"
 #include "sysemu/sysemu.h"
 #include "qom/cpu.h"
+#include "hw/nvram/fw_cfg.h"
+#include "qemu/cutils.h"
 
 /*****************************************************************************/
 /* ICH9 LPC PCI to ISA bridge */
 
 static void ich9_lpc_reset(DeviceState *qdev);
@@ -358,17 +360,68 @@ static void ich9_set_sci(void *opaque, int irq_num, int level)
     } else {
         ich9_lpc_update_pic(lpc, irq);
     }
 }
 
-void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled)
+static void smi_features_ok_callback(void *opaque)
+{
+    ICH9LPCState *lpc = opaque;
+    uint64_t host_features, guest_features;
+
+    if (lpc->smi_features_ok) {
+        /* negotiation already complete, features locked */
+        return;
+    }
+
+    memcpy(&host_features, lpc->smi_host_features, sizeof host_features);
+    memcpy(&guest_features, lpc->smi_guest_features, sizeof guest_features);
+    le64_to_cpus(&host_features);
+    le64_to_cpus(&guest_features);
+
+    if (guest_features & ~host_features) {
+        /* guest requests invalid features, leave @features_ok at zero */
+        return;
+    }
+
+    /* valid feature subset requested, lock it down, report success */
+    lpc->smi_negotiated_features = guest_features;
+    lpc->smi_features_ok = 1;
+}
+
+void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled,
+                      uint64_t smi_host_features)
 {
     ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
     qemu_irq sci_irq;
+    FWCfgState *fw_cfg = fw_cfg_find();
 
     sci_irq = qemu_allocate_irq(ich9_set_sci, lpc, 0);
     ich9_pm_init(lpc_pci, &lpc->pm, smm_enabled, sci_irq);
+
+    if (smi_host_features && fw_cfg) {
+        cpu_to_le64s(&smi_host_features);
+        memcpy(lpc->smi_host_features, &smi_host_features,
+               sizeof smi_host_features);
+        fw_cfg_add_file(fw_cfg, "etc/smi/host-features",
+                        lpc->smi_host_features,
+                        sizeof lpc->smi_host_features);
+
+        /* The other two guest-visible fields are cleared on device reset, we
+         * just link them into fw_cfg here.
+         */
+        fw_cfg_add_file_callback(fw_cfg, "etc/smi/guest-features",
+                                 NULL, NULL,
+                                 lpc->smi_guest_features,
+                                 sizeof lpc->smi_guest_features,
+                                 false);
+        fw_cfg_add_file_callback(fw_cfg, "etc/smi/features-ok",
+                                 smi_features_ok_callback, lpc,
+                                 &lpc->smi_features_ok,
+                                 sizeof lpc->smi_features_ok,
+                                 true);
+    }
+
     ich9_lpc_reset(&lpc->d.qdev);
 }
 
 /* APM */
 
@@ -505,10 +558,14 @@ static void ich9_lpc_reset(DeviceState *qdev)
     ich9_lpc_pmbase_sci_update(lpc);
     ich9_lpc_rcba_update(lpc, rcba_old);
 
     lpc->sci_level = 0;
     lpc->rst_cnt = 0;
+
+    memset(lpc->smi_guest_features, 0, sizeof lpc->smi_guest_features);
+    lpc->smi_features_ok = 0;
+    lpc->smi_negotiated_features = 0;
 }
 
 /* root complex register block is mapped into memory space */
 static const MemoryRegionOps rcrb_mmio_ops = {
     .read = ich9_cc_read,
@@ -666,10 +723,33 @@ static const VMStateDescription vmstate_ich9_rst_cnt = {
         VMSTATE_UINT8(rst_cnt, ICH9LPCState),
         VMSTATE_END_OF_LIST()
     }
 };
 
+static bool ich9_smi_feat_needed(void *opaque)
+{
+    ICH9LPCState *lpc = opaque;
+
+    return !buffer_is_zero(lpc->smi_guest_features,
+                           sizeof lpc->smi_guest_features) ||
+           lpc->smi_features_ok;
+}
+
+static const VMStateDescription vmstate_ich9_smi_feat = {
+    .name = "ICH9LPC/smi_feat",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = ich9_smi_feat_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8_ARRAY(smi_guest_features, ICH9LPCState,
+                            sizeof(uint64_t)),
+        VMSTATE_UINT8(smi_features_ok, ICH9LPCState),
+        VMSTATE_UINT64(smi_negotiated_features, ICH9LPCState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_ich9_lpc = {
     .name = "ICH9LPC",
     .version_id = 1,
     .minimum_version_id = 1,
     .post_load = ich9_lpc_post_load,
@@ -681,10 +761,11 @@ static const VMStateDescription vmstate_ich9_lpc = {
         VMSTATE_UINT32(sci_level, ICH9LPCState),
         VMSTATE_END_OF_LIST()
     },
     .subsections = (const VMStateDescription*[]) {
         &vmstate_ich9_rst_cnt,
+        &vmstate_ich9_smi_feat,
         NULL
     }
 };
 
 static Property ich9_lpc_properties[] = {
-- 
2.9.2

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

* [Qemu-devel] [PATCH v4 6/7] hw/isa/lpc_ich9: add broadcast SMI feature
  2016-12-01 17:06 [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI Laszlo Ersek
                   ` (4 preceding siblings ...)
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 5/7] hw/isa/lpc_ich9: add SMI feature negotiation via fw_cfg Laszlo Ersek
@ 2016-12-01 17:06 ` Laszlo Ersek
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 7/7] hw/i386/pc_q35: advertise broadcast SMI if VCPU hotplug is turned off Laszlo Ersek
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 46+ messages in thread
From: Laszlo Ersek @ 2016-12-01 17:06 UTC (permalink / raw)
  To: qemu devel list
  Cc: Michael S. Tsirkin, Gerd Hoffmann, Igor Mammedov, Paolo Bonzini

The generic edk2 SMM infrastructure prefers
EFI_SMM_CONTROL2_PROTOCOL.Trigger() to inject an SMI on each processor. If
Trigger() only brings the current processor into SMM, then edk2 handles it
in the following ways:

(1) If Trigger() is executed by the BSP (which is guaranteed before
    ExitBootServices(), but is not necessarily true at runtime), then:

    (a) If edk2 has been configured for "traditional" SMM synchronization,
        then the BSP sends directed SMIs to the APs with APIC delivery,
        bringing them into SMM individually. Then the BSP runs the SMI
        handler / dispatcher.

    (b) If edk2 has been configured for "relaxed" SMM synchronization,
        then the APs that are not already in SMM are not brought in, and
        the BSP runs the SMI handler / dispatcher.

(2) If Trigger() is executed by an AP (which is possible after
    ExitBootServices(), and can be forced e.g. by "taskset -c 1
    efibootmgr"), then the AP in question brings in the BSP with a
    directed SMI, and the BSP runs the SMI handler / dispatcher.

The smaller problem with (1a) and (2) is that the BSP and AP
synchronization is slow. For example, the "taskset -c 1 efibootmgr"
command from (2) can take more than 3 seconds to complete, because
efibootmgr accesses non-volatile UEFI variables intensively.

The larger problem is that QEMU's current behavior diverges from the
behavior usually seen on physical hardware, and that keeps exposing
obscure corner cases, race conditions and other instabilities in edk2,
which generally expects / prefers a software SMI to affect all CPUs at
once.

Therefore introduce the "broadcast SMI" feature (ICH9_LPC_SMI_F_BROADCAST)
that causes QEMU to inject the SMI on all VCPUs.

While the original posting of this patch
<http://lists.nongnu.org/archive/html/qemu-devel/2015-10/msg05658.html>
only intended to speed up (2), based on our recent "stress testing" of SMM
this patch actually provides functional improvements.

Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 include/hw/i386/ich9.h | 3 +++
 hw/isa/lpc_ich9.c      | 9 ++++++++-
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h
index 33142eb37252..e914b3f56fd8 100644
--- a/include/hw/i386/ich9.h
+++ b/include/hw/i386/ich9.h
@@ -248,6 +248,9 @@ Object *ich9_lpc_find(void);
 #define ICH9_SMB_XMIT_SLVA                      0x04
 #define ICH9_SMB_HST_D0                         0x05
 #define ICH9_SMB_HST_D1                         0x06
 #define ICH9_SMB_HOST_BLOCK_DB                  0x07
 
+/* bits used in fw_cfg SMI feature negotiation */
+#define ICH9_LPC_SMI_F_BROADCAST               (UINT64_C(1) << 0)
+
 #endif /* HW_ICH9_H */
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index ee1fa553bfee..6e9edbe62226 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -437,11 +437,18 @@ static void ich9_apm_ctrl_changed(uint32_t val, void *arg)
         return;
     }
 
     /* SMI_EN = PMBASE + 30. SMI control and enable register */
     if (lpc->pm.smi_en & ICH9_PMIO_SMI_EN_APMC_EN) {
-        cpu_interrupt(current_cpu, CPU_INTERRUPT_SMI);
+        if (lpc->smi_negotiated_features & ICH9_LPC_SMI_F_BROADCAST) {
+            CPUState *cs;
+            CPU_FOREACH(cs) {
+                cpu_interrupt(cs, CPU_INTERRUPT_SMI);
+            }
+        } else {
+            cpu_interrupt(current_cpu, CPU_INTERRUPT_SMI);
+        }
     }
 }
 
 /* config:PMBASE */
 static void
-- 
2.9.2

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

* [Qemu-devel] [PATCH v4 7/7] hw/i386/pc_q35: advertise broadcast SMI if VCPU hotplug is turned off
  2016-12-01 17:06 [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI Laszlo Ersek
                   ` (5 preceding siblings ...)
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 6/7] hw/isa/lpc_ich9: add broadcast SMI feature Laszlo Ersek
@ 2016-12-01 17:06 ` Laszlo Ersek
  2016-12-01 19:13   ` Eduardo Habkost
  2016-12-20 23:01 ` [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI no-reply
  2017-01-10 15:06 ` [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI Michael S. Tsirkin
  8 siblings, 1 reply; 46+ messages in thread
From: Laszlo Ersek @ 2016-12-01 17:06 UTC (permalink / raw)
  To: qemu devel list
  Cc: Michael S. Tsirkin, Eduardo Habkost, Gerd Hoffmann,
	Igor Mammedov, Paolo Bonzini

For the time being, we cannot handle SMIs in OVMF if VCPUs can show up
after boot. Otherwise, advertise ICH9_LPC_SMI_F_BROADCAST.

Implement this generally, by introducing a new PCMachineClass method,
namely get_smi_host_features(), and implement the above logic for
pc-q35-2.9 and later. The idea is that future machine types might want to
calculate (the same or different) SMI host features from different
information, and that shouldn't affect earlier machine types.

In turn, validating guest feature requests (inter-feature dependencies)
should be possible purely based on the available host feature set. For
example, in the future we might enforce that the guest select
ICH9_LPC_SMI_F_VCPU_PARKING as a prerequisite for
ICH9_LPC_SMI_F_BROADCAST, but only if the machine type itself advertises
ICH9_LPC_SMI_F_VCPU_PARKING.

Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Eduardo Habkost <ehabkost@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 include/hw/i386/pc.h |  1 +
 hw/i386/pc_q35.c     | 24 +++++++++++++++++++++++-
 2 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 430735e501dd..e164947116b6 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -116,10 +116,11 @@ struct PCMachineClass {
     /*< public >*/
 
     /* Methods: */
     HotplugHandler *(*get_hotplug_handler)(MachineState *machine,
                                            DeviceState *dev);
+    uint64_t (*get_smi_host_features)(void);
 
     /* Device configuration: */
     bool pci_enabled;
     bool kvmclock_enabled;
 
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index eb0953bb6b16..bc1ab48d2c4f 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -228,11 +228,13 @@ static void pc_q35_init(MachineState *machine)
     /* init basic PC hardware */
     pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, !mc->no_floppy,
                          (pcms->vmport != ON_OFF_AUTO_ON), 0xff0104);
 
     /* connect pm stuff to lpc */
-    ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms), 0);
+    ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms),
+                     pcmc->get_smi_host_features == NULL ? 0 :
+                     pcmc->get_smi_host_features());
 
     /* ahci and SATA device, for q35 1 ahci controller is built-in */
     ahci = pci_create_simple_multifunction(host_bus,
                                            PCI_DEVFN(ICH9_SATA1_DEV,
                                                      ICH9_SATA1_FUNC),
@@ -267,10 +269,26 @@ static void pc_q35_init(MachineState *machine)
         nvdimm_init_acpi_state(&pcms->acpi_nvdimm_state, system_io,
                                pcms->fw_cfg, OBJECT(pcms));
     }
 }
 
+static uint64_t pc_q35_get_smi_host_features(void)
+{
+    uint64_t host_features = 0;
+
+    /* The host features are computed only at startup, they don't depend on
+     * guest actions. For now we only advertise SMI broadcast if VCPU hot-plug
+     * / hot-unplug are disabled. In the future we might advertise it
+     * unconditionally, but negotiate it only if VCPU hot-plug / hot-unplug are
+     * disabled, or if the guest negotiates another feature bit (VCPU parking).
+     */
+    if (smp_cpus == max_cpus) {
+        host_features |= ICH9_LPC_SMI_F_BROADCAST;
+    }
+    return host_features;
+}
+
 #define DEFINE_Q35_MACHINE(suffix, name, compatfn, optionfn) \
     static void pc_init_##suffix(MachineState *machine) \
     { \
         void (*compat)(MachineState *m) = (compatfn); \
         if (compat) { \
@@ -281,19 +299,21 @@ static void pc_q35_init(MachineState *machine)
     DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
 
 
 static void pc_q35_machine_options(MachineClass *m)
 {
+    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
     m->family = "pc_q35";
     m->desc = "Standard PC (Q35 + ICH9, 2009)";
     m->hot_add_cpu = pc_hot_add_cpu;
     m->units_per_default_bus = 1;
     m->default_machine_opts = "firmware=bios-256k.bin";
     m->default_display = "std";
     m->no_floppy = 1;
     m->has_dynamic_sysbus = true;
     m->max_cpus = 288;
+    pcmc->get_smi_host_features = pc_q35_get_smi_host_features;
 }
 
 static void pc_q35_2_9_machine_options(MachineClass *m)
 {
     pc_q35_machine_options(m);
@@ -303,12 +323,14 @@ static void pc_q35_2_9_machine_options(MachineClass *m)
 DEFINE_Q35_MACHINE(v2_9, "pc-q35-2.9", NULL,
                    pc_q35_2_9_machine_options);
 
 static void pc_q35_2_8_machine_options(MachineClass *m)
 {
+    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
     pc_q35_2_9_machine_options(m);
     m->alias = NULL;
+    pcmc->get_smi_host_features = NULL;
     SET_MACHINE_COMPAT(m, PC_COMPAT_2_8);
 }
 
 DEFINE_Q35_MACHINE(v2_8, "pc-q35-2.8", NULL,
                    pc_q35_2_8_machine_options);
-- 
2.9.2

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

* Re: [Qemu-devel] [PATCH v4 7/7] hw/i386/pc_q35: advertise broadcast SMI if VCPU hotplug is turned off
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 7/7] hw/i386/pc_q35: advertise broadcast SMI if VCPU hotplug is turned off Laszlo Ersek
@ 2016-12-01 19:13   ` Eduardo Habkost
  2016-12-01 20:42     ` Laszlo Ersek
  0 siblings, 1 reply; 46+ messages in thread
From: Eduardo Habkost @ 2016-12-01 19:13 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: qemu devel list, Michael S. Tsirkin, Gerd Hoffmann,
	Igor Mammedov, Paolo Bonzini

On Thu, Dec 01, 2016 at 06:06:24PM +0100, Laszlo Ersek wrote:
> For the time being, we cannot handle SMIs in OVMF if VCPUs can show up
> after boot. Otherwise, advertise ICH9_LPC_SMI_F_BROADCAST.
> 
> Implement this generally, by introducing a new PCMachineClass method,
> namely get_smi_host_features(), and implement the above logic for
> pc-q35-2.9 and later. The idea is that future machine types might want to
> calculate (the same or different) SMI host features from different
> information, and that shouldn't affect earlier machine types.
> 
> In turn, validating guest feature requests (inter-feature dependencies)
> should be possible purely based on the available host feature set. For
> example, in the future we might enforce that the guest select
> ICH9_LPC_SMI_F_VCPU_PARKING as a prerequisite for
> ICH9_LPC_SMI_F_BROADCAST, but only if the machine type itself advertises
> ICH9_LPC_SMI_F_VCPU_PARKING.
> 
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Eduardo Habkost <ehabkost@redhat.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  include/hw/i386/pc.h |  1 +
>  hw/i386/pc_q35.c     | 24 +++++++++++++++++++++++-
>  2 files changed, 24 insertions(+), 1 deletion(-)
> 
> diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> index 430735e501dd..e164947116b6 100644
> --- a/include/hw/i386/pc.h
> +++ b/include/hw/i386/pc.h
> @@ -116,10 +116,11 @@ struct PCMachineClass {
>      /*< public >*/
>  
>      /* Methods: */
>      HotplugHandler *(*get_hotplug_handler)(MachineState *machine,
>                                             DeviceState *dev);
> +    uint64_t (*get_smi_host_features)(void);

I'd prefer to encode the differences between machine-types as
data, instead of code, to make introspection easier in the
future. Is it possible to encode this in a simple PCMachineClass
struct data field or (even bettter) a QOM property?

-- 
Eduardo

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

* Re: [Qemu-devel] [PATCH v4 7/7] hw/i386/pc_q35: advertise broadcast SMI if VCPU hotplug is turned off
  2016-12-01 19:13   ` Eduardo Habkost
@ 2016-12-01 20:42     ` Laszlo Ersek
  2016-12-01 20:53       ` Eduardo Habkost
  2016-12-02 12:18       ` Igor Mammedov
  0 siblings, 2 replies; 46+ messages in thread
From: Laszlo Ersek @ 2016-12-01 20:42 UTC (permalink / raw)
  To: Eduardo Habkost
  Cc: qemu devel list, Michael S. Tsirkin, Gerd Hoffmann,
	Igor Mammedov, Paolo Bonzini

On 12/01/16 20:13, Eduardo Habkost wrote:
> On Thu, Dec 01, 2016 at 06:06:24PM +0100, Laszlo Ersek wrote:
>> For the time being, we cannot handle SMIs in OVMF if VCPUs can show up
>> after boot. Otherwise, advertise ICH9_LPC_SMI_F_BROADCAST.
>>
>> Implement this generally, by introducing a new PCMachineClass method,
>> namely get_smi_host_features(), and implement the above logic for
>> pc-q35-2.9 and later. The idea is that future machine types might want to
>> calculate (the same or different) SMI host features from different
>> information, and that shouldn't affect earlier machine types.
>>
>> In turn, validating guest feature requests (inter-feature dependencies)
>> should be possible purely based on the available host feature set. For
>> example, in the future we might enforce that the guest select
>> ICH9_LPC_SMI_F_VCPU_PARKING as a prerequisite for
>> ICH9_LPC_SMI_F_BROADCAST, but only if the machine type itself advertises
>> ICH9_LPC_SMI_F_VCPU_PARKING.
>>
>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
>> Cc: Eduardo Habkost <ehabkost@redhat.com>
>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>> Cc: Igor Mammedov <imammedo@redhat.com>
>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>> ---
>>  include/hw/i386/pc.h |  1 +
>>  hw/i386/pc_q35.c     | 24 +++++++++++++++++++++++-
>>  2 files changed, 24 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
>> index 430735e501dd..e164947116b6 100644
>> --- a/include/hw/i386/pc.h
>> +++ b/include/hw/i386/pc.h
>> @@ -116,10 +116,11 @@ struct PCMachineClass {
>>      /*< public >*/
>>  
>>      /* Methods: */
>>      HotplugHandler *(*get_hotplug_handler)(MachineState *machine,
>>                                             DeviceState *dev);
>> +    uint64_t (*get_smi_host_features)(void);
> 
> I'd prefer to encode the differences between machine-types as
> data, instead of code, to make introspection easier in the
> future. Is it possible to encode this in a simple PCMachineClass
> struct data field or (even bettter) a QOM property?
> 

I don't know how else to capture the (smp_cpus == max_cpus) question,
for saying that "this machine type supports SMI broadcast, as long as
VCPU hotplug is disabled in the configuration".

Technically we could give PCMC two new (data) fields, a host features
bitmap for when VCPU hotplug is enabled, and another for when VCPU
hotplug is disabled. Then board code would take the right field and pass
it on to ich9_lpc_pm_init().

Thanks
Laszlo

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

* Re: [Qemu-devel] [PATCH v4 7/7] hw/i386/pc_q35: advertise broadcast SMI if VCPU hotplug is turned off
  2016-12-01 20:42     ` Laszlo Ersek
@ 2016-12-01 20:53       ` Eduardo Habkost
  2016-12-02 12:18       ` Igor Mammedov
  1 sibling, 0 replies; 46+ messages in thread
From: Eduardo Habkost @ 2016-12-01 20:53 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: qemu devel list, Michael S. Tsirkin, Gerd Hoffmann,
	Igor Mammedov, Paolo Bonzini

On Thu, Dec 01, 2016 at 09:42:58PM +0100, Laszlo Ersek wrote:
> On 12/01/16 20:13, Eduardo Habkost wrote:
> > On Thu, Dec 01, 2016 at 06:06:24PM +0100, Laszlo Ersek wrote:
> >> For the time being, we cannot handle SMIs in OVMF if VCPUs can show up
> >> after boot. Otherwise, advertise ICH9_LPC_SMI_F_BROADCAST.
> >>
> >> Implement this generally, by introducing a new PCMachineClass method,
> >> namely get_smi_host_features(), and implement the above logic for
> >> pc-q35-2.9 and later. The idea is that future machine types might want to
> >> calculate (the same or different) SMI host features from different
> >> information, and that shouldn't affect earlier machine types.
> >>
> >> In turn, validating guest feature requests (inter-feature dependencies)
> >> should be possible purely based on the available host feature set. For
> >> example, in the future we might enforce that the guest select
> >> ICH9_LPC_SMI_F_VCPU_PARKING as a prerequisite for
> >> ICH9_LPC_SMI_F_BROADCAST, but only if the machine type itself advertises
> >> ICH9_LPC_SMI_F_VCPU_PARKING.
> >>
> >> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> >> Cc: Eduardo Habkost <ehabkost@redhat.com>
> >> Cc: Gerd Hoffmann <kraxel@redhat.com>
> >> Cc: Igor Mammedov <imammedo@redhat.com>
> >> Cc: Paolo Bonzini <pbonzini@redhat.com>
> >> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> >> ---
> >>  include/hw/i386/pc.h |  1 +
> >>  hw/i386/pc_q35.c     | 24 +++++++++++++++++++++++-
> >>  2 files changed, 24 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> >> index 430735e501dd..e164947116b6 100644
> >> --- a/include/hw/i386/pc.h
> >> +++ b/include/hw/i386/pc.h
> >> @@ -116,10 +116,11 @@ struct PCMachineClass {
> >>      /*< public >*/
> >>  
> >>      /* Methods: */
> >>      HotplugHandler *(*get_hotplug_handler)(MachineState *machine,
> >>                                             DeviceState *dev);
> >> +    uint64_t (*get_smi_host_features)(void);
> > 
> > I'd prefer to encode the differences between machine-types as
> > data, instead of code, to make introspection easier in the
> > future. Is it possible to encode this in a simple PCMachineClass
> > struct data field or (even bettter) a QOM property?
> > 
> 
> I don't know how else to capture the (smp_cpus == max_cpus) question,
> for saying that "this machine type supports SMI broadcast, as long as
> VCPU hotplug is disabled in the configuration".
> 
> Technically we could give PCMC two new (data) fields, a host features
> bitmap for when VCPU hotplug is enabled, and another for when VCPU
> hotplug is disabled. Then board code would take the right field and pass
> it on to ich9_lpc_pm_init().

It's more complex than I expected, but I would still prefer that
than having a growing collection of get_smi_host_features()
functions.

However, I am not strongly against the function pointer if others
want to avoid the complexity of two extra bitmaps.

-- 
Eduardo

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

* Re: [Qemu-devel] [PATCH v4 2/7] fw-cfg: turn FW_CFG_FILE_SLOTS into a device property
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 2/7] fw-cfg: turn FW_CFG_FILE_SLOTS into a device property Laszlo Ersek
@ 2016-12-02 11:10   ` Gerd Hoffmann
  2016-12-02 11:48     ` Laszlo Ersek
  2016-12-06 10:50   ` Igor Mammedov
  2017-01-10 15:02   ` Michael S. Tsirkin
  2 siblings, 1 reply; 46+ messages in thread
From: Gerd Hoffmann @ 2016-12-02 11:10 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: qemu devel list, Gabriel L. Somlo, Michael S. Tsirkin,
	Igor Mammedov, Paolo Bonzini

On Do, 2016-12-01 at 18:06 +0100, Laszlo Ersek wrote:
> We'd like to raise the value of FW_CFG_FILE_SLOTS. Doing it naively could
> lead to problems with backward migration: a more recent QEMU (running an
> older machine type) would allow the guest, in fw_cfg_select(), to select a
> high key value that is unavailable in the same machine type implemented by
> the older (target) QEMU.

I don't think we need this.  fw_cfg changes are guest-visible so they
must not happen for a given machine type.  So if current machine types
don't hit the limit that should continue to be the case even if we
simply raise FW_CFG_FILE_SLOTS.

But we have to take care that new files show up on new machine types
only.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH v4 2/7] fw-cfg: turn FW_CFG_FILE_SLOTS into a device property
  2016-12-02 11:10   ` Gerd Hoffmann
@ 2016-12-02 11:48     ` Laszlo Ersek
  2016-12-02 12:47       ` Gerd Hoffmann
  0 siblings, 1 reply; 46+ messages in thread
From: Laszlo Ersek @ 2016-12-02 11:48 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: qemu devel list, Gabriel L. Somlo, Michael S. Tsirkin,
	Igor Mammedov, Paolo Bonzini

On 12/02/16 12:10, Gerd Hoffmann wrote:
> On Do, 2016-12-01 at 18:06 +0100, Laszlo Ersek wrote:
>> We'd like to raise the value of FW_CFG_FILE_SLOTS. Doing it naively could
>> lead to problems with backward migration: a more recent QEMU (running an
>> older machine type) would allow the guest, in fw_cfg_select(), to select a
>> high key value that is unavailable in the same machine type implemented by
>> the older (target) QEMU.
> 
> I don't think we need this.  fw_cfg changes are guest-visible so they
> must not happen for a given machine type.

Agreed.

> So if current machine types
> don't hit the limit

Please check one of the links in the blurb, under which Paolo noted that
we're already above the limit in the worst (theoretical) case.

In practice they don't hit the limit, indeed.

> that should continue to be the case even if we
> simply raise FW_CFG_FILE_SLOTS.

I'm not trying to make it hard for myself :), so in theory I don't
disagree with the idea. However, do consider backwards migration. (As
noted under the patch, I'm aware that upstream doesn't care, but that
shouldn't be reason enough to reject a patch that does care.)

Let's say we start a guest in the pc-q35-2.8 machtype on a new QEMU
release, as source QEMU host, which has the raised FW_CFG_FILE_SLOTS
value. The guest writes a high key value to the selector register, which
is valid under the raised limit, so the key value is stored (i.e.,
fw_cfg_select() won't store FW_CFG_INVALID in cur_entry).

Then the guest is migrated to the older release QEMU, where the value of
cur_entry is larger than or equal to FW_CFG_MAX_ENTRY. The guest then
reads the data register, and fw_cfg_data_read() does this:

    FWCfgEntry *e = (s->cur_entry == FW_CFG_INVALID) ? NULL :
                    &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
    uint64_t value = 0;

    assert(size > 0 && size <= sizeof(value));
    if (s->cur_entry != FW_CFG_INVALID && e->data && s->cur_offset <
e->len) {

Just computing the pointer "e" is undefined behavior, let alone
evaluating "e->data".

Once again, I know upstream doesn't care about backward migration, but
we (at Red Hat) do, for specific machine types at least. I would rather
carry this patch in upstream than in downstream only.

As far as I understand, this is the first time in QEMU history that
we're looking into raising FW_CFG_FILE_SLOTS, so I'd rather be careful.
(I definitely don't want to win the privilege to implement the patch in
downstream!)

> But we have to take care that new files show up on new machine types
> only.

The series covers that, yes -- if the SMI host features bitmap that is
returned by the new machtype-specific callback function at board
initialization is zero (or the callback doesn't exist), then the fw_cfg
files are not created. See how ich9_lpc_pm_init() is called, and how it
handles the new "smi_host_features" parameter.

Thanks
Laszlo

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

* Re: [Qemu-devel] [PATCH v4 5/7] hw/isa/lpc_ich9: add SMI feature negotiation via fw_cfg
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 5/7] hw/isa/lpc_ich9: add SMI feature negotiation via fw_cfg Laszlo Ersek
@ 2016-12-02 11:54   ` Igor Mammedov
  2016-12-02 12:00     ` Laszlo Ersek
  0 siblings, 1 reply; 46+ messages in thread
From: Igor Mammedov @ 2016-12-02 11:54 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: qemu devel list, Michael S. Tsirkin, Gerd Hoffmann, Paolo Bonzini

On Thu,  1 Dec 2016 18:06:22 +0100
Laszlo Ersek <lersek@redhat.com> wrote:

> Introduce the following fw_cfg files:
> 
> - "etc/smi/host-features": a little endian uint64_t feature bitmap,
>   presenting the features known by the host to the guest. Read-only for
>   the guest.
'host' here is a little bit confusing, I'd suggest 'supported-features'
instead.

 
>   The content of this file is calculated by QEMU at startup (the
>   calculation will be added later). The same machine type is supposed to
>   expose the same SMI features regardless of QEMU version, hence this file
>   is not migrated.
> 
> - "etc/smi/guest-features": a little endian uint64_t feature bitmap,
>   representing the features the guest would like to request. Read-write
>   for the guest.
and to match above 'requested-features'

 
>   The guest can freely (re)write this file, it has no direct consequence.
>   Initial value is zero. A nonzero value causes the SMI-related fw_cfg
>   files and fields that are under guest influence to be migrated.
> 
> - "etc/smi/features-ok": contains a uint8_t value, and it is read-only for
>   the guest. When the guest selects the associated fw_cfg key, the guest
>   features are validated against the host features. In case of error, the
>   negotiation doesn't proceed, and the features-ok file remains zero. In
>   case of success, the features-ok file becomes (uint8_t)1, and the
>   negotiated features are locked down internally (to which no further
>   changes are possible until reset).
> 
>   The initial value is zero.  A nonzero value causes the SMI-related
>   fw_cfg files and fields that are under guest influence to be migrated.
> 
> The C-language fields backing the host-features and guest-features files
> are uint8_t arrays. This is because they carry guest-side representation
> (our choice is little endian), while VMSTATE_UINT64() assumes / implies
> host-side endianness for any uint64_t fields. If we migrate a guest
> between hosts with different endiannesses (which is possible with TCG),
> then the host-side value is preserved, and the host-side representation is
> translated. This would be visible to the guest through fw_cfg, unless we
> used plain byte arrays. So we do.
> 
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  include/hw/i386/ich9.h | 12 +++++++-
>  hw/i386/pc_q35.c       |  2 +-
>  hw/isa/lpc_ich9.c      | 83 +++++++++++++++++++++++++++++++++++++++++++++++++-
>  3 files changed, 94 insertions(+), 3 deletions(-)
> 
> diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h
> index 5fd7e97d2347..33142eb37252 100644
> --- a/include/hw/i386/ich9.h
> +++ b/include/hw/i386/ich9.h
> @@ -15,11 +15,12 @@
>  #include "hw/pci/pci_bus.h"
>  
>  void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
>  int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx);
>  PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin);
> -void ich9_lpc_pm_init(PCIDevice *pci_lpc, bool smm_enabled);
> +void ich9_lpc_pm_init(PCIDevice *pci_lpc, bool smm_enabled,
> +                      uint64_t smi_host_features);
>  I2CBus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
>  
>  void ich9_generate_smi(void);
>  void ich9_generate_nmi(void);
>  
> @@ -62,10 +63,19 @@ typedef struct ICH9LPCState {
>       * register contents and IO memory region
>       */
>      uint8_t rst_cnt;
>      MemoryRegion rst_cnt_mem;
>  
> +    /* SMI feature negotiation via fw_cfg */
> +    uint8_t smi_host_features[8];     /* guest-visible, read-only, little
> +                                       * endian uint64_t */
> +    uint8_t smi_guest_features[8];    /* guest-visible, read-write, little
> +                                       * endian uint64_t */
how about adding _le suffix to 2 above fields?
that way it would be easier to read usage places without chance to misinterpret content

> +    uint8_t smi_features_ok;          /* guest-visible, read-only; selecting it
> +                                       * triggers feature lockdown */
> +    uint64_t smi_negotiated_features; /* guest-invisible, host endian */
> +
>      /* isa bus */
>      ISABus *isa_bus;
>      MemoryRegion rcrb_mem; /* root complex register block */
>      Notifier machine_ready;
>  
> diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
> index 7fa40e7cbe0e..eb0953bb6b16 100644
> --- a/hw/i386/pc_q35.c
> +++ b/hw/i386/pc_q35.c
> @@ -228,11 +228,11 @@ static void pc_q35_init(MachineState *machine)
>      /* init basic PC hardware */
>      pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, !mc->no_floppy,
>                           (pcms->vmport != ON_OFF_AUTO_ON), 0xff0104);
>  
>      /* connect pm stuff to lpc */
> -    ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms));
> +    ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms), 0);
>  
>      /* ahci and SATA device, for q35 1 ahci controller is built-in */
>      ahci = pci_create_simple_multifunction(host_bus,
>                                             PCI_DEVFN(ICH9_SATA1_DEV,
>                                                       ICH9_SATA1_FUNC),
> diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
> index 10d1ee8b9310..ee1fa553bfee 100644
> --- a/hw/isa/lpc_ich9.c
> +++ b/hw/isa/lpc_ich9.c
> @@ -46,10 +46,12 @@
>  #include "hw/acpi/ich9.h"
>  #include "hw/pci/pci_bus.h"
>  #include "exec/address-spaces.h"
>  #include "sysemu/sysemu.h"
>  #include "qom/cpu.h"
> +#include "hw/nvram/fw_cfg.h"
> +#include "qemu/cutils.h"
>  
>  /*****************************************************************************/
>  /* ICH9 LPC PCI to ISA bridge */
>  
>  static void ich9_lpc_reset(DeviceState *qdev);
> @@ -358,17 +360,68 @@ static void ich9_set_sci(void *opaque, int irq_num, int level)
>      } else {
>          ich9_lpc_update_pic(lpc, irq);
>      }
>  }
>  
> -void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled)
> +static void smi_features_ok_callback(void *opaque)
> +{
> +    ICH9LPCState *lpc = opaque;
> +    uint64_t host_features, guest_features;
> +
> +    if (lpc->smi_features_ok) {
> +        /* negotiation already complete, features locked */
> +        return;
> +    }
> +
> +    memcpy(&host_features, lpc->smi_host_features, sizeof host_features);
> +    memcpy(&guest_features, lpc->smi_guest_features, sizeof guest_features);
> +    le64_to_cpus(&host_features);
> +    le64_to_cpus(&guest_features);
> +
> +    if (guest_features & ~host_features) {
> +        /* guest requests invalid features, leave @features_ok at zero */
> +        return;
> +    }
> +
> +    /* valid feature subset requested, lock it down, report success */
> +    lpc->smi_negotiated_features = guest_features;
> +    lpc->smi_features_ok = 1;
> +}
> +
> +void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled,
> +                      uint64_t smi_host_features)
>  {
>      ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
>      qemu_irq sci_irq;
> +    FWCfgState *fw_cfg = fw_cfg_find();
>  
>      sci_irq = qemu_allocate_irq(ich9_set_sci, lpc, 0);
>      ich9_pm_init(lpc_pci, &lpc->pm, smm_enabled, sci_irq);
> +
> +    if (smi_host_features && fw_cfg) {
> +        cpu_to_le64s(&smi_host_features);
> +        memcpy(lpc->smi_host_features, &smi_host_features,
> +               sizeof smi_host_features);
> +        fw_cfg_add_file(fw_cfg, "etc/smi/host-features",
> +                        lpc->smi_host_features,
> +                        sizeof lpc->smi_host_features);
> +
> +        /* The other two guest-visible fields are cleared on device reset, we
> +         * just link them into fw_cfg here.
> +         */
> +        fw_cfg_add_file_callback(fw_cfg, "etc/smi/guest-features",
> +                                 NULL, NULL,
> +                                 lpc->smi_guest_features,
> +                                 sizeof lpc->smi_guest_features,
> +                                 false);
> +        fw_cfg_add_file_callback(fw_cfg, "etc/smi/features-ok",
> +                                 smi_features_ok_callback, lpc,
> +                                 &lpc->smi_features_ok,
> +                                 sizeof lpc->smi_features_ok,
> +                                 true);
> +    }
> +
>      ich9_lpc_reset(&lpc->d.qdev);
>  }
>  
>  /* APM */
>  
> @@ -505,10 +558,14 @@ static void ich9_lpc_reset(DeviceState *qdev)
>      ich9_lpc_pmbase_sci_update(lpc);
>      ich9_lpc_rcba_update(lpc, rcba_old);
>  
>      lpc->sci_level = 0;
>      lpc->rst_cnt = 0;
> +
> +    memset(lpc->smi_guest_features, 0, sizeof lpc->smi_guest_features);
> +    lpc->smi_features_ok = 0;
> +    lpc->smi_negotiated_features = 0;
>  }
>  
>  /* root complex register block is mapped into memory space */
>  static const MemoryRegionOps rcrb_mmio_ops = {
>      .read = ich9_cc_read,
> @@ -666,10 +723,33 @@ static const VMStateDescription vmstate_ich9_rst_cnt = {
>          VMSTATE_UINT8(rst_cnt, ICH9LPCState),
>          VMSTATE_END_OF_LIST()
>      }
>  };
>  
> +static bool ich9_smi_feat_needed(void *opaque)
> +{
> +    ICH9LPCState *lpc = opaque;
> +
> +    return !buffer_is_zero(lpc->smi_guest_features,
> +                           sizeof lpc->smi_guest_features) ||
> +           lpc->smi_features_ok;
> +}
> +
> +static const VMStateDescription vmstate_ich9_smi_feat = {
> +    .name = "ICH9LPC/smi_feat",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = ich9_smi_feat_needed,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8_ARRAY(smi_guest_features, ICH9LPCState,
> +                            sizeof(uint64_t)),
> +        VMSTATE_UINT8(smi_features_ok, ICH9LPCState),
> +        VMSTATE_UINT64(smi_negotiated_features, ICH9LPCState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
>  static const VMStateDescription vmstate_ich9_lpc = {
>      .name = "ICH9LPC",
>      .version_id = 1,
>      .minimum_version_id = 1,
>      .post_load = ich9_lpc_post_load,
> @@ -681,10 +761,11 @@ static const VMStateDescription vmstate_ich9_lpc = {
>          VMSTATE_UINT32(sci_level, ICH9LPCState),
>          VMSTATE_END_OF_LIST()
>      },
>      .subsections = (const VMStateDescription*[]) {
>          &vmstate_ich9_rst_cnt,
> +        &vmstate_ich9_smi_feat,
>          NULL
>      }
>  };
>  
>  static Property ich9_lpc_properties[] = {

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

* Re: [Qemu-devel] [PATCH v4 5/7] hw/isa/lpc_ich9: add SMI feature negotiation via fw_cfg
  2016-12-02 11:54   ` Igor Mammedov
@ 2016-12-02 12:00     ` Laszlo Ersek
  0 siblings, 0 replies; 46+ messages in thread
From: Laszlo Ersek @ 2016-12-02 12:00 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: qemu devel list, Michael S. Tsirkin, Gerd Hoffmann, Paolo Bonzini

On 12/02/16 12:54, Igor Mammedov wrote:
> On Thu,  1 Dec 2016 18:06:22 +0100
> Laszlo Ersek <lersek@redhat.com> wrote:
> 
>> Introduce the following fw_cfg files:
>>
>> - "etc/smi/host-features": a little endian uint64_t feature bitmap,
>>   presenting the features known by the host to the guest. Read-only for
>>   the guest.
> 'host' here is a little bit confusing, I'd suggest 'supported-features'
> instead.
> 
>  
>>   The content of this file is calculated by QEMU at startup (the
>>   calculation will be added later). The same machine type is supposed to
>>   expose the same SMI features regardless of QEMU version, hence this file
>>   is not migrated.
>>
>> - "etc/smi/guest-features": a little endian uint64_t feature bitmap,
>>   representing the features the guest would like to request. Read-write
>>   for the guest.
> and to match above 'requested-features'

The names were supposed to follow virtio 1.0, which calls these things
"device features" and "driver features".

Not a big deal anyway, I can update the file names as you suggest.

>>   The guest can freely (re)write this file, it has no direct consequence.
>>   Initial value is zero. A nonzero value causes the SMI-related fw_cfg
>>   files and fields that are under guest influence to be migrated.
>>
>> - "etc/smi/features-ok": contains a uint8_t value, and it is read-only for
>>   the guest. When the guest selects the associated fw_cfg key, the guest
>>   features are validated against the host features. In case of error, the
>>   negotiation doesn't proceed, and the features-ok file remains zero. In
>>   case of success, the features-ok file becomes (uint8_t)1, and the
>>   negotiated features are locked down internally (to which no further
>>   changes are possible until reset).
>>
>>   The initial value is zero.  A nonzero value causes the SMI-related
>>   fw_cfg files and fields that are under guest influence to be migrated.
>>
>> The C-language fields backing the host-features and guest-features files
>> are uint8_t arrays. This is because they carry guest-side representation
>> (our choice is little endian), while VMSTATE_UINT64() assumes / implies
>> host-side endianness for any uint64_t fields. If we migrate a guest
>> between hosts with different endiannesses (which is possible with TCG),
>> then the host-side value is preserved, and the host-side representation is
>> translated. This would be visible to the guest through fw_cfg, unless we
>> used plain byte arrays. So we do.
>>
>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>> Cc: Igor Mammedov <imammedo@redhat.com>
>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>> ---
>>  include/hw/i386/ich9.h | 12 +++++++-
>>  hw/i386/pc_q35.c       |  2 +-
>>  hw/isa/lpc_ich9.c      | 83 +++++++++++++++++++++++++++++++++++++++++++++++++-
>>  3 files changed, 94 insertions(+), 3 deletions(-)
>>
>> diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h
>> index 5fd7e97d2347..33142eb37252 100644
>> --- a/include/hw/i386/ich9.h
>> +++ b/include/hw/i386/ich9.h
>> @@ -15,11 +15,12 @@
>>  #include "hw/pci/pci_bus.h"
>>  
>>  void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
>>  int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx);
>>  PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin);
>> -void ich9_lpc_pm_init(PCIDevice *pci_lpc, bool smm_enabled);
>> +void ich9_lpc_pm_init(PCIDevice *pci_lpc, bool smm_enabled,
>> +                      uint64_t smi_host_features);
>>  I2CBus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
>>  
>>  void ich9_generate_smi(void);
>>  void ich9_generate_nmi(void);
>>  
>> @@ -62,10 +63,19 @@ typedef struct ICH9LPCState {
>>       * register contents and IO memory region
>>       */
>>      uint8_t rst_cnt;
>>      MemoryRegion rst_cnt_mem;
>>  
>> +    /* SMI feature negotiation via fw_cfg */
>> +    uint8_t smi_host_features[8];     /* guest-visible, read-only, little
>> +                                       * endian uint64_t */
>> +    uint8_t smi_guest_features[8];    /* guest-visible, read-write, little
>> +                                       * endian uint64_t */
> how about adding _le suffix to 2 above fields?
> that way it would be easier to read usage places without chance to misinterpret content

Good idea, I will do that.

Thanks!
Laszlo

> 
>> +    uint8_t smi_features_ok;          /* guest-visible, read-only; selecting it
>> +                                       * triggers feature lockdown */
>> +    uint64_t smi_negotiated_features; /* guest-invisible, host endian */
>> +
>>      /* isa bus */
>>      ISABus *isa_bus;
>>      MemoryRegion rcrb_mem; /* root complex register block */
>>      Notifier machine_ready;
>>  
>> diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
>> index 7fa40e7cbe0e..eb0953bb6b16 100644
>> --- a/hw/i386/pc_q35.c
>> +++ b/hw/i386/pc_q35.c
>> @@ -228,11 +228,11 @@ static void pc_q35_init(MachineState *machine)
>>      /* init basic PC hardware */
>>      pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, !mc->no_floppy,
>>                           (pcms->vmport != ON_OFF_AUTO_ON), 0xff0104);
>>  
>>      /* connect pm stuff to lpc */
>> -    ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms));
>> +    ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms), 0);
>>  
>>      /* ahci and SATA device, for q35 1 ahci controller is built-in */
>>      ahci = pci_create_simple_multifunction(host_bus,
>>                                             PCI_DEVFN(ICH9_SATA1_DEV,
>>                                                       ICH9_SATA1_FUNC),
>> diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
>> index 10d1ee8b9310..ee1fa553bfee 100644
>> --- a/hw/isa/lpc_ich9.c
>> +++ b/hw/isa/lpc_ich9.c
>> @@ -46,10 +46,12 @@
>>  #include "hw/acpi/ich9.h"
>>  #include "hw/pci/pci_bus.h"
>>  #include "exec/address-spaces.h"
>>  #include "sysemu/sysemu.h"
>>  #include "qom/cpu.h"
>> +#include "hw/nvram/fw_cfg.h"
>> +#include "qemu/cutils.h"
>>  
>>  /*****************************************************************************/
>>  /* ICH9 LPC PCI to ISA bridge */
>>  
>>  static void ich9_lpc_reset(DeviceState *qdev);
>> @@ -358,17 +360,68 @@ static void ich9_set_sci(void *opaque, int irq_num, int level)
>>      } else {
>>          ich9_lpc_update_pic(lpc, irq);
>>      }
>>  }
>>  
>> -void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled)
>> +static void smi_features_ok_callback(void *opaque)
>> +{
>> +    ICH9LPCState *lpc = opaque;
>> +    uint64_t host_features, guest_features;
>> +
>> +    if (lpc->smi_features_ok) {
>> +        /* negotiation already complete, features locked */
>> +        return;
>> +    }
>> +
>> +    memcpy(&host_features, lpc->smi_host_features, sizeof host_features);
>> +    memcpy(&guest_features, lpc->smi_guest_features, sizeof guest_features);
>> +    le64_to_cpus(&host_features);
>> +    le64_to_cpus(&guest_features);
>> +
>> +    if (guest_features & ~host_features) {
>> +        /* guest requests invalid features, leave @features_ok at zero */
>> +        return;
>> +    }
>> +
>> +    /* valid feature subset requested, lock it down, report success */
>> +    lpc->smi_negotiated_features = guest_features;
>> +    lpc->smi_features_ok = 1;
>> +}
>> +
>> +void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled,
>> +                      uint64_t smi_host_features)
>>  {
>>      ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
>>      qemu_irq sci_irq;
>> +    FWCfgState *fw_cfg = fw_cfg_find();
>>  
>>      sci_irq = qemu_allocate_irq(ich9_set_sci, lpc, 0);
>>      ich9_pm_init(lpc_pci, &lpc->pm, smm_enabled, sci_irq);
>> +
>> +    if (smi_host_features && fw_cfg) {
>> +        cpu_to_le64s(&smi_host_features);
>> +        memcpy(lpc->smi_host_features, &smi_host_features,
>> +               sizeof smi_host_features);
>> +        fw_cfg_add_file(fw_cfg, "etc/smi/host-features",
>> +                        lpc->smi_host_features,
>> +                        sizeof lpc->smi_host_features);
>> +
>> +        /* The other two guest-visible fields are cleared on device reset, we
>> +         * just link them into fw_cfg here.
>> +         */
>> +        fw_cfg_add_file_callback(fw_cfg, "etc/smi/guest-features",
>> +                                 NULL, NULL,
>> +                                 lpc->smi_guest_features,
>> +                                 sizeof lpc->smi_guest_features,
>> +                                 false);
>> +        fw_cfg_add_file_callback(fw_cfg, "etc/smi/features-ok",
>> +                                 smi_features_ok_callback, lpc,
>> +                                 &lpc->smi_features_ok,
>> +                                 sizeof lpc->smi_features_ok,
>> +                                 true);
>> +    }
>> +
>>      ich9_lpc_reset(&lpc->d.qdev);
>>  }
>>  
>>  /* APM */
>>  
>> @@ -505,10 +558,14 @@ static void ich9_lpc_reset(DeviceState *qdev)
>>      ich9_lpc_pmbase_sci_update(lpc);
>>      ich9_lpc_rcba_update(lpc, rcba_old);
>>  
>>      lpc->sci_level = 0;
>>      lpc->rst_cnt = 0;
>> +
>> +    memset(lpc->smi_guest_features, 0, sizeof lpc->smi_guest_features);
>> +    lpc->smi_features_ok = 0;
>> +    lpc->smi_negotiated_features = 0;
>>  }
>>  
>>  /* root complex register block is mapped into memory space */
>>  static const MemoryRegionOps rcrb_mmio_ops = {
>>      .read = ich9_cc_read,
>> @@ -666,10 +723,33 @@ static const VMStateDescription vmstate_ich9_rst_cnt = {
>>          VMSTATE_UINT8(rst_cnt, ICH9LPCState),
>>          VMSTATE_END_OF_LIST()
>>      }
>>  };
>>  
>> +static bool ich9_smi_feat_needed(void *opaque)
>> +{
>> +    ICH9LPCState *lpc = opaque;
>> +
>> +    return !buffer_is_zero(lpc->smi_guest_features,
>> +                           sizeof lpc->smi_guest_features) ||
>> +           lpc->smi_features_ok;
>> +}
>> +
>> +static const VMStateDescription vmstate_ich9_smi_feat = {
>> +    .name = "ICH9LPC/smi_feat",
>> +    .version_id = 1,
>> +    .minimum_version_id = 1,
>> +    .needed = ich9_smi_feat_needed,
>> +    .fields = (VMStateField[]) {
>> +        VMSTATE_UINT8_ARRAY(smi_guest_features, ICH9LPCState,
>> +                            sizeof(uint64_t)),
>> +        VMSTATE_UINT8(smi_features_ok, ICH9LPCState),
>> +        VMSTATE_UINT64(smi_negotiated_features, ICH9LPCState),
>> +        VMSTATE_END_OF_LIST()
>> +    }
>> +};
>> +
>>  static const VMStateDescription vmstate_ich9_lpc = {
>>      .name = "ICH9LPC",
>>      .version_id = 1,
>>      .minimum_version_id = 1,
>>      .post_load = ich9_lpc_post_load,
>> @@ -681,10 +761,11 @@ static const VMStateDescription vmstate_ich9_lpc = {
>>          VMSTATE_UINT32(sci_level, ICH9LPCState),
>>          VMSTATE_END_OF_LIST()
>>      },
>>      .subsections = (const VMStateDescription*[]) {
>>          &vmstate_ich9_rst_cnt,
>> +        &vmstate_ich9_smi_feat,
>>          NULL
>>      }
>>  };
>>  
>>  static Property ich9_lpc_properties[] = {
> 

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

* Re: [Qemu-devel] [PATCH v4 7/7] hw/i386/pc_q35: advertise broadcast SMI if VCPU hotplug is turned off
  2016-12-01 20:42     ` Laszlo Ersek
  2016-12-01 20:53       ` Eduardo Habkost
@ 2016-12-02 12:18       ` Igor Mammedov
  2016-12-02 19:32         ` Laszlo Ersek
  1 sibling, 1 reply; 46+ messages in thread
From: Igor Mammedov @ 2016-12-02 12:18 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: Eduardo Habkost, qemu devel list, Michael S. Tsirkin,
	Gerd Hoffmann, Paolo Bonzini

On Thu, 1 Dec 2016 21:42:58 +0100
Laszlo Ersek <lersek@redhat.com> wrote:

> On 12/01/16 20:13, Eduardo Habkost wrote:
> > On Thu, Dec 01, 2016 at 06:06:24PM +0100, Laszlo Ersek wrote:  
> >> For the time being, we cannot handle SMIs in OVMF if VCPUs can show up
> >> after boot. Otherwise, advertise ICH9_LPC_SMI_F_BROADCAST.
> >>
> >> Implement this generally, by introducing a new PCMachineClass method,
> >> namely get_smi_host_features(), and implement the above logic for
> >> pc-q35-2.9 and later. The idea is that future machine types might want to
> >> calculate (the same or different) SMI host features from different
> >> information, and that shouldn't affect earlier machine types.
> >>
> >> In turn, validating guest feature requests (inter-feature dependencies)
> >> should be possible purely based on the available host feature set. For
> >> example, in the future we might enforce that the guest select
> >> ICH9_LPC_SMI_F_VCPU_PARKING as a prerequisite for
> >> ICH9_LPC_SMI_F_BROADCAST, but only if the machine type itself advertises
> >> ICH9_LPC_SMI_F_VCPU_PARKING.
> >>
> >> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> >> Cc: Eduardo Habkost <ehabkost@redhat.com>
> >> Cc: Gerd Hoffmann <kraxel@redhat.com>
> >> Cc: Igor Mammedov <imammedo@redhat.com>
> >> Cc: Paolo Bonzini <pbonzini@redhat.com>
> >> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> >> ---
> >>  include/hw/i386/pc.h |  1 +
> >>  hw/i386/pc_q35.c     | 24 +++++++++++++++++++++++-
> >>  2 files changed, 24 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> >> index 430735e501dd..e164947116b6 100644
> >> --- a/include/hw/i386/pc.h
> >> +++ b/include/hw/i386/pc.h
> >> @@ -116,10 +116,11 @@ struct PCMachineClass {
> >>      /*< public >*/
> >>  
> >>      /* Methods: */
> >>      HotplugHandler *(*get_hotplug_handler)(MachineState *machine,
> >>                                             DeviceState *dev);
> >> +    uint64_t (*get_smi_host_features)(void);  
> > 
> > I'd prefer to encode the differences between machine-types as
> > data, instead of code, to make introspection easier in the
> > future. Is it possible to encode this in a simple PCMachineClass
> > struct data field or (even bettter) a QOM property?
> >   
> 
> I don't know how else to capture the (smp_cpus == max_cpus) question,
> for saying that "this machine type supports SMI broadcast, as long as
> VCPU hotplug is disabled in the configuration".
(smp_cpus == max_cpus) doesn't mean that CPU hotplug is disabled
(it actually can't be disabled at all).

In addition, it's possible to start machine with
 -smp 1,sockets=2,max_cpus=2 -device mycputype,socket=2

where all cpus will be coldpugged
It would be better to use PCMachineState.boot_cpus which contains
present cpus count.

I'd drop hotplug check (as usecase is broken in many places anyway)
and even won't touch PCMachineState, instead add a property like
ICH9_LPC.enable_smi_broadcast(on by default) and disable it for
old machine types using compat props.

We can work on making CPU hotplug and OVMF work in follow up patches.

> Technically we could give PCMC two new (data) fields, a host features
> bitmap for when VCPU hotplug is enabled, and another for when VCPU
> hotplug is disabled. Then board code would take the right field and pass
> it on to ich9_lpc_pm_init().
> 
> Thanks
> Laszlo

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

* Re: [Qemu-devel] [PATCH v4 2/7] fw-cfg: turn FW_CFG_FILE_SLOTS into a device property
  2016-12-02 11:48     ` Laszlo Ersek
@ 2016-12-02 12:47       ` Gerd Hoffmann
  0 siblings, 0 replies; 46+ messages in thread
From: Gerd Hoffmann @ 2016-12-02 12:47 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: qemu devel list, Gabriel L. Somlo, Michael S. Tsirkin,
	Igor Mammedov, Paolo Bonzini

  Hi,

> Please check one of the links in the blurb, under which Paolo noted that
> we're already above the limit in the worst (theoretical) case.

Oh, ok.  That changes the picture.

> In practice they don't hit the limit, indeed.

But creating such a case being possible (even if unlikely) is reason
enough to care, from a security point of view.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH v4 7/7] hw/i386/pc_q35: advertise broadcast SMI if VCPU hotplug is turned off
  2016-12-02 12:18       ` Igor Mammedov
@ 2016-12-02 19:32         ` Laszlo Ersek
  0 siblings, 0 replies; 46+ messages in thread
From: Laszlo Ersek @ 2016-12-02 19:32 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Eduardo Habkost, qemu devel list, Michael S. Tsirkin,
	Gerd Hoffmann, Paolo Bonzini

On 12/02/16 13:18, Igor Mammedov wrote:
> On Thu, 1 Dec 2016 21:42:58 +0100
> Laszlo Ersek <lersek@redhat.com> wrote:
> 
>> On 12/01/16 20:13, Eduardo Habkost wrote:
>>> On Thu, Dec 01, 2016 at 06:06:24PM +0100, Laszlo Ersek wrote:  
>>>> For the time being, we cannot handle SMIs in OVMF if VCPUs can show up
>>>> after boot. Otherwise, advertise ICH9_LPC_SMI_F_BROADCAST.
>>>>
>>>> Implement this generally, by introducing a new PCMachineClass method,
>>>> namely get_smi_host_features(), and implement the above logic for
>>>> pc-q35-2.9 and later. The idea is that future machine types might want to
>>>> calculate (the same or different) SMI host features from different
>>>> information, and that shouldn't affect earlier machine types.
>>>>
>>>> In turn, validating guest feature requests (inter-feature dependencies)
>>>> should be possible purely based on the available host feature set. For
>>>> example, in the future we might enforce that the guest select
>>>> ICH9_LPC_SMI_F_VCPU_PARKING as a prerequisite for
>>>> ICH9_LPC_SMI_F_BROADCAST, but only if the machine type itself advertises
>>>> ICH9_LPC_SMI_F_VCPU_PARKING.
>>>>
>>>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
>>>> Cc: Eduardo Habkost <ehabkost@redhat.com>
>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>>> Cc: Igor Mammedov <imammedo@redhat.com>
>>>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>>>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>>>> ---
>>>>  include/hw/i386/pc.h |  1 +
>>>>  hw/i386/pc_q35.c     | 24 +++++++++++++++++++++++-
>>>>  2 files changed, 24 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
>>>> index 430735e501dd..e164947116b6 100644
>>>> --- a/include/hw/i386/pc.h
>>>> +++ b/include/hw/i386/pc.h
>>>> @@ -116,10 +116,11 @@ struct PCMachineClass {
>>>>      /*< public >*/
>>>>  
>>>>      /* Methods: */
>>>>      HotplugHandler *(*get_hotplug_handler)(MachineState *machine,
>>>>                                             DeviceState *dev);
>>>> +    uint64_t (*get_smi_host_features)(void);  
>>>
>>> I'd prefer to encode the differences between machine-types as
>>> data, instead of code, to make introspection easier in the
>>> future. Is it possible to encode this in a simple PCMachineClass
>>> struct data field or (even bettter) a QOM property?
>>>   
>>
>> I don't know how else to capture the (smp_cpus == max_cpus) question,
>> for saying that "this machine type supports SMI broadcast, as long as
>> VCPU hotplug is disabled in the configuration".
> (smp_cpus == max_cpus) doesn't mean that CPU hotplug is disabled
> (it actually can't be disabled at all).
> 
> In addition, it's possible to start machine with
>  -smp 1,sockets=2,max_cpus=2 -device mycputype,socket=2
> 
> where all cpus will be coldpugged
> It would be better to use PCMachineState.boot_cpus which contains
> present cpus count.
> 
> I'd drop hotplug check (as usecase is broken in many places anyway)
> and even won't touch PCMachineState, instead add a property like
> ICH9_LPC.enable_smi_broadcast(on by default) and disable it for
> old machine types using compat props.

I'll look into that, thanks!
Laszlo

> 
> We can work on making CPU hotplug and OVMF work in follow up patches.
> 
>> Technically we could give PCMC two new (data) fields, a host features
>> bitmap for when VCPU hotplug is enabled, and another for when VCPU
>> hotplug is disabled. Then board code would take the right field and pass
>> it on to ich9_lpc_pm_init().
>>
>> Thanks
>> Laszlo
> 

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

* Re: [Qemu-devel] [PATCH v4 2/7] fw-cfg: turn FW_CFG_FILE_SLOTS into a device property
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 2/7] fw-cfg: turn FW_CFG_FILE_SLOTS into a device property Laszlo Ersek
  2016-12-02 11:10   ` Gerd Hoffmann
@ 2016-12-06 10:50   ` Igor Mammedov
  2016-12-06 11:43     ` Laszlo Ersek
  2017-01-10 15:02   ` Michael S. Tsirkin
  2 siblings, 1 reply; 46+ messages in thread
From: Igor Mammedov @ 2016-12-06 10:50 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: qemu devel list, Gabriel L. Somlo, Michael S. Tsirkin,
	Gerd Hoffmann, Paolo Bonzini

On Thu,  1 Dec 2016 18:06:19 +0100
Laszlo Ersek <lersek@redhat.com> wrote:

> We'd like to raise the value of FW_CFG_FILE_SLOTS. Doing it naively could
> lead to problems with backward migration: a more recent QEMU (running an
> older machine type) would allow the guest, in fw_cfg_select(), to select a
> high key value that is unavailable in the same machine type implemented by
> the older (target) QEMU. On the target host, fw_cfg_data_read() for
> example could dereference nonexistent entries.
> 
> As first step, size the FWCfgState.entries[*] and FWCfgState.entry_order
> arrays dynamically. All three array sizes will be influenced by the new
> field (and device property) FWCfgState.file_slots.
> 
> Make the following changes:
> 
> - Replace the FW_CFG_FILE_SLOTS macro with FW_CFG_FILE_SLOTS_TRAD
>   (traditional count of fw_cfg file slots) in the header file. The value
>   remains 0x10.
> 
> - Replace all uses of FW_CFG_FILE_SLOTS with a helper function called
>   fw_cfg_file_slots(), returning the new property.
> 
> - Eliminate the macro FW_CFG_MAX_ENTRY, and replace all its uses with a
>   helper function called fw_cfg_max_entry().
> 
> - In the MMIO- and IO-mapped realize functions both, allocate all three
>   arrays dynamically, based on the new property.
> 
> - The new property defaults to 0x20; however at the moment we forcibly set
>   it to FW_CFG_FILE_SLOTS_TRAD on all code paths available to board code
>   (namely in the fw_cfg_init_io_dma() and fw_cfg_init_mem_wide() helper
>   functions). This is going to be customized in the following patches.
> 
> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
> 
> Notes:
>     I know that upstream doesn't care about backward migration, but some
>     downstreams might.
> 
>  docs/specs/fw_cfg.txt          |  2 +-
>  include/hw/nvram/fw_cfg_keys.h |  3 +-
>  hw/nvram/fw_cfg.c              | 85 ++++++++++++++++++++++++++++++++++++++----
>  3 files changed, 79 insertions(+), 11 deletions(-)
> 
> diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
> index a19e2adbe1c6..84e2978706f5 100644
> --- a/docs/specs/fw_cfg.txt
> +++ b/docs/specs/fw_cfg.txt
> @@ -154,11 +154,11 @@ Selector Reg.    Range Usage
>  0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW
>                                   through the DMA interface in QEMU v2.9+)
>  0xc000 - 0xffff  Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
>  
>  In practice, the number of allowed firmware configuration items is given
> -by the value of FW_CFG_MAX_ENTRY (see fw_cfg.h).
> +by the value (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS_TRAD) (see fw_cfg.h).
>  
>  = Guest-side DMA Interface =
>  
>  If bit 1 of the feature bitmap is set, the DMA interface is present. This does
>  not replace the existing fw_cfg interface, it is an add-on. This interface
> diff --git a/include/hw/nvram/fw_cfg_keys.h b/include/hw/nvram/fw_cfg_keys.h
> index 0f3e871884c0..627589793671 100644
> --- a/include/hw/nvram/fw_cfg_keys.h
> +++ b/include/hw/nvram/fw_cfg_keys.h
> @@ -27,12 +27,11 @@
>  #define FW_CFG_SETUP_SIZE       0x17
>  #define FW_CFG_SETUP_DATA       0x18
>  #define FW_CFG_FILE_DIR         0x19
>  
>  #define FW_CFG_FILE_FIRST       0x20
> -#define FW_CFG_FILE_SLOTS       0x10
> -#define FW_CFG_MAX_ENTRY        (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS)
> +#define FW_CFG_FILE_SLOTS_TRAD  0x10
>  
>  #define FW_CFG_WRITE_CHANNEL    0x4000
>  #define FW_CFG_ARCH_LOCAL       0x8000
>  #define FW_CFG_ENTRY_MASK       (~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL))
>  
> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> index e0145c11a19b..2e1441c09750 100644
> --- a/hw/nvram/fw_cfg.c
> +++ b/hw/nvram/fw_cfg.c
> @@ -31,10 +31,13 @@
>  #include "hw/sysbus.h"
>  #include "trace.h"
>  #include "qemu/error-report.h"
>  #include "qemu/config-file.h"
>  #include "qemu/cutils.h"
> +#include "qapi/error.h"
> +
> +#define FW_CFG_FILE_SLOTS_DFLT 0x20
>  
>  #define FW_CFG_NAME "fw_cfg"
>  #define FW_CFG_PATH "/machine/" FW_CFG_NAME
>  
>  #define TYPE_FW_CFG     "fw_cfg"
> @@ -69,12 +72,13 @@ typedef struct FWCfgEntry {
>  struct FWCfgState {
>      /*< private >*/
>      SysBusDevice parent_obj;
>      /*< public >*/
>  
> -    FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
> -    int entry_order[FW_CFG_MAX_ENTRY];
> +    uint32_t file_slots;
should it be uint16_t?
As below you use "uint16_t file_slots_max;" and do some UINT16
to calculate max limit.

> +    FWCfgEntry *entries[2];
> +    int *entry_order;
>      FWCfgFiles *files;
>      uint16_t cur_entry;
>      uint32_t cur_offset;
>      Notifier machine_ready;
>  
> @@ -255,17 +259,27 @@ static void fw_cfg_reboot(FWCfgState *s)
>  static void fw_cfg_write(FWCfgState *s, uint8_t value)
>  {
>      /* nothing, write support removed in QEMU v2.4+ */
>  }
>  
> +static inline uint32_t fw_cfg_file_slots(const FWCfgState *s)
> +{
> +    return s->file_slots;
> +}
so far it doesn't look like this wrapper function is necessary,
I'd prefer accessing field directly as it's used only internally.
Or do you have plans to extend wrapper later?
(then it would be better introduce wrapper at that time)

> +
> +static inline uint32_t fw_cfg_max_entry(const FWCfgState *s)
> +{
> +    return FW_CFG_FILE_FIRST + fw_cfg_file_slots(s);
> +}
> +
>  static int fw_cfg_select(FWCfgState *s, uint16_t key)
>  {
>      int arch, ret;
>      FWCfgEntry *e;
>  
>      s->cur_offset = 0;
> -    if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
> +    if ((key & FW_CFG_ENTRY_MASK) >= fw_cfg_max_entry(s)) {
>          s->cur_entry = FW_CFG_INVALID;
>          ret = 0;
>      } else {
>          s->cur_entry = key;
>          ret = 1;
> @@ -608,11 +622,11 @@ static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key,
>  {
>      int arch = !!(key & FW_CFG_ARCH_LOCAL);
>  
>      key &= FW_CFG_ENTRY_MASK;
>  
> -    assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
> +    assert(key < fw_cfg_max_entry(s) && len < UINT32_MAX);
>      assert(s->entries[arch][key].data == NULL); /* avoid key conflict */
>  
>      s->entries[arch][key].data = data;
>      s->entries[arch][key].len = (uint32_t)len;
>      s->entries[arch][key].read_callback = callback;
> @@ -626,11 +640,11 @@ static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key,
>      void *ptr;
>      int arch = !!(key & FW_CFG_ARCH_LOCAL);
>  
>      key &= FW_CFG_ENTRY_MASK;
>  
> -    assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
> +    assert(key < fw_cfg_max_entry(s) && len < UINT32_MAX);
>  
>      /* 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;
> @@ -775,17 +789,17 @@ void fw_cfg_add_file_callback(FWCfgState *s,  const char *filename,
>      size_t dsize;
>      MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
>      int order = 0;
>  
>      if (!s->files) {
> -        dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * FW_CFG_FILE_SLOTS;
> +        dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * fw_cfg_file_slots(s);
>          s->files = g_malloc0(dsize);
>          fw_cfg_add_bytes(s, FW_CFG_FILE_DIR, s->files, dsize);
>      }
>  
>      count = be32_to_cpu(s->files->count);
> -    assert(count < FW_CFG_FILE_SLOTS);
> +    assert(count < fw_cfg_file_slots(s));
>  
>      /* Find the insertion point. */
>      if (mc->legacy_fw_cfg_order) {
>          /*
>           * Sort by order. For files with the same order, we keep them
> @@ -855,11 +869,11 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
>      void *ptr = NULL;
>  
>      assert(s->files);
>  
>      index = be32_to_cpu(s->files->count);
> -    assert(index < FW_CFG_FILE_SLOTS);
> +    assert(index < fw_cfg_file_slots(s));
>  
>      for (i = 0; i < index; i++) {
>          if (strcmp(filename, s->files->f[i].name) == 0) {
>              ptr = fw_cfg_modify_bytes_read(s, FW_CFG_FILE_FIRST + i,
>                                             data, len);
> @@ -926,10 +940,16 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
>      qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase);
>      if (!dma_requested) {
>          qdev_prop_set_bit(dev, "dma_enabled", false);
>      }
>  
> +    /* Once we expose the "file_slots" property to callers of
> +     * fw_cfg_init_io_dma(), the following setting should become conditional on
> +     * the input parameter being lower than the current value of the property.
> +     */
> +    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
> +
>      fw_cfg_init1(dev);
>      s = FW_CFG(dev);
>  
>      if (s->dma_enabled) {
>          /* 64 bits for the address field */
> @@ -963,10 +983,17 @@ FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
>      qdev_prop_set_uint32(dev, "data_width", data_width);
>      if (!dma_requested) {
>          qdev_prop_set_bit(dev, "dma_enabled", false);
>      }
>  
> +    /* Once we expose the "file_slots" property to callers of
> +     * fw_cfg_init_mem_wide(), the following setting should become conditional
> +     * on the input parameter being lower than the current value of the
> +     * property. Refer to fw_cfg_init_io_dma().
> +     */
> +    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
both above cases of qdev_prop_set_uint32() could be replaced by
compat property for fwcfg device which would clamp "file_slots"
to old value for old machine types in a cleaner way.

> +
>      fw_cfg_init1(dev);
>  
>      sbd = SYS_BUS_DEVICE(dev);
>      sysbus_mmio_map(sbd, 0, ctl_addr);
>      sysbus_mmio_map(sbd, 1, data_addr);
> @@ -1012,23 +1039,56 @@ static const TypeInfo fw_cfg_info = {
>      .abstract      = true,
>      .instance_size = sizeof(FWCfgState),
>      .class_init    = fw_cfg_class_init,
>  };
>  
> +static void fw_cfg_file_slots_allocate(FWCfgState *s, Error **errp)
> +{
> +    uint16_t file_slots_max;
> +
> +    if (fw_cfg_file_slots(s) < FW_CFG_FILE_SLOTS_TRAD) {
> +        error_setg(errp, "\"file_slots\" must be at least 0x%x",
> +                   FW_CFG_FILE_SLOTS_TRAD);
> +        return;
> +    }
> +
> +    /* (UINT16_MAX & FW_CFG_ENTRY_MASK) is the highest inclusive selector value
> +     * that we permit. The actual (exclusive) value coming from the
> +     * configuration is (FW_CFG_FILE_FIRST + fw_cfg_file_slots(s)). */
> +    file_slots_max = (UINT16_MAX & FW_CFG_ENTRY_MASK) - FW_CFG_FILE_FIRST + 1;
> +    if (fw_cfg_file_slots(s) > file_slots_max) {
> +        error_setg(errp, "\"file_slots\" must not exceed 0x%" PRIx16,
> +                   file_slots_max);
> +        return;
> +    }
> +
> +    s->entries[0] = g_new0(FWCfgEntry, fw_cfg_max_entry(s));
> +    s->entries[1] = g_new0(FWCfgEntry, fw_cfg_max_entry(s));
> +    s->entry_order = g_new0(int, fw_cfg_max_entry(s));
> +}
>  
>  static Property fw_cfg_io_properties[] = {
>      DEFINE_PROP_UINT32("iobase", FWCfgIoState, iobase, -1),
>      DEFINE_PROP_UINT32("dma_iobase", FWCfgIoState, dma_iobase, -1),
>      DEFINE_PROP_BOOL("dma_enabled", FWCfgIoState, parent_obj.dma_enabled,
>                       true),
> +    DEFINE_PROP_UINT32("file_slots", FWCfgIoState, parent_obj.file_slots,
> +                       FW_CFG_FILE_SLOTS_DFLT),
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
>  static void fw_cfg_io_realize(DeviceState *dev, Error **errp)
>  {
>      FWCfgIoState *s = FW_CFG_IO(dev);
>      SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +    Error *local_err = NULL;
> +
> +    fw_cfg_file_slots_allocate(FW_CFG(s), &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
>  
>      /* when using port i/o, the 8-bit data register ALWAYS overlaps
>       * with half of the 16-bit control register. Hence, the total size
>       * of the i/o region used is FW_CFG_CTL_SIZE */
>      memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops,
> @@ -1061,18 +1121,27 @@ static const TypeInfo fw_cfg_io_info = {
>  
>  static Property fw_cfg_mem_properties[] = {
>      DEFINE_PROP_UINT32("data_width", FWCfgMemState, data_width, -1),
>      DEFINE_PROP_BOOL("dma_enabled", FWCfgMemState, parent_obj.dma_enabled,
>                       true),
> +    DEFINE_PROP_UINT32("file_slots", FWCfgMemState, parent_obj.file_slots,
> +                       FW_CFG_FILE_SLOTS_DFLT),
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
>  static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
>  {
>      FWCfgMemState *s = FW_CFG_MEM(dev);
>      SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>      const MemoryRegionOps *data_ops = &fw_cfg_data_mem_ops;
> +    Error *local_err = NULL;
> +
> +    fw_cfg_file_slots_allocate(FW_CFG(s), &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
>  
>      memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops,
>                            FW_CFG(s), "fwcfg.ctl", FW_CFG_CTL_SIZE);
>      sysbus_init_mmio(sbd, &s->ctl_iomem);
>  

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

* Re: [Qemu-devel] [PATCH v4 2/7] fw-cfg: turn FW_CFG_FILE_SLOTS into a device property
  2016-12-06 10:50   ` Igor Mammedov
@ 2016-12-06 11:43     ` Laszlo Ersek
  2016-12-06 12:02       ` Igor Mammedov
  0 siblings, 1 reply; 46+ messages in thread
From: Laszlo Ersek @ 2016-12-06 11:43 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: qemu devel list, Gabriel L. Somlo, Michael S. Tsirkin,
	Gerd Hoffmann, Paolo Bonzini

On 12/06/16 11:50, Igor Mammedov wrote:
> On Thu,  1 Dec 2016 18:06:19 +0100
> Laszlo Ersek <lersek@redhat.com> wrote:
> 
>> We'd like to raise the value of FW_CFG_FILE_SLOTS. Doing it naively could
>> lead to problems with backward migration: a more recent QEMU (running an
>> older machine type) would allow the guest, in fw_cfg_select(), to select a
>> high key value that is unavailable in the same machine type implemented by
>> the older (target) QEMU. On the target host, fw_cfg_data_read() for
>> example could dereference nonexistent entries.
>>
>> As first step, size the FWCfgState.entries[*] and FWCfgState.entry_order
>> arrays dynamically. All three array sizes will be influenced by the new
>> field (and device property) FWCfgState.file_slots.
>>
>> Make the following changes:
>>
>> - Replace the FW_CFG_FILE_SLOTS macro with FW_CFG_FILE_SLOTS_TRAD
>>   (traditional count of fw_cfg file slots) in the header file. The value
>>   remains 0x10.
>>
>> - Replace all uses of FW_CFG_FILE_SLOTS with a helper function called
>>   fw_cfg_file_slots(), returning the new property.
>>
>> - Eliminate the macro FW_CFG_MAX_ENTRY, and replace all its uses with a
>>   helper function called fw_cfg_max_entry().
>>
>> - In the MMIO- and IO-mapped realize functions both, allocate all three
>>   arrays dynamically, based on the new property.
>>
>> - The new property defaults to 0x20; however at the moment we forcibly set
>>   it to FW_CFG_FILE_SLOTS_TRAD on all code paths available to board code
>>   (namely in the fw_cfg_init_io_dma() and fw_cfg_init_mem_wide() helper
>>   functions). This is going to be customized in the following patches.
>>
>> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>> Cc: Igor Mammedov <imammedo@redhat.com>
>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>> ---
>>
>> Notes:
>>     I know that upstream doesn't care about backward migration, but some
>>     downstreams might.
>>
>>  docs/specs/fw_cfg.txt          |  2 +-
>>  include/hw/nvram/fw_cfg_keys.h |  3 +-
>>  hw/nvram/fw_cfg.c              | 85 ++++++++++++++++++++++++++++++++++++++----
>>  3 files changed, 79 insertions(+), 11 deletions(-)
>>
>> diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
>> index a19e2adbe1c6..84e2978706f5 100644
>> --- a/docs/specs/fw_cfg.txt
>> +++ b/docs/specs/fw_cfg.txt
>> @@ -154,11 +154,11 @@ Selector Reg.    Range Usage
>>  0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW
>>                                   through the DMA interface in QEMU v2.9+)
>>  0xc000 - 0xffff  Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
>>  
>>  In practice, the number of allowed firmware configuration items is given
>> -by the value of FW_CFG_MAX_ENTRY (see fw_cfg.h).
>> +by the value (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS_TRAD) (see fw_cfg.h).
>>  
>>  = Guest-side DMA Interface =
>>  
>>  If bit 1 of the feature bitmap is set, the DMA interface is present. This does
>>  not replace the existing fw_cfg interface, it is an add-on. This interface
>> diff --git a/include/hw/nvram/fw_cfg_keys.h b/include/hw/nvram/fw_cfg_keys.h
>> index 0f3e871884c0..627589793671 100644
>> --- a/include/hw/nvram/fw_cfg_keys.h
>> +++ b/include/hw/nvram/fw_cfg_keys.h
>> @@ -27,12 +27,11 @@
>>  #define FW_CFG_SETUP_SIZE       0x17
>>  #define FW_CFG_SETUP_DATA       0x18
>>  #define FW_CFG_FILE_DIR         0x19
>>  
>>  #define FW_CFG_FILE_FIRST       0x20
>> -#define FW_CFG_FILE_SLOTS       0x10
>> -#define FW_CFG_MAX_ENTRY        (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS)
>> +#define FW_CFG_FILE_SLOTS_TRAD  0x10
>>  
>>  #define FW_CFG_WRITE_CHANNEL    0x4000
>>  #define FW_CFG_ARCH_LOCAL       0x8000
>>  #define FW_CFG_ENTRY_MASK       (~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL))
>>  
>> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
>> index e0145c11a19b..2e1441c09750 100644
>> --- a/hw/nvram/fw_cfg.c
>> +++ b/hw/nvram/fw_cfg.c
>> @@ -31,10 +31,13 @@
>>  #include "hw/sysbus.h"
>>  #include "trace.h"
>>  #include "qemu/error-report.h"
>>  #include "qemu/config-file.h"
>>  #include "qemu/cutils.h"
>> +#include "qapi/error.h"
>> +
>> +#define FW_CFG_FILE_SLOTS_DFLT 0x20
>>  
>>  #define FW_CFG_NAME "fw_cfg"
>>  #define FW_CFG_PATH "/machine/" FW_CFG_NAME
>>  
>>  #define TYPE_FW_CFG     "fw_cfg"
>> @@ -69,12 +72,13 @@ typedef struct FWCfgEntry {
>>  struct FWCfgState {
>>      /*< private >*/
>>      SysBusDevice parent_obj;
>>      /*< public >*/
>>  
>> -    FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
>> -    int entry_order[FW_CFG_MAX_ENTRY];
>> +    uint32_t file_slots;
> should it be uint16_t?
> As below you use "uint16_t file_slots_max;" and do some UINT16
> to calculate max limit.

I think I had a reason for making this uint32_t. I think the argument
was that fw_cfg_max_entry() could theoretically return a value that
doesn't fit in a uint16_t. Looking again at the patch however, I think I
can try to make this a uint16_t for the next version.

> 
>> +    FWCfgEntry *entries[2];
>> +    int *entry_order;
>>      FWCfgFiles *files;
>>      uint16_t cur_entry;
>>      uint32_t cur_offset;
>>      Notifier machine_ready;
>>  
>> @@ -255,17 +259,27 @@ static void fw_cfg_reboot(FWCfgState *s)
>>  static void fw_cfg_write(FWCfgState *s, uint8_t value)
>>  {
>>      /* nothing, write support removed in QEMU v2.4+ */
>>  }
>>  
>> +static inline uint32_t fw_cfg_file_slots(const FWCfgState *s)
>> +{
>> +    return s->file_slots;
>> +}
> so far it doesn't look like this wrapper function is necessary,
> I'd prefer accessing field directly as it's used only internally.
> Or do you have plans to extend wrapper later?
> (then it would be better introduce wrapper at that time)

Originally I used "s->file_slots" in this patch, like you say, without
this small wrapper function,, but the resultant patch was harder to
review. With this wrapper, you have two kinds of changes in the patch:

*     FW_CFG_MAX_ENTRY
  --> fw_cfg_max_entry(s)

*     FW_CFG_FILE_SLOTS
  --> fw_cfg_file_slots(s)

Without the wrapper, the second bullet looks

*     FW_CFG_FILE_SLOTS
  --> s->file_slots

and to me that made the patch harder to verify.

> 
>> +
>> +static inline uint32_t fw_cfg_max_entry(const FWCfgState *s)
>> +{
>> +    return FW_CFG_FILE_FIRST + fw_cfg_file_slots(s);
>> +}
>> +
>>  static int fw_cfg_select(FWCfgState *s, uint16_t key)
>>  {
>>      int arch, ret;
>>      FWCfgEntry *e;
>>  
>>      s->cur_offset = 0;
>> -    if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
>> +    if ((key & FW_CFG_ENTRY_MASK) >= fw_cfg_max_entry(s)) {
>>          s->cur_entry = FW_CFG_INVALID;
>>          ret = 0;
>>      } else {
>>          s->cur_entry = key;
>>          ret = 1;
>> @@ -608,11 +622,11 @@ static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key,
>>  {
>>      int arch = !!(key & FW_CFG_ARCH_LOCAL);
>>  
>>      key &= FW_CFG_ENTRY_MASK;
>>  
>> -    assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
>> +    assert(key < fw_cfg_max_entry(s) && len < UINT32_MAX);
>>      assert(s->entries[arch][key].data == NULL); /* avoid key conflict */
>>  
>>      s->entries[arch][key].data = data;
>>      s->entries[arch][key].len = (uint32_t)len;
>>      s->entries[arch][key].read_callback = callback;
>> @@ -626,11 +640,11 @@ static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key,
>>      void *ptr;
>>      int arch = !!(key & FW_CFG_ARCH_LOCAL);
>>  
>>      key &= FW_CFG_ENTRY_MASK;
>>  
>> -    assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
>> +    assert(key < fw_cfg_max_entry(s) && len < UINT32_MAX);
>>  
>>      /* 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;
>> @@ -775,17 +789,17 @@ void fw_cfg_add_file_callback(FWCfgState *s,  const char *filename,
>>      size_t dsize;
>>      MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
>>      int order = 0;
>>  
>>      if (!s->files) {
>> -        dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * FW_CFG_FILE_SLOTS;
>> +        dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * fw_cfg_file_slots(s);
>>          s->files = g_malloc0(dsize);
>>          fw_cfg_add_bytes(s, FW_CFG_FILE_DIR, s->files, dsize);
>>      }
>>  
>>      count = be32_to_cpu(s->files->count);
>> -    assert(count < FW_CFG_FILE_SLOTS);
>> +    assert(count < fw_cfg_file_slots(s));
>>  
>>      /* Find the insertion point. */
>>      if (mc->legacy_fw_cfg_order) {
>>          /*
>>           * Sort by order. For files with the same order, we keep them
>> @@ -855,11 +869,11 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
>>      void *ptr = NULL;
>>  
>>      assert(s->files);
>>  
>>      index = be32_to_cpu(s->files->count);
>> -    assert(index < FW_CFG_FILE_SLOTS);
>> +    assert(index < fw_cfg_file_slots(s));
>>  
>>      for (i = 0; i < index; i++) {
>>          if (strcmp(filename, s->files->f[i].name) == 0) {
>>              ptr = fw_cfg_modify_bytes_read(s, FW_CFG_FILE_FIRST + i,
>>                                             data, len);
>> @@ -926,10 +940,16 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
>>      qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase);
>>      if (!dma_requested) {
>>          qdev_prop_set_bit(dev, "dma_enabled", false);
>>      }
>>  
>> +    /* Once we expose the "file_slots" property to callers of
>> +     * fw_cfg_init_io_dma(), the following setting should become conditional on
>> +     * the input parameter being lower than the current value of the property.
>> +     */
>> +    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
>> +
>>      fw_cfg_init1(dev);
>>      s = FW_CFG(dev);
>>  
>>      if (s->dma_enabled) {
>>          /* 64 bits for the address field */
>> @@ -963,10 +983,17 @@ FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
>>      qdev_prop_set_uint32(dev, "data_width", data_width);
>>      if (!dma_requested) {
>>          qdev_prop_set_bit(dev, "dma_enabled", false);
>>      }
>>  
>> +    /* Once we expose the "file_slots" property to callers of
>> +     * fw_cfg_init_mem_wide(), the following setting should become conditional
>> +     * on the input parameter being lower than the current value of the
>> +     * property. Refer to fw_cfg_init_io_dma().
>> +     */
>> +    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
> both above cases of qdev_prop_set_uint32() could be replaced by
> compat property for fwcfg device which would clamp "file_slots"
> to old value for old machine types in a cleaner way.

The unconditional qdev_prop_set_uint32() call is already replaced, in
fw_cfg_init_io_dma(), in the next patch, and the compat properties are
added in the patch after it.

The current approach is:
- patch #2 adds the property with the raised default, but clamps it
  down in code that calls fw_cfg_init1() directly
- patch #3 propagates the clamping-down a little bit outwards, towards
  board code, but only in the IO-port mapped case,
- patch #4 adds the 2.8 compat props and raises the limit in 2.9 pc
  board code (i.e., 2.9 pc opts in)

The point is that
(a) no old machine type should see any change
(b) even for new machine types, the higher file slot count is opt-in for
    board code (i.e., it shouldn't affect callers of
    fw_cfg_init_mem_wide() and fw_cfg_init_io())

The qdev_prop_set_uint32() call that unconditionally remains in
fw_cfg_init_mem_wide() at the end of this series is for ensuring (b).

The "hw/arm/virt.c" board calls fw_cfg_init_mem_wide(), and that board
should not receive the increased fw_cfg file count even in 2.9+ (to
which the compat props would not apply).

In order to remove the unconditional property setting from
fw_cfg_init_mem_wide() too, I'd either have to modify the
fw_cfg_init_mem_wide() prototype and also the call site in
"hw/arm/virt.c", or we'd have to carry forward the compat property to
2.9 and later, indefinitely.

I'm open to reworking this code, but both goals (a) and (b) should be
considered in any alternative implementation.

Thanks!
Laszlo

> 
>> +
>>      fw_cfg_init1(dev);
>>  
>>      sbd = SYS_BUS_DEVICE(dev);
>>      sysbus_mmio_map(sbd, 0, ctl_addr);
>>      sysbus_mmio_map(sbd, 1, data_addr);
>> @@ -1012,23 +1039,56 @@ static const TypeInfo fw_cfg_info = {
>>      .abstract      = true,
>>      .instance_size = sizeof(FWCfgState),
>>      .class_init    = fw_cfg_class_init,
>>  };
>>  
>> +static void fw_cfg_file_slots_allocate(FWCfgState *s, Error **errp)
>> +{
>> +    uint16_t file_slots_max;
>> +
>> +    if (fw_cfg_file_slots(s) < FW_CFG_FILE_SLOTS_TRAD) {
>> +        error_setg(errp, "\"file_slots\" must be at least 0x%x",
>> +                   FW_CFG_FILE_SLOTS_TRAD);
>> +        return;
>> +    }
>> +
>> +    /* (UINT16_MAX & FW_CFG_ENTRY_MASK) is the highest inclusive selector value
>> +     * that we permit. The actual (exclusive) value coming from the
>> +     * configuration is (FW_CFG_FILE_FIRST + fw_cfg_file_slots(s)). */
>> +    file_slots_max = (UINT16_MAX & FW_CFG_ENTRY_MASK) - FW_CFG_FILE_FIRST + 1;
>> +    if (fw_cfg_file_slots(s) > file_slots_max) {
>> +        error_setg(errp, "\"file_slots\" must not exceed 0x%" PRIx16,
>> +                   file_slots_max);
>> +        return;
>> +    }
>> +
>> +    s->entries[0] = g_new0(FWCfgEntry, fw_cfg_max_entry(s));
>> +    s->entries[1] = g_new0(FWCfgEntry, fw_cfg_max_entry(s));
>> +    s->entry_order = g_new0(int, fw_cfg_max_entry(s));
>> +}
>>  
>>  static Property fw_cfg_io_properties[] = {
>>      DEFINE_PROP_UINT32("iobase", FWCfgIoState, iobase, -1),
>>      DEFINE_PROP_UINT32("dma_iobase", FWCfgIoState, dma_iobase, -1),
>>      DEFINE_PROP_BOOL("dma_enabled", FWCfgIoState, parent_obj.dma_enabled,
>>                       true),
>> +    DEFINE_PROP_UINT32("file_slots", FWCfgIoState, parent_obj.file_slots,
>> +                       FW_CFG_FILE_SLOTS_DFLT),
>>      DEFINE_PROP_END_OF_LIST(),
>>  };
>>  
>>  static void fw_cfg_io_realize(DeviceState *dev, Error **errp)
>>  {
>>      FWCfgIoState *s = FW_CFG_IO(dev);
>>      SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>> +    Error *local_err = NULL;
>> +
>> +    fw_cfg_file_slots_allocate(FW_CFG(s), &local_err);
>> +    if (local_err) {
>> +        error_propagate(errp, local_err);
>> +        return;
>> +    }
>>  
>>      /* when using port i/o, the 8-bit data register ALWAYS overlaps
>>       * with half of the 16-bit control register. Hence, the total size
>>       * of the i/o region used is FW_CFG_CTL_SIZE */
>>      memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops,
>> @@ -1061,18 +1121,27 @@ static const TypeInfo fw_cfg_io_info = {
>>  
>>  static Property fw_cfg_mem_properties[] = {
>>      DEFINE_PROP_UINT32("data_width", FWCfgMemState, data_width, -1),
>>      DEFINE_PROP_BOOL("dma_enabled", FWCfgMemState, parent_obj.dma_enabled,
>>                       true),
>> +    DEFINE_PROP_UINT32("file_slots", FWCfgMemState, parent_obj.file_slots,
>> +                       FW_CFG_FILE_SLOTS_DFLT),
>>      DEFINE_PROP_END_OF_LIST(),
>>  };
>>  
>>  static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
>>  {
>>      FWCfgMemState *s = FW_CFG_MEM(dev);
>>      SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>>      const MemoryRegionOps *data_ops = &fw_cfg_data_mem_ops;
>> +    Error *local_err = NULL;
>> +
>> +    fw_cfg_file_slots_allocate(FW_CFG(s), &local_err);
>> +    if (local_err) {
>> +        error_propagate(errp, local_err);
>> +        return;
>> +    }
>>  
>>      memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops,
>>                            FW_CFG(s), "fwcfg.ctl", FW_CFG_CTL_SIZE);
>>      sysbus_init_mmio(sbd, &s->ctl_iomem);
>>  
> 

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

* Re: [Qemu-devel] [PATCH v4 3/7] fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma()
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 3/7] fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma() Laszlo Ersek
@ 2016-12-06 11:49   ` Igor Mammedov
  2016-12-06 16:46     ` Laszlo Ersek
  2017-01-10 15:02   ` [Qemu-devel] " Michael S. Tsirkin
  1 sibling, 1 reply; 46+ messages in thread
From: Igor Mammedov @ 2016-12-06 11:49 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: qemu devel list, Gabriel L. Somlo, Michael S. Tsirkin,
	Gerd Hoffmann, Paolo Bonzini

On Thu,  1 Dec 2016 18:06:20 +0100
Laszlo Ersek <lersek@redhat.com> wrote:

> Accordingly, generalize the "file_slots" minimum calculation in
> fw_cfg_init_io_dma(), and move the constant FW_CFG_FILE_SLOTS_TRAD
> argument to the callers of fw_cfg_init_io_dma().
If I get idea correctly you're extending fw_cfg_init_io_dma() and
setting
 qdev_prop_set_uint32(dev, "file_slots", file_slots);
manually to keep old fw_cfg_init_io() the same without touching
xen/sun4u machines.
That way we would have 2 different ways to set defaults
per machine type/version rather then the single COMPAT property way.

How about dropping this patch and adding
 SET_MACHINE_COMPAT
to xen/sun4u machines instead and dropping fw_cfg_init_io() in
favor of fw_cfg_init_io_dma() along the way.

> 
> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  docs/specs/fw_cfg.txt     |  4 ++--
>  include/hw/nvram/fw_cfg.h |  2 +-
>  hw/i386/pc.c              |  3 ++-
>  hw/nvram/fw_cfg.c         | 13 ++++++-------
>  4 files changed, 11 insertions(+), 11 deletions(-)
> 
> diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
> index 84e2978706f5..4a6888b511f4 100644
> --- a/docs/specs/fw_cfg.txt
> +++ b/docs/specs/fw_cfg.txt
> @@ -153,12 +153,12 @@ Selector Reg.    Range Usage
>  0x4000 - 0x7fff  Generic (0x0000 - 0x3fff, RW, ignored in QEMU v2.4+)
>  0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW
>                                   through the DMA interface in QEMU v2.9+)
>  0xc000 - 0xffff  Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
>  
> -In practice, the number of allowed firmware configuration items is given
> -by the value (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS_TRAD) (see fw_cfg.h).
> +In practice, the number of allowed firmware configuration items depends on the
> +machine type.
machine type/version

>  
>  = Guest-side DMA Interface =
>  
>  If bit 1 of the feature bitmap is set, the DMA interface is present. This does
>  not replace the existing fw_cfg interface, it is an add-on. This interface
> diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
> index b980cbaebf43..e9a6b6aa968c 100644
> --- a/include/hw/nvram/fw_cfg.h
> +++ b/include/hw/nvram/fw_cfg.h
> @@ -173,11 +173,11 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
>   */
>  void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data,
>                           size_t len);
>  
>  FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
> -                                AddressSpace *dma_as);
> +                                AddressSpace *dma_as, uint32_t file_slots);
>  FWCfgState *fw_cfg_init_io(uint32_t iobase);
>  FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr);
>  FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
>                                   hwaddr data_addr, uint32_t data_width,
>                                   hwaddr dma_addr, AddressSpace *dma_as);
> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> index a9e64a88e5e7..5d929d8fc887 100644
> --- a/hw/i386/pc.c
> +++ b/hw/i386/pc.c
> @@ -741,11 +741,12 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms)
>  {
>      FWCfgState *fw_cfg;
>      uint64_t *numa_fw_cfg;
>      int i, j;
>  
> -    fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as);
> +    fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as,
> +                                FW_CFG_FILE_SLOTS_TRAD);
>      fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus);
>  
>      /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
>       *
>       * For machine types prior to 1.8, SeaBIOS needs FW_CFG_MAX_CPUS for
> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> index 2e1441c09750..c33c76ab93b1 100644
> --- a/hw/nvram/fw_cfg.c
> +++ b/hw/nvram/fw_cfg.c
> @@ -926,11 +926,11 @@ static void fw_cfg_init1(DeviceState *dev)
>      s->machine_ready.notify = fw_cfg_machine_ready;
>      qemu_add_machine_init_done_notifier(&s->machine_ready);
>  }
>  
>  FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
> -                                AddressSpace *dma_as)
> +                                AddressSpace *dma_as, uint32_t file_slots)
>  {
>      DeviceState *dev;
>      FWCfgState *s;
>      uint32_t version = FW_CFG_VERSION;
>      bool dma_requested = dma_iobase && dma_as;
> @@ -940,15 +940,14 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
>      qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase);
>      if (!dma_requested) {
>          qdev_prop_set_bit(dev, "dma_enabled", false);
>      }
>  
> -    /* Once we expose the "file_slots" property to callers of
> -     * fw_cfg_init_io_dma(), the following setting should become conditional on
> -     * the input parameter being lower than the current value of the property.
> -     */
> -    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
> +    if (file_slots < object_property_get_int(OBJECT(dev), "file_slots",
> +                                             &error_abort)) {
> +        qdev_prop_set_uint32(dev, "file_slots", file_slots);
> +    }
>  
>      fw_cfg_init1(dev);
>      s = FW_CFG(dev);
>  
>      if (s->dma_enabled) {
> @@ -964,11 +963,11 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
>      return s;
>  }
>  
>  FWCfgState *fw_cfg_init_io(uint32_t iobase)
>  {
> -    return fw_cfg_init_io_dma(iobase, 0, NULL);
> +    return fw_cfg_init_io_dma(iobase, 0, NULL, FW_CFG_FILE_SLOTS_TRAD);
>  }
>  
>  FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
>                                   hwaddr data_addr, uint32_t data_width,
>                                   hwaddr dma_addr, AddressSpace *dma_as)

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

* Re: [Qemu-devel] [PATCH v4 2/7] fw-cfg: turn FW_CFG_FILE_SLOTS into a device property
  2016-12-06 11:43     ` Laszlo Ersek
@ 2016-12-06 12:02       ` Igor Mammedov
  2016-12-06 16:22         ` Laszlo Ersek
  0 siblings, 1 reply; 46+ messages in thread
From: Igor Mammedov @ 2016-12-06 12:02 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: qemu devel list, Gabriel L. Somlo, Michael S. Tsirkin,
	Gerd Hoffmann, Paolo Bonzini

On Tue, 6 Dec 2016 12:43:06 +0100
Laszlo Ersek <lersek@redhat.com> wrote:

> On 12/06/16 11:50, Igor Mammedov wrote:
> > On Thu,  1 Dec 2016 18:06:19 +0100
> > Laszlo Ersek <lersek@redhat.com> wrote:
> >   
> >> We'd like to raise the value of FW_CFG_FILE_SLOTS. Doing it naively could
> >> lead to problems with backward migration: a more recent QEMU (running an
> >> older machine type) would allow the guest, in fw_cfg_select(), to select a
> >> high key value that is unavailable in the same machine type implemented by
> >> the older (target) QEMU. On the target host, fw_cfg_data_read() for
> >> example could dereference nonexistent entries.
> >>
> >> As first step, size the FWCfgState.entries[*] and FWCfgState.entry_order
> >> arrays dynamically. All three array sizes will be influenced by the new
> >> field (and device property) FWCfgState.file_slots.
> >>
> >> Make the following changes:
> >>
> >> - Replace the FW_CFG_FILE_SLOTS macro with FW_CFG_FILE_SLOTS_TRAD
> >>   (traditional count of fw_cfg file slots) in the header file. The value
> >>   remains 0x10.
> >>
> >> - Replace all uses of FW_CFG_FILE_SLOTS with a helper function called
> >>   fw_cfg_file_slots(), returning the new property.
> >>
> >> - Eliminate the macro FW_CFG_MAX_ENTRY, and replace all its uses with a
> >>   helper function called fw_cfg_max_entry().
> >>
> >> - In the MMIO- and IO-mapped realize functions both, allocate all three
> >>   arrays dynamically, based on the new property.
> >>
> >> - The new property defaults to 0x20; however at the moment we forcibly set
> >>   it to FW_CFG_FILE_SLOTS_TRAD on all code paths available to board code
> >>   (namely in the fw_cfg_init_io_dma() and fw_cfg_init_mem_wide() helper
> >>   functions). This is going to be customized in the following patches.
> >>
> >> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
> >> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> >> Cc: Gerd Hoffmann <kraxel@redhat.com>
> >> Cc: Igor Mammedov <imammedo@redhat.com>
> >> Cc: Paolo Bonzini <pbonzini@redhat.com>
> >> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> >> ---
> >>
> >> Notes:
> >>     I know that upstream doesn't care about backward migration, but some
> >>     downstreams might.
> >>
> >>  docs/specs/fw_cfg.txt          |  2 +-
> >>  include/hw/nvram/fw_cfg_keys.h |  3 +-
> >>  hw/nvram/fw_cfg.c              | 85 ++++++++++++++++++++++++++++++++++++++----
> >>  3 files changed, 79 insertions(+), 11 deletions(-)
> >>
> >> diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
> >> index a19e2adbe1c6..84e2978706f5 100644
> >> --- a/docs/specs/fw_cfg.txt
> >> +++ b/docs/specs/fw_cfg.txt
> >> @@ -154,11 +154,11 @@ Selector Reg.    Range Usage
> >>  0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW
> >>                                   through the DMA interface in QEMU v2.9+)
> >>  0xc000 - 0xffff  Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
> >>  
> >>  In practice, the number of allowed firmware configuration items is given
> >> -by the value of FW_CFG_MAX_ENTRY (see fw_cfg.h).
> >> +by the value (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS_TRAD) (see fw_cfg.h).
> >>  
> >>  = Guest-side DMA Interface =
> >>  
> >>  If bit 1 of the feature bitmap is set, the DMA interface is present. This does
> >>  not replace the existing fw_cfg interface, it is an add-on. This interface
> >> diff --git a/include/hw/nvram/fw_cfg_keys.h b/include/hw/nvram/fw_cfg_keys.h
> >> index 0f3e871884c0..627589793671 100644
> >> --- a/include/hw/nvram/fw_cfg_keys.h
> >> +++ b/include/hw/nvram/fw_cfg_keys.h
> >> @@ -27,12 +27,11 @@
> >>  #define FW_CFG_SETUP_SIZE       0x17
> >>  #define FW_CFG_SETUP_DATA       0x18
> >>  #define FW_CFG_FILE_DIR         0x19
> >>  
> >>  #define FW_CFG_FILE_FIRST       0x20
> >> -#define FW_CFG_FILE_SLOTS       0x10
> >> -#define FW_CFG_MAX_ENTRY        (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS)
> >> +#define FW_CFG_FILE_SLOTS_TRAD  0x10
> >>  
> >>  #define FW_CFG_WRITE_CHANNEL    0x4000
> >>  #define FW_CFG_ARCH_LOCAL       0x8000
> >>  #define FW_CFG_ENTRY_MASK       (~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL))
> >>  
> >> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> >> index e0145c11a19b..2e1441c09750 100644
> >> --- a/hw/nvram/fw_cfg.c
> >> +++ b/hw/nvram/fw_cfg.c
> >> @@ -31,10 +31,13 @@
> >>  #include "hw/sysbus.h"
> >>  #include "trace.h"
> >>  #include "qemu/error-report.h"
> >>  #include "qemu/config-file.h"
> >>  #include "qemu/cutils.h"
> >> +#include "qapi/error.h"
> >> +
> >> +#define FW_CFG_FILE_SLOTS_DFLT 0x20
> >>  
> >>  #define FW_CFG_NAME "fw_cfg"
> >>  #define FW_CFG_PATH "/machine/" FW_CFG_NAME
> >>  
> >>  #define TYPE_FW_CFG     "fw_cfg"
> >> @@ -69,12 +72,13 @@ typedef struct FWCfgEntry {
> >>  struct FWCfgState {
> >>      /*< private >*/
> >>      SysBusDevice parent_obj;
> >>      /*< public >*/
> >>  
> >> -    FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
> >> -    int entry_order[FW_CFG_MAX_ENTRY];
> >> +    uint32_t file_slots;  
> > should it be uint16_t?
> > As below you use "uint16_t file_slots_max;" and do some UINT16
> > to calculate max limit.  
> 
> I think I had a reason for making this uint32_t. I think the argument
> was that fw_cfg_max_entry() could theoretically return a value that
> doesn't fit in a uint16_t. Looking again at the patch however, I think I
> can try to make this a uint16_t for the next version.
> 
> >   
> >> +    FWCfgEntry *entries[2];
> >> +    int *entry_order;
> >>      FWCfgFiles *files;
> >>      uint16_t cur_entry;
> >>      uint32_t cur_offset;
> >>      Notifier machine_ready;
> >>  
> >> @@ -255,17 +259,27 @@ static void fw_cfg_reboot(FWCfgState *s)
> >>  static void fw_cfg_write(FWCfgState *s, uint8_t value)
> >>  {
> >>      /* nothing, write support removed in QEMU v2.4+ */
> >>  }
> >>  
> >> +static inline uint32_t fw_cfg_file_slots(const FWCfgState *s)
> >> +{
> >> +    return s->file_slots;
> >> +}  
> > so far it doesn't look like this wrapper function is necessary,
> > I'd prefer accessing field directly as it's used only internally.
> > Or do you have plans to extend wrapper later?
> > (then it would be better introduce wrapper at that time)  
> 
> Originally I used "s->file_slots" in this patch, like you say, without
> this small wrapper function,, but the resultant patch was harder to
> review. With this wrapper, you have two kinds of changes in the patch:
> 
> *     FW_CFG_MAX_ENTRY
>   --> fw_cfg_max_entry(s)  
> 
> *     FW_CFG_FILE_SLOTS
>   --> fw_cfg_file_slots(s)  
> 
> Without the wrapper, the second bullet looks
> 
> *     FW_CFG_FILE_SLOTS
>   --> s->file_slots  
> 
> and to me that made the patch harder to verify.
to me this variant look clearer as I don't have to recall that 
fw_cfg_file_slots(s) is s->file_slots  and does nothing more.
But if you prefer wrapper I'm also fine with it.

> 
> >   
> >> +
> >> +static inline uint32_t fw_cfg_max_entry(const FWCfgState *s)
> >> +{
> >> +    return FW_CFG_FILE_FIRST + fw_cfg_file_slots(s);
> >> +}
> >> +
> >>  static int fw_cfg_select(FWCfgState *s, uint16_t key)
> >>  {
> >>      int arch, ret;
> >>      FWCfgEntry *e;
> >>  
> >>      s->cur_offset = 0;
> >> -    if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
> >> +    if ((key & FW_CFG_ENTRY_MASK) >= fw_cfg_max_entry(s)) {
> >>          s->cur_entry = FW_CFG_INVALID;
> >>          ret = 0;
> >>      } else {
> >>          s->cur_entry = key;
> >>          ret = 1;
> >> @@ -608,11 +622,11 @@ static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key,
> >>  {
> >>      int arch = !!(key & FW_CFG_ARCH_LOCAL);
> >>  
> >>      key &= FW_CFG_ENTRY_MASK;
> >>  
> >> -    assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
> >> +    assert(key < fw_cfg_max_entry(s) && len < UINT32_MAX);
> >>      assert(s->entries[arch][key].data == NULL); /* avoid key conflict */
> >>  
> >>      s->entries[arch][key].data = data;
> >>      s->entries[arch][key].len = (uint32_t)len;
> >>      s->entries[arch][key].read_callback = callback;
> >> @@ -626,11 +640,11 @@ static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key,
> >>      void *ptr;
> >>      int arch = !!(key & FW_CFG_ARCH_LOCAL);
> >>  
> >>      key &= FW_CFG_ENTRY_MASK;
> >>  
> >> -    assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
> >> +    assert(key < fw_cfg_max_entry(s) && len < UINT32_MAX);
> >>  
> >>      /* 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;
> >> @@ -775,17 +789,17 @@ void fw_cfg_add_file_callback(FWCfgState *s,  const char *filename,
> >>      size_t dsize;
> >>      MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
> >>      int order = 0;
> >>  
> >>      if (!s->files) {
> >> -        dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * FW_CFG_FILE_SLOTS;
> >> +        dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * fw_cfg_file_slots(s);
> >>          s->files = g_malloc0(dsize);
> >>          fw_cfg_add_bytes(s, FW_CFG_FILE_DIR, s->files, dsize);
> >>      }
> >>  
> >>      count = be32_to_cpu(s->files->count);
> >> -    assert(count < FW_CFG_FILE_SLOTS);
> >> +    assert(count < fw_cfg_file_slots(s));
> >>  
> >>      /* Find the insertion point. */
> >>      if (mc->legacy_fw_cfg_order) {
> >>          /*
> >>           * Sort by order. For files with the same order, we keep them
> >> @@ -855,11 +869,11 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
> >>      void *ptr = NULL;
> >>  
> >>      assert(s->files);
> >>  
> >>      index = be32_to_cpu(s->files->count);
> >> -    assert(index < FW_CFG_FILE_SLOTS);
> >> +    assert(index < fw_cfg_file_slots(s));
> >>  
> >>      for (i = 0; i < index; i++) {
> >>          if (strcmp(filename, s->files->f[i].name) == 0) {
> >>              ptr = fw_cfg_modify_bytes_read(s, FW_CFG_FILE_FIRST + i,
> >>                                             data, len);
> >> @@ -926,10 +940,16 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
> >>      qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase);
> >>      if (!dma_requested) {
> >>          qdev_prop_set_bit(dev, "dma_enabled", false);
> >>      }
> >>  
> >> +    /* Once we expose the "file_slots" property to callers of
> >> +     * fw_cfg_init_io_dma(), the following setting should become conditional on
> >> +     * the input parameter being lower than the current value of the property.
> >> +     */
> >> +    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
> >> +
> >>      fw_cfg_init1(dev);
> >>      s = FW_CFG(dev);
> >>  
> >>      if (s->dma_enabled) {
> >>          /* 64 bits for the address field */
> >> @@ -963,10 +983,17 @@ FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
> >>      qdev_prop_set_uint32(dev, "data_width", data_width);
> >>      if (!dma_requested) {
> >>          qdev_prop_set_bit(dev, "dma_enabled", false);
> >>      }
> >>  
> >> +    /* Once we expose the "file_slots" property to callers of
> >> +     * fw_cfg_init_mem_wide(), the following setting should become conditional
> >> +     * on the input parameter being lower than the current value of the
> >> +     * property. Refer to fw_cfg_init_io_dma().
> >> +     */
> >> +    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);  
> > both above cases of qdev_prop_set_uint32() could be replaced by
> > compat property for fwcfg device which would clamp "file_slots"
> > to old value for old machine types in a cleaner way.  
> 
> The unconditional qdev_prop_set_uint32() call is already replaced, in
> fw_cfg_init_io_dma(), in the next patch, and the compat properties are
> added in the patch after it.
> 
> The current approach is:
> - patch #2 adds the property with the raised default, but clamps it
>   down in code that calls fw_cfg_init1() directly
> - patch #3 propagates the clamping-down a little bit outwards, towards
>   board code, but only in the IO-port mapped case,
> - patch #4 adds the 2.8 compat props and raises the limit in 2.9 pc
>   board code (i.e., 2.9 pc opts in)
> 
> The point is that
> (a) no old machine type should see any change
> (b) even for new machine types, the higher file slot count is opt-in for
>     board code (i.e., it shouldn't affect callers of
>     fw_cfg_init_mem_wide() and fw_cfg_init_io())
I'm not sure that we need (b) (i.e. optin for new machine versions)
Maybe all new machine types should use new default and we should
clamp it down for all old machine types the same way (compat prop).
It would be uniform and less confusing possibly making series simpler.

> 
> The qdev_prop_set_uint32() call that unconditionally remains in
> fw_cfg_init_mem_wide() at the end of this series is for ensuring (b).
> 
> The "hw/arm/virt.c" board calls fw_cfg_init_mem_wide(), and that board
> should not receive the increased fw_cfg file count even in 2.9+ (to
> which the compat props would not apply).
> 
> In order to remove the unconditional property setting from
> fw_cfg_init_mem_wide() too, I'd either have to modify the
> fw_cfg_init_mem_wide() prototype and also the call site in
> "hw/arm/virt.c", or we'd have to carry forward the compat property to
> 2.9 and later, indefinitely.
> 
> I'm open to reworking this code, but both goals (a) and (b) should be
> considered in any alternative implementation.
> 
> Thanks!
> Laszlo
> 
> >   
> >> +
> >>      fw_cfg_init1(dev);
> >>  
> >>      sbd = SYS_BUS_DEVICE(dev);
> >>      sysbus_mmio_map(sbd, 0, ctl_addr);
> >>      sysbus_mmio_map(sbd, 1, data_addr);
> >> @@ -1012,23 +1039,56 @@ static const TypeInfo fw_cfg_info = {
> >>      .abstract      = true,
> >>      .instance_size = sizeof(FWCfgState),
> >>      .class_init    = fw_cfg_class_init,
> >>  };
> >>  
> >> +static void fw_cfg_file_slots_allocate(FWCfgState *s, Error **errp)
> >> +{
> >> +    uint16_t file_slots_max;
> >> +
> >> +    if (fw_cfg_file_slots(s) < FW_CFG_FILE_SLOTS_TRAD) {
> >> +        error_setg(errp, "\"file_slots\" must be at least 0x%x",
> >> +                   FW_CFG_FILE_SLOTS_TRAD);
> >> +        return;
> >> +    }
> >> +
> >> +    /* (UINT16_MAX & FW_CFG_ENTRY_MASK) is the highest inclusive selector value
> >> +     * that we permit. The actual (exclusive) value coming from the
> >> +     * configuration is (FW_CFG_FILE_FIRST + fw_cfg_file_slots(s)). */
> >> +    file_slots_max = (UINT16_MAX & FW_CFG_ENTRY_MASK) - FW_CFG_FILE_FIRST + 1;
> >> +    if (fw_cfg_file_slots(s) > file_slots_max) {
> >> +        error_setg(errp, "\"file_slots\" must not exceed 0x%" PRIx16,
> >> +                   file_slots_max);
> >> +        return;
> >> +    }
> >> +
> >> +    s->entries[0] = g_new0(FWCfgEntry, fw_cfg_max_entry(s));
> >> +    s->entries[1] = g_new0(FWCfgEntry, fw_cfg_max_entry(s));
> >> +    s->entry_order = g_new0(int, fw_cfg_max_entry(s));
> >> +}
> >>  
> >>  static Property fw_cfg_io_properties[] = {
> >>      DEFINE_PROP_UINT32("iobase", FWCfgIoState, iobase, -1),
> >>      DEFINE_PROP_UINT32("dma_iobase", FWCfgIoState, dma_iobase, -1),
> >>      DEFINE_PROP_BOOL("dma_enabled", FWCfgIoState, parent_obj.dma_enabled,
> >>                       true),
> >> +    DEFINE_PROP_UINT32("file_slots", FWCfgIoState, parent_obj.file_slots,
> >> +                       FW_CFG_FILE_SLOTS_DFLT),
> >>      DEFINE_PROP_END_OF_LIST(),
> >>  };
> >>  
> >>  static void fw_cfg_io_realize(DeviceState *dev, Error **errp)
> >>  {
> >>      FWCfgIoState *s = FW_CFG_IO(dev);
> >>      SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> >> +    Error *local_err = NULL;
> >> +
> >> +    fw_cfg_file_slots_allocate(FW_CFG(s), &local_err);
> >> +    if (local_err) {
> >> +        error_propagate(errp, local_err);
> >> +        return;
> >> +    }
> >>  
> >>      /* when using port i/o, the 8-bit data register ALWAYS overlaps
> >>       * with half of the 16-bit control register. Hence, the total size
> >>       * of the i/o region used is FW_CFG_CTL_SIZE */
> >>      memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops,
> >> @@ -1061,18 +1121,27 @@ static const TypeInfo fw_cfg_io_info = {
> >>  
> >>  static Property fw_cfg_mem_properties[] = {
> >>      DEFINE_PROP_UINT32("data_width", FWCfgMemState, data_width, -1),
> >>      DEFINE_PROP_BOOL("dma_enabled", FWCfgMemState, parent_obj.dma_enabled,
> >>                       true),
> >> +    DEFINE_PROP_UINT32("file_slots", FWCfgMemState, parent_obj.file_slots,
> >> +                       FW_CFG_FILE_SLOTS_DFLT),
> >>      DEFINE_PROP_END_OF_LIST(),
> >>  };
> >>  
> >>  static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
> >>  {
> >>      FWCfgMemState *s = FW_CFG_MEM(dev);
> >>      SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> >>      const MemoryRegionOps *data_ops = &fw_cfg_data_mem_ops;
> >> +    Error *local_err = NULL;
> >> +
> >> +    fw_cfg_file_slots_allocate(FW_CFG(s), &local_err);
> >> +    if (local_err) {
> >> +        error_propagate(errp, local_err);
> >> +        return;
> >> +    }
> >>  
> >>      memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops,
> >>                            FW_CFG(s), "fwcfg.ctl", FW_CFG_CTL_SIZE);
> >>      sysbus_init_mmio(sbd, &s->ctl_iomem);
> >>    
> >   
> 

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

* Re: [Qemu-devel] [PATCH v4 2/7] fw-cfg: turn FW_CFG_FILE_SLOTS into a device property
  2016-12-06 12:02       ` Igor Mammedov
@ 2016-12-06 16:22         ` Laszlo Ersek
  0 siblings, 0 replies; 46+ messages in thread
From: Laszlo Ersek @ 2016-12-06 16:22 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: qemu devel list, Gabriel L. Somlo, Michael S. Tsirkin,
	Gerd Hoffmann, Paolo Bonzini

On 12/06/16 13:02, Igor Mammedov wrote:
> On Tue, 6 Dec 2016 12:43:06 +0100
> Laszlo Ersek <lersek@redhat.com> wrote:
> 
>> On 12/06/16 11:50, Igor Mammedov wrote:
>>> On Thu,  1 Dec 2016 18:06:19 +0100
>>> Laszlo Ersek <lersek@redhat.com> wrote:
>>>   
>>>> We'd like to raise the value of FW_CFG_FILE_SLOTS. Doing it naively could
>>>> lead to problems with backward migration: a more recent QEMU (running an
>>>> older machine type) would allow the guest, in fw_cfg_select(), to select a
>>>> high key value that is unavailable in the same machine type implemented by
>>>> the older (target) QEMU. On the target host, fw_cfg_data_read() for
>>>> example could dereference nonexistent entries.
>>>>
>>>> As first step, size the FWCfgState.entries[*] and FWCfgState.entry_order
>>>> arrays dynamically. All three array sizes will be influenced by the new
>>>> field (and device property) FWCfgState.file_slots.
>>>>
>>>> Make the following changes:
>>>>
>>>> - Replace the FW_CFG_FILE_SLOTS macro with FW_CFG_FILE_SLOTS_TRAD
>>>>   (traditional count of fw_cfg file slots) in the header file. The value
>>>>   remains 0x10.
>>>>
>>>> - Replace all uses of FW_CFG_FILE_SLOTS with a helper function called
>>>>   fw_cfg_file_slots(), returning the new property.
>>>>
>>>> - Eliminate the macro FW_CFG_MAX_ENTRY, and replace all its uses with a
>>>>   helper function called fw_cfg_max_entry().
>>>>
>>>> - In the MMIO- and IO-mapped realize functions both, allocate all three
>>>>   arrays dynamically, based on the new property.
>>>>
>>>> - The new property defaults to 0x20; however at the moment we forcibly set
>>>>   it to FW_CFG_FILE_SLOTS_TRAD on all code paths available to board code
>>>>   (namely in the fw_cfg_init_io_dma() and fw_cfg_init_mem_wide() helper
>>>>   functions). This is going to be customized in the following patches.
>>>>
>>>> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
>>>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>>> Cc: Igor Mammedov <imammedo@redhat.com>
>>>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>>>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>>>> ---
>>>>
>>>> Notes:
>>>>     I know that upstream doesn't care about backward migration, but some
>>>>     downstreams might.
>>>>
>>>>  docs/specs/fw_cfg.txt          |  2 +-
>>>>  include/hw/nvram/fw_cfg_keys.h |  3 +-
>>>>  hw/nvram/fw_cfg.c              | 85 ++++++++++++++++++++++++++++++++++++++----
>>>>  3 files changed, 79 insertions(+), 11 deletions(-)
>>>>
>>>> diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
>>>> index a19e2adbe1c6..84e2978706f5 100644
>>>> --- a/docs/specs/fw_cfg.txt
>>>> +++ b/docs/specs/fw_cfg.txt
>>>> @@ -154,11 +154,11 @@ Selector Reg.    Range Usage
>>>>  0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW
>>>>                                   through the DMA interface in QEMU v2.9+)
>>>>  0xc000 - 0xffff  Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
>>>>  
>>>>  In practice, the number of allowed firmware configuration items is given
>>>> -by the value of FW_CFG_MAX_ENTRY (see fw_cfg.h).
>>>> +by the value (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS_TRAD) (see fw_cfg.h).
>>>>  
>>>>  = Guest-side DMA Interface =
>>>>  
>>>>  If bit 1 of the feature bitmap is set, the DMA interface is present. This does
>>>>  not replace the existing fw_cfg interface, it is an add-on. This interface
>>>> diff --git a/include/hw/nvram/fw_cfg_keys.h b/include/hw/nvram/fw_cfg_keys.h
>>>> index 0f3e871884c0..627589793671 100644
>>>> --- a/include/hw/nvram/fw_cfg_keys.h
>>>> +++ b/include/hw/nvram/fw_cfg_keys.h
>>>> @@ -27,12 +27,11 @@
>>>>  #define FW_CFG_SETUP_SIZE       0x17
>>>>  #define FW_CFG_SETUP_DATA       0x18
>>>>  #define FW_CFG_FILE_DIR         0x19
>>>>  
>>>>  #define FW_CFG_FILE_FIRST       0x20
>>>> -#define FW_CFG_FILE_SLOTS       0x10
>>>> -#define FW_CFG_MAX_ENTRY        (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS)
>>>> +#define FW_CFG_FILE_SLOTS_TRAD  0x10
>>>>  
>>>>  #define FW_CFG_WRITE_CHANNEL    0x4000
>>>>  #define FW_CFG_ARCH_LOCAL       0x8000
>>>>  #define FW_CFG_ENTRY_MASK       (~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL))
>>>>  
>>>> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
>>>> index e0145c11a19b..2e1441c09750 100644
>>>> --- a/hw/nvram/fw_cfg.c
>>>> +++ b/hw/nvram/fw_cfg.c
>>>> @@ -31,10 +31,13 @@
>>>>  #include "hw/sysbus.h"
>>>>  #include "trace.h"
>>>>  #include "qemu/error-report.h"
>>>>  #include "qemu/config-file.h"
>>>>  #include "qemu/cutils.h"
>>>> +#include "qapi/error.h"
>>>> +
>>>> +#define FW_CFG_FILE_SLOTS_DFLT 0x20
>>>>  
>>>>  #define FW_CFG_NAME "fw_cfg"
>>>>  #define FW_CFG_PATH "/machine/" FW_CFG_NAME
>>>>  
>>>>  #define TYPE_FW_CFG     "fw_cfg"
>>>> @@ -69,12 +72,13 @@ typedef struct FWCfgEntry {
>>>>  struct FWCfgState {
>>>>      /*< private >*/
>>>>      SysBusDevice parent_obj;
>>>>      /*< public >*/
>>>>  
>>>> -    FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
>>>> -    int entry_order[FW_CFG_MAX_ENTRY];
>>>> +    uint32_t file_slots;  
>>> should it be uint16_t?
>>> As below you use "uint16_t file_slots_max;" and do some UINT16
>>> to calculate max limit.  
>>
>> I think I had a reason for making this uint32_t. I think the argument
>> was that fw_cfg_max_entry() could theoretically return a value that
>> doesn't fit in a uint16_t. Looking again at the patch however, I think I
>> can try to make this a uint16_t for the next version.
>>
>>>   
>>>> +    FWCfgEntry *entries[2];
>>>> +    int *entry_order;
>>>>      FWCfgFiles *files;
>>>>      uint16_t cur_entry;
>>>>      uint32_t cur_offset;
>>>>      Notifier machine_ready;
>>>>  
>>>> @@ -255,17 +259,27 @@ static void fw_cfg_reboot(FWCfgState *s)
>>>>  static void fw_cfg_write(FWCfgState *s, uint8_t value)
>>>>  {
>>>>      /* nothing, write support removed in QEMU v2.4+ */
>>>>  }
>>>>  
>>>> +static inline uint32_t fw_cfg_file_slots(const FWCfgState *s)
>>>> +{
>>>> +    return s->file_slots;
>>>> +}  
>>> so far it doesn't look like this wrapper function is necessary,
>>> I'd prefer accessing field directly as it's used only internally.
>>> Or do you have plans to extend wrapper later?
>>> (then it would be better introduce wrapper at that time)  
>>
>> Originally I used "s->file_slots" in this patch, like you say, without
>> this small wrapper function,, but the resultant patch was harder to
>> review. With this wrapper, you have two kinds of changes in the patch:
>>
>> *     FW_CFG_MAX_ENTRY
>>   --> fw_cfg_max_entry(s)  
>>
>> *     FW_CFG_FILE_SLOTS
>>   --> fw_cfg_file_slots(s)  
>>
>> Without the wrapper, the second bullet looks
>>
>> *     FW_CFG_FILE_SLOTS
>>   --> s->file_slots  
>>
>> and to me that made the patch harder to verify.
> to me this variant look clearer as I don't have to recall that 
> fw_cfg_file_slots(s) is s->file_slots  and does nothing more.
> But if you prefer wrapper I'm also fine with it.
> 
>>
>>>   
>>>> +
>>>> +static inline uint32_t fw_cfg_max_entry(const FWCfgState *s)
>>>> +{
>>>> +    return FW_CFG_FILE_FIRST + fw_cfg_file_slots(s);
>>>> +}
>>>> +
>>>>  static int fw_cfg_select(FWCfgState *s, uint16_t key)
>>>>  {
>>>>      int arch, ret;
>>>>      FWCfgEntry *e;
>>>>  
>>>>      s->cur_offset = 0;
>>>> -    if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
>>>> +    if ((key & FW_CFG_ENTRY_MASK) >= fw_cfg_max_entry(s)) {
>>>>          s->cur_entry = FW_CFG_INVALID;
>>>>          ret = 0;
>>>>      } else {
>>>>          s->cur_entry = key;
>>>>          ret = 1;
>>>> @@ -608,11 +622,11 @@ static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key,
>>>>  {
>>>>      int arch = !!(key & FW_CFG_ARCH_LOCAL);
>>>>  
>>>>      key &= FW_CFG_ENTRY_MASK;
>>>>  
>>>> -    assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
>>>> +    assert(key < fw_cfg_max_entry(s) && len < UINT32_MAX);
>>>>      assert(s->entries[arch][key].data == NULL); /* avoid key conflict */
>>>>  
>>>>      s->entries[arch][key].data = data;
>>>>      s->entries[arch][key].len = (uint32_t)len;
>>>>      s->entries[arch][key].read_callback = callback;
>>>> @@ -626,11 +640,11 @@ static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key,
>>>>      void *ptr;
>>>>      int arch = !!(key & FW_CFG_ARCH_LOCAL);
>>>>  
>>>>      key &= FW_CFG_ENTRY_MASK;
>>>>  
>>>> -    assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
>>>> +    assert(key < fw_cfg_max_entry(s) && len < UINT32_MAX);
>>>>  
>>>>      /* 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;
>>>> @@ -775,17 +789,17 @@ void fw_cfg_add_file_callback(FWCfgState *s,  const char *filename,
>>>>      size_t dsize;
>>>>      MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
>>>>      int order = 0;
>>>>  
>>>>      if (!s->files) {
>>>> -        dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * FW_CFG_FILE_SLOTS;
>>>> +        dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * fw_cfg_file_slots(s);
>>>>          s->files = g_malloc0(dsize);
>>>>          fw_cfg_add_bytes(s, FW_CFG_FILE_DIR, s->files, dsize);
>>>>      }
>>>>  
>>>>      count = be32_to_cpu(s->files->count);
>>>> -    assert(count < FW_CFG_FILE_SLOTS);
>>>> +    assert(count < fw_cfg_file_slots(s));
>>>>  
>>>>      /* Find the insertion point. */
>>>>      if (mc->legacy_fw_cfg_order) {
>>>>          /*
>>>>           * Sort by order. For files with the same order, we keep them
>>>> @@ -855,11 +869,11 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
>>>>      void *ptr = NULL;
>>>>  
>>>>      assert(s->files);
>>>>  
>>>>      index = be32_to_cpu(s->files->count);
>>>> -    assert(index < FW_CFG_FILE_SLOTS);
>>>> +    assert(index < fw_cfg_file_slots(s));
>>>>  
>>>>      for (i = 0; i < index; i++) {
>>>>          if (strcmp(filename, s->files->f[i].name) == 0) {
>>>>              ptr = fw_cfg_modify_bytes_read(s, FW_CFG_FILE_FIRST + i,
>>>>                                             data, len);
>>>> @@ -926,10 +940,16 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
>>>>      qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase);
>>>>      if (!dma_requested) {
>>>>          qdev_prop_set_bit(dev, "dma_enabled", false);
>>>>      }
>>>>  
>>>> +    /* Once we expose the "file_slots" property to callers of
>>>> +     * fw_cfg_init_io_dma(), the following setting should become conditional on
>>>> +     * the input parameter being lower than the current value of the property.
>>>> +     */
>>>> +    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
>>>> +
>>>>      fw_cfg_init1(dev);
>>>>      s = FW_CFG(dev);
>>>>  
>>>>      if (s->dma_enabled) {
>>>>          /* 64 bits for the address field */
>>>> @@ -963,10 +983,17 @@ FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
>>>>      qdev_prop_set_uint32(dev, "data_width", data_width);
>>>>      if (!dma_requested) {
>>>>          qdev_prop_set_bit(dev, "dma_enabled", false);
>>>>      }
>>>>  
>>>> +    /* Once we expose the "file_slots" property to callers of
>>>> +     * fw_cfg_init_mem_wide(), the following setting should become conditional
>>>> +     * on the input parameter being lower than the current value of the
>>>> +     * property. Refer to fw_cfg_init_io_dma().
>>>> +     */
>>>> +    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);  
>>> both above cases of qdev_prop_set_uint32() could be replaced by
>>> compat property for fwcfg device which would clamp "file_slots"
>>> to old value for old machine types in a cleaner way.  
>>
>> The unconditional qdev_prop_set_uint32() call is already replaced, in
>> fw_cfg_init_io_dma(), in the next patch, and the compat properties are
>> added in the patch after it.
>>
>> The current approach is:
>> - patch #2 adds the property with the raised default, but clamps it
>>   down in code that calls fw_cfg_init1() directly
>> - patch #3 propagates the clamping-down a little bit outwards, towards
>>   board code, but only in the IO-port mapped case,
>> - patch #4 adds the 2.8 compat props and raises the limit in 2.9 pc
>>   board code (i.e., 2.9 pc opts in)
>>
>> The point is that
>> (a) no old machine type should see any change
>> (b) even for new machine types, the higher file slot count is opt-in for
>>     board code (i.e., it shouldn't affect callers of
>>     fw_cfg_init_mem_wide() and fw_cfg_init_io())
> I'm not sure that we need (b) (i.e. optin for new machine versions)
> Maybe all new machine types should use new default and we should
> clamp it down for all old machine types the same way (compat prop).
> It would be uniform and less confusing possibly making series simpler.

Works for me if (b) is a non-goal. I'll update the patches.

Thanks!
Laszlo

> 
>>
>> The qdev_prop_set_uint32() call that unconditionally remains in
>> fw_cfg_init_mem_wide() at the end of this series is for ensuring (b).
>>
>> The "hw/arm/virt.c" board calls fw_cfg_init_mem_wide(), and that board
>> should not receive the increased fw_cfg file count even in 2.9+ (to
>> which the compat props would not apply).
>>
>> In order to remove the unconditional property setting from
>> fw_cfg_init_mem_wide() too, I'd either have to modify the
>> fw_cfg_init_mem_wide() prototype and also the call site in
>> "hw/arm/virt.c", or we'd have to carry forward the compat property to
>> 2.9 and later, indefinitely.
>>
>> I'm open to reworking this code, but both goals (a) and (b) should be
>> considered in any alternative implementation.
>>
>> Thanks!
>> Laszlo
>>
>>>   
>>>> +
>>>>      fw_cfg_init1(dev);
>>>>  
>>>>      sbd = SYS_BUS_DEVICE(dev);
>>>>      sysbus_mmio_map(sbd, 0, ctl_addr);
>>>>      sysbus_mmio_map(sbd, 1, data_addr);
>>>> @@ -1012,23 +1039,56 @@ static const TypeInfo fw_cfg_info = {
>>>>      .abstract      = true,
>>>>      .instance_size = sizeof(FWCfgState),
>>>>      .class_init    = fw_cfg_class_init,
>>>>  };
>>>>  
>>>> +static void fw_cfg_file_slots_allocate(FWCfgState *s, Error **errp)
>>>> +{
>>>> +    uint16_t file_slots_max;
>>>> +
>>>> +    if (fw_cfg_file_slots(s) < FW_CFG_FILE_SLOTS_TRAD) {
>>>> +        error_setg(errp, "\"file_slots\" must be at least 0x%x",
>>>> +                   FW_CFG_FILE_SLOTS_TRAD);
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    /* (UINT16_MAX & FW_CFG_ENTRY_MASK) is the highest inclusive selector value
>>>> +     * that we permit. The actual (exclusive) value coming from the
>>>> +     * configuration is (FW_CFG_FILE_FIRST + fw_cfg_file_slots(s)). */
>>>> +    file_slots_max = (UINT16_MAX & FW_CFG_ENTRY_MASK) - FW_CFG_FILE_FIRST + 1;
>>>> +    if (fw_cfg_file_slots(s) > file_slots_max) {
>>>> +        error_setg(errp, "\"file_slots\" must not exceed 0x%" PRIx16,
>>>> +                   file_slots_max);
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    s->entries[0] = g_new0(FWCfgEntry, fw_cfg_max_entry(s));
>>>> +    s->entries[1] = g_new0(FWCfgEntry, fw_cfg_max_entry(s));
>>>> +    s->entry_order = g_new0(int, fw_cfg_max_entry(s));
>>>> +}
>>>>  
>>>>  static Property fw_cfg_io_properties[] = {
>>>>      DEFINE_PROP_UINT32("iobase", FWCfgIoState, iobase, -1),
>>>>      DEFINE_PROP_UINT32("dma_iobase", FWCfgIoState, dma_iobase, -1),
>>>>      DEFINE_PROP_BOOL("dma_enabled", FWCfgIoState, parent_obj.dma_enabled,
>>>>                       true),
>>>> +    DEFINE_PROP_UINT32("file_slots", FWCfgIoState, parent_obj.file_slots,
>>>> +                       FW_CFG_FILE_SLOTS_DFLT),
>>>>      DEFINE_PROP_END_OF_LIST(),
>>>>  };
>>>>  
>>>>  static void fw_cfg_io_realize(DeviceState *dev, Error **errp)
>>>>  {
>>>>      FWCfgIoState *s = FW_CFG_IO(dev);
>>>>      SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>>>> +    Error *local_err = NULL;
>>>> +
>>>> +    fw_cfg_file_slots_allocate(FW_CFG(s), &local_err);
>>>> +    if (local_err) {
>>>> +        error_propagate(errp, local_err);
>>>> +        return;
>>>> +    }
>>>>  
>>>>      /* when using port i/o, the 8-bit data register ALWAYS overlaps
>>>>       * with half of the 16-bit control register. Hence, the total size
>>>>       * of the i/o region used is FW_CFG_CTL_SIZE */
>>>>      memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops,
>>>> @@ -1061,18 +1121,27 @@ static const TypeInfo fw_cfg_io_info = {
>>>>  
>>>>  static Property fw_cfg_mem_properties[] = {
>>>>      DEFINE_PROP_UINT32("data_width", FWCfgMemState, data_width, -1),
>>>>      DEFINE_PROP_BOOL("dma_enabled", FWCfgMemState, parent_obj.dma_enabled,
>>>>                       true),
>>>> +    DEFINE_PROP_UINT32("file_slots", FWCfgMemState, parent_obj.file_slots,
>>>> +                       FW_CFG_FILE_SLOTS_DFLT),
>>>>      DEFINE_PROP_END_OF_LIST(),
>>>>  };
>>>>  
>>>>  static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
>>>>  {
>>>>      FWCfgMemState *s = FW_CFG_MEM(dev);
>>>>      SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>>>>      const MemoryRegionOps *data_ops = &fw_cfg_data_mem_ops;
>>>> +    Error *local_err = NULL;
>>>> +
>>>> +    fw_cfg_file_slots_allocate(FW_CFG(s), &local_err);
>>>> +    if (local_err) {
>>>> +        error_propagate(errp, local_err);
>>>> +        return;
>>>> +    }
>>>>  
>>>>      memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops,
>>>>                            FW_CFG(s), "fwcfg.ctl", FW_CFG_CTL_SIZE);
>>>>      sysbus_init_mmio(sbd, &s->ctl_iomem);
>>>>    
>>>   
>>
> 

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

* Re: [Qemu-devel] [PATCH v4 3/7] fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma()
  2016-12-06 11:49   ` Igor Mammedov
@ 2016-12-06 16:46     ` Laszlo Ersek
  2016-12-06 16:52       ` Laszlo Ersek
  2016-12-06 18:09         ` Igor Mammedov
  0 siblings, 2 replies; 46+ messages in thread
From: Laszlo Ersek @ 2016-12-06 16:46 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: qemu devel list, Gabriel L. Somlo, Michael S. Tsirkin,
	Gerd Hoffmann, Paolo Bonzini

On 12/06/16 12:49, Igor Mammedov wrote:
> On Thu,  1 Dec 2016 18:06:20 +0100
> Laszlo Ersek <lersek@redhat.com> wrote:
> 
>> Accordingly, generalize the "file_slots" minimum calculation in
>> fw_cfg_init_io_dma(), and move the constant FW_CFG_FILE_SLOTS_TRAD
>> argument to the callers of fw_cfg_init_io_dma().
> If I get idea correctly you're extending fw_cfg_init_io_dma() and
> setting
>  qdev_prop_set_uint32(dev, "file_slots", file_slots);
> manually to keep old fw_cfg_init_io() the same without touching
> xen/sun4u machines.

First, to my knowledge, Xen does not use fw_cfg. The following call
chains depend on (!xen_enabled()):

pc_init1() | pc_q35_init()
  if (!xen_enabled()):
    pc_memory_init()
      bochs_bios_init()
        fw_cfg_init_io_dma()

Second, I wanted to keep the fw_cfg_init_io() call sites un-touched. In
this patch, the fw_cfg_init_io() function passes an additional /
internal-only parameter to fw_cfg_init_io_dma(), and the unconditional
qdev_prop_set_uint32() call in fw_cfg_init_io_dma() is replaced with a
conditional one (so that the property can only be lowered, not raised,
by board code).

> That way we would have 2 different ways to set defaults
> per machine type/version rather then the single COMPAT property way.
> 
> How about dropping this patch and adding
>  SET_MACHINE_COMPAT
> to xen/sun4u machines instead and dropping fw_cfg_init_io() in
> favor of fw_cfg_init_io_dma() along the way.

For the conditional qdev_prop_set_uint32() call, added in this patch, I
used commit e6915b5f3a87 ("fw_cfg: unbreak migration compatibility for
2.4 and earlier machines") as model. According to that model, I couldn't
drop this patch completely, because the new feature -- i.e., DMA in that
patch, and higher fw_cfg file slots in this patch -- depends on both
machine versions and board opt-in.

However, if we agree (according to your feedback on patch v4 2/7) that
we will silently bump the fw_cfg file count for all new machine
versions, without requiring (or permitting) board opt-in / opt-out, then
I agree your above suggestion is consistent with that.

I think I don't have to drop fw_cfg_init_io() actually. But, with the
board opt-in going away, I can drop both the additional "file_slots"
parameter in fw_cfg_init_io_dma(), and the qdev_prop_set_uint32() call
in it (even the unconditional one).

In fact I like this simplicity more, I just wanted to be extra cautious
in the first version of the series that turned file_slots into a property.

... Actually, are sun4u machines versioned? Hm... "hw/sparc64/sun4u.c"
doesn't seem to define versioned machine types. Doesn't that imply that
migration is *completely* unsupported for sun4u? Because, if that's the
case, then I wouldn't even have to add SET_MACHINE_COMPAT().

Thanks!
Laszlo

> 
>>
>> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>> Cc: Igor Mammedov <imammedo@redhat.com>
>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>> ---
>>  docs/specs/fw_cfg.txt     |  4 ++--
>>  include/hw/nvram/fw_cfg.h |  2 +-
>>  hw/i386/pc.c              |  3 ++-
>>  hw/nvram/fw_cfg.c         | 13 ++++++-------
>>  4 files changed, 11 insertions(+), 11 deletions(-)
>>
>> diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
>> index 84e2978706f5..4a6888b511f4 100644
>> --- a/docs/specs/fw_cfg.txt
>> +++ b/docs/specs/fw_cfg.txt
>> @@ -153,12 +153,12 @@ Selector Reg.    Range Usage
>>  0x4000 - 0x7fff  Generic (0x0000 - 0x3fff, RW, ignored in QEMU v2.4+)
>>  0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW
>>                                   through the DMA interface in QEMU v2.9+)
>>  0xc000 - 0xffff  Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
>>  
>> -In practice, the number of allowed firmware configuration items is given
>> -by the value (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS_TRAD) (see fw_cfg.h).
>> +In practice, the number of allowed firmware configuration items depends on the
>> +machine type.
> machine type/version
> 
>>  
>>  = Guest-side DMA Interface =
>>  
>>  If bit 1 of the feature bitmap is set, the DMA interface is present. This does
>>  not replace the existing fw_cfg interface, it is an add-on. This interface
>> diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
>> index b980cbaebf43..e9a6b6aa968c 100644
>> --- a/include/hw/nvram/fw_cfg.h
>> +++ b/include/hw/nvram/fw_cfg.h
>> @@ -173,11 +173,11 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
>>   */
>>  void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data,
>>                           size_t len);
>>  
>>  FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
>> -                                AddressSpace *dma_as);
>> +                                AddressSpace *dma_as, uint32_t file_slots);
>>  FWCfgState *fw_cfg_init_io(uint32_t iobase);
>>  FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr);
>>  FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
>>                                   hwaddr data_addr, uint32_t data_width,
>>                                   hwaddr dma_addr, AddressSpace *dma_as);
>> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
>> index a9e64a88e5e7..5d929d8fc887 100644
>> --- a/hw/i386/pc.c
>> +++ b/hw/i386/pc.c
>> @@ -741,11 +741,12 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms)
>>  {
>>      FWCfgState *fw_cfg;
>>      uint64_t *numa_fw_cfg;
>>      int i, j;
>>  
>> -    fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as);
>> +    fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as,
>> +                                FW_CFG_FILE_SLOTS_TRAD);
>>      fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus);
>>  
>>      /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
>>       *
>>       * For machine types prior to 1.8, SeaBIOS needs FW_CFG_MAX_CPUS for
>> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
>> index 2e1441c09750..c33c76ab93b1 100644
>> --- a/hw/nvram/fw_cfg.c
>> +++ b/hw/nvram/fw_cfg.c
>> @@ -926,11 +926,11 @@ static void fw_cfg_init1(DeviceState *dev)
>>      s->machine_ready.notify = fw_cfg_machine_ready;
>>      qemu_add_machine_init_done_notifier(&s->machine_ready);
>>  }
>>  
>>  FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
>> -                                AddressSpace *dma_as)
>> +                                AddressSpace *dma_as, uint32_t file_slots)
>>  {
>>      DeviceState *dev;
>>      FWCfgState *s;
>>      uint32_t version = FW_CFG_VERSION;
>>      bool dma_requested = dma_iobase && dma_as;
>> @@ -940,15 +940,14 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
>>      qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase);
>>      if (!dma_requested) {
>>          qdev_prop_set_bit(dev, "dma_enabled", false);
>>      }
>>  
>> -    /* Once we expose the "file_slots" property to callers of
>> -     * fw_cfg_init_io_dma(), the following setting should become conditional on
>> -     * the input parameter being lower than the current value of the property.
>> -     */
>> -    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
>> +    if (file_slots < object_property_get_int(OBJECT(dev), "file_slots",
>> +                                             &error_abort)) {
>> +        qdev_prop_set_uint32(dev, "file_slots", file_slots);
>> +    }
>>  
>>      fw_cfg_init1(dev);
>>      s = FW_CFG(dev);
>>  
>>      if (s->dma_enabled) {
>> @@ -964,11 +963,11 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
>>      return s;
>>  }
>>  
>>  FWCfgState *fw_cfg_init_io(uint32_t iobase)
>>  {
>> -    return fw_cfg_init_io_dma(iobase, 0, NULL);
>> +    return fw_cfg_init_io_dma(iobase, 0, NULL, FW_CFG_FILE_SLOTS_TRAD);
>>  }
>>  
>>  FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
>>                                   hwaddr data_addr, uint32_t data_width,
>>                                   hwaddr dma_addr, AddressSpace *dma_as)
> 

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

* Re: [Qemu-devel] [PATCH v4 3/7] fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma()
  2016-12-06 16:46     ` Laszlo Ersek
@ 2016-12-06 16:52       ` Laszlo Ersek
  2016-12-06 23:21         ` David Gibson
  2016-12-06 18:09         ` Igor Mammedov
  1 sibling, 1 reply; 46+ messages in thread
From: Laszlo Ersek @ 2016-12-06 16:52 UTC (permalink / raw)
  To: Mark Cave-Ayland, Artyom Tarasenko, Alexander Graf, David Gibson
  Cc: Igor Mammedov, qemu devel list, Gabriel L. Somlo,
	Michael S. Tsirkin, Gerd Hoffmann, Paolo Bonzini

Mark, Artyom, do the sun4u machines support any kind of migration, given
that they are not versioned?

Alex, David, do the mac_newworld / mac_oldworld machines support
migration, given that they are not versioned?

Thanks
Laszlo

On 12/06/16 17:46, Laszlo Ersek wrote:
> On 12/06/16 12:49, Igor Mammedov wrote:
>> On Thu,  1 Dec 2016 18:06:20 +0100
>> Laszlo Ersek <lersek@redhat.com> wrote:
>>
>>> Accordingly, generalize the "file_slots" minimum calculation in
>>> fw_cfg_init_io_dma(), and move the constant FW_CFG_FILE_SLOTS_TRAD
>>> argument to the callers of fw_cfg_init_io_dma().
>> If I get idea correctly you're extending fw_cfg_init_io_dma() and
>> setting
>>  qdev_prop_set_uint32(dev, "file_slots", file_slots);
>> manually to keep old fw_cfg_init_io() the same without touching
>> xen/sun4u machines.
> 
> First, to my knowledge, Xen does not use fw_cfg. The following call
> chains depend on (!xen_enabled()):
> 
> pc_init1() | pc_q35_init()
>   if (!xen_enabled()):
>     pc_memory_init()
>       bochs_bios_init()
>         fw_cfg_init_io_dma()
> 
> Second, I wanted to keep the fw_cfg_init_io() call sites un-touched. In
> this patch, the fw_cfg_init_io() function passes an additional /
> internal-only parameter to fw_cfg_init_io_dma(), and the unconditional
> qdev_prop_set_uint32() call in fw_cfg_init_io_dma() is replaced with a
> conditional one (so that the property can only be lowered, not raised,
> by board code).
> 
>> That way we would have 2 different ways to set defaults
>> per machine type/version rather then the single COMPAT property way.
>>
>> How about dropping this patch and adding
>>  SET_MACHINE_COMPAT
>> to xen/sun4u machines instead and dropping fw_cfg_init_io() in
>> favor of fw_cfg_init_io_dma() along the way.
> 
> For the conditional qdev_prop_set_uint32() call, added in this patch, I
> used commit e6915b5f3a87 ("fw_cfg: unbreak migration compatibility for
> 2.4 and earlier machines") as model. According to that model, I couldn't
> drop this patch completely, because the new feature -- i.e., DMA in that
> patch, and higher fw_cfg file slots in this patch -- depends on both
> machine versions and board opt-in.
> 
> However, if we agree (according to your feedback on patch v4 2/7) that
> we will silently bump the fw_cfg file count for all new machine
> versions, without requiring (or permitting) board opt-in / opt-out, then
> I agree your above suggestion is consistent with that.
> 
> I think I don't have to drop fw_cfg_init_io() actually. But, with the
> board opt-in going away, I can drop both the additional "file_slots"
> parameter in fw_cfg_init_io_dma(), and the qdev_prop_set_uint32() call
> in it (even the unconditional one).
> 
> In fact I like this simplicity more, I just wanted to be extra cautious
> in the first version of the series that turned file_slots into a property.
> 
> ... Actually, are sun4u machines versioned? Hm... "hw/sparc64/sun4u.c"
> doesn't seem to define versioned machine types. Doesn't that imply that
> migration is *completely* unsupported for sun4u? Because, if that's the
> case, then I wouldn't even have to add SET_MACHINE_COMPAT().
> 
> Thanks!
> Laszlo
> 
>>
>>>
>>> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
>>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>> Cc: Igor Mammedov <imammedo@redhat.com>
>>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>>> ---
>>>  docs/specs/fw_cfg.txt     |  4 ++--
>>>  include/hw/nvram/fw_cfg.h |  2 +-
>>>  hw/i386/pc.c              |  3 ++-
>>>  hw/nvram/fw_cfg.c         | 13 ++++++-------
>>>  4 files changed, 11 insertions(+), 11 deletions(-)
>>>
>>> diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
>>> index 84e2978706f5..4a6888b511f4 100644
>>> --- a/docs/specs/fw_cfg.txt
>>> +++ b/docs/specs/fw_cfg.txt
>>> @@ -153,12 +153,12 @@ Selector Reg.    Range Usage
>>>  0x4000 - 0x7fff  Generic (0x0000 - 0x3fff, RW, ignored in QEMU v2.4+)
>>>  0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW
>>>                                   through the DMA interface in QEMU v2.9+)
>>>  0xc000 - 0xffff  Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
>>>  
>>> -In practice, the number of allowed firmware configuration items is given
>>> -by the value (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS_TRAD) (see fw_cfg.h).
>>> +In practice, the number of allowed firmware configuration items depends on the
>>> +machine type.
>> machine type/version
>>
>>>  
>>>  = Guest-side DMA Interface =
>>>  
>>>  If bit 1 of the feature bitmap is set, the DMA interface is present. This does
>>>  not replace the existing fw_cfg interface, it is an add-on. This interface
>>> diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
>>> index b980cbaebf43..e9a6b6aa968c 100644
>>> --- a/include/hw/nvram/fw_cfg.h
>>> +++ b/include/hw/nvram/fw_cfg.h
>>> @@ -173,11 +173,11 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
>>>   */
>>>  void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data,
>>>                           size_t len);
>>>  
>>>  FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
>>> -                                AddressSpace *dma_as);
>>> +                                AddressSpace *dma_as, uint32_t file_slots);
>>>  FWCfgState *fw_cfg_init_io(uint32_t iobase);
>>>  FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr);
>>>  FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
>>>                                   hwaddr data_addr, uint32_t data_width,
>>>                                   hwaddr dma_addr, AddressSpace *dma_as);
>>> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
>>> index a9e64a88e5e7..5d929d8fc887 100644
>>> --- a/hw/i386/pc.c
>>> +++ b/hw/i386/pc.c
>>> @@ -741,11 +741,12 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms)
>>>  {
>>>      FWCfgState *fw_cfg;
>>>      uint64_t *numa_fw_cfg;
>>>      int i, j;
>>>  
>>> -    fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as);
>>> +    fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as,
>>> +                                FW_CFG_FILE_SLOTS_TRAD);
>>>      fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus);
>>>  
>>>      /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
>>>       *
>>>       * For machine types prior to 1.8, SeaBIOS needs FW_CFG_MAX_CPUS for
>>> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
>>> index 2e1441c09750..c33c76ab93b1 100644
>>> --- a/hw/nvram/fw_cfg.c
>>> +++ b/hw/nvram/fw_cfg.c
>>> @@ -926,11 +926,11 @@ static void fw_cfg_init1(DeviceState *dev)
>>>      s->machine_ready.notify = fw_cfg_machine_ready;
>>>      qemu_add_machine_init_done_notifier(&s->machine_ready);
>>>  }
>>>  
>>>  FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
>>> -                                AddressSpace *dma_as)
>>> +                                AddressSpace *dma_as, uint32_t file_slots)
>>>  {
>>>      DeviceState *dev;
>>>      FWCfgState *s;
>>>      uint32_t version = FW_CFG_VERSION;
>>>      bool dma_requested = dma_iobase && dma_as;
>>> @@ -940,15 +940,14 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
>>>      qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase);
>>>      if (!dma_requested) {
>>>          qdev_prop_set_bit(dev, "dma_enabled", false);
>>>      }
>>>  
>>> -    /* Once we expose the "file_slots" property to callers of
>>> -     * fw_cfg_init_io_dma(), the following setting should become conditional on
>>> -     * the input parameter being lower than the current value of the property.
>>> -     */
>>> -    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
>>> +    if (file_slots < object_property_get_int(OBJECT(dev), "file_slots",
>>> +                                             &error_abort)) {
>>> +        qdev_prop_set_uint32(dev, "file_slots", file_slots);
>>> +    }
>>>  
>>>      fw_cfg_init1(dev);
>>>      s = FW_CFG(dev);
>>>  
>>>      if (s->dma_enabled) {
>>> @@ -964,11 +963,11 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
>>>      return s;
>>>  }
>>>  
>>>  FWCfgState *fw_cfg_init_io(uint32_t iobase)
>>>  {
>>> -    return fw_cfg_init_io_dma(iobase, 0, NULL);
>>> +    return fw_cfg_init_io_dma(iobase, 0, NULL, FW_CFG_FILE_SLOTS_TRAD);
>>>  }
>>>  
>>>  FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
>>>                                   hwaddr data_addr, uint32_t data_width,
>>>                                   hwaddr dma_addr, AddressSpace *dma_as)
>>
> 

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

* Re: [Qemu-devel] [PATCH v4 3/7] fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma()
  2016-12-06 16:46     ` Laszlo Ersek
@ 2016-12-06 18:09         ` Igor Mammedov
  2016-12-06 18:09         ` Igor Mammedov
  1 sibling, 0 replies; 46+ messages in thread
From: Igor Mammedov @ 2016-12-06 18:09 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: Paolo Bonzini, Gabriel L. Somlo, Gerd Hoffmann, qemu devel list,
	Michael S. Tsirkin, sstabellini, anthony.perard, xen-devel

On Tue, 6 Dec 2016 17:46:51 +0100
Laszlo Ersek <lersek@redhat.com> wrote:

> On 12/06/16 12:49, Igor Mammedov wrote:
> > On Thu,  1 Dec 2016 18:06:20 +0100
> > Laszlo Ersek <lersek@redhat.com> wrote:
> > 
> >> Accordingly, generalize the "file_slots" minimum calculation in
> >> fw_cfg_init_io_dma(), and move the constant FW_CFG_FILE_SLOTS_TRAD
> >> argument to the callers of fw_cfg_init_io_dma().
> > If I get idea correctly you're extending fw_cfg_init_io_dma() and
> > setting
> >  qdev_prop_set_uint32(dev, "file_slots", file_slots);
> > manually to keep old fw_cfg_init_io() the same without touching
> > xen/sun4u machines.
> 
> First, to my knowledge, Xen does not use fw_cfg. The following call
> chains depend on (!xen_enabled()):
maybe not, it's just grep gave me:
  xen_load_linux() -> fw_cfg_init_io()
maybe it's dead code now

> 
> pc_init1() | pc_q35_init()
>   if (!xen_enabled()):
>     pc_memory_init()
>       bochs_bios_init()
>         fw_cfg_init_io_dma()
> 
> Second, I wanted to keep the fw_cfg_init_io() call sites un-touched. In
> this patch, the fw_cfg_init_io() function passes an additional /
> internal-only parameter to fw_cfg_init_io_dma(), and the unconditional
> qdev_prop_set_uint32() call in fw_cfg_init_io_dma() is replaced with a
> conditional one (so that the property can only be lowered, not raised,
> by board code).
looking one way, it's easier to just fixup current usage
by using more duct tape, however is one considers where default
is originated from it would become 3 place to consider witch is not nice.

PS:
Keeping defaults in well known places like DEFINE_PROP_FOO and compat props
would also help in the view of introspection that Eduardo works on
trying to provide interface that shows default property values for
devices/machines.


> > That way we would have 2 different ways to set defaults
> > per machine type/version rather then the single COMPAT property way.
> > 
> > How about dropping this patch and adding
> >  SET_MACHINE_COMPAT
> > to xen/sun4u machines instead and dropping fw_cfg_init_io() in
> > favor of fw_cfg_init_io_dma() along the way.
> 
> For the conditional qdev_prop_set_uint32() call, added in this patch, I
> used commit e6915b5f3a87 ("fw_cfg: unbreak migration compatibility for
> 2.4 and earlier machines") as model. According to that model, I couldn't
> drop this patch completely, because the new feature -- i.e., DMA in that
> patch, and higher fw_cfg file slots in this patch -- depends on both
> machine versions and board opt-in.
maybe it's been written this way not to touch fw_cfg_init_io(), however
just using compat props could have worked out as well if fw_cfg_init_io()
call sites were update to use fw_cfg_init_io_dma() and board specific 'false'
defaults could be set machine specific compat props
(not really conventional way but it should work) keeping defaults as data.


> However, if we agree (according to your feedback on patch v4 2/7) that
> we will silently bump the fw_cfg file count for all new machine
> versions, without requiring (or permitting) board opt-in / opt-out, then
> I agree your above suggestion is consistent with that.
Question is if opt-in is needed?
My take on it that it's not for default value in this case as new machine
types would be able to migrate to the same or newer QEMU version.
and backward migration kept in check by machine/version specific compat
props. So it simplifies code a little and boards that don't wish new default
have a way to opt-out using compat prop mechanism.


> I think I don't have to drop fw_cfg_init_io() actually. But, with the
> board opt-in going away, I can drop both the additional "file_slots"
> parameter in fw_cfg_init_io_dma(), and the qdev_prop_set_uint32() call
> in it (even the unconditional one).
sure if it keeps patches simpler.
It's just seemed logical to cleanup useless fw_cfg_init_io() while at it,
making reader to do one less hop while reading code.

> In fact I like this simplicity more, I just wanted to be extra cautious
> in the first version of the series that turned file_slots into a property.
> 
> ... Actually, are sun4u machines versioned? Hm... "hw/sparc64/sun4u.c"
> doesn't seem to define versioned machine types. Doesn't that imply that
> migration is *completely* unsupported for sun4u? Because, if that's the
> case, then I wouldn't even have to add SET_MACHINE_COMPAT().
If sun4u/xen are not migratable/versioned we probably shouldn't even bother.

But we still can use SET_MACHINE_COMPAT() to set board specific defaults where necessary.

PS:
 CCing xen folks.

> 
> Thanks!
> Laszlo
> 
> > 
> >>
> >> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
> >> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> >> Cc: Gerd Hoffmann <kraxel@redhat.com>
> >> Cc: Igor Mammedov <imammedo@redhat.com>
> >> Cc: Paolo Bonzini <pbonzini@redhat.com>
> >> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> >> ---
> >>  docs/specs/fw_cfg.txt     |  4 ++--
> >>  include/hw/nvram/fw_cfg.h |  2 +-
> >>  hw/i386/pc.c              |  3 ++-
> >>  hw/nvram/fw_cfg.c         | 13 ++++++-------
> >>  4 files changed, 11 insertions(+), 11 deletions(-)
> >>
> >> diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
> >> index 84e2978706f5..4a6888b511f4 100644
> >> --- a/docs/specs/fw_cfg.txt
> >> +++ b/docs/specs/fw_cfg.txt
> >> @@ -153,12 +153,12 @@ Selector Reg.    Range Usage
> >>  0x4000 - 0x7fff  Generic (0x0000 - 0x3fff, RW, ignored in QEMU v2.4+)
> >>  0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW
> >>                                   through the DMA interface in QEMU v2.9+)
> >>  0xc000 - 0xffff  Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
> >>  
> >> -In practice, the number of allowed firmware configuration items is given
> >> -by the value (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS_TRAD) (see fw_cfg.h).
> >> +In practice, the number of allowed firmware configuration items depends on the
> >> +machine type.
> > machine type/version
> > 
> >>  
> >>  = Guest-side DMA Interface =
> >>  
> >>  If bit 1 of the feature bitmap is set, the DMA interface is present. This does
> >>  not replace the existing fw_cfg interface, it is an add-on. This interface
> >> diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
> >> index b980cbaebf43..e9a6b6aa968c 100644
> >> --- a/include/hw/nvram/fw_cfg.h
> >> +++ b/include/hw/nvram/fw_cfg.h
> >> @@ -173,11 +173,11 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
> >>   */
> >>  void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data,
> >>                           size_t len);
> >>  
> >>  FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
> >> -                                AddressSpace *dma_as);
> >> +                                AddressSpace *dma_as, uint32_t file_slots);
> >>  FWCfgState *fw_cfg_init_io(uint32_t iobase);
> >>  FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr);
> >>  FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
> >>                                   hwaddr data_addr, uint32_t data_width,
> >>                                   hwaddr dma_addr, AddressSpace *dma_as);
> >> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> >> index a9e64a88e5e7..5d929d8fc887 100644
> >> --- a/hw/i386/pc.c
> >> +++ b/hw/i386/pc.c
> >> @@ -741,11 +741,12 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms)
> >>  {
> >>      FWCfgState *fw_cfg;
> >>      uint64_t *numa_fw_cfg;
> >>      int i, j;
> >>  
> >> -    fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as);
> >> +    fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as,
> >> +                                FW_CFG_FILE_SLOTS_TRAD);
> >>      fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus);
> >>  
> >>      /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
> >>       *
> >>       * For machine types prior to 1.8, SeaBIOS needs FW_CFG_MAX_CPUS for
> >> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> >> index 2e1441c09750..c33c76ab93b1 100644
> >> --- a/hw/nvram/fw_cfg.c
> >> +++ b/hw/nvram/fw_cfg.c
> >> @@ -926,11 +926,11 @@ static void fw_cfg_init1(DeviceState *dev)
> >>      s->machine_ready.notify = fw_cfg_machine_ready;
> >>      qemu_add_machine_init_done_notifier(&s->machine_ready);
> >>  }
> >>  
> >>  FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
> >> -                                AddressSpace *dma_as)
> >> +                                AddressSpace *dma_as, uint32_t file_slots)
> >>  {
> >>      DeviceState *dev;
> >>      FWCfgState *s;
> >>      uint32_t version = FW_CFG_VERSION;
> >>      bool dma_requested = dma_iobase && dma_as;
> >> @@ -940,15 +940,14 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
> >>      qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase);
> >>      if (!dma_requested) {
> >>          qdev_prop_set_bit(dev, "dma_enabled", false);
> >>      }
> >>  
> >> -    /* Once we expose the "file_slots" property to callers of
> >> -     * fw_cfg_init_io_dma(), the following setting should become conditional on
> >> -     * the input parameter being lower than the current value of the property.
> >> -     */
> >> -    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
> >> +    if (file_slots < object_property_get_int(OBJECT(dev), "file_slots",
> >> +                                             &error_abort)) {
> >> +        qdev_prop_set_uint32(dev, "file_slots", file_slots);
> >> +    }
> >>  
> >>      fw_cfg_init1(dev);
> >>      s = FW_CFG(dev);
> >>  
> >>      if (s->dma_enabled) {
> >> @@ -964,11 +963,11 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
> >>      return s;
> >>  }
> >>  
> >>  FWCfgState *fw_cfg_init_io(uint32_t iobase)
> >>  {
> >> -    return fw_cfg_init_io_dma(iobase, 0, NULL);
> >> +    return fw_cfg_init_io_dma(iobase, 0, NULL, FW_CFG_FILE_SLOTS_TRAD);
> >>  }
> >>  
> >>  FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
> >>                                   hwaddr data_addr, uint32_t data_width,
> >>                                   hwaddr dma_addr, AddressSpace *dma_as)
> > 
> 
> 

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

* Re: [PATCH v4 3/7] fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma()
@ 2016-12-06 18:09         ` Igor Mammedov
  0 siblings, 0 replies; 46+ messages in thread
From: Igor Mammedov @ 2016-12-06 18:09 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: sstabellini, Michael S. Tsirkin, Gabriel L. Somlo,
	qemu devel list, xen-devel, Gerd Hoffmann, anthony.perard,
	Paolo Bonzini

On Tue, 6 Dec 2016 17:46:51 +0100
Laszlo Ersek <lersek@redhat.com> wrote:

> On 12/06/16 12:49, Igor Mammedov wrote:
> > On Thu,  1 Dec 2016 18:06:20 +0100
> > Laszlo Ersek <lersek@redhat.com> wrote:
> > 
> >> Accordingly, generalize the "file_slots" minimum calculation in
> >> fw_cfg_init_io_dma(), and move the constant FW_CFG_FILE_SLOTS_TRAD
> >> argument to the callers of fw_cfg_init_io_dma().
> > If I get idea correctly you're extending fw_cfg_init_io_dma() and
> > setting
> >  qdev_prop_set_uint32(dev, "file_slots", file_slots);
> > manually to keep old fw_cfg_init_io() the same without touching
> > xen/sun4u machines.
> 
> First, to my knowledge, Xen does not use fw_cfg. The following call
> chains depend on (!xen_enabled()):
maybe not, it's just grep gave me:
  xen_load_linux() -> fw_cfg_init_io()
maybe it's dead code now

> 
> pc_init1() | pc_q35_init()
>   if (!xen_enabled()):
>     pc_memory_init()
>       bochs_bios_init()
>         fw_cfg_init_io_dma()
> 
> Second, I wanted to keep the fw_cfg_init_io() call sites un-touched. In
> this patch, the fw_cfg_init_io() function passes an additional /
> internal-only parameter to fw_cfg_init_io_dma(), and the unconditional
> qdev_prop_set_uint32() call in fw_cfg_init_io_dma() is replaced with a
> conditional one (so that the property can only be lowered, not raised,
> by board code).
looking one way, it's easier to just fixup current usage
by using more duct tape, however is one considers where default
is originated from it would become 3 place to consider witch is not nice.

PS:
Keeping defaults in well known places like DEFINE_PROP_FOO and compat props
would also help in the view of introspection that Eduardo works on
trying to provide interface that shows default property values for
devices/machines.


> > That way we would have 2 different ways to set defaults
> > per machine type/version rather then the single COMPAT property way.
> > 
> > How about dropping this patch and adding
> >  SET_MACHINE_COMPAT
> > to xen/sun4u machines instead and dropping fw_cfg_init_io() in
> > favor of fw_cfg_init_io_dma() along the way.
> 
> For the conditional qdev_prop_set_uint32() call, added in this patch, I
> used commit e6915b5f3a87 ("fw_cfg: unbreak migration compatibility for
> 2.4 and earlier machines") as model. According to that model, I couldn't
> drop this patch completely, because the new feature -- i.e., DMA in that
> patch, and higher fw_cfg file slots in this patch -- depends on both
> machine versions and board opt-in.
maybe it's been written this way not to touch fw_cfg_init_io(), however
just using compat props could have worked out as well if fw_cfg_init_io()
call sites were update to use fw_cfg_init_io_dma() and board specific 'false'
defaults could be set machine specific compat props
(not really conventional way but it should work) keeping defaults as data.


> However, if we agree (according to your feedback on patch v4 2/7) that
> we will silently bump the fw_cfg file count for all new machine
> versions, without requiring (or permitting) board opt-in / opt-out, then
> I agree your above suggestion is consistent with that.
Question is if opt-in is needed?
My take on it that it's not for default value in this case as new machine
types would be able to migrate to the same or newer QEMU version.
and backward migration kept in check by machine/version specific compat
props. So it simplifies code a little and boards that don't wish new default
have a way to opt-out using compat prop mechanism.


> I think I don't have to drop fw_cfg_init_io() actually. But, with the
> board opt-in going away, I can drop both the additional "file_slots"
> parameter in fw_cfg_init_io_dma(), and the qdev_prop_set_uint32() call
> in it (even the unconditional one).
sure if it keeps patches simpler.
It's just seemed logical to cleanup useless fw_cfg_init_io() while at it,
making reader to do one less hop while reading code.

> In fact I like this simplicity more, I just wanted to be extra cautious
> in the first version of the series that turned file_slots into a property.
> 
> ... Actually, are sun4u machines versioned? Hm... "hw/sparc64/sun4u.c"
> doesn't seem to define versioned machine types. Doesn't that imply that
> migration is *completely* unsupported for sun4u? Because, if that's the
> case, then I wouldn't even have to add SET_MACHINE_COMPAT().
If sun4u/xen are not migratable/versioned we probably shouldn't even bother.

But we still can use SET_MACHINE_COMPAT() to set board specific defaults where necessary.

PS:
 CCing xen folks.

> 
> Thanks!
> Laszlo
> 
> > 
> >>
> >> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
> >> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> >> Cc: Gerd Hoffmann <kraxel@redhat.com>
> >> Cc: Igor Mammedov <imammedo@redhat.com>
> >> Cc: Paolo Bonzini <pbonzini@redhat.com>
> >> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> >> ---
> >>  docs/specs/fw_cfg.txt     |  4 ++--
> >>  include/hw/nvram/fw_cfg.h |  2 +-
> >>  hw/i386/pc.c              |  3 ++-
> >>  hw/nvram/fw_cfg.c         | 13 ++++++-------
> >>  4 files changed, 11 insertions(+), 11 deletions(-)
> >>
> >> diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
> >> index 84e2978706f5..4a6888b511f4 100644
> >> --- a/docs/specs/fw_cfg.txt
> >> +++ b/docs/specs/fw_cfg.txt
> >> @@ -153,12 +153,12 @@ Selector Reg.    Range Usage
> >>  0x4000 - 0x7fff  Generic (0x0000 - 0x3fff, RW, ignored in QEMU v2.4+)
> >>  0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW
> >>                                   through the DMA interface in QEMU v2.9+)
> >>  0xc000 - 0xffff  Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
> >>  
> >> -In practice, the number of allowed firmware configuration items is given
> >> -by the value (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS_TRAD) (see fw_cfg.h).
> >> +In practice, the number of allowed firmware configuration items depends on the
> >> +machine type.
> > machine type/version
> > 
> >>  
> >>  = Guest-side DMA Interface =
> >>  
> >>  If bit 1 of the feature bitmap is set, the DMA interface is present. This does
> >>  not replace the existing fw_cfg interface, it is an add-on. This interface
> >> diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
> >> index b980cbaebf43..e9a6b6aa968c 100644
> >> --- a/include/hw/nvram/fw_cfg.h
> >> +++ b/include/hw/nvram/fw_cfg.h
> >> @@ -173,11 +173,11 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
> >>   */
> >>  void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data,
> >>                           size_t len);
> >>  
> >>  FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
> >> -                                AddressSpace *dma_as);
> >> +                                AddressSpace *dma_as, uint32_t file_slots);
> >>  FWCfgState *fw_cfg_init_io(uint32_t iobase);
> >>  FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr);
> >>  FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
> >>                                   hwaddr data_addr, uint32_t data_width,
> >>                                   hwaddr dma_addr, AddressSpace *dma_as);
> >> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> >> index a9e64a88e5e7..5d929d8fc887 100644
> >> --- a/hw/i386/pc.c
> >> +++ b/hw/i386/pc.c
> >> @@ -741,11 +741,12 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms)
> >>  {
> >>      FWCfgState *fw_cfg;
> >>      uint64_t *numa_fw_cfg;
> >>      int i, j;
> >>  
> >> -    fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as);
> >> +    fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as,
> >> +                                FW_CFG_FILE_SLOTS_TRAD);
> >>      fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus);
> >>  
> >>      /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
> >>       *
> >>       * For machine types prior to 1.8, SeaBIOS needs FW_CFG_MAX_CPUS for
> >> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> >> index 2e1441c09750..c33c76ab93b1 100644
> >> --- a/hw/nvram/fw_cfg.c
> >> +++ b/hw/nvram/fw_cfg.c
> >> @@ -926,11 +926,11 @@ static void fw_cfg_init1(DeviceState *dev)
> >>      s->machine_ready.notify = fw_cfg_machine_ready;
> >>      qemu_add_machine_init_done_notifier(&s->machine_ready);
> >>  }
> >>  
> >>  FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
> >> -                                AddressSpace *dma_as)
> >> +                                AddressSpace *dma_as, uint32_t file_slots)
> >>  {
> >>      DeviceState *dev;
> >>      FWCfgState *s;
> >>      uint32_t version = FW_CFG_VERSION;
> >>      bool dma_requested = dma_iobase && dma_as;
> >> @@ -940,15 +940,14 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
> >>      qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase);
> >>      if (!dma_requested) {
> >>          qdev_prop_set_bit(dev, "dma_enabled", false);
> >>      }
> >>  
> >> -    /* Once we expose the "file_slots" property to callers of
> >> -     * fw_cfg_init_io_dma(), the following setting should become conditional on
> >> -     * the input parameter being lower than the current value of the property.
> >> -     */
> >> -    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
> >> +    if (file_slots < object_property_get_int(OBJECT(dev), "file_slots",
> >> +                                             &error_abort)) {
> >> +        qdev_prop_set_uint32(dev, "file_slots", file_slots);
> >> +    }
> >>  
> >>      fw_cfg_init1(dev);
> >>      s = FW_CFG(dev);
> >>  
> >>      if (s->dma_enabled) {
> >> @@ -964,11 +963,11 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
> >>      return s;
> >>  }
> >>  
> >>  FWCfgState *fw_cfg_init_io(uint32_t iobase)
> >>  {
> >> -    return fw_cfg_init_io_dma(iobase, 0, NULL);
> >> +    return fw_cfg_init_io_dma(iobase, 0, NULL, FW_CFG_FILE_SLOTS_TRAD);
> >>  }
> >>  
> >>  FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
> >>                                   hwaddr data_addr, uint32_t data_width,
> >>                                   hwaddr dma_addr, AddressSpace *dma_as)
> > 
> 
> 

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

* Re: [Qemu-devel] [PATCH v4 3/7] fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma()
  2016-12-06 18:09         ` Igor Mammedov
@ 2016-12-06 19:29           ` Stefano Stabellini
  -1 siblings, 0 replies; 46+ messages in thread
From: Stefano Stabellini @ 2016-12-06 19:29 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Laszlo Ersek, Paolo Bonzini, Gabriel L. Somlo, Gerd Hoffmann,
	qemu devel list, Michael S. Tsirkin, sstabellini, anthony.perard,
	xen-devel

On Tue, 6 Dec 2016, Igor Mammedov wrote:
> > First, to my knowledge, Xen does not use fw_cfg. The following call
> > chains depend on (!xen_enabled()):
> maybe not, it's just grep gave me:
>   xen_load_linux() -> fw_cfg_init_io()
> maybe it's dead code now

[...]

> > 
> > pc_init1() | pc_q35_init()
> >   if (!xen_enabled()):
> >     pc_memory_init()
> >       bochs_bios_init()
> >         fw_cfg_init_io_dma()


We have a couple of idiosyncrasies with Xen support in QEMU; this is one
of them.

Xen doesn't use fw_cfg, because hvmloader [1][2] runs in guest context
before SeaBios setting things up, including ACPI tables. So usually we
don't need it. However direct kernel boot is done via xen_load_linux
which is based on fw_cfg. So when kernel= and ramdisk= are specified in
a Xen HVM config file (which is not common), they are passed to QEMU as
-kernel and -initrd, then QEMU ends up using fw_cfg to load the kernel
in the guest. That's the only use case we have for it at the moment.

Direct kernel boot with Xen HVM guests is not tested by OSSTest (Xen
Project CI loop), as a consequence it broke in the past without anybody
noticing.

[1]: http://xenbits.xenproject.org/gitweb/?p=xen.git;a=tree;f=tools/firmware/hvmloader;h=069e29fa3820364c69c95798d56ef097148fddd2;hb=HEAD
[2]: https://wiki.xenproject.org/wiki/Hvmloader

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

* Re: [PATCH v4 3/7] fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma()
@ 2016-12-06 19:29           ` Stefano Stabellini
  0 siblings, 0 replies; 46+ messages in thread
From: Stefano Stabellini @ 2016-12-06 19:29 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: sstabellini, Michael S. Tsirkin, Gabriel L. Somlo,
	qemu devel list, xen-devel, Gerd Hoffmann, anthony.perard,
	Paolo Bonzini, Laszlo Ersek

On Tue, 6 Dec 2016, Igor Mammedov wrote:
> > First, to my knowledge, Xen does not use fw_cfg. The following call
> > chains depend on (!xen_enabled()):
> maybe not, it's just grep gave me:
>   xen_load_linux() -> fw_cfg_init_io()
> maybe it's dead code now

[...]

> > 
> > pc_init1() | pc_q35_init()
> >   if (!xen_enabled()):
> >     pc_memory_init()
> >       bochs_bios_init()
> >         fw_cfg_init_io_dma()


We have a couple of idiosyncrasies with Xen support in QEMU; this is one
of them.

Xen doesn't use fw_cfg, because hvmloader [1][2] runs in guest context
before SeaBios setting things up, including ACPI tables. So usually we
don't need it. However direct kernel boot is done via xen_load_linux
which is based on fw_cfg. So when kernel= and ramdisk= are specified in
a Xen HVM config file (which is not common), they are passed to QEMU as
-kernel and -initrd, then QEMU ends up using fw_cfg to load the kernel
in the guest. That's the only use case we have for it at the moment.

Direct kernel boot with Xen HVM guests is not tested by OSSTest (Xen
Project CI loop), as a consequence it broke in the past without anybody
noticing.

[1]: http://xenbits.xenproject.org/gitweb/?p=xen.git;a=tree;f=tools/firmware/hvmloader;h=069e29fa3820364c69c95798d56ef097148fddd2;hb=HEAD
[2]: https://wiki.xenproject.org/wiki/Hvmloader

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

* Re: [Qemu-devel] [PATCH v4 3/7] fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma()
  2016-12-06 16:52       ` Laszlo Ersek
@ 2016-12-06 23:21         ` David Gibson
  0 siblings, 0 replies; 46+ messages in thread
From: David Gibson @ 2016-12-06 23:21 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: Mark Cave-Ayland, Artyom Tarasenko, Alexander Graf,
	Igor Mammedov, qemu devel list, Gabriel L. Somlo,
	Michael S. Tsirkin, Gerd Hoffmann, Paolo Bonzini

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

On Tue, Dec 06, 2016 at 05:52:26PM +0100, Laszlo Ersek wrote:
> Mark, Artyom, do the sun4u machines support any kind of migration, given
> that they are not versioned?
> 
> Alex, David, do the mac_newworld / mac_oldworld machines support
> migration, given that they are not versioned?

I don't believe so.  There might be some bits and pieces of migration
code, but I don't think it's ever been in a state where it was really
expected to work.

> 
> Thanks
> Laszlo
> 
> On 12/06/16 17:46, Laszlo Ersek wrote:
> > On 12/06/16 12:49, Igor Mammedov wrote:
> >> On Thu,  1 Dec 2016 18:06:20 +0100
> >> Laszlo Ersek <lersek@redhat.com> wrote:
> >>
> >>> Accordingly, generalize the "file_slots" minimum calculation in
> >>> fw_cfg_init_io_dma(), and move the constant FW_CFG_FILE_SLOTS_TRAD
> >>> argument to the callers of fw_cfg_init_io_dma().
> >> If I get idea correctly you're extending fw_cfg_init_io_dma() and
> >> setting
> >>  qdev_prop_set_uint32(dev, "file_slots", file_slots);
> >> manually to keep old fw_cfg_init_io() the same without touching
> >> xen/sun4u machines.
> > 
> > First, to my knowledge, Xen does not use fw_cfg. The following call
> > chains depend on (!xen_enabled()):
> > 
> > pc_init1() | pc_q35_init()
> >   if (!xen_enabled()):
> >     pc_memory_init()
> >       bochs_bios_init()
> >         fw_cfg_init_io_dma()
> > 
> > Second, I wanted to keep the fw_cfg_init_io() call sites un-touched. In
> > this patch, the fw_cfg_init_io() function passes an additional /
> > internal-only parameter to fw_cfg_init_io_dma(), and the unconditional
> > qdev_prop_set_uint32() call in fw_cfg_init_io_dma() is replaced with a
> > conditional one (so that the property can only be lowered, not raised,
> > by board code).
> > 
> >> That way we would have 2 different ways to set defaults
> >> per machine type/version rather then the single COMPAT property way.
> >>
> >> How about dropping this patch and adding
> >>  SET_MACHINE_COMPAT
> >> to xen/sun4u machines instead and dropping fw_cfg_init_io() in
> >> favor of fw_cfg_init_io_dma() along the way.
> > 
> > For the conditional qdev_prop_set_uint32() call, added in this patch, I
> > used commit e6915b5f3a87 ("fw_cfg: unbreak migration compatibility for
> > 2.4 and earlier machines") as model. According to that model, I couldn't
> > drop this patch completely, because the new feature -- i.e., DMA in that
> > patch, and higher fw_cfg file slots in this patch -- depends on both
> > machine versions and board opt-in.
> > 
> > However, if we agree (according to your feedback on patch v4 2/7) that
> > we will silently bump the fw_cfg file count for all new machine
> > versions, without requiring (or permitting) board opt-in / opt-out, then
> > I agree your above suggestion is consistent with that.
> > 
> > I think I don't have to drop fw_cfg_init_io() actually. But, with the
> > board opt-in going away, I can drop both the additional "file_slots"
> > parameter in fw_cfg_init_io_dma(), and the qdev_prop_set_uint32() call
> > in it (even the unconditional one).
> > 
> > In fact I like this simplicity more, I just wanted to be extra cautious
> > in the first version of the series that turned file_slots into a property.
> > 
> > ... Actually, are sun4u machines versioned? Hm... "hw/sparc64/sun4u.c"
> > doesn't seem to define versioned machine types. Doesn't that imply that
> > migration is *completely* unsupported for sun4u? Because, if that's the
> > case, then I wouldn't even have to add SET_MACHINE_COMPAT().
> > 
> > Thanks!
> > Laszlo
> > 
> >>
> >>>
> >>> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
> >>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> >>> Cc: Gerd Hoffmann <kraxel@redhat.com>
> >>> Cc: Igor Mammedov <imammedo@redhat.com>
> >>> Cc: Paolo Bonzini <pbonzini@redhat.com>
> >>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> >>> ---
> >>>  docs/specs/fw_cfg.txt     |  4 ++--
> >>>  include/hw/nvram/fw_cfg.h |  2 +-
> >>>  hw/i386/pc.c              |  3 ++-
> >>>  hw/nvram/fw_cfg.c         | 13 ++++++-------
> >>>  4 files changed, 11 insertions(+), 11 deletions(-)
> >>>
> >>> diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
> >>> index 84e2978706f5..4a6888b511f4 100644
> >>> --- a/docs/specs/fw_cfg.txt
> >>> +++ b/docs/specs/fw_cfg.txt
> >>> @@ -153,12 +153,12 @@ Selector Reg.    Range Usage
> >>>  0x4000 - 0x7fff  Generic (0x0000 - 0x3fff, RW, ignored in QEMU v2.4+)
> >>>  0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW
> >>>                                   through the DMA interface in QEMU v2.9+)
> >>>  0xc000 - 0xffff  Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
> >>>  
> >>> -In practice, the number of allowed firmware configuration items is given
> >>> -by the value (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS_TRAD) (see fw_cfg.h).
> >>> +In practice, the number of allowed firmware configuration items depends on the
> >>> +machine type.
> >> machine type/version
> >>
> >>>  
> >>>  = Guest-side DMA Interface =
> >>>  
> >>>  If bit 1 of the feature bitmap is set, the DMA interface is present. This does
> >>>  not replace the existing fw_cfg interface, it is an add-on. This interface
> >>> diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
> >>> index b980cbaebf43..e9a6b6aa968c 100644
> >>> --- a/include/hw/nvram/fw_cfg.h
> >>> +++ b/include/hw/nvram/fw_cfg.h
> >>> @@ -173,11 +173,11 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
> >>>   */
> >>>  void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data,
> >>>                           size_t len);
> >>>  
> >>>  FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
> >>> -                                AddressSpace *dma_as);
> >>> +                                AddressSpace *dma_as, uint32_t file_slots);
> >>>  FWCfgState *fw_cfg_init_io(uint32_t iobase);
> >>>  FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr);
> >>>  FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
> >>>                                   hwaddr data_addr, uint32_t data_width,
> >>>                                   hwaddr dma_addr, AddressSpace *dma_as);
> >>> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> >>> index a9e64a88e5e7..5d929d8fc887 100644
> >>> --- a/hw/i386/pc.c
> >>> +++ b/hw/i386/pc.c
> >>> @@ -741,11 +741,12 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms)
> >>>  {
> >>>      FWCfgState *fw_cfg;
> >>>      uint64_t *numa_fw_cfg;
> >>>      int i, j;
> >>>  
> >>> -    fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as);
> >>> +    fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as,
> >>> +                                FW_CFG_FILE_SLOTS_TRAD);
> >>>      fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus);
> >>>  
> >>>      /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
> >>>       *
> >>>       * For machine types prior to 1.8, SeaBIOS needs FW_CFG_MAX_CPUS for
> >>> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> >>> index 2e1441c09750..c33c76ab93b1 100644
> >>> --- a/hw/nvram/fw_cfg.c
> >>> +++ b/hw/nvram/fw_cfg.c
> >>> @@ -926,11 +926,11 @@ static void fw_cfg_init1(DeviceState *dev)
> >>>      s->machine_ready.notify = fw_cfg_machine_ready;
> >>>      qemu_add_machine_init_done_notifier(&s->machine_ready);
> >>>  }
> >>>  
> >>>  FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
> >>> -                                AddressSpace *dma_as)
> >>> +                                AddressSpace *dma_as, uint32_t file_slots)
> >>>  {
> >>>      DeviceState *dev;
> >>>      FWCfgState *s;
> >>>      uint32_t version = FW_CFG_VERSION;
> >>>      bool dma_requested = dma_iobase && dma_as;
> >>> @@ -940,15 +940,14 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
> >>>      qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase);
> >>>      if (!dma_requested) {
> >>>          qdev_prop_set_bit(dev, "dma_enabled", false);
> >>>      }
> >>>  
> >>> -    /* Once we expose the "file_slots" property to callers of
> >>> -     * fw_cfg_init_io_dma(), the following setting should become conditional on
> >>> -     * the input parameter being lower than the current value of the property.
> >>> -     */
> >>> -    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
> >>> +    if (file_slots < object_property_get_int(OBJECT(dev), "file_slots",
> >>> +                                             &error_abort)) {
> >>> +        qdev_prop_set_uint32(dev, "file_slots", file_slots);
> >>> +    }
> >>>  
> >>>      fw_cfg_init1(dev);
> >>>      s = FW_CFG(dev);
> >>>  
> >>>      if (s->dma_enabled) {
> >>> @@ -964,11 +963,11 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
> >>>      return s;
> >>>  }
> >>>  
> >>>  FWCfgState *fw_cfg_init_io(uint32_t iobase)
> >>>  {
> >>> -    return fw_cfg_init_io_dma(iobase, 0, NULL);
> >>> +    return fw_cfg_init_io_dma(iobase, 0, NULL, FW_CFG_FILE_SLOTS_TRAD);
> >>>  }
> >>>  
> >>>  FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
> >>>                                   hwaddr data_addr, uint32_t data_width,
> >>>                                   hwaddr dma_addr, AddressSpace *dma_as)
> >>
> > 
> 

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [Qemu-devel] [PATCH v4 1/7] fw-cfg: support writeable blobs
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 1/7] fw-cfg: support writeable blobs Laszlo Ersek
@ 2016-12-20 15:58   ` Marcel Apfelbaum
  2017-01-10 13:33     ` Laszlo Ersek
  0 siblings, 1 reply; 46+ messages in thread
From: Marcel Apfelbaum @ 2016-12-20 15:58 UTC (permalink / raw)
  To: Laszlo Ersek, qemu devel list
  Cc: Peter Maydell, Michael S. Tsirkin, Gabriel L. Somlo,
	Shannon Zhao, Michael Walle, qemu-arm, Gerd Hoffmann,
	Paolo Bonzini, Igor Mammedov

On 12/01/2016 07:06 PM, Laszlo Ersek wrote:
> From: "Michael S. Tsirkin" <mst@redhat.com>
>
> Useful to send guest data back to QEMU.
>
> Changes from Laszlo Ersek <lersek@redhat.com>:
> - rebase the patch from Michael Tsirkin's original postings at [1] and [2]
>   to the following patches:
>   - loader: Allow a custom AddressSpace when loading ROMs
>   - loader: Add AddressSpace loading support to uImages
>   - loader: fix handling of custom address spaces when adding ROM blobs
> - reject such writes immediately that would exceed the end of the array,
>   rather than performing a partial write before setting the error bit: see
>   the (len != dma.length) condition
> - document the write interface
>
> [1] http://lists.nongnu.org/archive/html/qemu-devel/2016-02/msg04968.html
> [2] http://lists.nongnu.org/archive/html/qemu-devel/2016-03/msg02735.html
>
> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Michael Walle <michael@walle.cc>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Peter Maydell <peter.maydell@linaro.org>
> Cc: Shannon Zhao <zhaoshenglong@huawei.com>
> Cc: qemu-arm@nongnu.org
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  docs/specs/fw_cfg.txt     | 32 +++++++++++++++++++++++++-------
>  hw/lm32/lm32_hwsetup.h    |  2 +-
>  include/hw/loader.h       |  7 ++++---
>  include/hw/nvram/fw_cfg.h |  3 ++-
>  hw/arm/virt-acpi-build.c  |  2 +-
>  hw/core/loader.c          | 18 +++++++++++-------
>  hw/i386/acpi-build.c      |  4 ++--
>  hw/nvram/fw_cfg.c         | 37 +++++++++++++++++++++++++++++--------
>  8 files changed, 75 insertions(+), 30 deletions(-)
>
> diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
> index 7a5f8c7824ce..a19e2adbe1c6 100644
> --- a/docs/specs/fw_cfg.txt
> +++ b/docs/specs/fw_cfg.txt
> @@ -31,21 +31,25 @@ register. In other words, configuration write mode is enabled when
>  the selector value is between 0x4000-0x7fff or 0xc000-0xffff.
>
>  NOTE: As of QEMU v2.4, writes to the fw_cfg data register are no
>        longer supported, and will be ignored (treated as no-ops)!
>
> +NOTE: As of QEMU v2.9, writes are reinstated, but only through the DMA
> +      interface (see below). Furthermore, writeability of any specific item is
> +      governed independently of Bit14 in the selector key value.
> +
>  Bit15 of the selector register indicates whether the configuration
>  setting is architecture specific. A value of 0 means the item is a
>  generic configuration item. A value of 1 means the item is specific
>  to a particular architecture. In other words, generic configuration
>  items are accessed with a selector value between 0x0000-0x7fff, and
>  architecture specific configuration items are accessed with a selector
>  value between 0x8000-0xffff.
>
>  == Data Register ==
>
> -* Read/Write (writes ignored as of QEMU v2.4)
> +* Read/Write (writes ignored as of QEMU v2.4, but see the DMA interface)
>  * Location: platform dependent (IOport [*] or MMIO)
>  * Width: 8-bit (if IOport), 8/16/32/64-bit (if MMIO)
>  * Endianness: string-preserving
>
>  [*] On platforms where the data register is exposed as an IOport, its
> @@ -132,23 +136,25 @@ struct FWCfgFile {		/* an individual file entry, 64 bytes total */
>      char name[56];		/* fw_cfg item name, NUL-terminated ascii */
>  };
>
>  === All Other Data Items ===
>
> -Please consult the QEMU source for the most up-to-date and authoritative
> -list of selector keys and their respective items' purpose and format.
> +Please consult the QEMU source for the most up-to-date and authoritative list
> +of selector keys and their respective items' purpose, format and writeability.
>
>  === Ranges ===
>
>  Theoretically, there may be up to 0x4000 generic firmware configuration
>  items, and up to 0x4000 architecturally specific ones.
>
>  Selector Reg.    Range Usage
>  ---------------  -----------
> -0x0000 - 0x3fff  Generic (0x0000 - 0x3fff, RO)
> +0x0000 - 0x3fff  Generic (0x0000 - 0x3fff, generally RO, possibly RW through
> +                          the DMA interface in QEMU v2.9+)
>  0x4000 - 0x7fff  Generic (0x0000 - 0x3fff, RW, ignored in QEMU v2.4+)
> -0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, RO)
> +0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW
> +                                 through the DMA interface in QEMU v2.9+)
>  0xc000 - 0xffff  Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
>
>  In practice, the number of allowed firmware configuration items is given
>  by the value of FW_CFG_MAX_ENTRY (see fw_cfg.h).
>
> @@ -180,21 +186,31 @@ address is the "control" field.
>  The "control" field has the following bits:
>   - Bit 0: Error
>   - Bit 1: Read
>   - Bit 2: Skip
>   - Bit 3: Select. The upper 16 bits are the selected index.
> + - Bit 4: Write
>
>  When an operation is triggered, if the "control" field has bit 3 set, the
>  upper 16 bits are interpreted as an index of a firmware configuration item.
>  This has the same effect as writing the selector register.
>
>  If the "control" field has bit 1 set, a read operation will be performed.
>  "length" bytes for the current selector and offset will be copied into the
>  physical RAM address specified by the "address" field.
>
> -If the "control" field has bit 2 set (and not bit 1), a skip operation will be
> -performed. The offset for the current selector will be advanced "length" bytes.
> +If the "control" field has bit 4 set (and not bit 1), a write operation will be
> +performed. "length" bytes will be copied from the physical RAM address
> +specified by the "address" field to the current selector and offset. QEMU
> +prevents starting or finishing the write beyond the end of the item associated
> +with the current selector (i.e., the item cannot be resized). Truncated writes
> +are dropped entirely. Writes to read-only items are also rejected. All of these
> +write errors set bit 0 (the error bit) in the "control" field.
> +
> +If the "control" field has bit 2 set (and neither bit 1 nor bit 4), a skip
> +operation will be performed. The offset for the current selector will be
> +advanced "length" bytes.
>
>  To check the result, read the "control" field:
>     error bit set        ->  something went wrong.
>     all bits cleared     ->  transfer finished successfully.
>     otherwise            ->  transfer still in progress (doesn't happen
> @@ -232,5 +248,7 @@ For historical reasons, "opt/ovmf/" is reserved for OVMF firmware.
>
>  Prefix "opt/org.qemu/" is reserved for QEMU itself.
>
>  Use of names not beginning with "opt/" is potentially dangerous and
>  entirely unsupported.  QEMU will warn if you try.
> +
> +All externally provided fw_cfg items are read-only to the guest.
> diff --git a/hw/lm32/lm32_hwsetup.h b/hw/lm32/lm32_hwsetup.h
> index 23e18784dffd..a01f6bc5dfeb 100644
> --- a/hw/lm32/lm32_hwsetup.h
> +++ b/hw/lm32/lm32_hwsetup.h
> @@ -73,11 +73,11 @@ static inline void hwsetup_free(HWSetup *hw)
>
>  static inline void hwsetup_create_rom(HWSetup *hw,
>          hwaddr base)
>  {
>      rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE,
> -                 TARGET_PAGE_SIZE, base, NULL, NULL, NULL, NULL);
> +                 TARGET_PAGE_SIZE, base, NULL, NULL, NULL, NULL, true);
>  }
>
>  static inline void hwsetup_add_u8(HWSetup *hw, uint8_t u)
>  {
>      stb_p(hw->ptr, u);
> diff --git a/include/hw/loader.h b/include/hw/loader.h
> index 0c864cfd6046..0dbd8d6bf37a 100644
> --- a/include/hw/loader.h
> +++ b/include/hw/loader.h
> @@ -178,11 +178,12 @@ int rom_add_file(const char *file, const char *fw_dir,
>                   bool option_rom, MemoryRegion *mr, AddressSpace *as);
>  MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
>                             size_t max_len, hwaddr addr,
>                             const char *fw_file_name,
>                             FWCfgReadCallback fw_callback,
> -                           void *callback_opaque, AddressSpace *as);
> +                           void *callback_opaque, AddressSpace *as,
> +                           bool read_only);
>  int rom_add_elf_program(const char *name, void *data, size_t datasize,
>                          size_t romsize, hwaddr addr, AddressSpace *as);
>  int rom_check_and_register_reset(void);
>  void rom_set_fw(FWCfgState *f);
>  void rom_set_order_override(int order);
> @@ -192,19 +193,19 @@ void *rom_ptr(hwaddr addr);
>  void hmp_info_roms(Monitor *mon, const QDict *qdict);
>
>  #define rom_add_file_fixed(_f, _a, _i)          \
>      rom_add_file(_f, NULL, _a, _i, false, NULL, NULL)
>  #define rom_add_blob_fixed(_f, _b, _l, _a)      \
> -    rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL, NULL)
> +    rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL, NULL, true)
>  #define rom_add_file_mr(_f, _mr, _i)            \
>      rom_add_file(_f, NULL, 0, _i, false, _mr, NULL)
>  #define rom_add_file_as(_f, _as, _i)            \
>      rom_add_file(_f, NULL, 0, _i, false, NULL, _as)
>  #define rom_add_file_fixed_as(_f, _a, _i, _as)          \
>      rom_add_file(_f, NULL, _a, _i, false, NULL, _as)
>  #define rom_add_blob_fixed_as(_f, _b, _l, _a, _as)      \
> -    rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL, _as)
> +    rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL, _as, true)
>
>  #define PC_ROM_MIN_VGA     0xc0000
>  #define PC_ROM_MIN_OPTION  0xc8000
>  #define PC_ROM_MAX         0xe0000
>  #define PC_ROM_ALIGN       0x800
> diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
> index 5c27a1f0d50b..b980cbaebf43 100644
> --- a/include/hw/nvram/fw_cfg.h
> +++ b/include/hw/nvram/fw_cfg.h
> @@ -134,10 +134,11 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data,
>   * @filename: name of new fw_cfg file item
>   * @callback: callback function
>   * @callback_opaque: argument to be passed into callback function
>   * @data: pointer to start of item data
>   * @len: size of item data
> + * @read_only: is file read only
>   *
>   * Add a new NAMED fw_cfg item as a raw "blob" of the given size. The data
>   * referenced by the starting pointer is only linked, NOT copied, into the
>   * data structure of the fw_cfg device.
>   * The next available (unused) selector key starting at FW_CFG_FILE_FIRST
> @@ -149,11 +150,11 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data,
>   * the fw_cfg control register, or passed to QEMU in FWCfgDmaAccess.control
>   * with FW_CFG_DMA_CTL_SELECT).
>   */
>  void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
>                                FWCfgReadCallback callback, void *callback_opaque,
> -                              void *data, size_t len);
> +                              void *data, size_t len, bool read_only);
>
>  /**
>   * fw_cfg_modify_file:
>   * @s: fw_cfg device being modified
>   * @filename: name of new fw_cfg file item
> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
> index d4160dfa7d34..542fb67239db 100644
> --- a/hw/arm/virt-acpi-build.c
> +++ b/hw/arm/virt-acpi-build.c
> @@ -807,11 +807,11 @@ static void virt_acpi_build_reset(void *build_opaque)
>  static MemoryRegion *acpi_add_rom_blob(AcpiBuildState *build_state,
>                                         GArray *blob, const char *name,
>                                         uint64_t max_size)
>  {
>      return rom_add_blob(name, blob->data, acpi_data_len(blob), max_size, -1,
> -                        name, virt_acpi_build_update, build_state, NULL);
> +                        name, virt_acpi_build_update, build_state, NULL, true);
>  }
>
>  static const VMStateDescription vmstate_virt_acpi_build = {
>      .name = "virt_acpi_build",
>      .version_id = 1,
> diff --git a/hw/core/loader.c b/hw/core/loader.c
> index 45742494e6fd..ee5abd6eb7f4 100644
> --- a/hw/core/loader.c
> +++ b/hw/core/loader.c
> @@ -851,20 +851,20 @@ static void fw_cfg_resized(const char *id, uint64_t length, void *host)
>      if (fw_cfg) {
>          fw_cfg_modify_file(fw_cfg, id + strlen("/rom@"), host, length);
>      }
>  }
>
> -static void *rom_set_mr(Rom *rom, Object *owner, const char *name)
> +static void *rom_set_mr(Rom *rom, Object *owner, const char *name, bool ro)
>  {
>      void *data;
>
>      rom->mr = g_malloc(sizeof(*rom->mr));
>      memory_region_init_resizeable_ram(rom->mr, owner, name,
>                                        rom->datasize, rom->romsize,
>                                        fw_cfg_resized,
>                                        &error_fatal);
> -    memory_region_set_readonly(rom->mr, true);
> +    memory_region_set_readonly(rom->mr, ro);
>      vmstate_register_ram_global(rom->mr);
>
>      data = memory_region_get_ram_ptr(rom->mr);
>      memcpy(data, rom->data, rom->datasize);
>
> @@ -940,11 +940,11 @@ int rom_add_file(const char *file, const char *fw_dir,
>          snprintf(fw_file_name, sizeof(fw_file_name), "%s/%s", rom->fw_dir,
>                   basename);
>          snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
>
>          if ((!option_rom || mc->option_rom_has_mr) && mc->rom_file_has_mr) {
> -            data = rom_set_mr(rom, OBJECT(fw_cfg), devpath);
> +            data = rom_set_mr(rom, OBJECT(fw_cfg), devpath, true);
>          } else {
>              data = rom->data;
>          }
>
>          fw_cfg_add_file(fw_cfg, fw_file_name, data, rom->romsize);
> @@ -977,11 +977,11 @@ err:
>  }
>
>  MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
>                     size_t max_len, hwaddr addr, const char *fw_file_name,
>                     FWCfgReadCallback fw_callback, void *callback_opaque,
> -                   AddressSpace *as)
> +                   AddressSpace *as, bool read_only)
>  {
>      MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
>      Rom *rom;
>      MemoryRegion *mr = NULL;
>
> @@ -996,22 +996,26 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
>      rom_insert(rom);
>      if (fw_file_name && fw_cfg) {
>          char devpath[100];
>          void *data;
>
> -        snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
> +        if (read_only) {
> +            snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
> +        } else {
> +            snprintf(devpath, sizeof(devpath), "/ram@%s", fw_file_name);
> +        }
>
>          if (mc->rom_file_has_mr) {
> -            data = rom_set_mr(rom, OBJECT(fw_cfg), devpath);
> +            data = rom_set_mr(rom, OBJECT(fw_cfg), devpath, read_only);
>              mr = rom->mr;
>          } else {
>              data = rom->data;
>          }
>
>          fw_cfg_add_file_callback(fw_cfg, fw_file_name,
>                                   fw_callback, callback_opaque,
> -                                 data, rom->datasize);
> +                                 data, rom->datasize, read_only);
>      }
>      return mr;
>  }
>
>  /* This function is specific for elf program because we don't need to allocate
> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> index 9708cdc463df..965cb4cd4c51 100644
> --- a/hw/i386/acpi-build.c
> +++ b/hw/i386/acpi-build.c
> @@ -2934,11 +2934,11 @@ static void acpi_build_reset(void *build_opaque)
>  static MemoryRegion *acpi_add_rom_blob(AcpiBuildState *build_state,
>                                         GArray *blob, const char *name,
>                                         uint64_t max_size)
>  {
>      return rom_add_blob(name, blob->data, acpi_data_len(blob), max_size, -1,
> -                        name, acpi_build_update, build_state, NULL);
> +                        name, acpi_build_update, build_state, NULL, true);
>  }
>
>  static const VMStateDescription vmstate_acpi_build = {
>      .name = "acpi_build",
>      .version_id = 1,
> @@ -3000,11 +3000,11 @@ void acpi_setup(void)
>          uint32_t rsdp_size = acpi_data_len(tables.rsdp);
>
>          build_state->rsdp = g_memdup(tables.rsdp->data, rsdp_size);
>          fw_cfg_add_file_callback(pcms->fw_cfg, ACPI_BUILD_RSDP_FILE,
>                                   acpi_build_update, build_state,
> -                                 build_state->rsdp, rsdp_size);
> +                                 build_state->rsdp, rsdp_size, true);
>          build_state->rsdp_mr = NULL;
>      } else {
>          build_state->rsdp = NULL;
>          build_state->rsdp_mr = acpi_add_rom_blob(build_state, tables.rsdp,
>                                                    ACPI_BUILD_RSDP_FILE, 0);
> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> index 3ebecb22606a..e0145c11a19b 100644
> --- a/hw/nvram/fw_cfg.c
> +++ b/hw/nvram/fw_cfg.c
> @@ -52,15 +52,17 @@
>  /* FW_CFG_DMA_CONTROL bits */
>  #define FW_CFG_DMA_CTL_ERROR   0x01
>  #define FW_CFG_DMA_CTL_READ    0x02
>  #define FW_CFG_DMA_CTL_SKIP    0x04
>  #define FW_CFG_DMA_CTL_SELECT  0x08
> +#define FW_CFG_DMA_CTL_WRITE   0x10
>
>  #define FW_CFG_DMA_SIGNATURE 0x51454d5520434647ULL /* "QEMU CFG" */
>
>  typedef struct FWCfgEntry {
>      uint32_t len;
> +    bool allow_write;
>      uint8_t *data;
>      void *callback_opaque;
>      FWCfgReadCallback read_callback;
>  } FWCfgEntry;
>
> @@ -324,11 +326,11 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
>  {
>      dma_addr_t len;
>      FWCfgDmaAccess dma;
>      int arch;
>      FWCfgEntry *e;
> -    int read;
> +    int read = 0, write = 0;
>      dma_addr_t dma_addr;
>
>      /* Reset the address before the next access */
>      dma_addr = s->dma_addr;
>      s->dma_addr = 0;
> @@ -351,12 +353,17 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
>      e = (s->cur_entry == FW_CFG_INVALID) ? NULL :
>          &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
>
>      if (dma.control & FW_CFG_DMA_CTL_READ) {
>          read = 1;
> +        write = 0;
> +    } else if (dma.control & FW_CFG_DMA_CTL_WRITE) {
> +        read = 0;
> +        write = 1;
>      } else if (dma.control & FW_CFG_DMA_CTL_SKIP) {
>          read = 0;
> +        write = 0;
>      } else {
>          dma.length = 0;
>      }
>
>      dma.control = 0;
> @@ -372,11 +379,13 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
>              if (read) {
>                  if (dma_memory_set(s->dma_as, dma.address, 0, len)) {
>                      dma.control |= FW_CFG_DMA_CTL_ERROR;
>                  }
>              }
> -
> +            if (write) {
> +                dma.control |= FW_CFG_DMA_CTL_ERROR;
> +            }
>          } else {
>              if (dma.length <= (e->len - s->cur_offset)) {
>                  len = dma.length;
>              } else {
>                  len = (e->len - s->cur_offset);
> @@ -389,10 +398,18 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
>                  if (dma_memory_write(s->dma_as, dma.address,
>                                      &e->data[s->cur_offset], len)) {
>                      dma.control |= FW_CFG_DMA_CTL_ERROR;
>                  }
>              }
> +            if (write) {
> +                if (!e->allow_write ||
> +                    len != dma.length ||
> +                    dma_memory_read(s->dma_as, dma.address,
> +                                    &e->data[s->cur_offset], len)) {
> +                    dma.control |= FW_CFG_DMA_CTL_ERROR;
> +                }
> +            }
>
>              s->cur_offset += len;
>          }
>
>          dma.address += len;
> @@ -584,11 +601,12 @@ static const VMStateDescription vmstate_fw_cfg = {
>  };
>
>  static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key,
>                                             FWCfgReadCallback callback,
>                                             void *callback_opaque,
> -                                           void *data, size_t len)
> +                                           void *data, size_t len,
> +                                           bool read_only)
>  {
>      int arch = !!(key & FW_CFG_ARCH_LOCAL);
>
>      key &= FW_CFG_ENTRY_MASK;
>
> @@ -597,10 +615,11 @@ static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key,
>
>      s->entries[arch][key].data = data;
>      s->entries[arch][key].len = (uint32_t)len;
>      s->entries[arch][key].read_callback = callback;
>      s->entries[arch][key].callback_opaque = callback_opaque;
> +    s->entries[arch][key].allow_write = !read_only;
>  }
>
>  static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key,
>                                                void *data, size_t len)
>  {
> @@ -614,17 +633,18 @@ static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key,
>      /* 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;
>
>      return ptr;
>  }
>
>  void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len)
>  {
> -    fw_cfg_add_bytes_read_callback(s, key, NULL, NULL, data, len);
> +    fw_cfg_add_bytes_read_callback(s, key, NULL, NULL, data, len, true);
>  }
>
>  void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value)
>  {
>      size_t sz = strlen(value) + 1;
> @@ -747,11 +767,11 @@ static int get_fw_cfg_order(FWCfgState *s, const char *name)
>      return FW_CFG_ORDER_OVERRIDE_LAST;
>  }
>
>  void fw_cfg_add_file_callback(FWCfgState *s,  const char *filename,
>                                FWCfgReadCallback callback, void *callback_opaque,
> -                              void *data, size_t len)
> +                              void *data, size_t len, bool read_only)
>  {
>      int i, index, count;
>      size_t dsize;
>      MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
>      int order = 0;
> @@ -809,11 +829,12 @@ void fw_cfg_add_file_callback(FWCfgState *s,  const char *filename,
>              exit(1);
>          }
>      }
>
>      fw_cfg_add_bytes_read_callback(s, FW_CFG_FILE_FIRST + index,
> -                                   callback, callback_opaque, data, len);
> +                                   callback, callback_opaque, data, len,
> +                                   read_only);
>
>      s->files->f[index].size   = cpu_to_be32(len);
>      s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index);
>      s->entry_order[index] = order;
>      trace_fw_cfg_add_file(s, index, s->files->f[index].name, len);
> @@ -822,11 +843,11 @@ void fw_cfg_add_file_callback(FWCfgState *s,  const char *filename,
>  }
>
>  void fw_cfg_add_file(FWCfgState *s,  const char *filename,
>                       void *data, size_t len)
>  {
> -    fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len);
> +    fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len, true);
>  }
>
>  void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
>                          void *data, size_t len)
>  {
> @@ -845,11 +866,11 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
>              s->files->f[i].size   = cpu_to_be32(len);
>              return ptr;
>          }
>      }
>      /* add new one */
> -    fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len);
> +    fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len, true);
>      return NULL;
>  }
>
>  static void fw_cfg_machine_reset(void *opaque)
>  {
>

Hi Laszlo,
The 'write' documentation is very helpful, thanks.
I would add that QEMU will 'use' the written values
when the guest selects another file (for reading),
that being protocol specific, of course.
But maybe is not connected directly.

Reviewed-by: Marcel Apfelbaum <marcel@redhat.com>

Thanks,
Marcel

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

* Re: [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI
  2016-12-01 17:06 [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI Laszlo Ersek
                   ` (6 preceding siblings ...)
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 7/7] hw/i386/pc_q35: advertise broadcast SMI if VCPU hotplug is turned off Laszlo Ersek
@ 2016-12-20 23:01 ` no-reply
  2016-12-21 15:22   ` [Qemu-devel] checkpatch.pl false positive (was Re: [PATCH v4 0/7] q35: add negotiable broadcast SMI) Eduardo Habkost
  2017-01-10 15:06 ` [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI Michael S. Tsirkin
  8 siblings, 1 reply; 46+ messages in thread
From: no-reply @ 2016-12-20 23:01 UTC (permalink / raw)
  To: lersek
  Cc: famz, qemu-devel, peter.maydell, ehabkost, mst, somlo,
	zhaoshenglong, michael, qemu-arm, kraxel, pbonzini, imammedo

Hi,

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

Subject: [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI
Message-id: 20161201170624.26496-1-lersek@redhat.com
Type: series

=== TEST SCRIPT BEGIN ===
#!/bin/bash

BASE=base
n=1
total=$(git log --oneline $BASE.. | wc -l)
failed=0

# Useful git options
git config --local diff.renamelimit 0
git config --local diff.renames True

commits="$(git log --format=%H --reverse $BASE..)"
for c in $commits; do
    echo "Checking PATCH $n/$total: $(git log -n 1 --format=%s $c)..."
    if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then
        failed=1
        echo
    fi
    n=$((n+1))
done

exit $failed
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
From https://github.com/patchew-project/qemu
 - [tag update]      patchew/1480926904-17596-1-git-send-email-zhang.zhanghailiang@huawei.com -> patchew/1480926904-17596-1-git-send-email-zhang.zhanghailiang@huawei.com
 - [tag update]      patchew/1481625384-15077-1-git-send-email-peter.maydell@linaro.org -> patchew/1481625384-15077-1-git-send-email-peter.maydell@linaro.org
 - [tag update]      patchew/1481856403-23599-1-git-send-email-zhangchen.fnst@cn.fujitsu.com -> patchew/1481856403-23599-1-git-send-email-zhangchen.fnst@cn.fujitsu.com
 * [new tag]         patchew/1482137486-9843-1-git-send-email-douly.fnst@cn.fujitsu.com -> patchew/1482137486-9843-1-git-send-email-douly.fnst@cn.fujitsu.com
 * [new tag]         patchew/1482140507-23607-1-git-send-email-vlad.lungu@windriver.com -> patchew/1482140507-23607-1-git-send-email-vlad.lungu@windriver.com
 * [new tag]         patchew/1482145554-88823-1-git-send-email-wei.w.wang@intel.com -> patchew/1482145554-88823-1-git-send-email-wei.w.wang@intel.com
 * [new tag]         patchew/1482156623-9111-1-git-send-email-peterx@redhat.com -> patchew/1482156623-9111-1-git-send-email-peterx@redhat.com
 * [new tag]         patchew/148215768690.13973.9042496691140000163.stgit@bahia -> patchew/148215768690.13973.9042496691140000163.stgit@bahia
 * [new tag]         patchew/1482158486-18597-1-git-send-email-peterx@redhat.com -> patchew/1482158486-18597-1-git-send-email-peterx@redhat.com
 * [new tag]         patchew/1482187106-85065-1-git-send-email-sochin.jiang@huawei.com -> patchew/1482187106-85065-1-git-send-email-sochin.jiang@huawei.com
 * [new tag]         patchew/1482255793-19057-1-git-send-email-ehabkost@redhat.com -> patchew/1482255793-19057-1-git-send-email-ehabkost@redhat.com
 * [new tag]         patchew/1482268300-10082-1-git-send-email-andrew.smirnov@gmail.com -> patchew/1482268300-10082-1-git-send-email-andrew.smirnov@gmail.com
 * [new tag]         patchew/1482268598-27422-1-git-send-email-thuth@redhat.com -> patchew/1482268598-27422-1-git-send-email-thuth@redhat.com
 * [new tag]         patchew/1482269164-14642-1-git-send-email-minyard@acm.org -> patchew/1482269164-14642-1-git-send-email-minyard@acm.org
 * [new tag]         patchew/20161201170624.26496-1-lersek@redhat.com -> patchew/20161201170624.26496-1-lersek@redhat.com
 - [tag update]      patchew/20161212224325.20790-1-marcandre.lureau@redhat.com -> patchew/20161212224325.20790-1-marcandre.lureau@redhat.com
 - [tag update]      patchew/20161214070156.23368-1-ppandit@redhat.com -> patchew/20161214070156.23368-1-ppandit@redhat.com
 * [new tag]         patchew/20161219205054.4677-1-kirkseraph@gmail.com -> patchew/20161219205054.4677-1-kirkseraph@gmail.com
 * [new tag]         patchew/20161220163139.12016-1-famz@redhat.com -> patchew/20161220163139.12016-1-famz@redhat.com
 * [new tag]         patchew/b0619e40-daca-9b28-2c78-1e2709d9f0ad@tuxfamily.org -> patchew/b0619e40-daca-9b28-2c78-1e2709d9f0ad@tuxfamily.org
 * [new tag]         patchew/cover.1482143215.git.vpalatin@chromium.org -> patchew/cover.1482143215.git.vpalatin@chromium.org
 * [new tag]         patchew/cover.1482164622.git.vpalatin@chromium.org -> patchew/cover.1482164622.git.vpalatin@chromium.org
 * [new tag]         patchew/cover.1482187052.git.ben@skyportsystems.com -> patchew/cover.1482187052.git.ben@skyportsystems.com
Switched to a new branch 'test'
2d2326b hw/i386/pc_q35: advertise broadcast SMI if VCPU hotplug is turned off
3443a68 hw/isa/lpc_ich9: add broadcast SMI feature
3863642 hw/isa/lpc_ich9: add SMI feature negotiation via fw_cfg
12b2efd hw/i386/pc: introduce 2.9 machine types with 0x20 fw_cfg file slots
5387420 fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma()
c550b2c fw-cfg: turn FW_CFG_FILE_SLOTS into a device property
1f40c84 fw-cfg: support writeable blobs

=== OUTPUT BEGIN ===
Checking PATCH 1/7: fw-cfg: support writeable blobs...
Checking PATCH 2/7: fw-cfg: turn FW_CFG_FILE_SLOTS into a device property...
Checking PATCH 3/7: fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma()...
Checking PATCH 4/7: hw/i386/pc: introduce 2.9 machine types with 0x20 fw_cfg file slots...
ERROR: Macros with multiple statements should be enclosed in a do - while loop
#126: FILE: include/hw/compat.h:4:
+#define HW_COMPAT_2_8 \
+    {\
+        .driver   = "fw_cfg_mem",\
+        .property = "file_slots",\
+        .value    = stringify(0x10),\
+    },{\
+        .driver   = "fw_cfg_io",\
+        .property = "file_slots",\
+        .value    = stringify(0x10),\
+    },

total: 1 errors, 0 warnings, 119 lines checked

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

Checking PATCH 5/7: hw/isa/lpc_ich9: add SMI feature negotiation via fw_cfg...
Checking PATCH 6/7: hw/isa/lpc_ich9: add broadcast SMI feature...
Checking PATCH 7/7: hw/i386/pc_q35: advertise broadcast SMI if VCPU hotplug is turned off...
=== OUTPUT END ===

Test command exited with code: 1


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org

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

* [Qemu-devel] checkpatch.pl false positive (was Re: [PATCH v4 0/7] q35: add negotiable broadcast SMI)
  2016-12-20 23:01 ` [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI no-reply
@ 2016-12-21 15:22   ` Eduardo Habkost
  2016-12-21 17:47     ` Paolo Bonzini
  0 siblings, 1 reply; 46+ messages in thread
From: Eduardo Habkost @ 2016-12-21 15:22 UTC (permalink / raw)
  To: qemu-devel
  Cc: lersek, famz, peter.maydell, mst, somlo, zhaoshenglong, michael,
	qemu-arm, kraxel, pbonzini, imammedo, Markus Armbruster,
	Eric Blake

On Tue, Dec 20, 2016 at 03:01:17PM -0800, no-reply@patchew.org wrote:
[...]
> Checking PATCH 4/7: hw/i386/pc: introduce 2.9 machine types with 0x20 fw_cfg file slots...
> ERROR: Macros with multiple statements should be enclosed in a do - while loop
> #126: FILE: include/hw/compat.h:4:
> +#define HW_COMPAT_2_8 \
> +    {\
> +        .driver   = "fw_cfg_mem",\
> +        .property = "file_slots",\
> +        .value    = stringify(0x10),\
> +    },{\
> +        .driver   = "fw_cfg_io",\
> +        .property = "file_slots",\
> +        .value    = stringify(0x10),\
> +    },
> 
> total: 1 errors, 0 warnings, 119 lines checked
> 
> Your patch has style problems, please review.  If any of these errors
> are false positives report them to the maintainer, see
> CHECKPATCH in MAINTAINERS.

It is a false positive, but how exactly can we fix it? Should it
become a warning instead of an error?

-- 
Eduardo

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

* Re: [Qemu-devel] checkpatch.pl false positive (was Re: [PATCH v4 0/7] q35: add negotiable broadcast SMI)
  2016-12-21 15:22   ` [Qemu-devel] checkpatch.pl false positive (was Re: [PATCH v4 0/7] q35: add negotiable broadcast SMI) Eduardo Habkost
@ 2016-12-21 17:47     ` Paolo Bonzini
  2016-12-21 18:01       ` Eduardo Habkost
  0 siblings, 1 reply; 46+ messages in thread
From: Paolo Bonzini @ 2016-12-21 17:47 UTC (permalink / raw)
  To: Eduardo Habkost, qemu-devel
  Cc: peter.maydell, famz, mst, somlo, Markus Armbruster, michael,
	qemu-arm, kraxel, zhaoshenglong, lersek, imammedo



On 21/12/2016 16:22, Eduardo Habkost wrote:
> On Tue, Dec 20, 2016 at 03:01:17PM -0800, no-reply@patchew.org wrote:
> [...]
>> Checking PATCH 4/7: hw/i386/pc: introduce 2.9 machine types with 0x20 fw_cfg file slots...
>> ERROR: Macros with multiple statements should be enclosed in a do - while loop
>> #126: FILE: include/hw/compat.h:4:
>> +#define HW_COMPAT_2_8 \
>> +    {\
>> +        .driver   = "fw_cfg_mem",\
>> +        .property = "file_slots",\
>> +        .value    = stringify(0x10),\
>> +    },{\
>> +        .driver   = "fw_cfg_io",\
>> +        .property = "file_slots",\
>> +        .value    = stringify(0x10),\
>> +    },
>>
>> total: 1 errors, 0 warnings, 119 lines checked
>>
>> Your patch has style problems, please review.  If any of these errors
>> are false positives report them to the maintainer, see
>> CHECKPATCH in MAINTAINERS.
> 
> It is a false positive, but how exactly can we fix it? Should it
> become a warning instead of an error?

It should already be treated as an exception:

                        my $exceptions = qr{
                                $Declare|
                                module_param_named|
                                MODULE_PARAM_DESC|
                                DECLARE_PER_CPU|
                                DEFINE_PER_CPU|
                                __typeof__\(|
                                union|
                                struct|
                                \.$Ident\s*=\s*|       # <---- see here
                                ^\"|\"$
                        }x;
                        #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n";
                        if ($rest ne '' && $rest ne ',') {
                                if ($rest !~ /while\s*\(/ &&
                                    $dstat !~ /$exceptions/)
                                {
                                        ERROR("Macros with multiple statements should be enclosed in a do - while loop\n" . "$here\n$ctx\n");
                                }


so I guess the first step is debugging it. :)

Paolo

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

* Re: [Qemu-devel] checkpatch.pl false positive (was Re: [PATCH v4 0/7] q35: add negotiable broadcast SMI)
  2016-12-21 17:47     ` Paolo Bonzini
@ 2016-12-21 18:01       ` Eduardo Habkost
  2016-12-21 18:08         ` Paolo Bonzini
  0 siblings, 1 reply; 46+ messages in thread
From: Eduardo Habkost @ 2016-12-21 18:01 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: qemu-devel, peter.maydell, famz, mst, somlo, Markus Armbruster,
	michael, qemu-arm, kraxel, zhaoshenglong, lersek, imammedo

On Wed, Dec 21, 2016 at 06:47:01PM +0100, Paolo Bonzini wrote:
> 
> 
> On 21/12/2016 16:22, Eduardo Habkost wrote:
> > On Tue, Dec 20, 2016 at 03:01:17PM -0800, no-reply@patchew.org wrote:
> > [...]
> >> Checking PATCH 4/7: hw/i386/pc: introduce 2.9 machine types with 0x20 fw_cfg file slots...
> >> ERROR: Macros with multiple statements should be enclosed in a do - while loop
> >> #126: FILE: include/hw/compat.h:4:
> >> +#define HW_COMPAT_2_8 \
> >> +    {\
> >> +        .driver   = "fw_cfg_mem",\
> >> +        .property = "file_slots",\
> >> +        .value    = stringify(0x10),\
> >> +    },{\
> >> +        .driver   = "fw_cfg_io",\
> >> +        .property = "file_slots",\
> >> +        .value    = stringify(0x10),\
> >> +    },
> >>
> >> total: 1 errors, 0 warnings, 119 lines checked
> >>
> >> Your patch has style problems, please review.  If any of these errors
> >> are false positives report them to the maintainer, see
> >> CHECKPATCH in MAINTAINERS.
> > 
> > It is a false positive, but how exactly can we fix it? Should it
> > become a warning instead of an error?
> 
> It should already be treated as an exception:
> 
>                         my $exceptions = qr{
>                                 $Declare|
>                                 module_param_named|
>                                 MODULE_PARAM_DESC|
>                                 DECLARE_PER_CPU|
>                                 DEFINE_PER_CPU|
>                                 __typeof__\(|
>                                 union|
>                                 struct|
>                                 \.$Ident\s*=\s*|       # <---- see here
>                                 ^\"|\"$
>                         }x;
>                         #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n";
>                         if ($rest ne '' && $rest ne ',') {
>                                 if ($rest !~ /while\s*\(/ &&
>                                     $dstat !~ /$exceptions/)
>                                 {
>                                         ERROR("Macros with multiple statements should be enclosed in a do - while loop\n" . "$here\n$ctx\n");
>                                 }
> 
> 
> so I guess the first step is debugging it. :)

The following code replaces the whole "{ .driver = ... }" block
with "1":

	# Flatten any parentheses and braces
	while ($dstat =~ s/\([^\(\)]*\)/1/ ||
	       $dstat =~ s/\{[^\{\}]*\}/1/ ||
	       $dstat =~ s/\[[^\{\}]*\]/1/)
	{
	}

The following change fixes the bug, but I don't know if it has
unwanted side-effects:

diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index f084542..0aab3ac 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2200,6 +2200,10 @@ sub process {
                        $dstat =~ s/^\s*//s;
                        $dstat =~ s/\s*$//s;
 
+                       # remove braces that cover the whole block, if any:
+                       $dstat =~ s/^\{//;
+                       $dstat =~ s/\}$//;
+
                        # Flatten any parentheses and braces
                        while ($dstat =~ s/\([^\(\)]*\)/1/ ||
                               $dstat =~ s/\{[^\{\}]*\}/1/ ||


-- 
Eduardo

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

* Re: [Qemu-devel] checkpatch.pl false positive (was Re: [PATCH v4 0/7] q35: add negotiable broadcast SMI)
  2016-12-21 18:01       ` Eduardo Habkost
@ 2016-12-21 18:08         ` Paolo Bonzini
  2016-12-21 18:19           ` Eduardo Habkost
  0 siblings, 1 reply; 46+ messages in thread
From: Paolo Bonzini @ 2016-12-21 18:08 UTC (permalink / raw)
  To: Eduardo Habkost
  Cc: qemu-devel, peter.maydell, famz, mst, somlo, Markus Armbruster,
	michael, qemu-arm, kraxel, zhaoshenglong, lersek, imammedo



On 21/12/2016 19:01, Eduardo Habkost wrote:
> The following code replaces the whole "{ .driver = ... }" block
> with "1":
> 
> 	# Flatten any parentheses and braces
> 	while ($dstat =~ s/\([^\(\)]*\)/1/ ||
> 	       $dstat =~ s/\{[^\{\}]*\}/1/ ||
> 	       $dstat =~ s/\[[^\{\}]*\]/1/)
> 	{
> 	}

Maybe change it like

- 	       $dstat =~ s/\{[^\{\}]*\}/1/ ||
+ 	       $dstat =~ s/\{[^\{\}]*;[^\{\}]*\}/1;/ ||

so that it requires a statement?  It would have a false positive on
strings containing a semicolon, but that's not a big deal (or could be
fixed by similarly turning strings into just "").

Paolo

> The following change fixes the bug, but I don't know if it has
> unwanted side-effects:
> 
> diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
> index f084542..0aab3ac 100755
> --- a/scripts/checkpatch.pl
> +++ b/scripts/checkpatch.pl
> @@ -2200,6 +2200,10 @@ sub process {
>                         $dstat =~ s/^\s*//s;
>                         $dstat =~ s/\s*$//s;
>  
> +                       # remove braces that cover the whole block, if any:
> +                       $dstat =~ s/^\{//;
> +                       $dstat =~ s/\}$//;
> +
>                         # Flatten any parentheses and braces
>                         while ($dstat =~ s/\([^\(\)]*\)/1/ ||
>                                $dstat =~ s/\{[^\{\}]*\}/1/ ||


Paolo

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

* Re: [Qemu-devel] checkpatch.pl false positive (was Re: [PATCH v4 0/7] q35: add negotiable broadcast SMI)
  2016-12-21 18:08         ` Paolo Bonzini
@ 2016-12-21 18:19           ` Eduardo Habkost
  0 siblings, 0 replies; 46+ messages in thread
From: Eduardo Habkost @ 2016-12-21 18:19 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: qemu-devel, peter.maydell, famz, mst, somlo, Markus Armbruster,
	michael, qemu-arm, kraxel, zhaoshenglong, lersek, imammedo

On Wed, Dec 21, 2016 at 07:08:29PM +0100, Paolo Bonzini wrote:
> 
> 
> On 21/12/2016 19:01, Eduardo Habkost wrote:
> > The following code replaces the whole "{ .driver = ... }" block
> > with "1":
> > 
> > 	# Flatten any parentheses and braces
> > 	while ($dstat =~ s/\([^\(\)]*\)/1/ ||
> > 	       $dstat =~ s/\{[^\{\}]*\}/1/ ||
> > 	       $dstat =~ s/\[[^\{\}]*\]/1/)
> > 	{
> > 	}
> 
> Maybe change it like
> 
> - 	       $dstat =~ s/\{[^\{\}]*\}/1/ ||
> + 	       $dstat =~ s/\{[^\{\}]*;[^\{\}]*\}/1;/ ||
> 
> so that it requires a statement?

I am not sure the point of this line is to detect multi-statement
blocks, but to replace other types of expressions containing {}
that could incorrectly match $exceptions, like:

#define FOO { \
   Foo f = { .somefield = 1 }; \
   some_statement(); \
   another_statement();
  }

In this case, $dstat would become:
"{ Foo f = 1; some_statement(); another_statement(); }"


>                                   It would have a false positive on
> strings containing a semicolon, but that's not a big deal (or could be
> fixed by similarly turning strings into just "").

String contents are already replaced with "XXX" by some other
code. These are the contents of $dstat:

 '{        .driver   = "XXXXXXXXXX",        .property = "XXXXXXXXXX",        .value    = stringify1,    }'

> 
> Paolo
> 
> > The following change fixes the bug, but I don't know if it has
> > unwanted side-effects:
> > 
> > diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
> > index f084542..0aab3ac 100755
> > --- a/scripts/checkpatch.pl
> > +++ b/scripts/checkpatch.pl
> > @@ -2200,6 +2200,10 @@ sub process {
> >                         $dstat =~ s/^\s*//s;
> >                         $dstat =~ s/\s*$//s;
> >  
> > +                       # remove braces that cover the whole block, if any:
> > +                       $dstat =~ s/^\{//;
> > +                       $dstat =~ s/\}$//;
> > +
> >                         # Flatten any parentheses and braces
> >                         while ($dstat =~ s/\([^\(\)]*\)/1/ ||
> >                                $dstat =~ s/\{[^\{\}]*\}/1/ ||
> 
> 
> Paolo

-- 
Eduardo

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

* Re: [Qemu-devel] [PATCH v4 1/7] fw-cfg: support writeable blobs
  2016-12-20 15:58   ` Marcel Apfelbaum
@ 2017-01-10 13:33     ` Laszlo Ersek
  0 siblings, 0 replies; 46+ messages in thread
From: Laszlo Ersek @ 2017-01-10 13:33 UTC (permalink / raw)
  To: marcel, qemu devel list
  Cc: Peter Maydell, Michael S. Tsirkin, Gabriel L. Somlo,
	Michael Walle, qemu-arm, Gerd Hoffmann, Shannon Zhao,
	Paolo Bonzini, Igor Mammedov

On 12/20/16 16:58, Marcel Apfelbaum wrote:
> On 12/01/2016 07:06 PM, Laszlo Ersek wrote:
>> From: "Michael S. Tsirkin" <mst@redhat.com>
>>
>> Useful to send guest data back to QEMU.
>>
>> Changes from Laszlo Ersek <lersek@redhat.com>:
>> - rebase the patch from Michael Tsirkin's original postings at [1] and
>> [2]
>>   to the following patches:
>>   - loader: Allow a custom AddressSpace when loading ROMs
>>   - loader: Add AddressSpace loading support to uImages
>>   - loader: fix handling of custom address spaces when adding ROM blobs
>> - reject such writes immediately that would exceed the end of the array,
>>   rather than performing a partial write before setting the error bit:
>> see
>>   the (len != dma.length) condition
>> - document the write interface
>>
>> [1] http://lists.nongnu.org/archive/html/qemu-devel/2016-02/msg04968.html
>> [2] http://lists.nongnu.org/archive/html/qemu-devel/2016-03/msg02735.html
>>
>> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>> Cc: Igor Mammedov <imammedo@redhat.com>
>> Cc: Michael Walle <michael@walle.cc>
>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>> Cc: Peter Maydell <peter.maydell@linaro.org>
>> Cc: Shannon Zhao <zhaoshenglong@huawei.com>
>> Cc: qemu-arm@nongnu.org
>> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>> ---
>>  docs/specs/fw_cfg.txt     | 32 +++++++++++++++++++++++++-------
>>  hw/lm32/lm32_hwsetup.h    |  2 +-
>>  include/hw/loader.h       |  7 ++++---
>>  include/hw/nvram/fw_cfg.h |  3 ++-
>>  hw/arm/virt-acpi-build.c  |  2 +-
>>  hw/core/loader.c          | 18 +++++++++++-------
>>  hw/i386/acpi-build.c      |  4 ++--
>>  hw/nvram/fw_cfg.c         | 37 +++++++++++++++++++++++++++++--------
>>  8 files changed, 75 insertions(+), 30 deletions(-)
>>
>> diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
>> index 7a5f8c7824ce..a19e2adbe1c6 100644
>> --- a/docs/specs/fw_cfg.txt
>> +++ b/docs/specs/fw_cfg.txt
>> @@ -31,21 +31,25 @@ register. In other words, configuration write mode
>> is enabled when
>>  the selector value is between 0x4000-0x7fff or 0xc000-0xffff.
>>
>>  NOTE: As of QEMU v2.4, writes to the fw_cfg data register are no
>>        longer supported, and will be ignored (treated as no-ops)!
>>
>> +NOTE: As of QEMU v2.9, writes are reinstated, but only through the DMA
>> +      interface (see below). Furthermore, writeability of any
>> specific item is
>> +      governed independently of Bit14 in the selector key value.
>> +
>>  Bit15 of the selector register indicates whether the configuration
>>  setting is architecture specific. A value of 0 means the item is a
>>  generic configuration item. A value of 1 means the item is specific
>>  to a particular architecture. In other words, generic configuration
>>  items are accessed with a selector value between 0x0000-0x7fff, and
>>  architecture specific configuration items are accessed with a selector
>>  value between 0x8000-0xffff.
>>
>>  == Data Register ==
>>
>> -* Read/Write (writes ignored as of QEMU v2.4)
>> +* Read/Write (writes ignored as of QEMU v2.4, but see the DMA interface)
>>  * Location: platform dependent (IOport [*] or MMIO)
>>  * Width: 8-bit (if IOport), 8/16/32/64-bit (if MMIO)
>>  * Endianness: string-preserving
>>
>>  [*] On platforms where the data register is exposed as an IOport, its
>> @@ -132,23 +136,25 @@ struct FWCfgFile {        /* an individual file
>> entry, 64 bytes total */
>>      char name[56];        /* fw_cfg item name, NUL-terminated ascii */
>>  };
>>
>>  === All Other Data Items ===
>>
>> -Please consult the QEMU source for the most up-to-date and authoritative
>> -list of selector keys and their respective items' purpose and format.
>> +Please consult the QEMU source for the most up-to-date and
>> authoritative list
>> +of selector keys and their respective items' purpose, format and
>> writeability.
>>
>>  === Ranges ===
>>
>>  Theoretically, there may be up to 0x4000 generic firmware configuration
>>  items, and up to 0x4000 architecturally specific ones.
>>
>>  Selector Reg.    Range Usage
>>  ---------------  -----------
>> -0x0000 - 0x3fff  Generic (0x0000 - 0x3fff, RO)
>> +0x0000 - 0x3fff  Generic (0x0000 - 0x3fff, generally RO, possibly RW
>> through
>> +                          the DMA interface in QEMU v2.9+)
>>  0x4000 - 0x7fff  Generic (0x0000 - 0x3fff, RW, ignored in QEMU v2.4+)
>> -0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, RO)
>> +0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, generally RO,
>> possibly RW
>> +                                 through the DMA interface in QEMU
>> v2.9+)
>>  0xc000 - 0xffff  Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
>>
>>  In practice, the number of allowed firmware configuration items is given
>>  by the value of FW_CFG_MAX_ENTRY (see fw_cfg.h).
>>
>> @@ -180,21 +186,31 @@ address is the "control" field.
>>  The "control" field has the following bits:
>>   - Bit 0: Error
>>   - Bit 1: Read
>>   - Bit 2: Skip
>>   - Bit 3: Select. The upper 16 bits are the selected index.
>> + - Bit 4: Write
>>
>>  When an operation is triggered, if the "control" field has bit 3 set,
>> the
>>  upper 16 bits are interpreted as an index of a firmware configuration
>> item.
>>  This has the same effect as writing the selector register.
>>
>>  If the "control" field has bit 1 set, a read operation will be
>> performed.
>>  "length" bytes for the current selector and offset will be copied
>> into the
>>  physical RAM address specified by the "address" field.
>>
>> -If the "control" field has bit 2 set (and not bit 1), a skip
>> operation will be
>> -performed. The offset for the current selector will be advanced
>> "length" bytes.
>> +If the "control" field has bit 4 set (and not bit 1), a write
>> operation will be
>> +performed. "length" bytes will be copied from the physical RAM address
>> +specified by the "address" field to the current selector and offset.
>> QEMU
>> +prevents starting or finishing the write beyond the end of the item
>> associated
>> +with the current selector (i.e., the item cannot be resized).
>> Truncated writes
>> +are dropped entirely. Writes to read-only items are also rejected.
>> All of these
>> +write errors set bit 0 (the error bit) in the "control" field.
>> +
>> +If the "control" field has bit 2 set (and neither bit 1 nor bit 4), a
>> skip
>> +operation will be performed. The offset for the current selector will be
>> +advanced "length" bytes.
>>
>>  To check the result, read the "control" field:
>>     error bit set        ->  something went wrong.
>>     all bits cleared     ->  transfer finished successfully.
>>     otherwise            ->  transfer still in progress (doesn't happen
>> @@ -232,5 +248,7 @@ For historical reasons, "opt/ovmf/" is reserved
>> for OVMF firmware.
>>
>>  Prefix "opt/org.qemu/" is reserved for QEMU itself.
>>
>>  Use of names not beginning with "opt/" is potentially dangerous and
>>  entirely unsupported.  QEMU will warn if you try.
>> +
>> +All externally provided fw_cfg items are read-only to the guest.
>> diff --git a/hw/lm32/lm32_hwsetup.h b/hw/lm32/lm32_hwsetup.h
>> index 23e18784dffd..a01f6bc5dfeb 100644
>> --- a/hw/lm32/lm32_hwsetup.h
>> +++ b/hw/lm32/lm32_hwsetup.h
>> @@ -73,11 +73,11 @@ static inline void hwsetup_free(HWSetup *hw)
>>
>>  static inline void hwsetup_create_rom(HWSetup *hw,
>>          hwaddr base)
>>  {
>>      rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE,
>> -                 TARGET_PAGE_SIZE, base, NULL, NULL, NULL, NULL);
>> +                 TARGET_PAGE_SIZE, base, NULL, NULL, NULL, NULL, true);
>>  }
>>
>>  static inline void hwsetup_add_u8(HWSetup *hw, uint8_t u)
>>  {
>>      stb_p(hw->ptr, u);
>> diff --git a/include/hw/loader.h b/include/hw/loader.h
>> index 0c864cfd6046..0dbd8d6bf37a 100644
>> --- a/include/hw/loader.h
>> +++ b/include/hw/loader.h
>> @@ -178,11 +178,12 @@ int rom_add_file(const char *file, const char
>> *fw_dir,
>>                   bool option_rom, MemoryRegion *mr, AddressSpace *as);
>>  MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t
>> len,
>>                             size_t max_len, hwaddr addr,
>>                             const char *fw_file_name,
>>                             FWCfgReadCallback fw_callback,
>> -                           void *callback_opaque, AddressSpace *as);
>> +                           void *callback_opaque, AddressSpace *as,
>> +                           bool read_only);
>>  int rom_add_elf_program(const char *name, void *data, size_t datasize,
>>                          size_t romsize, hwaddr addr, AddressSpace *as);
>>  int rom_check_and_register_reset(void);
>>  void rom_set_fw(FWCfgState *f);
>>  void rom_set_order_override(int order);
>> @@ -192,19 +193,19 @@ void *rom_ptr(hwaddr addr);
>>  void hmp_info_roms(Monitor *mon, const QDict *qdict);
>>
>>  #define rom_add_file_fixed(_f, _a, _i)          \
>>      rom_add_file(_f, NULL, _a, _i, false, NULL, NULL)
>>  #define rom_add_blob_fixed(_f, _b, _l, _a)      \
>> -    rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL, NULL)
>> +    rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL, NULL, true)
>>  #define rom_add_file_mr(_f, _mr, _i)            \
>>      rom_add_file(_f, NULL, 0, _i, false, _mr, NULL)
>>  #define rom_add_file_as(_f, _as, _i)            \
>>      rom_add_file(_f, NULL, 0, _i, false, NULL, _as)
>>  #define rom_add_file_fixed_as(_f, _a, _i, _as)          \
>>      rom_add_file(_f, NULL, _a, _i, false, NULL, _as)
>>  #define rom_add_blob_fixed_as(_f, _b, _l, _a, _as)      \
>> -    rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL, _as)
>> +    rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL, _as, true)
>>
>>  #define PC_ROM_MIN_VGA     0xc0000
>>  #define PC_ROM_MIN_OPTION  0xc8000
>>  #define PC_ROM_MAX         0xe0000
>>  #define PC_ROM_ALIGN       0x800
>> diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
>> index 5c27a1f0d50b..b980cbaebf43 100644
>> --- a/include/hw/nvram/fw_cfg.h
>> +++ b/include/hw/nvram/fw_cfg.h
>> @@ -134,10 +134,11 @@ void fw_cfg_add_file(FWCfgState *s, const char
>> *filename, void *data,
>>   * @filename: name of new fw_cfg file item
>>   * @callback: callback function
>>   * @callback_opaque: argument to be passed into callback function
>>   * @data: pointer to start of item data
>>   * @len: size of item data
>> + * @read_only: is file read only
>>   *
>>   * Add a new NAMED fw_cfg item as a raw "blob" of the given size. The
>> data
>>   * referenced by the starting pointer is only linked, NOT copied,
>> into the
>>   * data structure of the fw_cfg device.
>>   * The next available (unused) selector key starting at
>> FW_CFG_FILE_FIRST
>> @@ -149,11 +150,11 @@ void fw_cfg_add_file(FWCfgState *s, const char
>> *filename, void *data,
>>   * the fw_cfg control register, or passed to QEMU in
>> FWCfgDmaAccess.control
>>   * with FW_CFG_DMA_CTL_SELECT).
>>   */
>>  void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
>>                                FWCfgReadCallback callback, void
>> *callback_opaque,
>> -                              void *data, size_t len);
>> +                              void *data, size_t len, bool read_only);
>>
>>  /**
>>   * fw_cfg_modify_file:
>>   * @s: fw_cfg device being modified
>>   * @filename: name of new fw_cfg file item
>> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
>> index d4160dfa7d34..542fb67239db 100644
>> --- a/hw/arm/virt-acpi-build.c
>> +++ b/hw/arm/virt-acpi-build.c
>> @@ -807,11 +807,11 @@ static void virt_acpi_build_reset(void
>> *build_opaque)
>>  static MemoryRegion *acpi_add_rom_blob(AcpiBuildState *build_state,
>>                                         GArray *blob, const char *name,
>>                                         uint64_t max_size)
>>  {
>>      return rom_add_blob(name, blob->data, acpi_data_len(blob),
>> max_size, -1,
>> -                        name, virt_acpi_build_update, build_state,
>> NULL);
>> +                        name, virt_acpi_build_update, build_state,
>> NULL, true);
>>  }
>>
>>  static const VMStateDescription vmstate_virt_acpi_build = {
>>      .name = "virt_acpi_build",
>>      .version_id = 1,
>> diff --git a/hw/core/loader.c b/hw/core/loader.c
>> index 45742494e6fd..ee5abd6eb7f4 100644
>> --- a/hw/core/loader.c
>> +++ b/hw/core/loader.c
>> @@ -851,20 +851,20 @@ static void fw_cfg_resized(const char *id,
>> uint64_t length, void *host)
>>      if (fw_cfg) {
>>          fw_cfg_modify_file(fw_cfg, id + strlen("/rom@"), host, length);
>>      }
>>  }
>>
>> -static void *rom_set_mr(Rom *rom, Object *owner, const char *name)
>> +static void *rom_set_mr(Rom *rom, Object *owner, const char *name,
>> bool ro)
>>  {
>>      void *data;
>>
>>      rom->mr = g_malloc(sizeof(*rom->mr));
>>      memory_region_init_resizeable_ram(rom->mr, owner, name,
>>                                        rom->datasize, rom->romsize,
>>                                        fw_cfg_resized,
>>                                        &error_fatal);
>> -    memory_region_set_readonly(rom->mr, true);
>> +    memory_region_set_readonly(rom->mr, ro);
>>      vmstate_register_ram_global(rom->mr);
>>
>>      data = memory_region_get_ram_ptr(rom->mr);
>>      memcpy(data, rom->data, rom->datasize);
>>
>> @@ -940,11 +940,11 @@ int rom_add_file(const char *file, const char
>> *fw_dir,
>>          snprintf(fw_file_name, sizeof(fw_file_name), "%s/%s",
>> rom->fw_dir,
>>                   basename);
>>          snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
>>
>>          if ((!option_rom || mc->option_rom_has_mr) &&
>> mc->rom_file_has_mr) {
>> -            data = rom_set_mr(rom, OBJECT(fw_cfg), devpath);
>> +            data = rom_set_mr(rom, OBJECT(fw_cfg), devpath, true);
>>          } else {
>>              data = rom->data;
>>          }
>>
>>          fw_cfg_add_file(fw_cfg, fw_file_name, data, rom->romsize);
>> @@ -977,11 +977,11 @@ err:
>>  }
>>
>>  MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t
>> len,
>>                     size_t max_len, hwaddr addr, const char
>> *fw_file_name,
>>                     FWCfgReadCallback fw_callback, void *callback_opaque,
>> -                   AddressSpace *as)
>> +                   AddressSpace *as, bool read_only)
>>  {
>>      MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
>>      Rom *rom;
>>      MemoryRegion *mr = NULL;
>>
>> @@ -996,22 +996,26 @@ MemoryRegion *rom_add_blob(const char *name,
>> const void *blob, size_t len,
>>      rom_insert(rom);
>>      if (fw_file_name && fw_cfg) {
>>          char devpath[100];
>>          void *data;
>>
>> -        snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
>> +        if (read_only) {
>> +            snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
>> +        } else {
>> +            snprintf(devpath, sizeof(devpath), "/ram@%s", fw_file_name);
>> +        }
>>
>>          if (mc->rom_file_has_mr) {
>> -            data = rom_set_mr(rom, OBJECT(fw_cfg), devpath);
>> +            data = rom_set_mr(rom, OBJECT(fw_cfg), devpath, read_only);
>>              mr = rom->mr;
>>          } else {
>>              data = rom->data;
>>          }
>>
>>          fw_cfg_add_file_callback(fw_cfg, fw_file_name,
>>                                   fw_callback, callback_opaque,
>> -                                 data, rom->datasize);
>> +                                 data, rom->datasize, read_only);
>>      }
>>      return mr;
>>  }
>>
>>  /* This function is specific for elf program because we don't need to
>> allocate
>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>> index 9708cdc463df..965cb4cd4c51 100644
>> --- a/hw/i386/acpi-build.c
>> +++ b/hw/i386/acpi-build.c
>> @@ -2934,11 +2934,11 @@ static void acpi_build_reset(void *build_opaque)
>>  static MemoryRegion *acpi_add_rom_blob(AcpiBuildState *build_state,
>>                                         GArray *blob, const char *name,
>>                                         uint64_t max_size)
>>  {
>>      return rom_add_blob(name, blob->data, acpi_data_len(blob),
>> max_size, -1,
>> -                        name, acpi_build_update, build_state, NULL);
>> +                        name, acpi_build_update, build_state, NULL,
>> true);
>>  }
>>
>>  static const VMStateDescription vmstate_acpi_build = {
>>      .name = "acpi_build",
>>      .version_id = 1,
>> @@ -3000,11 +3000,11 @@ void acpi_setup(void)
>>          uint32_t rsdp_size = acpi_data_len(tables.rsdp);
>>
>>          build_state->rsdp = g_memdup(tables.rsdp->data, rsdp_size);
>>          fw_cfg_add_file_callback(pcms->fw_cfg, ACPI_BUILD_RSDP_FILE,
>>                                   acpi_build_update, build_state,
>> -                                 build_state->rsdp, rsdp_size);
>> +                                 build_state->rsdp, rsdp_size, true);
>>          build_state->rsdp_mr = NULL;
>>      } else {
>>          build_state->rsdp = NULL;
>>          build_state->rsdp_mr = acpi_add_rom_blob(build_state,
>> tables.rsdp,
>>                                                   
>> ACPI_BUILD_RSDP_FILE, 0);
>> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
>> index 3ebecb22606a..e0145c11a19b 100644
>> --- a/hw/nvram/fw_cfg.c
>> +++ b/hw/nvram/fw_cfg.c
>> @@ -52,15 +52,17 @@
>>  /* FW_CFG_DMA_CONTROL bits */
>>  #define FW_CFG_DMA_CTL_ERROR   0x01
>>  #define FW_CFG_DMA_CTL_READ    0x02
>>  #define FW_CFG_DMA_CTL_SKIP    0x04
>>  #define FW_CFG_DMA_CTL_SELECT  0x08
>> +#define FW_CFG_DMA_CTL_WRITE   0x10
>>
>>  #define FW_CFG_DMA_SIGNATURE 0x51454d5520434647ULL /* "QEMU CFG" */
>>
>>  typedef struct FWCfgEntry {
>>      uint32_t len;
>> +    bool allow_write;
>>      uint8_t *data;
>>      void *callback_opaque;
>>      FWCfgReadCallback read_callback;
>>  } FWCfgEntry;
>>
>> @@ -324,11 +326,11 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
>>  {
>>      dma_addr_t len;
>>      FWCfgDmaAccess dma;
>>      int arch;
>>      FWCfgEntry *e;
>> -    int read;
>> +    int read = 0, write = 0;
>>      dma_addr_t dma_addr;
>>
>>      /* Reset the address before the next access */
>>      dma_addr = s->dma_addr;
>>      s->dma_addr = 0;
>> @@ -351,12 +353,17 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
>>      e = (s->cur_entry == FW_CFG_INVALID) ? NULL :
>>          &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
>>
>>      if (dma.control & FW_CFG_DMA_CTL_READ) {
>>          read = 1;
>> +        write = 0;
>> +    } else if (dma.control & FW_CFG_DMA_CTL_WRITE) {
>> +        read = 0;
>> +        write = 1;
>>      } else if (dma.control & FW_CFG_DMA_CTL_SKIP) {
>>          read = 0;
>> +        write = 0;
>>      } else {
>>          dma.length = 0;
>>      }
>>
>>      dma.control = 0;
>> @@ -372,11 +379,13 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
>>              if (read) {
>>                  if (dma_memory_set(s->dma_as, dma.address, 0, len)) {
>>                      dma.control |= FW_CFG_DMA_CTL_ERROR;
>>                  }
>>              }
>> -
>> +            if (write) {
>> +                dma.control |= FW_CFG_DMA_CTL_ERROR;
>> +            }
>>          } else {
>>              if (dma.length <= (e->len - s->cur_offset)) {
>>                  len = dma.length;
>>              } else {
>>                  len = (e->len - s->cur_offset);
>> @@ -389,10 +398,18 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
>>                  if (dma_memory_write(s->dma_as, dma.address,
>>                                      &e->data[s->cur_offset], len)) {
>>                      dma.control |= FW_CFG_DMA_CTL_ERROR;
>>                  }
>>              }
>> +            if (write) {
>> +                if (!e->allow_write ||
>> +                    len != dma.length ||
>> +                    dma_memory_read(s->dma_as, dma.address,
>> +                                    &e->data[s->cur_offset], len)) {
>> +                    dma.control |= FW_CFG_DMA_CTL_ERROR;
>> +                }
>> +            }
>>
>>              s->cur_offset += len;
>>          }
>>
>>          dma.address += len;
>> @@ -584,11 +601,12 @@ static const VMStateDescription vmstate_fw_cfg = {
>>  };
>>
>>  static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key,
>>                                             FWCfgReadCallback callback,
>>                                             void *callback_opaque,
>> -                                           void *data, size_t len)
>> +                                           void *data, size_t len,
>> +                                           bool read_only)
>>  {
>>      int arch = !!(key & FW_CFG_ARCH_LOCAL);
>>
>>      key &= FW_CFG_ENTRY_MASK;
>>
>> @@ -597,10 +615,11 @@ static void
>> fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key,
>>
>>      s->entries[arch][key].data = data;
>>      s->entries[arch][key].len = (uint32_t)len;
>>      s->entries[arch][key].read_callback = callback;
>>      s->entries[arch][key].callback_opaque = callback_opaque;
>> +    s->entries[arch][key].allow_write = !read_only;
>>  }
>>
>>  static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key,
>>                                                void *data, size_t len)
>>  {
>> @@ -614,17 +633,18 @@ static void *fw_cfg_modify_bytes_read(FWCfgState
>> *s, uint16_t key,
>>      /* 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;
>>
>>      return ptr;
>>  }
>>
>>  void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t
>> len)
>>  {
>> -    fw_cfg_add_bytes_read_callback(s, key, NULL, NULL, data, len);
>> +    fw_cfg_add_bytes_read_callback(s, key, NULL, NULL, data, len, true);
>>  }
>>
>>  void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value)
>>  {
>>      size_t sz = strlen(value) + 1;
>> @@ -747,11 +767,11 @@ static int get_fw_cfg_order(FWCfgState *s, const
>> char *name)
>>      return FW_CFG_ORDER_OVERRIDE_LAST;
>>  }
>>
>>  void fw_cfg_add_file_callback(FWCfgState *s,  const char *filename,
>>                                FWCfgReadCallback callback, void
>> *callback_opaque,
>> -                              void *data, size_t len)
>> +                              void *data, size_t len, bool read_only)
>>  {
>>      int i, index, count;
>>      size_t dsize;
>>      MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
>>      int order = 0;
>> @@ -809,11 +829,12 @@ void fw_cfg_add_file_callback(FWCfgState *s, 
>> const char *filename,
>>              exit(1);
>>          }
>>      }
>>
>>      fw_cfg_add_bytes_read_callback(s, FW_CFG_FILE_FIRST + index,
>> -                                   callback, callback_opaque, data,
>> len);
>> +                                   callback, callback_opaque, data, len,
>> +                                   read_only);
>>
>>      s->files->f[index].size   = cpu_to_be32(len);
>>      s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index);
>>      s->entry_order[index] = order;
>>      trace_fw_cfg_add_file(s, index, s->files->f[index].name, len);
>> @@ -822,11 +843,11 @@ void fw_cfg_add_file_callback(FWCfgState *s, 
>> const char *filename,
>>  }
>>
>>  void fw_cfg_add_file(FWCfgState *s,  const char *filename,
>>                       void *data, size_t len)
>>  {
>> -    fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len);
>> +    fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len, true);
>>  }
>>
>>  void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
>>                          void *data, size_t len)
>>  {
>> @@ -845,11 +866,11 @@ void *fw_cfg_modify_file(FWCfgState *s, const
>> char *filename,
>>              s->files->f[i].size   = cpu_to_be32(len);
>>              return ptr;
>>          }
>>      }
>>      /* add new one */
>> -    fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len);
>> +    fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len, true);
>>      return NULL;
>>  }
>>
>>  static void fw_cfg_machine_reset(void *opaque)
>>  {
>>
> 
> Hi Laszlo,
> The 'write' documentation is very helpful, thanks.
> I would add that QEMU will 'use' the written values
> when the guest selects another file (for reading),
> that being protocol specific, of course.
> But maybe is not connected directly.

I think it's not connected; it's a general characteristic that callbacks
are invoked at item selection.

Also, the data that a given callback consumes to produce the selected
item's new contents may or may not include any fw_cfg data written
previously (for example, with the ACPI linker/loader, the regenerated
contents are independent of any fw_cfg writes).

> 
> Reviewed-by: Marcel Apfelbaum <marcel@redhat.com>

Thanks!

I'm about to rebase / rework this series; if this patch applies with at
most minor updates, I'll keep your R-b.

Cheers,
Laszlo

> Thanks,
> Marcel
> 

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

* Re: [Qemu-devel] [PATCH v4 2/7] fw-cfg: turn FW_CFG_FILE_SLOTS into a device property
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 2/7] fw-cfg: turn FW_CFG_FILE_SLOTS into a device property Laszlo Ersek
  2016-12-02 11:10   ` Gerd Hoffmann
  2016-12-06 10:50   ` Igor Mammedov
@ 2017-01-10 15:02   ` Michael S. Tsirkin
  2 siblings, 0 replies; 46+ messages in thread
From: Michael S. Tsirkin @ 2017-01-10 15:02 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: qemu devel list, Gabriel L. Somlo, Gerd Hoffmann, Igor Mammedov,
	Paolo Bonzini

On Thu, Dec 01, 2016 at 06:06:19PM +0100, Laszlo Ersek wrote:
> We'd like to raise the value of FW_CFG_FILE_SLOTS. Doing it naively could
> lead to problems with backward migration: a more recent QEMU (running an
> older machine type) would allow the guest, in fw_cfg_select(), to select a
> high key value that is unavailable in the same machine type implemented by
> the older (target) QEMU. On the target host, fw_cfg_data_read() for
> example could dereference nonexistent entries.
> 
> As first step, size the FWCfgState.entries[*] and FWCfgState.entry_order
> arrays dynamically. All three array sizes will be influenced by the new
> field (and device property) FWCfgState.file_slots.
> 
> Make the following changes:
> 
> - Replace the FW_CFG_FILE_SLOTS macro with FW_CFG_FILE_SLOTS_TRAD
>   (traditional count of fw_cfg file slots) in the header file. The value
>   remains 0x10.
> 
> - Replace all uses of FW_CFG_FILE_SLOTS with a helper function called
>   fw_cfg_file_slots(), returning the new property.
> 
> - Eliminate the macro FW_CFG_MAX_ENTRY, and replace all its uses with a
>   helper function called fw_cfg_max_entry().
> 
> - In the MMIO- and IO-mapped realize functions both, allocate all three
>   arrays dynamically, based on the new property.
> 
> - The new property defaults to 0x20; however at the moment we forcibly set
>   it to FW_CFG_FILE_SLOTS_TRAD on all code paths available to board code
>   (namely in the fw_cfg_init_io_dma() and fw_cfg_init_mem_wide() helper
>   functions). This is going to be customized in the following patches.
> 
> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>

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

> ---
> 
> Notes:
>     I know that upstream doesn't care about backward migration, but some
>     downstreams might.
> 
>  docs/specs/fw_cfg.txt          |  2 +-
>  include/hw/nvram/fw_cfg_keys.h |  3 +-
>  hw/nvram/fw_cfg.c              | 85 ++++++++++++++++++++++++++++++++++++++----
>  3 files changed, 79 insertions(+), 11 deletions(-)
> 
> diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
> index a19e2adbe1c6..84e2978706f5 100644
> --- a/docs/specs/fw_cfg.txt
> +++ b/docs/specs/fw_cfg.txt
> @@ -154,11 +154,11 @@ Selector Reg.    Range Usage
>  0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW
>                                   through the DMA interface in QEMU v2.9+)
>  0xc000 - 0xffff  Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
>  
>  In practice, the number of allowed firmware configuration items is given
> -by the value of FW_CFG_MAX_ENTRY (see fw_cfg.h).
> +by the value (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS_TRAD) (see fw_cfg.h).
>  
>  = Guest-side DMA Interface =
>  
>  If bit 1 of the feature bitmap is set, the DMA interface is present. This does
>  not replace the existing fw_cfg interface, it is an add-on. This interface
> diff --git a/include/hw/nvram/fw_cfg_keys.h b/include/hw/nvram/fw_cfg_keys.h
> index 0f3e871884c0..627589793671 100644
> --- a/include/hw/nvram/fw_cfg_keys.h
> +++ b/include/hw/nvram/fw_cfg_keys.h
> @@ -27,12 +27,11 @@
>  #define FW_CFG_SETUP_SIZE       0x17
>  #define FW_CFG_SETUP_DATA       0x18
>  #define FW_CFG_FILE_DIR         0x19
>  
>  #define FW_CFG_FILE_FIRST       0x20
> -#define FW_CFG_FILE_SLOTS       0x10
> -#define FW_CFG_MAX_ENTRY        (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS)
> +#define FW_CFG_FILE_SLOTS_TRAD  0x10
>  
>  #define FW_CFG_WRITE_CHANNEL    0x4000
>  #define FW_CFG_ARCH_LOCAL       0x8000
>  #define FW_CFG_ENTRY_MASK       (~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL))
>  
> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> index e0145c11a19b..2e1441c09750 100644
> --- a/hw/nvram/fw_cfg.c
> +++ b/hw/nvram/fw_cfg.c
> @@ -31,10 +31,13 @@
>  #include "hw/sysbus.h"
>  #include "trace.h"
>  #include "qemu/error-report.h"
>  #include "qemu/config-file.h"
>  #include "qemu/cutils.h"
> +#include "qapi/error.h"
> +
> +#define FW_CFG_FILE_SLOTS_DFLT 0x20
>  
>  #define FW_CFG_NAME "fw_cfg"
>  #define FW_CFG_PATH "/machine/" FW_CFG_NAME
>  
>  #define TYPE_FW_CFG     "fw_cfg"
> @@ -69,12 +72,13 @@ typedef struct FWCfgEntry {
>  struct FWCfgState {
>      /*< private >*/
>      SysBusDevice parent_obj;
>      /*< public >*/
>  
> -    FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
> -    int entry_order[FW_CFG_MAX_ENTRY];
> +    uint32_t file_slots;
> +    FWCfgEntry *entries[2];
> +    int *entry_order;
>      FWCfgFiles *files;
>      uint16_t cur_entry;
>      uint32_t cur_offset;
>      Notifier machine_ready;
>  
> @@ -255,17 +259,27 @@ static void fw_cfg_reboot(FWCfgState *s)
>  static void fw_cfg_write(FWCfgState *s, uint8_t value)
>  {
>      /* nothing, write support removed in QEMU v2.4+ */
>  }
>  
> +static inline uint32_t fw_cfg_file_slots(const FWCfgState *s)
> +{
> +    return s->file_slots;
> +}
> +
> +static inline uint32_t fw_cfg_max_entry(const FWCfgState *s)
> +{
> +    return FW_CFG_FILE_FIRST + fw_cfg_file_slots(s);
> +}
> +
>  static int fw_cfg_select(FWCfgState *s, uint16_t key)
>  {
>      int arch, ret;
>      FWCfgEntry *e;
>  
>      s->cur_offset = 0;
> -    if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
> +    if ((key & FW_CFG_ENTRY_MASK) >= fw_cfg_max_entry(s)) {
>          s->cur_entry = FW_CFG_INVALID;
>          ret = 0;
>      } else {
>          s->cur_entry = key;
>          ret = 1;
> @@ -608,11 +622,11 @@ static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key,
>  {
>      int arch = !!(key & FW_CFG_ARCH_LOCAL);
>  
>      key &= FW_CFG_ENTRY_MASK;
>  
> -    assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
> +    assert(key < fw_cfg_max_entry(s) && len < UINT32_MAX);
>      assert(s->entries[arch][key].data == NULL); /* avoid key conflict */
>  
>      s->entries[arch][key].data = data;
>      s->entries[arch][key].len = (uint32_t)len;
>      s->entries[arch][key].read_callback = callback;
> @@ -626,11 +640,11 @@ static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key,
>      void *ptr;
>      int arch = !!(key & FW_CFG_ARCH_LOCAL);
>  
>      key &= FW_CFG_ENTRY_MASK;
>  
> -    assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
> +    assert(key < fw_cfg_max_entry(s) && len < UINT32_MAX);
>  
>      /* 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;
> @@ -775,17 +789,17 @@ void fw_cfg_add_file_callback(FWCfgState *s,  const char *filename,
>      size_t dsize;
>      MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
>      int order = 0;
>  
>      if (!s->files) {
> -        dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * FW_CFG_FILE_SLOTS;
> +        dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * fw_cfg_file_slots(s);
>          s->files = g_malloc0(dsize);
>          fw_cfg_add_bytes(s, FW_CFG_FILE_DIR, s->files, dsize);
>      }
>  
>      count = be32_to_cpu(s->files->count);
> -    assert(count < FW_CFG_FILE_SLOTS);
> +    assert(count < fw_cfg_file_slots(s));
>  
>      /* Find the insertion point. */
>      if (mc->legacy_fw_cfg_order) {
>          /*
>           * Sort by order. For files with the same order, we keep them
> @@ -855,11 +869,11 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
>      void *ptr = NULL;
>  
>      assert(s->files);
>  
>      index = be32_to_cpu(s->files->count);
> -    assert(index < FW_CFG_FILE_SLOTS);
> +    assert(index < fw_cfg_file_slots(s));
>  
>      for (i = 0; i < index; i++) {
>          if (strcmp(filename, s->files->f[i].name) == 0) {
>              ptr = fw_cfg_modify_bytes_read(s, FW_CFG_FILE_FIRST + i,
>                                             data, len);
> @@ -926,10 +940,16 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
>      qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase);
>      if (!dma_requested) {
>          qdev_prop_set_bit(dev, "dma_enabled", false);
>      }
>  
> +    /* Once we expose the "file_slots" property to callers of
> +     * fw_cfg_init_io_dma(), the following setting should become conditional on
> +     * the input parameter being lower than the current value of the property.
> +     */
> +    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
> +
>      fw_cfg_init1(dev);
>      s = FW_CFG(dev);
>  
>      if (s->dma_enabled) {
>          /* 64 bits for the address field */
> @@ -963,10 +983,17 @@ FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
>      qdev_prop_set_uint32(dev, "data_width", data_width);
>      if (!dma_requested) {
>          qdev_prop_set_bit(dev, "dma_enabled", false);
>      }
>  
> +    /* Once we expose the "file_slots" property to callers of
> +     * fw_cfg_init_mem_wide(), the following setting should become conditional
> +     * on the input parameter being lower than the current value of the
> +     * property. Refer to fw_cfg_init_io_dma().
> +     */
> +    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
> +
>      fw_cfg_init1(dev);
>  
>      sbd = SYS_BUS_DEVICE(dev);
>      sysbus_mmio_map(sbd, 0, ctl_addr);
>      sysbus_mmio_map(sbd, 1, data_addr);
> @@ -1012,23 +1039,56 @@ static const TypeInfo fw_cfg_info = {
>      .abstract      = true,
>      .instance_size = sizeof(FWCfgState),
>      .class_init    = fw_cfg_class_init,
>  };
>  
> +static void fw_cfg_file_slots_allocate(FWCfgState *s, Error **errp)
> +{
> +    uint16_t file_slots_max;
> +
> +    if (fw_cfg_file_slots(s) < FW_CFG_FILE_SLOTS_TRAD) {
> +        error_setg(errp, "\"file_slots\" must be at least 0x%x",
> +                   FW_CFG_FILE_SLOTS_TRAD);
> +        return;
> +    }
> +
> +    /* (UINT16_MAX & FW_CFG_ENTRY_MASK) is the highest inclusive selector value
> +     * that we permit. The actual (exclusive) value coming from the
> +     * configuration is (FW_CFG_FILE_FIRST + fw_cfg_file_slots(s)). */
> +    file_slots_max = (UINT16_MAX & FW_CFG_ENTRY_MASK) - FW_CFG_FILE_FIRST + 1;
> +    if (fw_cfg_file_slots(s) > file_slots_max) {
> +        error_setg(errp, "\"file_slots\" must not exceed 0x%" PRIx16,
> +                   file_slots_max);
> +        return;
> +    }
> +
> +    s->entries[0] = g_new0(FWCfgEntry, fw_cfg_max_entry(s));
> +    s->entries[1] = g_new0(FWCfgEntry, fw_cfg_max_entry(s));
> +    s->entry_order = g_new0(int, fw_cfg_max_entry(s));
> +}
>  
>  static Property fw_cfg_io_properties[] = {
>      DEFINE_PROP_UINT32("iobase", FWCfgIoState, iobase, -1),
>      DEFINE_PROP_UINT32("dma_iobase", FWCfgIoState, dma_iobase, -1),
>      DEFINE_PROP_BOOL("dma_enabled", FWCfgIoState, parent_obj.dma_enabled,
>                       true),
> +    DEFINE_PROP_UINT32("file_slots", FWCfgIoState, parent_obj.file_slots,
> +                       FW_CFG_FILE_SLOTS_DFLT),
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
>  static void fw_cfg_io_realize(DeviceState *dev, Error **errp)
>  {
>      FWCfgIoState *s = FW_CFG_IO(dev);
>      SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +    Error *local_err = NULL;
> +
> +    fw_cfg_file_slots_allocate(FW_CFG(s), &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
>  
>      /* when using port i/o, the 8-bit data register ALWAYS overlaps
>       * with half of the 16-bit control register. Hence, the total size
>       * of the i/o region used is FW_CFG_CTL_SIZE */
>      memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops,
> @@ -1061,18 +1121,27 @@ static const TypeInfo fw_cfg_io_info = {
>  
>  static Property fw_cfg_mem_properties[] = {
>      DEFINE_PROP_UINT32("data_width", FWCfgMemState, data_width, -1),
>      DEFINE_PROP_BOOL("dma_enabled", FWCfgMemState, parent_obj.dma_enabled,
>                       true),
> +    DEFINE_PROP_UINT32("file_slots", FWCfgMemState, parent_obj.file_slots,
> +                       FW_CFG_FILE_SLOTS_DFLT),
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
>  static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
>  {
>      FWCfgMemState *s = FW_CFG_MEM(dev);
>      SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>      const MemoryRegionOps *data_ops = &fw_cfg_data_mem_ops;
> +    Error *local_err = NULL;
> +
> +    fw_cfg_file_slots_allocate(FW_CFG(s), &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
>  
>      memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops,
>                            FW_CFG(s), "fwcfg.ctl", FW_CFG_CTL_SIZE);
>      sysbus_init_mmio(sbd, &s->ctl_iomem);
>  
> -- 
> 2.9.2
> 

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

* Re: [Qemu-devel] [PATCH v4 3/7] fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma()
  2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 3/7] fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma() Laszlo Ersek
  2016-12-06 11:49   ` Igor Mammedov
@ 2017-01-10 15:02   ` Michael S. Tsirkin
  1 sibling, 0 replies; 46+ messages in thread
From: Michael S. Tsirkin @ 2017-01-10 15:02 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: qemu devel list, Gabriel L. Somlo, Gerd Hoffmann, Igor Mammedov,
	Paolo Bonzini

On Thu, Dec 01, 2016 at 06:06:20PM +0100, Laszlo Ersek wrote:
> Accordingly, generalize the "file_slots" minimum calculation in
> fw_cfg_init_io_dma(), and move the constant FW_CFG_FILE_SLOTS_TRAD
> argument to the callers of fw_cfg_init_io_dma().
> 
> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>

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

> ---
>  docs/specs/fw_cfg.txt     |  4 ++--
>  include/hw/nvram/fw_cfg.h |  2 +-
>  hw/i386/pc.c              |  3 ++-
>  hw/nvram/fw_cfg.c         | 13 ++++++-------
>  4 files changed, 11 insertions(+), 11 deletions(-)
> 
> diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
> index 84e2978706f5..4a6888b511f4 100644
> --- a/docs/specs/fw_cfg.txt
> +++ b/docs/specs/fw_cfg.txt
> @@ -153,12 +153,12 @@ Selector Reg.    Range Usage
>  0x4000 - 0x7fff  Generic (0x0000 - 0x3fff, RW, ignored in QEMU v2.4+)
>  0x8000 - 0xbfff  Arch. Specific (0x0000 - 0x3fff, generally RO, possibly RW
>                                   through the DMA interface in QEMU v2.9+)
>  0xc000 - 0xffff  Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
>  
> -In practice, the number of allowed firmware configuration items is given
> -by the value (FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS_TRAD) (see fw_cfg.h).
> +In practice, the number of allowed firmware configuration items depends on the
> +machine type.
>  
>  = Guest-side DMA Interface =
>  
>  If bit 1 of the feature bitmap is set, the DMA interface is present. This does
>  not replace the existing fw_cfg interface, it is an add-on. This interface
> diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
> index b980cbaebf43..e9a6b6aa968c 100644
> --- a/include/hw/nvram/fw_cfg.h
> +++ b/include/hw/nvram/fw_cfg.h
> @@ -173,11 +173,11 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
>   */
>  void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data,
>                           size_t len);
>  
>  FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
> -                                AddressSpace *dma_as);
> +                                AddressSpace *dma_as, uint32_t file_slots);
>  FWCfgState *fw_cfg_init_io(uint32_t iobase);
>  FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr);
>  FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
>                                   hwaddr data_addr, uint32_t data_width,
>                                   hwaddr dma_addr, AddressSpace *dma_as);
> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> index a9e64a88e5e7..5d929d8fc887 100644
> --- a/hw/i386/pc.c
> +++ b/hw/i386/pc.c
> @@ -741,11 +741,12 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms)
>  {
>      FWCfgState *fw_cfg;
>      uint64_t *numa_fw_cfg;
>      int i, j;
>  
> -    fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as);
> +    fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as,
> +                                FW_CFG_FILE_SLOTS_TRAD);
>      fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus);
>  
>      /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
>       *
>       * For machine types prior to 1.8, SeaBIOS needs FW_CFG_MAX_CPUS for
> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> index 2e1441c09750..c33c76ab93b1 100644
> --- a/hw/nvram/fw_cfg.c
> +++ b/hw/nvram/fw_cfg.c
> @@ -926,11 +926,11 @@ static void fw_cfg_init1(DeviceState *dev)
>      s->machine_ready.notify = fw_cfg_machine_ready;
>      qemu_add_machine_init_done_notifier(&s->machine_ready);
>  }
>  
>  FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
> -                                AddressSpace *dma_as)
> +                                AddressSpace *dma_as, uint32_t file_slots)
>  {
>      DeviceState *dev;
>      FWCfgState *s;
>      uint32_t version = FW_CFG_VERSION;
>      bool dma_requested = dma_iobase && dma_as;
> @@ -940,15 +940,14 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
>      qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase);
>      if (!dma_requested) {
>          qdev_prop_set_bit(dev, "dma_enabled", false);
>      }
>  
> -    /* Once we expose the "file_slots" property to callers of
> -     * fw_cfg_init_io_dma(), the following setting should become conditional on
> -     * the input parameter being lower than the current value of the property.
> -     */
> -    qdev_prop_set_uint32(dev, "file_slots", FW_CFG_FILE_SLOTS_TRAD);
> +    if (file_slots < object_property_get_int(OBJECT(dev), "file_slots",
> +                                             &error_abort)) {
> +        qdev_prop_set_uint32(dev, "file_slots", file_slots);
> +    }
>  
>      fw_cfg_init1(dev);
>      s = FW_CFG(dev);
>  
>      if (s->dma_enabled) {
> @@ -964,11 +963,11 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
>      return s;
>  }
>  
>  FWCfgState *fw_cfg_init_io(uint32_t iobase)
>  {
> -    return fw_cfg_init_io_dma(iobase, 0, NULL);
> +    return fw_cfg_init_io_dma(iobase, 0, NULL, FW_CFG_FILE_SLOTS_TRAD);
>  }
>  
>  FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
>                                   hwaddr data_addr, uint32_t data_width,
>                                   hwaddr dma_addr, AddressSpace *dma_as)
> -- 
> 2.9.2
> 

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

* Re: [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI
  2016-12-01 17:06 [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI Laszlo Ersek
                   ` (7 preceding siblings ...)
  2016-12-20 23:01 ` [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI no-reply
@ 2017-01-10 15:06 ` Michael S. Tsirkin
  2017-01-10 15:23   ` Laszlo Ersek
  8 siblings, 1 reply; 46+ messages in thread
From: Michael S. Tsirkin @ 2017-01-10 15:06 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: qemu devel list, Gabriel L. Somlo, Eduardo Habkost,
	Gerd Hoffmann, Igor Mammedov, Michael Walle, Paolo Bonzini,
	Peter Maydell, Shannon Zhao, qemu-arm

On Thu, Dec 01, 2016 at 06:06:17PM +0100, Laszlo Ersek wrote:
> * This is version 4 of the series; the last version was at
>   <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03582.html>.
> 
>   This version is practically a rewrite from scratch, seeking to address
>   the v3 feedback. Here's what the individual patches do:
> 
>   - Patch #1 rebases and extends Michael's "writeable fw_cfg blobs"
>     patch from Feb/March 2016. The changes relative to the original
>     patch are documented in the commit message (the code changes are
>     minimal).
> 
>   - Patches #2 and #3 turn the FW_CFG_FILE_SLOTS constant into a device
>     property, and expose the desired number of fw_cfg file slots to
>     board code. This is meant to address a concern raised by Paolo in
>     the v2 review
>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03125.html>,
>     namely that we're about to run out of FW_CFG_FILE_SLOTS.
> 
>   - Patch #4 introduces the "pc-q35-2.9" and "pc-i440fx-2.9" machine
>     types, which are allowed to take advantage of the new default for
>     fw_cfg file slots (0x20 rather than 0x10).
> 
>   - Patch #5 introduces SMI feature negotiation via fw_cfg, with the
>     following new files:
> 
>     - etc/smi/host-features
>     - etc/smi/guest-features
>     - etc/smi/features-ok
> 
>     This is supposed to follow Michael's recommendation re: imitating
>     virtio
>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03218.html>.
> 
>     The guest-features file is freely writeable by the guest (no write
>     callbacks in fw_cfg), and the feature validation & lockdown occurs
>     when the guest selects the features-ok file (for reading).
> 
>     Board code is allowed to choose the host feature bitmap to
>     advertise.
> 
>     This patch doesn't add any specific SMI features yet.
> 
>   - Patch #6 adds the ICH9_LPC_SMI_F_BROADCAST feature.
> 
>   - Patch #7 introduces the PCMachineClass.get_smi_host_features method,
>     and implements it for "pc-q35-2.9" and later. The idea is to tie the
>     SMI host features to machine types, and let the machine types
>     calculate their host features with code (i.e., not just a constant).
> 
>     In this patch, the "pc-q35-2.9" machine type exposes the
>     ICH9_LPC_SMI_F_BROADCAST feature iff (smp_cpus == max_cpus), that
>     is, when VCPU hotplug is not possible. (Also from Paolo's v3
>     feedback, in
>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg04919.html>.)
> 
> * I've written the OVMF side patches too and tested them together
>   (including gdb / debug messages for "white box" testing).
> 
> * Note that this version depends on the following PULL req from Michael:
> 
>   [Qemu-devel] [PULL 0/5] virtio, vhost, pc: fixes
>   http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg05503.html
> 
>   In particular on the following patch:
>   "loader: fix handling of custom address spaces when adding ROM blobs"
> 
> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Eduardo Habkost <ehabkost@redhat.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Michael Walle <michael@walle.cc>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Peter Maydell <peter.maydell@linaro.org>
> Cc: Shannon Zhao <zhaoshenglong@huawei.com>
> Cc: qemu-arm@nongnu.org
> 
> Thanks
> Laszlo

So I reviewed fw cfg stuff, looks good to me. I'd prefer Paolo to review
and merge broadcast SMI stuff as appropriate.  Paolo, makes sense?


> Laszlo Ersek (6):
>   fw-cfg: turn FW_CFG_FILE_SLOTS into a device property
>   fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma()
>   hw/i386/pc: introduce 2.9 machine types with 0x20 fw_cfg file slots
>   hw/isa/lpc_ich9: add SMI feature negotiation via fw_cfg
>   hw/isa/lpc_ich9: add broadcast SMI feature
>   hw/i386/pc_q35: advertise broadcast SMI if VCPU hotplug is turned off
> 
> Michael S. Tsirkin (1):
>   fw-cfg: support writeable blobs
> 
>  docs/specs/fw_cfg.txt          |  36 +++++++++---
>  hw/lm32/lm32_hwsetup.h         |   2 +-
>  include/hw/compat.h            |  11 ++++
>  include/hw/i386/ich9.h         |  15 ++++-
>  include/hw/i386/pc.h           |   4 ++
>  include/hw/loader.h            |   7 ++-
>  include/hw/nvram/fw_cfg.h      |   5 +-
>  include/hw/nvram/fw_cfg_keys.h |   7 ++-
>  hw/arm/virt-acpi-build.c       |   2 +-
>  hw/core/loader.c               |  18 +++---
>  hw/i386/acpi-build.c           |   4 +-
>  hw/i386/pc.c                   |   3 +-
>  hw/i386/pc_piix.c              |  16 +++++-
>  hw/i386/pc_q35.c               |  37 ++++++++++++-
>  hw/isa/lpc_ich9.c              |  92 +++++++++++++++++++++++++++++-
>  hw/nvram/fw_cfg.c              | 123 +++++++++++++++++++++++++++++++++++------
>  16 files changed, 326 insertions(+), 56 deletions(-)
> 
> -- 
> 2.9.2

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

* Re: [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI
  2017-01-10 15:06 ` [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI Michael S. Tsirkin
@ 2017-01-10 15:23   ` Laszlo Ersek
  2017-01-10 16:05     ` Michael S. Tsirkin
  2017-01-10 16:21     ` Igor Mammedov
  0 siblings, 2 replies; 46+ messages in thread
From: Laszlo Ersek @ 2017-01-10 15:23 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: qemu devel list, Gabriel L. Somlo, Eduardo Habkost,
	Gerd Hoffmann, Igor Mammedov, Michael Walle, Paolo Bonzini,
	Peter Maydell, Shannon Zhao, qemu-arm

On 01/10/17 16:06, Michael S. Tsirkin wrote:
> On Thu, Dec 01, 2016 at 06:06:17PM +0100, Laszlo Ersek wrote:
>> * This is version 4 of the series; the last version was at
>>   <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03582.html>.
>>
>>   This version is practically a rewrite from scratch, seeking to address
>>   the v3 feedback. Here's what the individual patches do:
>>
>>   - Patch #1 rebases and extends Michael's "writeable fw_cfg blobs"
>>     patch from Feb/March 2016. The changes relative to the original
>>     patch are documented in the commit message (the code changes are
>>     minimal).
>>
>>   - Patches #2 and #3 turn the FW_CFG_FILE_SLOTS constant into a device
>>     property, and expose the desired number of fw_cfg file slots to
>>     board code. This is meant to address a concern raised by Paolo in
>>     the v2 review
>>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03125.html>,
>>     namely that we're about to run out of FW_CFG_FILE_SLOTS.
>>
>>   - Patch #4 introduces the "pc-q35-2.9" and "pc-i440fx-2.9" machine
>>     types, which are allowed to take advantage of the new default for
>>     fw_cfg file slots (0x20 rather than 0x10).
>>
>>   - Patch #5 introduces SMI feature negotiation via fw_cfg, with the
>>     following new files:
>>
>>     - etc/smi/host-features
>>     - etc/smi/guest-features
>>     - etc/smi/features-ok
>>
>>     This is supposed to follow Michael's recommendation re: imitating
>>     virtio
>>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03218.html>.
>>
>>     The guest-features file is freely writeable by the guest (no write
>>     callbacks in fw_cfg), and the feature validation & lockdown occurs
>>     when the guest selects the features-ok file (for reading).
>>
>>     Board code is allowed to choose the host feature bitmap to
>>     advertise.
>>
>>     This patch doesn't add any specific SMI features yet.
>>
>>   - Patch #6 adds the ICH9_LPC_SMI_F_BROADCAST feature.
>>
>>   - Patch #7 introduces the PCMachineClass.get_smi_host_features method,
>>     and implements it for "pc-q35-2.9" and later. The idea is to tie the
>>     SMI host features to machine types, and let the machine types
>>     calculate their host features with code (i.e., not just a constant).
>>
>>     In this patch, the "pc-q35-2.9" machine type exposes the
>>     ICH9_LPC_SMI_F_BROADCAST feature iff (smp_cpus == max_cpus), that
>>     is, when VCPU hotplug is not possible. (Also from Paolo's v3
>>     feedback, in
>>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg04919.html>.)
>>
>> * I've written the OVMF side patches too and tested them together
>>   (including gdb / debug messages for "white box" testing).
>>
>> * Note that this version depends on the following PULL req from Michael:
>>
>>   [Qemu-devel] [PULL 0/5] virtio, vhost, pc: fixes
>>   http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg05503.html
>>
>>   In particular on the following patch:
>>   "loader: fix handling of custom address spaces when adding ROM blobs"
>>
>> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
>> Cc: Eduardo Habkost <ehabkost@redhat.com>
>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>> Cc: Igor Mammedov <imammedo@redhat.com>
>> Cc: Michael Walle <michael@walle.cc>
>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>> Cc: Peter Maydell <peter.maydell@linaro.org>
>> Cc: Shannon Zhao <zhaoshenglong@huawei.com>
>> Cc: qemu-arm@nongnu.org
>>
>> Thanks
>> Laszlo
> 
> So I reviewed fw cfg stuff, looks good to me.

Thank you.

I should note that Igor suggested / requested changes for patches #2 and
#3; the sub-threads start at

http://lists.nongnu.org/archive/html/qemu-devel/2016-12/msg00695.html
msg-id: <20161206115038.4495a217@nial.brq.redhat.com>

http://lists.nongnu.org/archive/html/qemu-devel/2016-12/msg00706.html
msg-id: <20161206124906.76a41896@nial.brq.redhat.com>

I was about to rework the patches based on his feedback. Should we
resume those discussions?

> I'd prefer Paolo to review
> and merge broadcast SMI stuff as appropriate.  Paolo, makes sense?

If it helps, I can split the series into two "waves", and deal only with
fw_cfg first.

Thanks!
Laszlo

> 
> 
>> Laszlo Ersek (6):
>>   fw-cfg: turn FW_CFG_FILE_SLOTS into a device property
>>   fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma()
>>   hw/i386/pc: introduce 2.9 machine types with 0x20 fw_cfg file slots
>>   hw/isa/lpc_ich9: add SMI feature negotiation via fw_cfg
>>   hw/isa/lpc_ich9: add broadcast SMI feature
>>   hw/i386/pc_q35: advertise broadcast SMI if VCPU hotplug is turned off
>>
>> Michael S. Tsirkin (1):
>>   fw-cfg: support writeable blobs
>>
>>  docs/specs/fw_cfg.txt          |  36 +++++++++---
>>  hw/lm32/lm32_hwsetup.h         |   2 +-
>>  include/hw/compat.h            |  11 ++++
>>  include/hw/i386/ich9.h         |  15 ++++-
>>  include/hw/i386/pc.h           |   4 ++
>>  include/hw/loader.h            |   7 ++-
>>  include/hw/nvram/fw_cfg.h      |   5 +-
>>  include/hw/nvram/fw_cfg_keys.h |   7 ++-
>>  hw/arm/virt-acpi-build.c       |   2 +-
>>  hw/core/loader.c               |  18 +++---
>>  hw/i386/acpi-build.c           |   4 +-
>>  hw/i386/pc.c                   |   3 +-
>>  hw/i386/pc_piix.c              |  16 +++++-
>>  hw/i386/pc_q35.c               |  37 ++++++++++++-
>>  hw/isa/lpc_ich9.c              |  92 +++++++++++++++++++++++++++++-
>>  hw/nvram/fw_cfg.c              | 123 +++++++++++++++++++++++++++++++++++------
>>  16 files changed, 326 insertions(+), 56 deletions(-)
>>
>> -- 
>> 2.9.2

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

* Re: [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI
  2017-01-10 15:23   ` Laszlo Ersek
@ 2017-01-10 16:05     ` Michael S. Tsirkin
  2017-01-10 16:19       ` Laszlo Ersek
  2017-01-10 16:21     ` Igor Mammedov
  1 sibling, 1 reply; 46+ messages in thread
From: Michael S. Tsirkin @ 2017-01-10 16:05 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: qemu devel list, Gabriel L. Somlo, Eduardo Habkost,
	Gerd Hoffmann, Igor Mammedov, Michael Walle, Paolo Bonzini,
	Peter Maydell, Shannon Zhao, qemu-arm

On Tue, Jan 10, 2017 at 04:23:41PM +0100, Laszlo Ersek wrote:
> On 01/10/17 16:06, Michael S. Tsirkin wrote:
> > On Thu, Dec 01, 2016 at 06:06:17PM +0100, Laszlo Ersek wrote:
> >> * This is version 4 of the series; the last version was at
> >>   <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03582.html>.
> >>
> >>   This version is practically a rewrite from scratch, seeking to address
> >>   the v3 feedback. Here's what the individual patches do:
> >>
> >>   - Patch #1 rebases and extends Michael's "writeable fw_cfg blobs"
> >>     patch from Feb/March 2016. The changes relative to the original
> >>     patch are documented in the commit message (the code changes are
> >>     minimal).
> >>
> >>   - Patches #2 and #3 turn the FW_CFG_FILE_SLOTS constant into a device
> >>     property, and expose the desired number of fw_cfg file slots to
> >>     board code. This is meant to address a concern raised by Paolo in
> >>     the v2 review
> >>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03125.html>,
> >>     namely that we're about to run out of FW_CFG_FILE_SLOTS.
> >>
> >>   - Patch #4 introduces the "pc-q35-2.9" and "pc-i440fx-2.9" machine
> >>     types, which are allowed to take advantage of the new default for
> >>     fw_cfg file slots (0x20 rather than 0x10).
> >>
> >>   - Patch #5 introduces SMI feature negotiation via fw_cfg, with the
> >>     following new files:
> >>
> >>     - etc/smi/host-features
> >>     - etc/smi/guest-features
> >>     - etc/smi/features-ok
> >>
> >>     This is supposed to follow Michael's recommendation re: imitating
> >>     virtio
> >>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03218.html>.
> >>
> >>     The guest-features file is freely writeable by the guest (no write
> >>     callbacks in fw_cfg), and the feature validation & lockdown occurs
> >>     when the guest selects the features-ok file (for reading).
> >>
> >>     Board code is allowed to choose the host feature bitmap to
> >>     advertise.
> >>
> >>     This patch doesn't add any specific SMI features yet.
> >>
> >>   - Patch #6 adds the ICH9_LPC_SMI_F_BROADCAST feature.
> >>
> >>   - Patch #7 introduces the PCMachineClass.get_smi_host_features method,
> >>     and implements it for "pc-q35-2.9" and later. The idea is to tie the
> >>     SMI host features to machine types, and let the machine types
> >>     calculate their host features with code (i.e., not just a constant).
> >>
> >>     In this patch, the "pc-q35-2.9" machine type exposes the
> >>     ICH9_LPC_SMI_F_BROADCAST feature iff (smp_cpus == max_cpus), that
> >>     is, when VCPU hotplug is not possible. (Also from Paolo's v3
> >>     feedback, in
> >>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg04919.html>.)
> >>
> >> * I've written the OVMF side patches too and tested them together
> >>   (including gdb / debug messages for "white box" testing).
> >>
> >> * Note that this version depends on the following PULL req from Michael:
> >>
> >>   [Qemu-devel] [PULL 0/5] virtio, vhost, pc: fixes
> >>   http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg05503.html
> >>
> >>   In particular on the following patch:
> >>   "loader: fix handling of custom address spaces when adding ROM blobs"
> >>
> >> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
> >> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> >> Cc: Eduardo Habkost <ehabkost@redhat.com>
> >> Cc: Gerd Hoffmann <kraxel@redhat.com>
> >> Cc: Igor Mammedov <imammedo@redhat.com>
> >> Cc: Michael Walle <michael@walle.cc>
> >> Cc: Paolo Bonzini <pbonzini@redhat.com>
> >> Cc: Peter Maydell <peter.maydell@linaro.org>
> >> Cc: Shannon Zhao <zhaoshenglong@huawei.com>
> >> Cc: qemu-arm@nongnu.org
> >>
> >> Thanks
> >> Laszlo
> > 
> > So I reviewed fw cfg stuff, looks good to me.
> 
> Thank you.
> 
> I should note that Igor suggested / requested changes for patches #2 and
> #3; the sub-threads start at
> 
> http://lists.nongnu.org/archive/html/qemu-devel/2016-12/msg00695.html
> msg-id: <20161206115038.4495a217@nial.brq.redhat.com>
> 
> http://lists.nongnu.org/archive/html/qemu-devel/2016-12/msg00706.html
> msg-id: <20161206124906.76a41896@nial.brq.redhat.com>
> 
> I was about to rework the patches based on his feedback. Should we
> resume those discussions?

If you both agree, pls go ahead and make these changes.

> > I'd prefer Paolo to review
> > and merge broadcast SMI stuff as appropriate.  Paolo, makes sense?
> 
> If it helps, I can split the series into two "waves", and deal only with
> fw_cfg first.
> 
> Thanks!
> Laszlo

I don't mind either way.

> > 
> > 
> >> Laszlo Ersek (6):
> >>   fw-cfg: turn FW_CFG_FILE_SLOTS into a device property
> >>   fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma()
> >>   hw/i386/pc: introduce 2.9 machine types with 0x20 fw_cfg file slots
> >>   hw/isa/lpc_ich9: add SMI feature negotiation via fw_cfg
> >>   hw/isa/lpc_ich9: add broadcast SMI feature
> >>   hw/i386/pc_q35: advertise broadcast SMI if VCPU hotplug is turned off
> >>
> >> Michael S. Tsirkin (1):
> >>   fw-cfg: support writeable blobs
> >>
> >>  docs/specs/fw_cfg.txt          |  36 +++++++++---
> >>  hw/lm32/lm32_hwsetup.h         |   2 +-
> >>  include/hw/compat.h            |  11 ++++
> >>  include/hw/i386/ich9.h         |  15 ++++-
> >>  include/hw/i386/pc.h           |   4 ++
> >>  include/hw/loader.h            |   7 ++-
> >>  include/hw/nvram/fw_cfg.h      |   5 +-
> >>  include/hw/nvram/fw_cfg_keys.h |   7 ++-
> >>  hw/arm/virt-acpi-build.c       |   2 +-
> >>  hw/core/loader.c               |  18 +++---
> >>  hw/i386/acpi-build.c           |   4 +-
> >>  hw/i386/pc.c                   |   3 +-
> >>  hw/i386/pc_piix.c              |  16 +++++-
> >>  hw/i386/pc_q35.c               |  37 ++++++++++++-
> >>  hw/isa/lpc_ich9.c              |  92 +++++++++++++++++++++++++++++-
> >>  hw/nvram/fw_cfg.c              | 123 +++++++++++++++++++++++++++++++++++------
> >>  16 files changed, 326 insertions(+), 56 deletions(-)
> >>
> >> -- 
> >> 2.9.2

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

* Re: [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI
  2017-01-10 16:05     ` Michael S. Tsirkin
@ 2017-01-10 16:19       ` Laszlo Ersek
  0 siblings, 0 replies; 46+ messages in thread
From: Laszlo Ersek @ 2017-01-10 16:19 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: qemu devel list, Gabriel L. Somlo, Eduardo Habkost,
	Gerd Hoffmann, Igor Mammedov, Michael Walle, Paolo Bonzini,
	Peter Maydell, Shannon Zhao, qemu-arm

On 01/10/17 17:05, Michael S. Tsirkin wrote:
> On Tue, Jan 10, 2017 at 04:23:41PM +0100, Laszlo Ersek wrote:
>> On 01/10/17 16:06, Michael S. Tsirkin wrote:
>>> On Thu, Dec 01, 2016 at 06:06:17PM +0100, Laszlo Ersek wrote:
>>>> * This is version 4 of the series; the last version was at
>>>>   <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03582.html>.
>>>>
>>>>   This version is practically a rewrite from scratch, seeking to address
>>>>   the v3 feedback. Here's what the individual patches do:
>>>>
>>>>   - Patch #1 rebases and extends Michael's "writeable fw_cfg blobs"
>>>>     patch from Feb/March 2016. The changes relative to the original
>>>>     patch are documented in the commit message (the code changes are
>>>>     minimal).
>>>>
>>>>   - Patches #2 and #3 turn the FW_CFG_FILE_SLOTS constant into a device
>>>>     property, and expose the desired number of fw_cfg file slots to
>>>>     board code. This is meant to address a concern raised by Paolo in
>>>>     the v2 review
>>>>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03125.html>,
>>>>     namely that we're about to run out of FW_CFG_FILE_SLOTS.
>>>>
>>>>   - Patch #4 introduces the "pc-q35-2.9" and "pc-i440fx-2.9" machine
>>>>     types, which are allowed to take advantage of the new default for
>>>>     fw_cfg file slots (0x20 rather than 0x10).
>>>>
>>>>   - Patch #5 introduces SMI feature negotiation via fw_cfg, with the
>>>>     following new files:
>>>>
>>>>     - etc/smi/host-features
>>>>     - etc/smi/guest-features
>>>>     - etc/smi/features-ok
>>>>
>>>>     This is supposed to follow Michael's recommendation re: imitating
>>>>     virtio
>>>>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03218.html>.
>>>>
>>>>     The guest-features file is freely writeable by the guest (no write
>>>>     callbacks in fw_cfg), and the feature validation & lockdown occurs
>>>>     when the guest selects the features-ok file (for reading).
>>>>
>>>>     Board code is allowed to choose the host feature bitmap to
>>>>     advertise.
>>>>
>>>>     This patch doesn't add any specific SMI features yet.
>>>>
>>>>   - Patch #6 adds the ICH9_LPC_SMI_F_BROADCAST feature.
>>>>
>>>>   - Patch #7 introduces the PCMachineClass.get_smi_host_features method,
>>>>     and implements it for "pc-q35-2.9" and later. The idea is to tie the
>>>>     SMI host features to machine types, and let the machine types
>>>>     calculate their host features with code (i.e., not just a constant).
>>>>
>>>>     In this patch, the "pc-q35-2.9" machine type exposes the
>>>>     ICH9_LPC_SMI_F_BROADCAST feature iff (smp_cpus == max_cpus), that
>>>>     is, when VCPU hotplug is not possible. (Also from Paolo's v3
>>>>     feedback, in
>>>>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg04919.html>.)
>>>>
>>>> * I've written the OVMF side patches too and tested them together
>>>>   (including gdb / debug messages for "white box" testing).
>>>>
>>>> * Note that this version depends on the following PULL req from Michael:
>>>>
>>>>   [Qemu-devel] [PULL 0/5] virtio, vhost, pc: fixes
>>>>   http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg05503.html
>>>>
>>>>   In particular on the following patch:
>>>>   "loader: fix handling of custom address spaces when adding ROM blobs"
>>>>
>>>> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
>>>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
>>>> Cc: Eduardo Habkost <ehabkost@redhat.com>
>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>>> Cc: Igor Mammedov <imammedo@redhat.com>
>>>> Cc: Michael Walle <michael@walle.cc>
>>>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>>>> Cc: Peter Maydell <peter.maydell@linaro.org>
>>>> Cc: Shannon Zhao <zhaoshenglong@huawei.com>
>>>> Cc: qemu-arm@nongnu.org
>>>>
>>>> Thanks
>>>> Laszlo
>>>
>>> So I reviewed fw cfg stuff, looks good to me.
>>
>> Thank you.
>>
>> I should note that Igor suggested / requested changes for patches #2 and
>> #3; the sub-threads start at
>>
>> http://lists.nongnu.org/archive/html/qemu-devel/2016-12/msg00695.html
>> msg-id: <20161206115038.4495a217@nial.brq.redhat.com>
>>
>> http://lists.nongnu.org/archive/html/qemu-devel/2016-12/msg00706.html
>> msg-id: <20161206124906.76a41896@nial.brq.redhat.com>
>>
>> I was about to rework the patches based on his feedback. Should we
>> resume those discussions?
> 
> If you both agree, pls go ahead and make these changes.

Okay, will do.

> 
>>> I'd prefer Paolo to review
>>> and merge broadcast SMI stuff as appropriate.  Paolo, makes sense?
>>
>> If it helps, I can split the series into two "waves", and deal only with
>> fw_cfg first.
>>
>> Thanks!
>> Laszlo
> 
> I don't mind either way.

I'll see then how I feel about splitting v5 when I'm ready to post it. :)

Thanks!
Laszlo

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

* Re: [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI
  2017-01-10 15:23   ` Laszlo Ersek
  2017-01-10 16:05     ` Michael S. Tsirkin
@ 2017-01-10 16:21     ` Igor Mammedov
  2017-01-10 16:30       ` Laszlo Ersek
  1 sibling, 1 reply; 46+ messages in thread
From: Igor Mammedov @ 2017-01-10 16:21 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: Michael S. Tsirkin, Peter Maydell, Eduardo Habkost,
	Gabriel L. Somlo, Shannon Zhao, qemu devel list, Michael Walle,
	qemu-arm, Gerd Hoffmann, Paolo Bonzini

On Tue, 10 Jan 2017 16:23:41 +0100
Laszlo Ersek <lersek@redhat.com> wrote:

> On 01/10/17 16:06, Michael S. Tsirkin wrote:
> > On Thu, Dec 01, 2016 at 06:06:17PM +0100, Laszlo Ersek wrote:
> >> * This is version 4 of the series; the last version was at
> >>   <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03582.html>.
> >>
> >>   This version is practically a rewrite from scratch, seeking to address
> >>   the v3 feedback. Here's what the individual patches do:
> >>
> >>   - Patch #1 rebases and extends Michael's "writeable fw_cfg blobs"
> >>     patch from Feb/March 2016. The changes relative to the original
> >>     patch are documented in the commit message (the code changes are
> >>     minimal).
> >>
> >>   - Patches #2 and #3 turn the FW_CFG_FILE_SLOTS constant into a device
> >>     property, and expose the desired number of fw_cfg file slots to
> >>     board code. This is meant to address a concern raised by Paolo in
> >>     the v2 review
> >>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03125.html>,
> >>     namely that we're about to run out of FW_CFG_FILE_SLOTS.
> >>
> >>   - Patch #4 introduces the "pc-q35-2.9" and "pc-i440fx-2.9" machine
> >>     types, which are allowed to take advantage of the new default for
> >>     fw_cfg file slots (0x20 rather than 0x10).
> >>
> >>   - Patch #5 introduces SMI feature negotiation via fw_cfg, with the
> >>     following new files:
> >>
> >>     - etc/smi/host-features
> >>     - etc/smi/guest-features
> >>     - etc/smi/features-ok
> >>
> >>     This is supposed to follow Michael's recommendation re: imitating
> >>     virtio
> >>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03218.html>.
> >>
> >>     The guest-features file is freely writeable by the guest (no write
> >>     callbacks in fw_cfg), and the feature validation & lockdown occurs
> >>     when the guest selects the features-ok file (for reading).
> >>
> >>     Board code is allowed to choose the host feature bitmap to
> >>     advertise.
> >>
> >>     This patch doesn't add any specific SMI features yet.
> >>
> >>   - Patch #6 adds the ICH9_LPC_SMI_F_BROADCAST feature.
> >>
> >>   - Patch #7 introduces the PCMachineClass.get_smi_host_features method,
> >>     and implements it for "pc-q35-2.9" and later. The idea is to tie the
> >>     SMI host features to machine types, and let the machine types
> >>     calculate their host features with code (i.e., not just a constant).
> >>
> >>     In this patch, the "pc-q35-2.9" machine type exposes the
> >>     ICH9_LPC_SMI_F_BROADCAST feature iff (smp_cpus == max_cpus), that
> >>     is, when VCPU hotplug is not possible. (Also from Paolo's v3
> >>     feedback, in
> >>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg04919.html>.)
> >>
> >> * I've written the OVMF side patches too and tested them together
> >>   (including gdb / debug messages for "white box" testing).
> >>
> >> * Note that this version depends on the following PULL req from Michael:
> >>
> >>   [Qemu-devel] [PULL 0/5] virtio, vhost, pc: fixes
> >>   http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg05503.html
> >>
> >>   In particular on the following patch:
> >>   "loader: fix handling of custom address spaces when adding ROM blobs"
> >>
> >> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
> >> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> >> Cc: Eduardo Habkost <ehabkost@redhat.com>
> >> Cc: Gerd Hoffmann <kraxel@redhat.com>
> >> Cc: Igor Mammedov <imammedo@redhat.com>
> >> Cc: Michael Walle <michael@walle.cc>
> >> Cc: Paolo Bonzini <pbonzini@redhat.com>
> >> Cc: Peter Maydell <peter.maydell@linaro.org>
> >> Cc: Shannon Zhao <zhaoshenglong@huawei.com>
> >> Cc: qemu-arm@nongnu.org
> >>
> >> Thanks
> >> Laszlo
> > 
> > So I reviewed fw cfg stuff, looks good to me.
> 
> Thank you.
> 
> I should note that Igor suggested / requested changes for patches #2 and
> #3; the sub-threads start at
> 
> http://lists.nongnu.org/archive/html/qemu-devel/2016-12/msg00695.html
> msg-id: <20161206115038.4495a217@nial.brq.redhat.com>
> 
> http://lists.nongnu.org/archive/html/qemu-devel/2016-12/msg00706.html
> msg-id: <20161206124906.76a41896@nial.brq.redhat.com>
> 
> I was about to rework the patches based on his feedback. Should we
> resume those discussions?
> 
> > I'd prefer Paolo to review
> > and merge broadcast SMI stuff as appropriate.  Paolo, makes sense?
> 
> If it helps, I can split the series into two "waves", and deal only with
> fw_cfg first.
2 waves looks better as vmgeneration stuff would depend on fw_cfg patches
so it would be good to first. And SMI could be follow up.

> 
> Thanks!
> Laszlo
> 
> > 
> > 
> >> Laszlo Ersek (6):
> >>   fw-cfg: turn FW_CFG_FILE_SLOTS into a device property
> >>   fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma()
> >>   hw/i386/pc: introduce 2.9 machine types with 0x20 fw_cfg file slots
> >>   hw/isa/lpc_ich9: add SMI feature negotiation via fw_cfg
> >>   hw/isa/lpc_ich9: add broadcast SMI feature
> >>   hw/i386/pc_q35: advertise broadcast SMI if VCPU hotplug is turned off
> >>
> >> Michael S. Tsirkin (1):
> >>   fw-cfg: support writeable blobs
> >>
> >>  docs/specs/fw_cfg.txt          |  36 +++++++++---
> >>  hw/lm32/lm32_hwsetup.h         |   2 +-
> >>  include/hw/compat.h            |  11 ++++
> >>  include/hw/i386/ich9.h         |  15 ++++-
> >>  include/hw/i386/pc.h           |   4 ++
> >>  include/hw/loader.h            |   7 ++-
> >>  include/hw/nvram/fw_cfg.h      |   5 +-
> >>  include/hw/nvram/fw_cfg_keys.h |   7 ++-
> >>  hw/arm/virt-acpi-build.c       |   2 +-
> >>  hw/core/loader.c               |  18 +++---
> >>  hw/i386/acpi-build.c           |   4 +-
> >>  hw/i386/pc.c                   |   3 +-
> >>  hw/i386/pc_piix.c              |  16 +++++-
> >>  hw/i386/pc_q35.c               |  37 ++++++++++++-
> >>  hw/isa/lpc_ich9.c              |  92 +++++++++++++++++++++++++++++-
> >>  hw/nvram/fw_cfg.c              | 123 +++++++++++++++++++++++++++++++++++------
> >>  16 files changed, 326 insertions(+), 56 deletions(-)
> >>
> >> -- 
> >> 2.9.2
> 
> 

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

* Re: [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI
  2017-01-10 16:21     ` Igor Mammedov
@ 2017-01-10 16:30       ` Laszlo Ersek
  0 siblings, 0 replies; 46+ messages in thread
From: Laszlo Ersek @ 2017-01-10 16:30 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Michael S. Tsirkin, Peter Maydell, Eduardo Habkost,
	Gabriel L. Somlo, Shannon Zhao, qemu devel list, Michael Walle,
	qemu-arm, Gerd Hoffmann, Paolo Bonzini

On 01/10/17 17:21, Igor Mammedov wrote:
> On Tue, 10 Jan 2017 16:23:41 +0100
> Laszlo Ersek <lersek@redhat.com> wrote:
> 
>> On 01/10/17 16:06, Michael S. Tsirkin wrote:
>>> On Thu, Dec 01, 2016 at 06:06:17PM +0100, Laszlo Ersek wrote:
>>>> * This is version 4 of the series; the last version was at
>>>>   <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03582.html>.
>>>>
>>>>   This version is practically a rewrite from scratch, seeking to address
>>>>   the v3 feedback. Here's what the individual patches do:
>>>>
>>>>   - Patch #1 rebases and extends Michael's "writeable fw_cfg blobs"
>>>>     patch from Feb/March 2016. The changes relative to the original
>>>>     patch are documented in the commit message (the code changes are
>>>>     minimal).
>>>>
>>>>   - Patches #2 and #3 turn the FW_CFG_FILE_SLOTS constant into a device
>>>>     property, and expose the desired number of fw_cfg file slots to
>>>>     board code. This is meant to address a concern raised by Paolo in
>>>>     the v2 review
>>>>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03125.html>,
>>>>     namely that we're about to run out of FW_CFG_FILE_SLOTS.
>>>>
>>>>   - Patch #4 introduces the "pc-q35-2.9" and "pc-i440fx-2.9" machine
>>>>     types, which are allowed to take advantage of the new default for
>>>>     fw_cfg file slots (0x20 rather than 0x10).
>>>>
>>>>   - Patch #5 introduces SMI feature negotiation via fw_cfg, with the
>>>>     following new files:
>>>>
>>>>     - etc/smi/host-features
>>>>     - etc/smi/guest-features
>>>>     - etc/smi/features-ok
>>>>
>>>>     This is supposed to follow Michael's recommendation re: imitating
>>>>     virtio
>>>>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg03218.html>.
>>>>
>>>>     The guest-features file is freely writeable by the guest (no write
>>>>     callbacks in fw_cfg), and the feature validation & lockdown occurs
>>>>     when the guest selects the features-ok file (for reading).
>>>>
>>>>     Board code is allowed to choose the host feature bitmap to
>>>>     advertise.
>>>>
>>>>     This patch doesn't add any specific SMI features yet.
>>>>
>>>>   - Patch #6 adds the ICH9_LPC_SMI_F_BROADCAST feature.
>>>>
>>>>   - Patch #7 introduces the PCMachineClass.get_smi_host_features method,
>>>>     and implements it for "pc-q35-2.9" and later. The idea is to tie the
>>>>     SMI host features to machine types, and let the machine types
>>>>     calculate their host features with code (i.e., not just a constant).
>>>>
>>>>     In this patch, the "pc-q35-2.9" machine type exposes the
>>>>     ICH9_LPC_SMI_F_BROADCAST feature iff (smp_cpus == max_cpus), that
>>>>     is, when VCPU hotplug is not possible. (Also from Paolo's v3
>>>>     feedback, in
>>>>     <http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg04919.html>.)
>>>>
>>>> * I've written the OVMF side patches too and tested them together
>>>>   (including gdb / debug messages for "white box" testing).
>>>>
>>>> * Note that this version depends on the following PULL req from Michael:
>>>>
>>>>   [Qemu-devel] [PULL 0/5] virtio, vhost, pc: fixes
>>>>   http://lists.nongnu.org/archive/html/qemu-devel/2016-11/msg05503.html
>>>>
>>>>   In particular on the following patch:
>>>>   "loader: fix handling of custom address spaces when adding ROM blobs"
>>>>
>>>> Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
>>>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
>>>> Cc: Eduardo Habkost <ehabkost@redhat.com>
>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>>> Cc: Igor Mammedov <imammedo@redhat.com>
>>>> Cc: Michael Walle <michael@walle.cc>
>>>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>>>> Cc: Peter Maydell <peter.maydell@linaro.org>
>>>> Cc: Shannon Zhao <zhaoshenglong@huawei.com>
>>>> Cc: qemu-arm@nongnu.org
>>>>
>>>> Thanks
>>>> Laszlo
>>>
>>> So I reviewed fw cfg stuff, looks good to me.
>>
>> Thank you.
>>
>> I should note that Igor suggested / requested changes for patches #2 and
>> #3; the sub-threads start at
>>
>> http://lists.nongnu.org/archive/html/qemu-devel/2016-12/msg00695.html
>> msg-id: <20161206115038.4495a217@nial.brq.redhat.com>
>>
>> http://lists.nongnu.org/archive/html/qemu-devel/2016-12/msg00706.html
>> msg-id: <20161206124906.76a41896@nial.brq.redhat.com>
>>
>> I was about to rework the patches based on his feedback. Should we
>> resume those discussions?
>>
>>> I'd prefer Paolo to review
>>> and merge broadcast SMI stuff as appropriate.  Paolo, makes sense?
>>
>> If it helps, I can split the series into two "waves", and deal only with
>> fw_cfg first.
> 2 waves looks better as vmgeneration stuff would depend on fw_cfg patches
> so it would be good to first. And SMI could be follow up.

Makes sense.
Laszlo

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

end of thread, other threads:[~2017-01-10 16:32 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-01 17:06 [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI Laszlo Ersek
2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 1/7] fw-cfg: support writeable blobs Laszlo Ersek
2016-12-20 15:58   ` Marcel Apfelbaum
2017-01-10 13:33     ` Laszlo Ersek
2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 2/7] fw-cfg: turn FW_CFG_FILE_SLOTS into a device property Laszlo Ersek
2016-12-02 11:10   ` Gerd Hoffmann
2016-12-02 11:48     ` Laszlo Ersek
2016-12-02 12:47       ` Gerd Hoffmann
2016-12-06 10:50   ` Igor Mammedov
2016-12-06 11:43     ` Laszlo Ersek
2016-12-06 12:02       ` Igor Mammedov
2016-12-06 16:22         ` Laszlo Ersek
2017-01-10 15:02   ` Michael S. Tsirkin
2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 3/7] fw-cfg: expose "file_slots" parameter in fw_cfg_init_io_dma() Laszlo Ersek
2016-12-06 11:49   ` Igor Mammedov
2016-12-06 16:46     ` Laszlo Ersek
2016-12-06 16:52       ` Laszlo Ersek
2016-12-06 23:21         ` David Gibson
2016-12-06 18:09       ` Igor Mammedov
2016-12-06 18:09         ` Igor Mammedov
2016-12-06 19:29         ` [Qemu-devel] " Stefano Stabellini
2016-12-06 19:29           ` Stefano Stabellini
2017-01-10 15:02   ` [Qemu-devel] " Michael S. Tsirkin
2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 4/7] hw/i386/pc: introduce 2.9 machine types with 0x20 fw_cfg file slots Laszlo Ersek
2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 5/7] hw/isa/lpc_ich9: add SMI feature negotiation via fw_cfg Laszlo Ersek
2016-12-02 11:54   ` Igor Mammedov
2016-12-02 12:00     ` Laszlo Ersek
2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 6/7] hw/isa/lpc_ich9: add broadcast SMI feature Laszlo Ersek
2016-12-01 17:06 ` [Qemu-devel] [PATCH v4 7/7] hw/i386/pc_q35: advertise broadcast SMI if VCPU hotplug is turned off Laszlo Ersek
2016-12-01 19:13   ` Eduardo Habkost
2016-12-01 20:42     ` Laszlo Ersek
2016-12-01 20:53       ` Eduardo Habkost
2016-12-02 12:18       ` Igor Mammedov
2016-12-02 19:32         ` Laszlo Ersek
2016-12-20 23:01 ` [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI no-reply
2016-12-21 15:22   ` [Qemu-devel] checkpatch.pl false positive (was Re: [PATCH v4 0/7] q35: add negotiable broadcast SMI) Eduardo Habkost
2016-12-21 17:47     ` Paolo Bonzini
2016-12-21 18:01       ` Eduardo Habkost
2016-12-21 18:08         ` Paolo Bonzini
2016-12-21 18:19           ` Eduardo Habkost
2017-01-10 15:06 ` [Qemu-devel] [PATCH v4 0/7] q35: add negotiable broadcast SMI Michael S. Tsirkin
2017-01-10 15:23   ` Laszlo Ersek
2017-01-10 16:05     ` Michael S. Tsirkin
2017-01-10 16:19       ` Laszlo Ersek
2017-01-10 16:21     ` Igor Mammedov
2017-01-10 16:30       ` Laszlo Ersek

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.