All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 0/4] fw_cfg: spec update, read optimization, misc. cleanup
@ 2015-10-28 17:20 Gabriel L. Somlo
  2015-10-28 17:20 ` [Qemu-devel] [PATCH v2 1/4] fw_cfg: move internal function call docs to header file Gabriel L. Somlo
                   ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Gabriel L. Somlo @ 2015-10-28 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, jordan.l.justen, kraxel, pbonzini, markmb, lersek

This series' main purpose is to update (and simplify) the specified
read callback behavior. An earlier standalone patch to move qemu function
call API documentation into fw_cfg.h should logically be part of the series.

Here's the summary of what each patch does:

	- Patch 1/4 is an updated version of the standalone v1 patch
	  I sent out earlier; it moves all the qemu-internal host-side
	  function call api documentation out of docs/specs/fw_cfg.txt,
	  and into the fw_cfg.h header file, next to the prototype of
	  each documented api function.

	- Patch 2/4 modifies the specified behavior of read callbacks
	  (from being invoked once per byte read, to being invoked once,
	   before ANY data is read, specifically once each time an item
	   is selected).

	- Patch 3/4 additionally removes the now-redundant offset argument
	  from the read callback prototype.

	- Finally, 4/4 consolidates (non-DMA) reads, minimizing the number
	  of times redundant sanity checks are performed, particularly for
	  wide (> byte) sized reads.

Comments, reviews, etc. much appreciated!

Thanks,
  Gabriel

Gabriel L. Somlo (4):
  fw_cfg: move internal function call docs to header file
  fw_cfg: amend callback behavior spec to once per select
  fw_cfg: remove offset argument from callback prototype
  fw_cfg: streamline (non-DMA) read operations

 docs/specs/fw_cfg.txt     |  85 +------------------------------
 hw/arm/virt-acpi-build.c  |   2 +-
 hw/i386/acpi-build.c      |   2 +-
 hw/nvram/fw_cfg.c         |  53 +++++++------------
 include/hw/nvram/fw_cfg.h | 127 +++++++++++++++++++++++++++++++++++++++++++++-
 trace-events              |   2 +-
 6 files changed, 147 insertions(+), 124 deletions(-)

-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 1/4] fw_cfg: move internal function call docs to header file
  2015-10-28 17:20 [Qemu-devel] [PATCH v2 0/4] fw_cfg: spec update, read optimization, misc. cleanup Gabriel L. Somlo
@ 2015-10-28 17:20 ` Gabriel L. Somlo
  2015-11-02 13:41   ` Laszlo Ersek
  2015-10-28 17:20 ` [Qemu-devel] [PATCH v2 2/4] fw_cfg: amend callback behavior spec to once per select Gabriel L. Somlo
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 13+ messages in thread
From: Gabriel L. Somlo @ 2015-10-28 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, jordan.l.justen, kraxel, pbonzini, markmb, lersek

Move documentation for fw_cfg functions internal to qemu from
docs/specs/fw_cfg.txt to the fw_cfg.h header file, next to their
prototype declarations, formatted as doc-comments.

Suggested-by: Peter Maydell <peter.maydell@linaro.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Marc Marí <markmb@redhat.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
---
 docs/specs/fw_cfg.txt     |  85 +-----------------------------
 include/hw/nvram/fw_cfg.h | 128 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 129 insertions(+), 84 deletions(-)

diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
index b8c794f..2099ad9 100644
--- a/docs/specs/fw_cfg.txt
+++ b/docs/specs/fw_cfg.txt
@@ -192,90 +192,7 @@ To check the result, read the "control" field:
                             today due to implementation not being async,
                             but may in the future).
 
-= Host-side API =
-
-The following functions are available to the QEMU programmer for adding
-data to a fw_cfg device during guest initialization (see fw_cfg.h for
-each function's complete prototype):
-
-== fw_cfg_add_bytes() ==
-
-Given a selector key value, starting pointer, and size, create an item
-as a raw "blob" of the given size, available by selecting the given key.
-The data referenced by the starting pointer is only linked, NOT copied,
-into the data structure of the fw_cfg device.
-
-== fw_cfg_add_string() ==
-
-Instead of a starting pointer and size, this function accepts a pointer
-to a NUL-terminated ascii string, and inserts a newly allocated copy of
-the string (including the NUL terminator) into the fw_cfg device data
-structure.
-
-== fw_cfg_add_iXX() ==
-
-Insert an XX-bit item, where XX may be 16, 32, or 64. These functions
-will convert a 16-, 32-, or 64-bit integer to little-endian, then add
-a dynamically allocated copy of the appropriately sized item to fw_cfg
-under the given selector key value.
-
-== fw_cfg_modify_iXX() ==
-
-Modify the value of an XX-bit item (where XX may be 16, 32, or 64).
-Similarly to the corresponding fw_cfg_add_iXX() function set, convert
-a 16-, 32-, or 64-bit integer to little endian, create a dynamically
-allocated copy of the required size, and replace the existing item at
-the given selector key value with the newly allocated one. The previous
-item, assumed to have been allocated during an earlier call to
-fw_cfg_add_iXX() or fw_cfg_modify_iXX() (of the same width XX), is freed
-before the function returns.
-
-== fw_cfg_add_file() ==
-
-Given a filename (i.e., fw_cfg item name), starting pointer, and size,
-create an item as a raw "blob" of the given size. Unlike fw_cfg_add_bytes()
-above, the next available selector key (above 0x0020, FW_CFG_FILE_FIRST)
-will be used, and a new entry will be added to the file directory structure
-(at key 0x0019), containing the item name, blob size, and automatically
-assigned selector key value. The data referenced by the starting pointer
-is only linked, NOT copied, into the fw_cfg data structure.
-
-== fw_cfg_add_file_callback() ==
-
-Like fw_cfg_add_file(), but additionally sets pointers to a callback
-function (and opaque argument), which will be executed host-side by
-QEMU each time a byte is read by the guest from this particular item.
-
-NOTE: The callback function is given the opaque argument set by
-fw_cfg_add_file_callback(), but also the current data offset,
-allowing it the option of only acting upon specific offset values
-(e.g., 0, before the first data byte of the selected item is
-returned to the guest).
-
-== fw_cfg_modify_file() ==
-
-Given a filename (i.e., fw_cfg item name), starting pointer, and size,
-completely replace the configuration item referenced by the given item
-name with the new given blob. If an existing blob is found, its
-callback information is removed, and a pointer to the old data is
-returned to allow the caller to free it, helping avoid memory leaks.
-If a configuration item does not already exist under the given item
-name, a new item will be created as with fw_cfg_add_file(), and NULL
-is returned to the caller. In any case, the data referenced by the
-starting pointer is only linked, NOT copied, into the fw_cfg data
-structure.
-
-== fw_cfg_add_callback() ==
-
-Like fw_cfg_add_bytes(), but additionally sets pointers to a callback
-function (and opaque argument), which will be executed host-side by
-QEMU each time a guest-side write operation to this particular item
-completes fully overwriting the item's data.
-
-NOTE: This function is deprecated, and will be completely removed
-starting with QEMU v2.4.
-
-== Externally Provided Items ==
+= Externally Provided Items =
 
 As of v2.4, "file" fw_cfg items (i.e., items with selector keys above
 FW_CFG_FILE_FIRST, and with a corresponding entry in the fw_cfg file
diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
index ee0cd8a..422e2e9 100644
--- a/include/hw/nvram/fw_cfg.h
+++ b/include/hw/nvram/fw_cfg.h
@@ -73,19 +73,147 @@ typedef struct FWCfgDmaAccess {
 typedef void (*FWCfgCallback)(void *opaque, uint8_t *data);
 typedef void (*FWCfgReadCallback)(void *opaque, uint32_t offset);
 
+/**
+ * fw_cfg_add_bytes:
+ * @s: fw_cfg device being modified
+ * @key: selector key value for new fw_cfg item
+ * @data: pointer to start of item data
+ * @len: size of item data
+ *
+ * Add a new fw_cfg item, available by selecting the given key, 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.
+ */
 void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len);
+
+/**
+ * fw_cfg_add_string:
+ * @s: fw_cfg device being modified
+ * @key: selector key value for new fw_cfg item
+ * @value: NUL-terminated ascii string
+ *
+ * Add a new fw_cfg item, available by selecting the given key. The item
+ * data will consist of a dynamically allocated copy of the provided string,
+ * including its NUL terminator.
+ */
 void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value);
+
+/**
+ * fw_cfg_add_i16:
+ * @s: fw_cfg device being modified
+ * @key: selector key value for new fw_cfg item
+ * @value: 16-bit integer
+ *
+ * Add a new fw_cfg item, available by selecting the given key. The item
+ * data will consist of a dynamically allocated copy of the given 16-bit
+ * value, converted to little-endian representation.
+ */
 void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value);
+
+/**
+ * fw_cfg_modify_i16:
+ * @s: fw_cfg device being modified
+ * @key: selector key value for new fw_cfg item
+ * @value: 16-bit integer
+ *
+ * Replace the fw_cfg item available by selecting the given key. The new
+ * data will consist of a dynamically allocated copy of the given 16-bit
+ * value, converted to little-endian representation. The data being replaced,
+ * assumed to have been dynamically allocated during an earlier call to
+ * either fw_cfg_add_i16() or fw_cfg_modify_i16(), is freed before returning.
+ */
 void fw_cfg_modify_i16(FWCfgState *s, uint16_t key, uint16_t value);
+
+/**
+ * fw_cfg_add_i32:
+ * @s: fw_cfg device being modified
+ * @key: selector key value for new fw_cfg item
+ * @value: 32-bit integer
+ *
+ * Add a new fw_cfg item, available by selecting the given key. The item
+ * data will consist of a dynamically allocated copy of the given 32-bit
+ * value, converted to little-endian representation.
+ */
 void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value);
+
+/**
+ * fw_cfg_add_i64:
+ * @s: fw_cfg device being modified
+ * @key: selector key value for new fw_cfg item
+ * @value: 64-bit integer
+ *
+ * Add a new fw_cfg item, available by selecting the given key. The item
+ * data will consist of a dynamically allocated copy of the given 64-bit
+ * value, converted to little-endian representation.
+ */
 void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value);
+
+/**
+ * fw_cfg_add_file:
+ * @s: fw_cfg device being modified
+ * @filename: name of new fw_cfg file item
+ * @data: pointer to start of item data
+ * @len: size of item data
+ *
+ * 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
+ * will be used; also, a new entry will be added to the file directory
+ * structure residing at key value FW_CFG_FILE_DIR, containing the item name,
+ * data size, and assigned selector key value.
+ */
 void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data,
                      size_t len);
+
+/**
+ * fw_cfg_add_file_callback:
+ * @s: fw_cfg device being modified
+ * @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
+ *
+ * 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
+ * will be used; also, a new entry will be added to the file directory
+ * structure residing at key value FW_CFG_FILE_DIR, containing the item name,
+ * data size, and assigned selector key value.
+ * Additionally, set a callback function (and argument) to be called each
+ * time a byte is read by the guest from this particular item, or once per
+ * each DMA guest read operation.
+ * NOTE: In addition to the opaque argument set here, the callback function
+ * takes the current data offset as an additional argument, allowing it the
+ * option of only acting upon specific offset values (e.g., 0, before the
+ * first data byte of the selected item is returned to the guest).
+ */
 void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
                               FWCfgReadCallback callback, void *callback_opaque,
                               void *data, size_t len);
+
+/**
+ * fw_cfg_modify_file:
+ * @s: fw_cfg device being modified
+ * @filename: name of new fw_cfg file item
+ * @data: pointer to start of item data
+ * @len: size of item data
+ *
+ * Replace a NAMED fw_cfg item. If an existing item is found, its callback
+ * information will be cleared, and a pointer to its data will be returned
+ * the caller, so that it may be freed if necessary. If an existing item is
+ * not found, this call defaults to fw_cfg_add_file(), and NULL is returned
+ * to the caller.
+ * In either case, the new item data is only linked, NOT copied, into the
+ * data structure of the fw_cfg device.
+ *
+ * Returns: pointer to old item's data, or NULL if old item does not exist.
+ */
 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);
 FWCfgState *fw_cfg_init_io(uint32_t iobase);
-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 2/4] fw_cfg: amend callback behavior spec to once per select
  2015-10-28 17:20 [Qemu-devel] [PATCH v2 0/4] fw_cfg: spec update, read optimization, misc. cleanup Gabriel L. Somlo
  2015-10-28 17:20 ` [Qemu-devel] [PATCH v2 1/4] fw_cfg: move internal function call docs to header file Gabriel L. Somlo
@ 2015-10-28 17:20 ` Gabriel L. Somlo
  2015-11-02 14:16   ` Laszlo Ersek
  2015-10-28 17:20 ` [Qemu-devel] [PATCH v2 3/4] fw_cfg: remove offset argument from callback prototype Gabriel L. Somlo
  2015-10-28 17:20 ` [Qemu-devel] [PATCH v2 4/4] fw_cfg: streamline (non-DMA) read operations Gabriel L. Somlo
  3 siblings, 1 reply; 13+ messages in thread
From: Gabriel L. Somlo @ 2015-10-28 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, jordan.l.justen, kraxel, pbonzini, markmb, lersek

Currently, the fw_cfg internal API specifies that if an item was set up
with a read callback, the callback must be run each time a byte is read
from the item. This behavior is both wasteful (most items do not have a
read callback set), and impractical for bulk transfers (e.g., DMA read).

At the time of this writing, the only items configured with a callback
are "/etc/table-loader", "/etc/acpi/tables", and "/etc/acpi/rsdp". They
all share the same callback functions: virt_acpi_build_update() on arm
(in hw/arm/virt-acpi-build.c), and acpi_build_update() on i386 (in
hw/i386/acpi.c). Both of these callbacks are one-shot (i.e. they return
without doing anything at all after the first time they are called on
each distinct item).

This patch amends the specification for fw_cfg_add_file_callback() to
state that any available read callback will only be invoked once each
time the item is selected. This change has no practical effect on the
current behavior of QEMU, and it enables us to significantly optimize
the behavior of fw_cfg reads during guest firmware setup, eliminating
a large amount of redundant callback checks and invocations.

Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Marc Marí <markmb@redhat.com>
Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
---
 hw/nvram/fw_cfg.c         | 16 ++++++++--------
 include/hw/nvram/fw_cfg.h |  8 ++------
 2 files changed, 10 insertions(+), 14 deletions(-)

diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 73b0a81..31fa5c8 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -252,7 +252,8 @@ static void fw_cfg_write(FWCfgState *s, uint8_t value)
 
 static int fw_cfg_select(FWCfgState *s, uint16_t key)
 {
-    int ret;
+    int arch, ret;
+    FWCfgEntry *e;
 
     s->cur_offset = 0;
     if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
@@ -261,6 +262,12 @@ static int fw_cfg_select(FWCfgState *s, uint16_t key)
     } else {
         s->cur_entry = key;
         ret = 1;
+        /* entry successfully selected, now run callback if present */
+        arch = !!(key & FW_CFG_ARCH_LOCAL);
+        e = &s->entries[arch][key & FW_CFG_ENTRY_MASK];
+        if (e->read_callback) {
+            e->read_callback(e->callback_opaque, s->cur_offset);
+        }
     }
 
     trace_fw_cfg_select(s, key, ret);
@@ -276,9 +283,6 @@ static uint8_t fw_cfg_read(FWCfgState *s)
     if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len)
         ret = 0;
     else {
-        if (e->read_callback) {
-            e->read_callback(e->callback_opaque, s->cur_offset);
-        }
         ret = e->data[s->cur_offset++];
     }
 
@@ -371,10 +375,6 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
                 len = (e->len - s->cur_offset);
             }
 
-            if (e->read_callback) {
-                e->read_callback(e->callback_opaque, s->cur_offset);
-            }
-
             /* If the access is not a read access, it will be a skip access,
              * tested before.
              */
diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
index 422e2e9..47ff118 100644
--- a/include/hw/nvram/fw_cfg.h
+++ b/include/hw/nvram/fw_cfg.h
@@ -183,12 +183,8 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data,
  * structure residing at key value FW_CFG_FILE_DIR, containing the item name,
  * data size, and assigned selector key value.
  * Additionally, set a callback function (and argument) to be called each
- * time a byte is read by the guest from this particular item, or once per
- * each DMA guest read operation.
- * NOTE: In addition to the opaque argument set here, the callback function
- * takes the current data offset as an additional argument, allowing it the
- * option of only acting upon specific offset values (e.g., 0, before the
- * first data byte of the selected item is returned to the guest).
+ * time this item is selected (by having its selector key written to the
+ * fw_cfg control register).
  */
 void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
                               FWCfgReadCallback callback, void *callback_opaque,
-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 3/4] fw_cfg: remove offset argument from callback prototype
  2015-10-28 17:20 [Qemu-devel] [PATCH v2 0/4] fw_cfg: spec update, read optimization, misc. cleanup Gabriel L. Somlo
  2015-10-28 17:20 ` [Qemu-devel] [PATCH v2 1/4] fw_cfg: move internal function call docs to header file Gabriel L. Somlo
  2015-10-28 17:20 ` [Qemu-devel] [PATCH v2 2/4] fw_cfg: amend callback behavior spec to once per select Gabriel L. Somlo
@ 2015-10-28 17:20 ` Gabriel L. Somlo
  2015-11-02 14:17   ` Laszlo Ersek
  2015-10-28 17:20 ` [Qemu-devel] [PATCH v2 4/4] fw_cfg: streamline (non-DMA) read operations Gabriel L. Somlo
  3 siblings, 1 reply; 13+ messages in thread
From: Gabriel L. Somlo @ 2015-10-28 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, jordan.l.justen, kraxel, pbonzini, markmb, lersek

Read callbacks are now only invoked at item selection, before any
data is read. As such, the value of the offset argument passed to
the callback will always be 0. Also, the two callback instances
currently in use both leave their offset argument unused.

This patch removes the offset argument from the fw_cfg read callback
prototype, and from the currently available instances. The unused
(write) callback prototype is also removed (write support was removed
earlier, in commit 023e3148).

Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Marc Marí <markmb@redhat.com>
Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
---
 hw/arm/virt-acpi-build.c  | 2 +-
 hw/i386/acpi-build.c      | 2 +-
 hw/nvram/fw_cfg.c         | 2 +-
 include/hw/nvram/fw_cfg.h | 3 +--
 4 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 1aaff1f..4eed24d 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -626,7 +626,7 @@ static void acpi_ram_update(MemoryRegion *mr, GArray *data)
     memory_region_set_dirty(mr, 0, size);
 }
 
-static void virt_acpi_build_update(void *build_opaque, uint32_t offset)
+static void virt_acpi_build_update(void *build_opaque)
 {
     AcpiBuildState *build_state = build_opaque;
     AcpiBuildTables tables;
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 95e0c65..29e30ce 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1818,7 +1818,7 @@ static void acpi_ram_update(MemoryRegion *mr, GArray *data)
     memory_region_set_dirty(mr, 0, size);
 }
 
-static void acpi_build_update(void *build_opaque, uint32_t offset)
+static void acpi_build_update(void *build_opaque)
 {
     AcpiBuildState *build_state = build_opaque;
     AcpiBuildTables tables;
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 31fa5c8..5de6dbc 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -266,7 +266,7 @@ static int fw_cfg_select(FWCfgState *s, uint16_t key)
         arch = !!(key & FW_CFG_ARCH_LOCAL);
         e = &s->entries[arch][key & FW_CFG_ENTRY_MASK];
         if (e->read_callback) {
-            e->read_callback(e->callback_opaque, s->cur_offset);
+            e->read_callback(e->callback_opaque);
         }
     }
 
diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
index 47ff118..6c459f3 100644
--- a/include/hw/nvram/fw_cfg.h
+++ b/include/hw/nvram/fw_cfg.h
@@ -70,8 +70,7 @@ typedef struct FWCfgDmaAccess {
     uint64_t address;
 } QEMU_PACKED FWCfgDmaAccess;
 
-typedef void (*FWCfgCallback)(void *opaque, uint8_t *data);
-typedef void (*FWCfgReadCallback)(void *opaque, uint32_t offset);
+typedef void (*FWCfgReadCallback)(void *opaque);
 
 /**
  * fw_cfg_add_bytes:
-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 4/4] fw_cfg: streamline (non-DMA) read operations
  2015-10-28 17:20 [Qemu-devel] [PATCH v2 0/4] fw_cfg: spec update, read optimization, misc. cleanup Gabriel L. Somlo
                   ` (2 preceding siblings ...)
  2015-10-28 17:20 ` [Qemu-devel] [PATCH v2 3/4] fw_cfg: remove offset argument from callback prototype Gabriel L. Somlo
@ 2015-10-28 17:20 ` Gabriel L. Somlo
  2015-11-02 14:38   ` Laszlo Ersek
  3 siblings, 1 reply; 13+ messages in thread
From: Gabriel L. Somlo @ 2015-10-28 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, jordan.l.justen, kraxel, pbonzini, markmb, lersek

Replace fw_cfg_comb_read(), fw_cfg_data_mem_read(), and fw_cfg_read()
with a single method, fw_cfg_data_read(), which works on all possible
read sizes (single- or multi-byte). The new method also eliminates
redundant validity checks caused by multi-byte reads repeatedly invoking
the old single-byte fw_cfg_read() method.

Also update trace_fw_cfg_read() prototype to accept a 64-bit value
argument.

Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Marc Marí <markmb@redhat.com>
Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
---
 hw/nvram/fw_cfg.c | 37 ++++++++++---------------------------
 trace-events      |  2 +-
 2 files changed, 11 insertions(+), 28 deletions(-)

diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 5de6dbc..cd477f9 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -274,32 +274,20 @@ static int fw_cfg_select(FWCfgState *s, uint16_t key)
     return ret;
 }
 
-static uint8_t fw_cfg_read(FWCfgState *s)
+static uint64_t fw_cfg_data_read(void *opaque, hwaddr addr, unsigned size)
 {
+    FWCfgState *s = opaque;
     int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
     FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
-    uint8_t ret;
-
-    if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len)
-        ret = 0;
-    else {
-        ret = e->data[s->cur_offset++];
-    }
-
-    trace_fw_cfg_read(s, ret);
-    return ret;
-}
-
-static uint64_t fw_cfg_data_mem_read(void *opaque, hwaddr addr,
-                                     unsigned size)
-{
-    FWCfgState *s = opaque;
     uint64_t value = 0;
-    unsigned i;
 
-    for (i = 0; i < size; ++i) {
-        value = (value << 8) | fw_cfg_read(s);
+    if (s->cur_entry != FW_CFG_INVALID && e->data) {
+        while (size-- && s->cur_offset < e->len) {
+            value = (value << 8) | e->data[s->cur_offset++];
+        }
     }
+
+    trace_fw_cfg_read(s, value);
     return value;
 }
 
@@ -451,11 +439,6 @@ static bool fw_cfg_ctl_mem_valid(void *opaque, hwaddr addr,
     return is_write && size == 2;
 }
 
-static uint64_t fw_cfg_comb_read(void *opaque, hwaddr addr,
-                                 unsigned size)
-{
-    return fw_cfg_read(opaque);
-}
 
 static void fw_cfg_comb_write(void *opaque, hwaddr addr,
                               uint64_t value, unsigned size)
@@ -483,7 +466,7 @@ static const MemoryRegionOps fw_cfg_ctl_mem_ops = {
 };
 
 static const MemoryRegionOps fw_cfg_data_mem_ops = {
-    .read = fw_cfg_data_mem_read,
+    .read = fw_cfg_data_read,
     .write = fw_cfg_data_mem_write,
     .endianness = DEVICE_BIG_ENDIAN,
     .valid = {
@@ -494,7 +477,7 @@ static const MemoryRegionOps fw_cfg_data_mem_ops = {
 };
 
 static const MemoryRegionOps fw_cfg_comb_mem_ops = {
-    .read = fw_cfg_comb_read,
+    .read = fw_cfg_data_read,
     .write = fw_cfg_comb_write,
     .endianness = DEVICE_LITTLE_ENDIAN,
     .valid.accepts = fw_cfg_comb_valid,
diff --git a/trace-events b/trace-events
index bdfe79f..a0eb1d8 100644
--- a/trace-events
+++ b/trace-events
@@ -196,7 +196,7 @@ ecc_diag_mem_readb(uint64_t addr, uint32_t ret) "Read diagnostic %"PRId64"= %02x
 
 # hw/nvram/fw_cfg.c
 fw_cfg_select(void *s, uint16_t key, int ret) "%p key %d = %d"
-fw_cfg_read(void *s, uint8_t ret) "%p = %d"
+fw_cfg_read(void *s, uint64_t ret) "%p = %"PRIx64
 fw_cfg_add_file(void *s, int index, char *name, size_t len) "%p #%d: %s (%zd bytes)"
 
 # hw/block/hd-geometry.c
-- 
2.4.3

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

* Re: [Qemu-devel] [PATCH v2 1/4] fw_cfg: move internal function call docs to header file
  2015-10-28 17:20 ` [Qemu-devel] [PATCH v2 1/4] fw_cfg: move internal function call docs to header file Gabriel L. Somlo
@ 2015-11-02 13:41   ` Laszlo Ersek
  2015-11-02 20:36     ` Gabriel L. Somlo
  0 siblings, 1 reply; 13+ messages in thread
From: Laszlo Ersek @ 2015-11-02 13:41 UTC (permalink / raw)
  To: Gabriel L. Somlo, qemu-devel
  Cc: peter.maydell, markmb, pbonzini, kraxel, jordan.l.justen

Three (well, two n' half) comments:

On 10/28/15 18:20, Gabriel L. Somlo wrote:
> Move documentation for fw_cfg functions internal to qemu from
> docs/specs/fw_cfg.txt to the fw_cfg.h header file, next to their
> prototype declarations, formatted as doc-comments.
> 
> Suggested-by: Peter Maydell <peter.maydell@linaro.org>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Marc Marí <markmb@redhat.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Peter Maydell <peter.maydell@linaro.org>
> Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
> ---
>  docs/specs/fw_cfg.txt     |  85 +-----------------------------
>  include/hw/nvram/fw_cfg.h | 128 ++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 129 insertions(+), 84 deletions(-)
> 
> diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
> index b8c794f..2099ad9 100644
> --- a/docs/specs/fw_cfg.txt
> +++ b/docs/specs/fw_cfg.txt
> @@ -192,90 +192,7 @@ To check the result, read the "control" field:
>                              today due to implementation not being async,
>                              but may in the future).
>  
> -= Host-side API =
> -
> -The following functions are available to the QEMU programmer for adding
> -data to a fw_cfg device during guest initialization (see fw_cfg.h for
> -each function's complete prototype):
> -
> -== fw_cfg_add_bytes() ==
> -
> -Given a selector key value, starting pointer, and size, create an item
> -as a raw "blob" of the given size, available by selecting the given key.
> -The data referenced by the starting pointer is only linked, NOT copied,
> -into the data structure of the fw_cfg device.
> -
> -== fw_cfg_add_string() ==
> -
> -Instead of a starting pointer and size, this function accepts a pointer
> -to a NUL-terminated ascii string, and inserts a newly allocated copy of
> -the string (including the NUL terminator) into the fw_cfg device data
> -structure.
> -
> -== fw_cfg_add_iXX() ==
> -
> -Insert an XX-bit item, where XX may be 16, 32, or 64. These functions
> -will convert a 16-, 32-, or 64-bit integer to little-endian, then add
> -a dynamically allocated copy of the appropriately sized item to fw_cfg
> -under the given selector key value.
> -
> -== fw_cfg_modify_iXX() ==
> -
> -Modify the value of an XX-bit item (where XX may be 16, 32, or 64).
> -Similarly to the corresponding fw_cfg_add_iXX() function set, convert
> -a 16-, 32-, or 64-bit integer to little endian, create a dynamically
> -allocated copy of the required size, and replace the existing item at
> -the given selector key value with the newly allocated one. The previous
> -item, assumed to have been allocated during an earlier call to
> -fw_cfg_add_iXX() or fw_cfg_modify_iXX() (of the same width XX), is freed
> -before the function returns.
> -
> -== fw_cfg_add_file() ==
> -
> -Given a filename (i.e., fw_cfg item name), starting pointer, and size,
> -create an item as a raw "blob" of the given size. Unlike fw_cfg_add_bytes()
> -above, the next available selector key (above 0x0020, FW_CFG_FILE_FIRST)
> -will be used, and a new entry will be added to the file directory structure
> -(at key 0x0019), containing the item name, blob size, and automatically
> -assigned selector key value. The data referenced by the starting pointer
> -is only linked, NOT copied, into the fw_cfg data structure.
> -
> -== fw_cfg_add_file_callback() ==
> -
> -Like fw_cfg_add_file(), but additionally sets pointers to a callback
> -function (and opaque argument), which will be executed host-side by
> -QEMU each time a byte is read by the guest from this particular item.
> -
> -NOTE: The callback function is given the opaque argument set by
> -fw_cfg_add_file_callback(), but also the current data offset,
> -allowing it the option of only acting upon specific offset values
> -(e.g., 0, before the first data byte of the selected item is
> -returned to the guest).
> -
> -== fw_cfg_modify_file() ==
> -
> -Given a filename (i.e., fw_cfg item name), starting pointer, and size,
> -completely replace the configuration item referenced by the given item
> -name with the new given blob. If an existing blob is found, its
> -callback information is removed, and a pointer to the old data is
> -returned to allow the caller to free it, helping avoid memory leaks.
> -If a configuration item does not already exist under the given item
> -name, a new item will be created as with fw_cfg_add_file(), and NULL
> -is returned to the caller. In any case, the data referenced by the
> -starting pointer is only linked, NOT copied, into the fw_cfg data
> -structure.
> -
> -== fw_cfg_add_callback() ==
> -
> -Like fw_cfg_add_bytes(), but additionally sets pointers to a callback
> -function (and opaque argument), which will be executed host-side by
> -QEMU each time a guest-side write operation to this particular item
> -completes fully overwriting the item's data.
> -
> -NOTE: This function is deprecated, and will be completely removed
> -starting with QEMU v2.4.

(1) Please mention in the commit message that this paragraph disappears
without replacement, because the fw_cfg_add_callback() function is
already gone.

> -
> -== Externally Provided Items ==
> += Externally Provided Items =
>  
>  As of v2.4, "file" fw_cfg items (i.e., items with selector keys above
>  FW_CFG_FILE_FIRST, and with a corresponding entry in the fw_cfg file
> diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
> index ee0cd8a..422e2e9 100644
> --- a/include/hw/nvram/fw_cfg.h
> +++ b/include/hw/nvram/fw_cfg.h
> @@ -73,19 +73,147 @@ typedef struct FWCfgDmaAccess {
>  typedef void (*FWCfgCallback)(void *opaque, uint8_t *data);
>  typedef void (*FWCfgReadCallback)(void *opaque, uint32_t offset);
>  
> +/**
> + * fw_cfg_add_bytes:
> + * @s: fw_cfg device being modified
> + * @key: selector key value for new fw_cfg item
> + * @data: pointer to start of item data
> + * @len: size of item data
> + *
> + * Add a new fw_cfg item, available by selecting the given key, 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.
> + */
>  void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len);
> +
> +/**
> + * fw_cfg_add_string:
> + * @s: fw_cfg device being modified
> + * @key: selector key value for new fw_cfg item
> + * @value: NUL-terminated ascii string
> + *
> + * Add a new fw_cfg item, available by selecting the given key. The item
> + * data will consist of a dynamically allocated copy of the provided string,
> + * including its NUL terminator.
> + */
>  void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value);
> +
> +/**
> + * fw_cfg_add_i16:
> + * @s: fw_cfg device being modified
> + * @key: selector key value for new fw_cfg item
> + * @value: 16-bit integer
> + *
> + * Add a new fw_cfg item, available by selecting the given key. The item
> + * data will consist of a dynamically allocated copy of the given 16-bit
> + * value, converted to little-endian representation.
> + */
>  void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value);
> +
> +/**
> + * fw_cfg_modify_i16:
> + * @s: fw_cfg device being modified
> + * @key: selector key value for new fw_cfg item
> + * @value: 16-bit integer
> + *
> + * Replace the fw_cfg item available by selecting the given key. The new
> + * data will consist of a dynamically allocated copy of the given 16-bit
> + * value, converted to little-endian representation. The data being replaced,
> + * assumed to have been dynamically allocated during an earlier call to
> + * either fw_cfg_add_i16() or fw_cfg_modify_i16(), is freed before returning.
> + */
>  void fw_cfg_modify_i16(FWCfgState *s, uint16_t key, uint16_t value);
> +
> +/**
> + * fw_cfg_add_i32:
> + * @s: fw_cfg device being modified
> + * @key: selector key value for new fw_cfg item
> + * @value: 32-bit integer
> + *
> + * Add a new fw_cfg item, available by selecting the given key. The item
> + * data will consist of a dynamically allocated copy of the given 32-bit
> + * value, converted to little-endian representation.
> + */
>  void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value);
> +
> +/**
> + * fw_cfg_add_i64:
> + * @s: fw_cfg device being modified
> + * @key: selector key value for new fw_cfg item
> + * @value: 64-bit integer
> + *
> + * Add a new fw_cfg item, available by selecting the given key. The item
> + * data will consist of a dynamically allocated copy of the given 64-bit
> + * value, converted to little-endian representation.
> + */
>  void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value);
> +
> +/**
> + * fw_cfg_add_file:
> + * @s: fw_cfg device being modified
> + * @filename: name of new fw_cfg file item
> + * @data: pointer to start of item data
> + * @len: size of item data
> + *
> + * 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
> + * will be used; also, a new entry will be added to the file directory
> + * structure residing at key value FW_CFG_FILE_DIR, containing the item name,
> + * data size, and assigned selector key value.
> + */
>  void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data,
>                       size_t len);
> +
> +/**
> + * fw_cfg_add_file_callback:
> + * @s: fw_cfg device being modified
> + * @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
> + *
> + * 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
> + * will be used; also, a new entry will be added to the file directory
> + * structure residing at key value FW_CFG_FILE_DIR, containing the item name,
> + * data size, and assigned selector key value.
> + * Additionally, set a callback function (and argument) to be called each
> + * time a byte is read by the guest from this particular item, or once per
> + * each DMA guest read operation.

(2) -- (This is the "half" comment.) We could make the DMA language a
bit more precise, because the callback is not invoked if the start
offset of the DMA transfer falls outside the fw_cfg blob in question.
However, I don't think it is necessary to update this paragraph, because
in the next patch precisely the callback-on-DMA behavior is changed.


> + * NOTE: In addition to the opaque argument set here, the callback function
> + * takes the current data offset as an additional argument, allowing it the
> + * option of only acting upon specific offset values (e.g., 0, before the
> + * first data byte of the selected item is returned to the guest).
> + */
>  void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
>                                FWCfgReadCallback callback, void *callback_opaque,
>                                void *data, size_t len);
> +
> +/**
> + * fw_cfg_modify_file:
> + * @s: fw_cfg device being modified
> + * @filename: name of new fw_cfg file item
> + * @data: pointer to start of item data
> + * @len: size of item data
> + *
> + * Replace a NAMED fw_cfg item. If an existing item is found, its callback
> + * information will be cleared, and a pointer to its data will be returned

(3) "returned [to] the caller"

> + * the caller, so that it may be freed if necessary. If an existing item is
> + * not found, this call defaults to fw_cfg_add_file(), and NULL is returned
> + * to the caller.
> + * In either case, the new item data is only linked, NOT copied, into the
> + * data structure of the fw_cfg device.
> + *
> + * Returns: pointer to old item's data, or NULL if old item does not exist.
> + */
>  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);
>  FWCfgState *fw_cfg_init_io(uint32_t iobase);
> 

With (1) and (3) addressed, and with our without fixing up (2):

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

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

* Re: [Qemu-devel] [PATCH v2 2/4] fw_cfg: amend callback behavior spec to once per select
  2015-10-28 17:20 ` [Qemu-devel] [PATCH v2 2/4] fw_cfg: amend callback behavior spec to once per select Gabriel L. Somlo
@ 2015-11-02 14:16   ` Laszlo Ersek
  2015-11-02 21:00     ` Gabriel L. Somlo
  0 siblings, 1 reply; 13+ messages in thread
From: Laszlo Ersek @ 2015-11-02 14:16 UTC (permalink / raw)
  To: Gabriel L. Somlo, qemu-devel
  Cc: peter.maydell, markmb, pbonzini, kraxel, jordan.l.justen

Comments below:

On 10/28/15 18:20, Gabriel L. Somlo wrote:
> Currently, the fw_cfg internal API specifies that if an item was set up
> with a read callback, the callback must be run each time a byte is read
> from the item. This behavior is both wasteful (most items do not have a
> read callback set), and impractical for bulk transfers (e.g., DMA read).
> 
> At the time of this writing, the only items configured with a callback
> are "/etc/table-loader", "/etc/acpi/tables", and "/etc/acpi/rsdp". They
> all share the same callback functions: virt_acpi_build_update() on arm

(1) I suggest "ARM".

> (in hw/arm/virt-acpi-build.c), and acpi_build_update() on i386 (in
> hw/i386/acpi.c). Both of these callbacks are one-shot (i.e. they return
> without doing anything at all after the first time they are called on
> each distinct item).

(2) Shouldn't this be:

    ... after the first time they are called, regardless of the
    associated item being read

?

> 
> This patch amends the specification for fw_cfg_add_file_callback() to
> state that any available read callback will only be invoked once each
> time the item is selected. This change has no practical effect on the
> current behavior of QEMU, and it enables us to significantly optimize
> the behavior of fw_cfg reads during guest firmware setup, eliminating
> a large amount of redundant callback checks and invocations.
> 
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Marc Marí <markmb@redhat.com>
> Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
> ---
>  hw/nvram/fw_cfg.c         | 16 ++++++++--------
>  include/hw/nvram/fw_cfg.h |  8 ++------
>  2 files changed, 10 insertions(+), 14 deletions(-)
> 
> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> index 73b0a81..31fa5c8 100644
> --- a/hw/nvram/fw_cfg.c
> +++ b/hw/nvram/fw_cfg.c
> @@ -252,7 +252,8 @@ static void fw_cfg_write(FWCfgState *s, uint8_t value)
>  
>  static int fw_cfg_select(FWCfgState *s, uint16_t key)
>  {
> -    int ret;
> +    int arch, ret;
> +    FWCfgEntry *e;
>  
>      s->cur_offset = 0;
>      if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
> @@ -261,6 +262,12 @@ static int fw_cfg_select(FWCfgState *s, uint16_t key)
>      } else {
>          s->cur_entry = key;
>          ret = 1;
> +        /* entry successfully selected, now run callback if present */
> +        arch = !!(key & FW_CFG_ARCH_LOCAL);
> +        e = &s->entries[arch][key & FW_CFG_ENTRY_MASK];

Seems to match the logic in fw_cfg_read().

> +        if (e->read_callback) {
> +            e->read_callback(e->callback_opaque, s->cur_offset);
> +        }

The offset is constant 0 here, but that's fine.

>      }
>  
>      trace_fw_cfg_select(s, key, ret);
> @@ -276,9 +283,6 @@ static uint8_t fw_cfg_read(FWCfgState *s)
>      if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len)
>          ret = 0;
>      else {
> -        if (e->read_callback) {
> -            e->read_callback(e->callback_opaque, s->cur_offset);
> -        }
>          ret = e->data[s->cur_offset++];
>      }
>  
> @@ -371,10 +375,6 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
>                  len = (e->len - s->cur_offset);
>              }
>  
> -            if (e->read_callback) {
> -                e->read_callback(e->callback_opaque, s->cur_offset);
> -            }
> -
>              /* If the access is not a read access, it will be a skip access,
>               * tested before.
>               */
> diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
> index 422e2e9..47ff118 100644
> --- a/include/hw/nvram/fw_cfg.h
> +++ b/include/hw/nvram/fw_cfg.h
> @@ -183,12 +183,8 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data,
>   * structure residing at key value FW_CFG_FILE_DIR, containing the item name,
>   * data size, and assigned selector key value.
>   * Additionally, set a callback function (and argument) to be called each
> - * time a byte is read by the guest from this particular item, or once per
> - * each DMA guest read operation.
> - * NOTE: In addition to the opaque argument set here, the callback function
> - * takes the current data offset as an additional argument, allowing it the
> - * option of only acting upon specific offset values (e.g., 0, before the
> - * first data byte of the selected item is returned to the guest).
> + * time this item is selected (by having its selector key written to the
> + * fw_cfg control register).

(3) This should be more precise. Selection doesn't only occur via an
explicit write to the control register. Kevin suggested the
FW_CFG_DMA_CTL_SELECT bit in FWCfgDmaAccess.control, for enabling
"single trap" transfers. For the last sentence, I recommend:

  Additionally, set a callback function (and argument) to be called each
  time this item is selected (by having its selector key either written
  to the fw_cfg control register, or passed to QEMU in
  FWCfgDmaAccess.control with FW_CFG_DMA_CTL_SELECT).

(4) Please add the following comment to the body of fw_cfg_reset():

    /* we never register a read callback for FW_CFG_SIGNATURE */

(You might want to replace the open-coded 0 argument in that
fw_cfg_select() call with FW_CFG_SIGNATURE as well.)

>   */
>  void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
>                                FWCfgReadCallback callback, void *callback_opaque,
> 

Thanks!
Laszlo

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

* Re: [Qemu-devel] [PATCH v2 3/4] fw_cfg: remove offset argument from callback prototype
  2015-10-28 17:20 ` [Qemu-devel] [PATCH v2 3/4] fw_cfg: remove offset argument from callback prototype Gabriel L. Somlo
@ 2015-11-02 14:17   ` Laszlo Ersek
  0 siblings, 0 replies; 13+ messages in thread
From: Laszlo Ersek @ 2015-11-02 14:17 UTC (permalink / raw)
  To: Gabriel L. Somlo, qemu-devel
  Cc: peter.maydell, markmb, pbonzini, kraxel, jordan.l.justen

On 10/28/15 18:20, Gabriel L. Somlo wrote:
> Read callbacks are now only invoked at item selection, before any
> data is read. As such, the value of the offset argument passed to
> the callback will always be 0. Also, the two callback instances
> currently in use both leave their offset argument unused.
> 
> This patch removes the offset argument from the fw_cfg read callback
> prototype, and from the currently available instances. The unused
> (write) callback prototype is also removed (write support was removed
> earlier, in commit 023e3148).
> 
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Marc Marí <markmb@redhat.com>
> Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
> ---
>  hw/arm/virt-acpi-build.c  | 2 +-
>  hw/i386/acpi-build.c      | 2 +-
>  hw/nvram/fw_cfg.c         | 2 +-
>  include/hw/nvram/fw_cfg.h | 3 +--
>  4 files changed, 4 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
> index 1aaff1f..4eed24d 100644
> --- a/hw/arm/virt-acpi-build.c
> +++ b/hw/arm/virt-acpi-build.c
> @@ -626,7 +626,7 @@ static void acpi_ram_update(MemoryRegion *mr, GArray *data)
>      memory_region_set_dirty(mr, 0, size);
>  }
>  
> -static void virt_acpi_build_update(void *build_opaque, uint32_t offset)
> +static void virt_acpi_build_update(void *build_opaque)
>  {
>      AcpiBuildState *build_state = build_opaque;
>      AcpiBuildTables tables;
> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> index 95e0c65..29e30ce 100644
> --- a/hw/i386/acpi-build.c
> +++ b/hw/i386/acpi-build.c
> @@ -1818,7 +1818,7 @@ static void acpi_ram_update(MemoryRegion *mr, GArray *data)
>      memory_region_set_dirty(mr, 0, size);
>  }
>  
> -static void acpi_build_update(void *build_opaque, uint32_t offset)
> +static void acpi_build_update(void *build_opaque)
>  {
>      AcpiBuildState *build_state = build_opaque;
>      AcpiBuildTables tables;
> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> index 31fa5c8..5de6dbc 100644
> --- a/hw/nvram/fw_cfg.c
> +++ b/hw/nvram/fw_cfg.c
> @@ -266,7 +266,7 @@ static int fw_cfg_select(FWCfgState *s, uint16_t key)
>          arch = !!(key & FW_CFG_ARCH_LOCAL);
>          e = &s->entries[arch][key & FW_CFG_ENTRY_MASK];
>          if (e->read_callback) {
> -            e->read_callback(e->callback_opaque, s->cur_offset);
> +            e->read_callback(e->callback_opaque);
>          }
>      }
>  
> diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
> index 47ff118..6c459f3 100644
> --- a/include/hw/nvram/fw_cfg.h
> +++ b/include/hw/nvram/fw_cfg.h
> @@ -70,8 +70,7 @@ typedef struct FWCfgDmaAccess {
>      uint64_t address;
>  } QEMU_PACKED FWCfgDmaAccess;
>  
> -typedef void (*FWCfgCallback)(void *opaque, uint8_t *data);
> -typedef void (*FWCfgReadCallback)(void *opaque, uint32_t offset);
> +typedef void (*FWCfgReadCallback)(void *opaque);
>  
>  /**
>   * fw_cfg_add_bytes:
> 

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

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

* Re: [Qemu-devel] [PATCH v2 4/4] fw_cfg: streamline (non-DMA) read operations
  2015-10-28 17:20 ` [Qemu-devel] [PATCH v2 4/4] fw_cfg: streamline (non-DMA) read operations Gabriel L. Somlo
@ 2015-11-02 14:38   ` Laszlo Ersek
  2015-11-02 16:41     ` Eric Blake
  0 siblings, 1 reply; 13+ messages in thread
From: Laszlo Ersek @ 2015-11-02 14:38 UTC (permalink / raw)
  To: Gabriel L. Somlo, qemu-devel
  Cc: peter.maydell, markmb, pbonzini, kraxel, jordan.l.justen

Two comments for now:

On 10/28/15 18:20, Gabriel L. Somlo wrote:
> Replace fw_cfg_comb_read(), fw_cfg_data_mem_read(), and fw_cfg_read()
> with a single method, fw_cfg_data_read(), which works on all possible
> read sizes (single- or multi-byte). The new method also eliminates
> redundant validity checks caused by multi-byte reads repeatedly invoking
> the old single-byte fw_cfg_read() method.
> 
> Also update trace_fw_cfg_read() prototype to accept a 64-bit value
> argument.
> 
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Marc Marí <markmb@redhat.com>
> Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
> ---
>  hw/nvram/fw_cfg.c | 37 ++++++++++---------------------------
>  trace-events      |  2 +-
>  2 files changed, 11 insertions(+), 28 deletions(-)
> 
> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> index 5de6dbc..cd477f9 100644
> --- a/hw/nvram/fw_cfg.c
> +++ b/hw/nvram/fw_cfg.c
> @@ -274,32 +274,20 @@ static int fw_cfg_select(FWCfgState *s, uint16_t key)
>      return ret;
>  }
>  
> -static uint8_t fw_cfg_read(FWCfgState *s)
> +static uint64_t fw_cfg_data_read(void *opaque, hwaddr addr, unsigned size)
>  {
> +    FWCfgState *s = opaque;
>      int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
>      FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
> -    uint8_t ret;
> -
> -    if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len)
> -        ret = 0;
> -    else {
> -        ret = e->data[s->cur_offset++];
> -    }
> -
> -    trace_fw_cfg_read(s, ret);
> -    return ret;
> -}
> -
> -static uint64_t fw_cfg_data_mem_read(void *opaque, hwaddr addr,
> -                                     unsigned size)
> -{
> -    FWCfgState *s = opaque;
>      uint64_t value = 0;
> -    unsigned i;
>  
> -    for (i = 0; i < size; ++i) {
> -        value = (value << 8) | fw_cfg_read(s);
> +    if (s->cur_entry != FW_CFG_INVALID && e->data) {
> +        while (size-- && s->cur_offset < e->len) {
> +            value = (value << 8) | e->data[s->cur_offset++];
> +        }
>      }
> +
> +    trace_fw_cfg_read(s, value);
>      return value;
>  }
>  
> @@ -451,11 +439,6 @@ static bool fw_cfg_ctl_mem_valid(void *opaque, hwaddr addr,
>      return is_write && size == 2;
>  }
>  
> -static uint64_t fw_cfg_comb_read(void *opaque, hwaddr addr,
> -                                 unsigned size)
> -{
> -    return fw_cfg_read(opaque);
> -}
>  
>  static void fw_cfg_comb_write(void *opaque, hwaddr addr,
>                                uint64_t value, unsigned size)
> @@ -483,7 +466,7 @@ static const MemoryRegionOps fw_cfg_ctl_mem_ops = {
>  };
>  
>  static const MemoryRegionOps fw_cfg_data_mem_ops = {
> -    .read = fw_cfg_data_mem_read,
> +    .read = fw_cfg_data_read,
>      .write = fw_cfg_data_mem_write,
>      .endianness = DEVICE_BIG_ENDIAN,
>      .valid = {
> @@ -494,7 +477,7 @@ static const MemoryRegionOps fw_cfg_data_mem_ops = {
>  };
>  
>  static const MemoryRegionOps fw_cfg_comb_mem_ops = {
> -    .read = fw_cfg_comb_read,
> +    .read = fw_cfg_data_read,
>      .write = fw_cfg_comb_write,
>      .endianness = DEVICE_LITTLE_ENDIAN,
>      .valid.accepts = fw_cfg_comb_valid,

(1) Can you please split this patch in two? Maybe I'm just particularly
slow today, but I feel that it would help me review this patch if I
could look at each .read conversion in separation. I'd like to see that
each conversion, individually, is unobservable from the guest.

The first patch would introduce the new function and convert one of the
callbacks. The second patch would convert the other callback and remove
the old function. (Un-called static functions would break the compile,
so the removal cannot be left for a third patch.)

Alternatively, you can keep this patch as-is, but then please prove in
the commit message, in detail, why the new shared callback is
*identical* (that is, neither stricter nor laxer) to the previous
specific callback, in *both* cases. Please spare me the burden of
thinking; I should be able to read the proof from you (rather than
derive it myself), and just nod. :)

> diff --git a/trace-events b/trace-events
> index bdfe79f..a0eb1d8 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -196,7 +196,7 @@ ecc_diag_mem_readb(uint64_t addr, uint32_t ret) "Read diagnostic %"PRId64"= %02x
>  
>  # hw/nvram/fw_cfg.c
>  fw_cfg_select(void *s, uint16_t key, int ret) "%p key %d = %d"
> -fw_cfg_read(void *s, uint8_t ret) "%p = %d"
> +fw_cfg_read(void *s, uint64_t ret) "%p = %"PRIx64

(2) This changes the trace format even for single byte reads (from
decimal to hex), but I think that should be fine; plus we never
guaranteed any kind of stability here. So this looks good to me.

>  fw_cfg_add_file(void *s, int index, char *name, size_t len) "%p #%d: %s (%zd bytes)"
>  
>  # hw/block/hd-geometry.c
> 

Thanks
Laszlo

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

* Re: [Qemu-devel] [PATCH v2 4/4] fw_cfg: streamline (non-DMA) read operations
  2015-11-02 14:38   ` Laszlo Ersek
@ 2015-11-02 16:41     ` Eric Blake
  0 siblings, 0 replies; 13+ messages in thread
From: Eric Blake @ 2015-11-02 16:41 UTC (permalink / raw)
  To: Laszlo Ersek, Gabriel L. Somlo, qemu-devel
  Cc: peter.maydell, markmb, kraxel, jordan.l.justen, pbonzini

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

On 11/02/2015 07:38 AM, Laszlo Ersek wrote:

> 
> (1) Can you please split this patch in two? Maybe I'm just particularly
> slow today, but I feel that it would help me review this patch if I
> could look at each .read conversion in separation. I'd like to see that
> each conversion, individually, is unobservable from the guest.
> 
> The first patch would introduce the new function and convert one of the
> callbacks. The second patch would convert the other callback and remove
> the old function. (Un-called static functions would break the compile,
> so the removal cannot be left for a third patch.)

You can mark static functions with __attribute__((__unused__)), and gcc
will then let you leave them for a later cleanup patch.  I'm not sure if
clang behaves similarly, though.

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


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

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

* Re: [Qemu-devel] [PATCH v2 1/4] fw_cfg: move internal function call docs to header file
  2015-11-02 13:41   ` Laszlo Ersek
@ 2015-11-02 20:36     ` Gabriel L. Somlo
  2015-11-02 20:44       ` Laszlo Ersek
  0 siblings, 1 reply; 13+ messages in thread
From: Gabriel L. Somlo @ 2015-11-02 20:36 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: peter.maydell, jordan.l.justen, qemu-devel, kraxel, pbonzini, markmb

On Mon, Nov 02, 2015 at 02:41:58PM +0100, Laszlo Ersek wrote:
> Three (well, two n' half) comments:
> 
> On 10/28/15 18:20, Gabriel L. Somlo wrote:
> > Move documentation for fw_cfg functions internal to qemu from
> > docs/specs/fw_cfg.txt to the fw_cfg.h header file, next to their
> > prototype declarations, formatted as doc-comments.
> > 
> > Suggested-by: Peter Maydell <peter.maydell@linaro.org>
> > Cc: Laszlo Ersek <lersek@redhat.com>
> > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > Cc: Marc Marí <markmb@redhat.com>
> > Cc: Jordan Justen <jordan.l.justen@intel.com>
> > Cc: Paolo Bonzini <pbonzini@redhat.com>
> > Cc: Peter Maydell <peter.maydell@linaro.org>
> > Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
> > ---
> >  docs/specs/fw_cfg.txt     |  85 +-----------------------------
> >  include/hw/nvram/fw_cfg.h | 128 ++++++++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 129 insertions(+), 84 deletions(-)
> > 
> > diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
> > index b8c794f..2099ad9 100644
> > --- a/docs/specs/fw_cfg.txt
> > +++ b/docs/specs/fw_cfg.txt
> > @@ -192,90 +192,7 @@ To check the result, read the "control" field:
> >                              today due to implementation not being async,
> >                              but may in the future).
> >  
> > -= Host-side API =
> > -
> > -The following functions are available to the QEMU programmer for adding
> > -data to a fw_cfg device during guest initialization (see fw_cfg.h for
> > -each function's complete prototype):
> > -
> > -== fw_cfg_add_bytes() ==
> > -
> > -Given a selector key value, starting pointer, and size, create an item
> > -as a raw "blob" of the given size, available by selecting the given key.
> > -The data referenced by the starting pointer is only linked, NOT copied,
> > -into the data structure of the fw_cfg device.
> > -
> > -== fw_cfg_add_string() ==
> > -
> > -Instead of a starting pointer and size, this function accepts a pointer
> > -to a NUL-terminated ascii string, and inserts a newly allocated copy of
> > -the string (including the NUL terminator) into the fw_cfg device data
> > -structure.
> > -
> > -== fw_cfg_add_iXX() ==
> > -
> > -Insert an XX-bit item, where XX may be 16, 32, or 64. These functions
> > -will convert a 16-, 32-, or 64-bit integer to little-endian, then add
> > -a dynamically allocated copy of the appropriately sized item to fw_cfg
> > -under the given selector key value.
> > -
> > -== fw_cfg_modify_iXX() ==
> > -
> > -Modify the value of an XX-bit item (where XX may be 16, 32, or 64).
> > -Similarly to the corresponding fw_cfg_add_iXX() function set, convert
> > -a 16-, 32-, or 64-bit integer to little endian, create a dynamically
> > -allocated copy of the required size, and replace the existing item at
> > -the given selector key value with the newly allocated one. The previous
> > -item, assumed to have been allocated during an earlier call to
> > -fw_cfg_add_iXX() or fw_cfg_modify_iXX() (of the same width XX), is freed
> > -before the function returns.
> > -
> > -== fw_cfg_add_file() ==
> > -
> > -Given a filename (i.e., fw_cfg item name), starting pointer, and size,
> > -create an item as a raw "blob" of the given size. Unlike fw_cfg_add_bytes()
> > -above, the next available selector key (above 0x0020, FW_CFG_FILE_FIRST)
> > -will be used, and a new entry will be added to the file directory structure
> > -(at key 0x0019), containing the item name, blob size, and automatically
> > -assigned selector key value. The data referenced by the starting pointer
> > -is only linked, NOT copied, into the fw_cfg data structure.
> > -
> > -== fw_cfg_add_file_callback() ==
> > -
> > -Like fw_cfg_add_file(), but additionally sets pointers to a callback
> > -function (and opaque argument), which will be executed host-side by
> > -QEMU each time a byte is read by the guest from this particular item.
> > -
> > -NOTE: The callback function is given the opaque argument set by
> > -fw_cfg_add_file_callback(), but also the current data offset,
> > -allowing it the option of only acting upon specific offset values
> > -(e.g., 0, before the first data byte of the selected item is
> > -returned to the guest).
> > -
> > -== fw_cfg_modify_file() ==
> > -
> > -Given a filename (i.e., fw_cfg item name), starting pointer, and size,
> > -completely replace the configuration item referenced by the given item
> > -name with the new given blob. If an existing blob is found, its
> > -callback information is removed, and a pointer to the old data is
> > -returned to allow the caller to free it, helping avoid memory leaks.
> > -If a configuration item does not already exist under the given item
> > -name, a new item will be created as with fw_cfg_add_file(), and NULL
> > -is returned to the caller. In any case, the data referenced by the
> > -starting pointer is only linked, NOT copied, into the fw_cfg data
> > -structure.
> > -
> > -== fw_cfg_add_callback() ==
> > -
> > -Like fw_cfg_add_bytes(), but additionally sets pointers to a callback
> > -function (and opaque argument), which will be executed host-side by
> > -QEMU each time a guest-side write operation to this particular item
> > -completes fully overwriting the item's data.
> > -
> > -NOTE: This function is deprecated, and will be completely removed
> > -starting with QEMU v2.4.
> 
> (1) Please mention in the commit message that this paragraph disappears
> without replacement, because the fw_cfg_add_callback() function is
> already gone.
> 
> > -
> > -== Externally Provided Items ==
> > += Externally Provided Items =
> >  
> >  As of v2.4, "file" fw_cfg items (i.e., items with selector keys above
> >  FW_CFG_FILE_FIRST, and with a corresponding entry in the fw_cfg file
> > diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
> > index ee0cd8a..422e2e9 100644
> > --- a/include/hw/nvram/fw_cfg.h
> > +++ b/include/hw/nvram/fw_cfg.h
> > @@ -73,19 +73,147 @@ typedef struct FWCfgDmaAccess {
> >  typedef void (*FWCfgCallback)(void *opaque, uint8_t *data);
> >  typedef void (*FWCfgReadCallback)(void *opaque, uint32_t offset);
> >  
> > +/**
> > + * fw_cfg_add_bytes:
> > + * @s: fw_cfg device being modified
> > + * @key: selector key value for new fw_cfg item
> > + * @data: pointer to start of item data
> > + * @len: size of item data
> > + *
> > + * Add a new fw_cfg item, available by selecting the given key, 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.
> > + */
> >  void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len);
> > +
> > +/**
> > + * fw_cfg_add_string:
> > + * @s: fw_cfg device being modified
> > + * @key: selector key value for new fw_cfg item
> > + * @value: NUL-terminated ascii string
> > + *
> > + * Add a new fw_cfg item, available by selecting the given key. The item
> > + * data will consist of a dynamically allocated copy of the provided string,
> > + * including its NUL terminator.
> > + */
> >  void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value);
> > +
> > +/**
> > + * fw_cfg_add_i16:
> > + * @s: fw_cfg device being modified
> > + * @key: selector key value for new fw_cfg item
> > + * @value: 16-bit integer
> > + *
> > + * Add a new fw_cfg item, available by selecting the given key. The item
> > + * data will consist of a dynamically allocated copy of the given 16-bit
> > + * value, converted to little-endian representation.
> > + */
> >  void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value);
> > +
> > +/**
> > + * fw_cfg_modify_i16:
> > + * @s: fw_cfg device being modified
> > + * @key: selector key value for new fw_cfg item
> > + * @value: 16-bit integer
> > + *
> > + * Replace the fw_cfg item available by selecting the given key. The new
> > + * data will consist of a dynamically allocated copy of the given 16-bit
> > + * value, converted to little-endian representation. The data being replaced,
> > + * assumed to have been dynamically allocated during an earlier call to
> > + * either fw_cfg_add_i16() or fw_cfg_modify_i16(), is freed before returning.
> > + */
> >  void fw_cfg_modify_i16(FWCfgState *s, uint16_t key, uint16_t value);
> > +
> > +/**
> > + * fw_cfg_add_i32:
> > + * @s: fw_cfg device being modified
> > + * @key: selector key value for new fw_cfg item
> > + * @value: 32-bit integer
> > + *
> > + * Add a new fw_cfg item, available by selecting the given key. The item
> > + * data will consist of a dynamically allocated copy of the given 32-bit
> > + * value, converted to little-endian representation.
> > + */
> >  void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value);
> > +
> > +/**
> > + * fw_cfg_add_i64:
> > + * @s: fw_cfg device being modified
> > + * @key: selector key value for new fw_cfg item
> > + * @value: 64-bit integer
> > + *
> > + * Add a new fw_cfg item, available by selecting the given key. The item
> > + * data will consist of a dynamically allocated copy of the given 64-bit
> > + * value, converted to little-endian representation.
> > + */
> >  void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value);
> > +
> > +/**
> > + * fw_cfg_add_file:
> > + * @s: fw_cfg device being modified
> > + * @filename: name of new fw_cfg file item
> > + * @data: pointer to start of item data
> > + * @len: size of item data
> > + *
> > + * 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
> > + * will be used; also, a new entry will be added to the file directory
> > + * structure residing at key value FW_CFG_FILE_DIR, containing the item name,
> > + * data size, and assigned selector key value.
> > + */
> >  void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data,
> >                       size_t len);
> > +
> > +/**
> > + * fw_cfg_add_file_callback:
> > + * @s: fw_cfg device being modified
> > + * @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
> > + *
> > + * 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
> > + * will be used; also, a new entry will be added to the file directory
> > + * structure residing at key value FW_CFG_FILE_DIR, containing the item name,
> > + * data size, and assigned selector key value.
> > + * Additionally, set a callback function (and argument) to be called each
> > + * time a byte is read by the guest from this particular item, or once per
> > + * each DMA guest read operation.
> 
> (2) -- (This is the "half" comment.) We could make the DMA language a
> bit more precise, because the callback is not invoked if the start
> offset of the DMA transfer falls outside the fw_cfg blob in question.
> However, I don't think it is necessary to update this paragraph, because
> in the next patch precisely the callback-on-DMA behavior is changed.

I'll do this, if only so that the historical record wouldn't be
unnecessarily hard to decipher on anyone who might (unlikely) end
up doing archaeology on this :)

How about this:

 Additionally, set a callback function (and argument) to be called each
 time a byte is read by the guest from this particular item, or, in the
 case of DMA, each time a read or skip request overlaps with a defined
 portion of the item.

ack on (and thanks for) the rest of the review!

--Gabriel

> 
> 
> > + * NOTE: In addition to the opaque argument set here, the callback function
> > + * takes the current data offset as an additional argument, allowing it the
> > + * option of only acting upon specific offset values (e.g., 0, before the
> > + * first data byte of the selected item is returned to the guest).
> > + */
> >  void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
> >                                FWCfgReadCallback callback, void *callback_opaque,
> >                                void *data, size_t len);
> > +
> > +/**
> > + * fw_cfg_modify_file:
> > + * @s: fw_cfg device being modified
> > + * @filename: name of new fw_cfg file item
> > + * @data: pointer to start of item data
> > + * @len: size of item data
> > + *
> > + * Replace a NAMED fw_cfg item. If an existing item is found, its callback
> > + * information will be cleared, and a pointer to its data will be returned
> 
> (3) "returned [to] the caller"
> 
> > + * the caller, so that it may be freed if necessary. If an existing item is
> > + * not found, this call defaults to fw_cfg_add_file(), and NULL is returned
> > + * to the caller.
> > + * In either case, the new item data is only linked, NOT copied, into the
> > + * data structure of the fw_cfg device.
> > + *
> > + * Returns: pointer to old item's data, or NULL if old item does not exist.
> > + */
> >  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);
> >  FWCfgState *fw_cfg_init_io(uint32_t iobase);
> > 
> 
> With (1) and (3) addressed, and with our without fixing up (2):
> 
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>

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

* Re: [Qemu-devel] [PATCH v2 1/4] fw_cfg: move internal function call docs to header file
  2015-11-02 20:36     ` Gabriel L. Somlo
@ 2015-11-02 20:44       ` Laszlo Ersek
  0 siblings, 0 replies; 13+ messages in thread
From: Laszlo Ersek @ 2015-11-02 20:44 UTC (permalink / raw)
  To: Gabriel L. Somlo
  Cc: peter.maydell, jordan.l.justen, qemu-devel, kraxel, pbonzini, markmb

On 11/02/15 21:36, Gabriel L. Somlo wrote:
> On Mon, Nov 02, 2015 at 02:41:58PM +0100, Laszlo Ersek wrote:
>> Three (well, two n' half) comments:
>>
>> On 10/28/15 18:20, Gabriel L. Somlo wrote:
>>> Move documentation for fw_cfg functions internal to qemu from
>>> docs/specs/fw_cfg.txt to the fw_cfg.h header file, next to their
>>> prototype declarations, formatted as doc-comments.
>>>
>>> Suggested-by: Peter Maydell <peter.maydell@linaro.org>
>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>> Cc: Marc Marí <markmb@redhat.com>
>>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>>> Cc: Peter Maydell <peter.maydell@linaro.org>
>>> Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
>>> ---
>>>  docs/specs/fw_cfg.txt     |  85 +-----------------------------
>>>  include/hw/nvram/fw_cfg.h | 128 ++++++++++++++++++++++++++++++++++++++++++++++
>>>  2 files changed, 129 insertions(+), 84 deletions(-)
>>>
>>> diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
>>> index b8c794f..2099ad9 100644
>>> --- a/docs/specs/fw_cfg.txt
>>> +++ b/docs/specs/fw_cfg.txt
>>> @@ -192,90 +192,7 @@ To check the result, read the "control" field:
>>>                              today due to implementation not being async,
>>>                              but may in the future).
>>>  
>>> -= Host-side API =
>>> -
>>> -The following functions are available to the QEMU programmer for adding
>>> -data to a fw_cfg device during guest initialization (see fw_cfg.h for
>>> -each function's complete prototype):
>>> -
>>> -== fw_cfg_add_bytes() ==
>>> -
>>> -Given a selector key value, starting pointer, and size, create an item
>>> -as a raw "blob" of the given size, available by selecting the given key.
>>> -The data referenced by the starting pointer is only linked, NOT copied,
>>> -into the data structure of the fw_cfg device.
>>> -
>>> -== fw_cfg_add_string() ==
>>> -
>>> -Instead of a starting pointer and size, this function accepts a pointer
>>> -to a NUL-terminated ascii string, and inserts a newly allocated copy of
>>> -the string (including the NUL terminator) into the fw_cfg device data
>>> -structure.
>>> -
>>> -== fw_cfg_add_iXX() ==
>>> -
>>> -Insert an XX-bit item, where XX may be 16, 32, or 64. These functions
>>> -will convert a 16-, 32-, or 64-bit integer to little-endian, then add
>>> -a dynamically allocated copy of the appropriately sized item to fw_cfg
>>> -under the given selector key value.
>>> -
>>> -== fw_cfg_modify_iXX() ==
>>> -
>>> -Modify the value of an XX-bit item (where XX may be 16, 32, or 64).
>>> -Similarly to the corresponding fw_cfg_add_iXX() function set, convert
>>> -a 16-, 32-, or 64-bit integer to little endian, create a dynamically
>>> -allocated copy of the required size, and replace the existing item at
>>> -the given selector key value with the newly allocated one. The previous
>>> -item, assumed to have been allocated during an earlier call to
>>> -fw_cfg_add_iXX() or fw_cfg_modify_iXX() (of the same width XX), is freed
>>> -before the function returns.
>>> -
>>> -== fw_cfg_add_file() ==
>>> -
>>> -Given a filename (i.e., fw_cfg item name), starting pointer, and size,
>>> -create an item as a raw "blob" of the given size. Unlike fw_cfg_add_bytes()
>>> -above, the next available selector key (above 0x0020, FW_CFG_FILE_FIRST)
>>> -will be used, and a new entry will be added to the file directory structure
>>> -(at key 0x0019), containing the item name, blob size, and automatically
>>> -assigned selector key value. The data referenced by the starting pointer
>>> -is only linked, NOT copied, into the fw_cfg data structure.
>>> -
>>> -== fw_cfg_add_file_callback() ==
>>> -
>>> -Like fw_cfg_add_file(), but additionally sets pointers to a callback
>>> -function (and opaque argument), which will be executed host-side by
>>> -QEMU each time a byte is read by the guest from this particular item.
>>> -
>>> -NOTE: The callback function is given the opaque argument set by
>>> -fw_cfg_add_file_callback(), but also the current data offset,
>>> -allowing it the option of only acting upon specific offset values
>>> -(e.g., 0, before the first data byte of the selected item is
>>> -returned to the guest).
>>> -
>>> -== fw_cfg_modify_file() ==
>>> -
>>> -Given a filename (i.e., fw_cfg item name), starting pointer, and size,
>>> -completely replace the configuration item referenced by the given item
>>> -name with the new given blob. If an existing blob is found, its
>>> -callback information is removed, and a pointer to the old data is
>>> -returned to allow the caller to free it, helping avoid memory leaks.
>>> -If a configuration item does not already exist under the given item
>>> -name, a new item will be created as with fw_cfg_add_file(), and NULL
>>> -is returned to the caller. In any case, the data referenced by the
>>> -starting pointer is only linked, NOT copied, into the fw_cfg data
>>> -structure.
>>> -
>>> -== fw_cfg_add_callback() ==
>>> -
>>> -Like fw_cfg_add_bytes(), but additionally sets pointers to a callback
>>> -function (and opaque argument), which will be executed host-side by
>>> -QEMU each time a guest-side write operation to this particular item
>>> -completes fully overwriting the item's data.
>>> -
>>> -NOTE: This function is deprecated, and will be completely removed
>>> -starting with QEMU v2.4.
>>
>> (1) Please mention in the commit message that this paragraph disappears
>> without replacement, because the fw_cfg_add_callback() function is
>> already gone.
>>
>>> -
>>> -== Externally Provided Items ==
>>> += Externally Provided Items =
>>>  
>>>  As of v2.4, "file" fw_cfg items (i.e., items with selector keys above
>>>  FW_CFG_FILE_FIRST, and with a corresponding entry in the fw_cfg file
>>> diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
>>> index ee0cd8a..422e2e9 100644
>>> --- a/include/hw/nvram/fw_cfg.h
>>> +++ b/include/hw/nvram/fw_cfg.h
>>> @@ -73,19 +73,147 @@ typedef struct FWCfgDmaAccess {
>>>  typedef void (*FWCfgCallback)(void *opaque, uint8_t *data);
>>>  typedef void (*FWCfgReadCallback)(void *opaque, uint32_t offset);
>>>  
>>> +/**
>>> + * fw_cfg_add_bytes:
>>> + * @s: fw_cfg device being modified
>>> + * @key: selector key value for new fw_cfg item
>>> + * @data: pointer to start of item data
>>> + * @len: size of item data
>>> + *
>>> + * Add a new fw_cfg item, available by selecting the given key, 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.
>>> + */
>>>  void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len);
>>> +
>>> +/**
>>> + * fw_cfg_add_string:
>>> + * @s: fw_cfg device being modified
>>> + * @key: selector key value for new fw_cfg item
>>> + * @value: NUL-terminated ascii string
>>> + *
>>> + * Add a new fw_cfg item, available by selecting the given key. The item
>>> + * data will consist of a dynamically allocated copy of the provided string,
>>> + * including its NUL terminator.
>>> + */
>>>  void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value);
>>> +
>>> +/**
>>> + * fw_cfg_add_i16:
>>> + * @s: fw_cfg device being modified
>>> + * @key: selector key value for new fw_cfg item
>>> + * @value: 16-bit integer
>>> + *
>>> + * Add a new fw_cfg item, available by selecting the given key. The item
>>> + * data will consist of a dynamically allocated copy of the given 16-bit
>>> + * value, converted to little-endian representation.
>>> + */
>>>  void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value);
>>> +
>>> +/**
>>> + * fw_cfg_modify_i16:
>>> + * @s: fw_cfg device being modified
>>> + * @key: selector key value for new fw_cfg item
>>> + * @value: 16-bit integer
>>> + *
>>> + * Replace the fw_cfg item available by selecting the given key. The new
>>> + * data will consist of a dynamically allocated copy of the given 16-bit
>>> + * value, converted to little-endian representation. The data being replaced,
>>> + * assumed to have been dynamically allocated during an earlier call to
>>> + * either fw_cfg_add_i16() or fw_cfg_modify_i16(), is freed before returning.
>>> + */
>>>  void fw_cfg_modify_i16(FWCfgState *s, uint16_t key, uint16_t value);
>>> +
>>> +/**
>>> + * fw_cfg_add_i32:
>>> + * @s: fw_cfg device being modified
>>> + * @key: selector key value for new fw_cfg item
>>> + * @value: 32-bit integer
>>> + *
>>> + * Add a new fw_cfg item, available by selecting the given key. The item
>>> + * data will consist of a dynamically allocated copy of the given 32-bit
>>> + * value, converted to little-endian representation.
>>> + */
>>>  void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value);
>>> +
>>> +/**
>>> + * fw_cfg_add_i64:
>>> + * @s: fw_cfg device being modified
>>> + * @key: selector key value for new fw_cfg item
>>> + * @value: 64-bit integer
>>> + *
>>> + * Add a new fw_cfg item, available by selecting the given key. The item
>>> + * data will consist of a dynamically allocated copy of the given 64-bit
>>> + * value, converted to little-endian representation.
>>> + */
>>>  void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value);
>>> +
>>> +/**
>>> + * fw_cfg_add_file:
>>> + * @s: fw_cfg device being modified
>>> + * @filename: name of new fw_cfg file item
>>> + * @data: pointer to start of item data
>>> + * @len: size of item data
>>> + *
>>> + * 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
>>> + * will be used; also, a new entry will be added to the file directory
>>> + * structure residing at key value FW_CFG_FILE_DIR, containing the item name,
>>> + * data size, and assigned selector key value.
>>> + */
>>>  void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data,
>>>                       size_t len);
>>> +
>>> +/**
>>> + * fw_cfg_add_file_callback:
>>> + * @s: fw_cfg device being modified
>>> + * @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
>>> + *
>>> + * 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
>>> + * will be used; also, a new entry will be added to the file directory
>>> + * structure residing at key value FW_CFG_FILE_DIR, containing the item name,
>>> + * data size, and assigned selector key value.
>>> + * Additionally, set a callback function (and argument) to be called each
>>> + * time a byte is read by the guest from this particular item, or once per
>>> + * each DMA guest read operation.
>>
>> (2) -- (This is the "half" comment.) We could make the DMA language a
>> bit more precise, because the callback is not invoked if the start
>> offset of the DMA transfer falls outside the fw_cfg blob in question.
>> However, I don't think it is necessary to update this paragraph, because
>> in the next patch precisely the callback-on-DMA behavior is changed.
> 
> I'll do this, if only so that the historical record wouldn't be
> unnecessarily hard to decipher on anyone who might (unlikely) end
> up doing archaeology on this :)
> 
> How about this:
> 
>  Additionally, set a callback function (and argument) to be called each
>  time a byte is read by the guest from this particular item, or, in the
>  case of DMA, each time a read or skip request overlaps with a defined
>  portion of the item.

s/a defined portion/the valid offset range/? :)

Thanks
Laszlo

> 
> ack on (and thanks for) the rest of the review!
> 
> --Gabriel
> 
>>
>>
>>> + * NOTE: In addition to the opaque argument set here, the callback function
>>> + * takes the current data offset as an additional argument, allowing it the
>>> + * option of only acting upon specific offset values (e.g., 0, before the
>>> + * first data byte of the selected item is returned to the guest).
>>> + */
>>>  void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
>>>                                FWCfgReadCallback callback, void *callback_opaque,
>>>                                void *data, size_t len);
>>> +
>>> +/**
>>> + * fw_cfg_modify_file:
>>> + * @s: fw_cfg device being modified
>>> + * @filename: name of new fw_cfg file item
>>> + * @data: pointer to start of item data
>>> + * @len: size of item data
>>> + *
>>> + * Replace a NAMED fw_cfg item. If an existing item is found, its callback
>>> + * information will be cleared, and a pointer to its data will be returned
>>
>> (3) "returned [to] the caller"
>>
>>> + * the caller, so that it may be freed if necessary. If an existing item is
>>> + * not found, this call defaults to fw_cfg_add_file(), and NULL is returned
>>> + * to the caller.
>>> + * In either case, the new item data is only linked, NOT copied, into the
>>> + * data structure of the fw_cfg device.
>>> + *
>>> + * Returns: pointer to old item's data, or NULL if old item does not exist.
>>> + */
>>>  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);
>>>  FWCfgState *fw_cfg_init_io(uint32_t iobase);
>>>
>>
>> With (1) and (3) addressed, and with our without fixing up (2):
>>
>> Reviewed-by: Laszlo Ersek <lersek@redhat.com>

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

* Re: [Qemu-devel] [PATCH v2 2/4] fw_cfg: amend callback behavior spec to once per select
  2015-11-02 14:16   ` Laszlo Ersek
@ 2015-11-02 21:00     ` Gabriel L. Somlo
  0 siblings, 0 replies; 13+ messages in thread
From: Gabriel L. Somlo @ 2015-11-02 21:00 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: peter.maydell, jordan.l.justen, qemu-devel, kraxel, pbonzini, markmb

On Mon, Nov 02, 2015 at 03:16:47PM +0100, Laszlo Ersek wrote:
> Comments below:
> 
> On 10/28/15 18:20, Gabriel L. Somlo wrote:
> > Currently, the fw_cfg internal API specifies that if an item was set up
> > with a read callback, the callback must be run each time a byte is read
> > from the item. This behavior is both wasteful (most items do not have a
> > read callback set), and impractical for bulk transfers (e.g., DMA read).
> > 
> > At the time of this writing, the only items configured with a callback
> > are "/etc/table-loader", "/etc/acpi/tables", and "/etc/acpi/rsdp". They
> > all share the same callback functions: virt_acpi_build_update() on arm
> 
> (1) I suggest "ARM".

OK.

> 
> > (in hw/arm/virt-acpi-build.c), and acpi_build_update() on i386 (in
> > hw/i386/acpi.c). Both of these callbacks are one-shot (i.e. they return
> > without doing anything at all after the first time they are called on
> > each distinct item).
> 
> (2) Shouldn't this be:
> 
>     ... after the first time they are called, regardless of the
>     associated item being read

Ha, you're right -- build-state is shared across all blobs, so the
callback only really fires once for the whole guest VM.

Thanks for catching that !

> > 
> > This patch amends the specification for fw_cfg_add_file_callback() to
> > state that any available read callback will only be invoked once each
> > time the item is selected. This change has no practical effect on the
> > current behavior of QEMU, and it enables us to significantly optimize
> > the behavior of fw_cfg reads during guest firmware setup, eliminating
> > a large amount of redundant callback checks and invocations.
> > 
> > Cc: Laszlo Ersek <lersek@redhat.com>
> > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > Cc: Marc Marí <markmb@redhat.com>
> > Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
> > ---
> >  hw/nvram/fw_cfg.c         | 16 ++++++++--------
> >  include/hw/nvram/fw_cfg.h |  8 ++------
> >  2 files changed, 10 insertions(+), 14 deletions(-)
> > 
> > diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> > index 73b0a81..31fa5c8 100644
> > --- a/hw/nvram/fw_cfg.c
> > +++ b/hw/nvram/fw_cfg.c
> > @@ -252,7 +252,8 @@ static void fw_cfg_write(FWCfgState *s, uint8_t value)
> >  
> >  static int fw_cfg_select(FWCfgState *s, uint16_t key)
> >  {
> > -    int ret;
> > +    int arch, ret;
> > +    FWCfgEntry *e;
> >  
> >      s->cur_offset = 0;
> >      if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
> > @@ -261,6 +262,12 @@ static int fw_cfg_select(FWCfgState *s, uint16_t key)
> >      } else {
> >          s->cur_entry = key;
> >          ret = 1;
> > +        /* entry successfully selected, now run callback if present */
> > +        arch = !!(key & FW_CFG_ARCH_LOCAL);
> > +        e = &s->entries[arch][key & FW_CFG_ENTRY_MASK];
> 
> Seems to match the logic in fw_cfg_read().
> 
> > +        if (e->read_callback) {
> > +            e->read_callback(e->callback_opaque, s->cur_offset);
> > +        }
> 
> The offset is constant 0 here, but that's fine.
> 
> >      }
> >  
> >      trace_fw_cfg_select(s, key, ret);
> > @@ -276,9 +283,6 @@ static uint8_t fw_cfg_read(FWCfgState *s)
> >      if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len)
> >          ret = 0;
> >      else {
> > -        if (e->read_callback) {
> > -            e->read_callback(e->callback_opaque, s->cur_offset);
> > -        }
> >          ret = e->data[s->cur_offset++];
> >      }
> >  
> > @@ -371,10 +375,6 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
> >                  len = (e->len - s->cur_offset);
> >              }
> >  
> > -            if (e->read_callback) {
> > -                e->read_callback(e->callback_opaque, s->cur_offset);
> > -            }
> > -
> >              /* If the access is not a read access, it will be a skip access,
> >               * tested before.
> >               */
> > diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
> > index 422e2e9..47ff118 100644
> > --- a/include/hw/nvram/fw_cfg.h
> > +++ b/include/hw/nvram/fw_cfg.h
> > @@ -183,12 +183,8 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data,
> >   * structure residing at key value FW_CFG_FILE_DIR, containing the item name,
> >   * data size, and assigned selector key value.
> >   * Additionally, set a callback function (and argument) to be called each
> > - * time a byte is read by the guest from this particular item, or once per
> > - * each DMA guest read operation.
> > - * NOTE: In addition to the opaque argument set here, the callback function
> > - * takes the current data offset as an additional argument, allowing it the
> > - * option of only acting upon specific offset values (e.g., 0, before the
> > - * first data byte of the selected item is returned to the guest).
> > + * time this item is selected (by having its selector key written to the
> > + * fw_cfg control register).
> 
> (3) This should be more precise. Selection doesn't only occur via an
> explicit write to the control register. Kevin suggested the
> FW_CFG_DMA_CTL_SELECT bit in FWCfgDmaAccess.control, for enabling
> "single trap" transfers. For the last sentence, I recommend:
> 
>   Additionally, set a callback function (and argument) to be called each
>   time this item is selected (by having its selector key either written
>   to the fw_cfg control register, or passed to QEMU in
>   FWCfgDmaAccess.control with FW_CFG_DMA_CTL_SELECT).

OK.

> 
> (4) Please add the following comment to the body of fw_cfg_reset():
> 
>     /* we never register a read callback for FW_CFG_SIGNATURE */
> 
> (You might want to replace the open-coded 0 argument in that
> fw_cfg_select() call with FW_CFG_SIGNATURE as well.)

Done.

Thanks,
--Gabriel

> 
> >   */
> >  void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
> >                                FWCfgReadCallback callback, void *callback_opaque,
> > 
> 
> Thanks!
> Laszlo

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

end of thread, other threads:[~2015-11-02 21:00 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-28 17:20 [Qemu-devel] [PATCH v2 0/4] fw_cfg: spec update, read optimization, misc. cleanup Gabriel L. Somlo
2015-10-28 17:20 ` [Qemu-devel] [PATCH v2 1/4] fw_cfg: move internal function call docs to header file Gabriel L. Somlo
2015-11-02 13:41   ` Laszlo Ersek
2015-11-02 20:36     ` Gabriel L. Somlo
2015-11-02 20:44       ` Laszlo Ersek
2015-10-28 17:20 ` [Qemu-devel] [PATCH v2 2/4] fw_cfg: amend callback behavior spec to once per select Gabriel L. Somlo
2015-11-02 14:16   ` Laszlo Ersek
2015-11-02 21:00     ` Gabriel L. Somlo
2015-10-28 17:20 ` [Qemu-devel] [PATCH v2 3/4] fw_cfg: remove offset argument from callback prototype Gabriel L. Somlo
2015-11-02 14:17   ` Laszlo Ersek
2015-10-28 17:20 ` [Qemu-devel] [PATCH v2 4/4] fw_cfg: streamline (non-DMA) read operations Gabriel L. Somlo
2015-11-02 14:38   ` Laszlo Ersek
2015-11-02 16:41     ` Eric Blake

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.