fw_cfg: doc updates, various optimizations.

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJWcnl0AAoJEEy22O7T6HE4vhgP/AxlVRTQ1vg1AhHPHuTmXLmq
 tS5m2FF73yzfy2eBDd2Vm3z1vdwmhbcZbV745dLLzVMaaFGmHSCbUQFnGPCCNdKt
 yXZkVh1Aqj2rR//Mmn293JWwVJq04LtGIXQxPMXO7m88fcdQ8PHiwyAVPUsV+6DY
 lLWxhtTTYeHb9xngIKnW7nSbL2OZUD49s0vwYb9w3Ih97cPFOBjBYiv3WowI9y48
 /fDb1POzV0/bVyhKvlkWfkDpZqF1ilob3v3zq2VniTkm5+wGmVIhlFwI6nGJNtne
 +aYrZgQSzsFjByrqWxfCIyp91e7+SEctDqtZZw1DA1gn01ksFvrX9Kz5UJTcXQw3
 eDhyxVnssjrakDR3KAEoIMroQPsrBT79pr7cRfyt0wqEfZ7p1kxH/iuyS+ZTCoST
 xVdM2HxzV7Qabo2iPQBeCu47Vbu8ON9prypM9BHegGFcS11zcLEIOTHTlrC0zO1U
 TqYpls1Nm+B0SfVgN7NkBNm+vj5321Qf/I+O8Gvtxks6AkspJMcbld8SX0xUiVQE
 VNos1DReR4CLh6Yc9UgmZAtdfzyCci8cpCrB2N5B/+AzLQetmrRnPXDBNCx2fTOB
 gkQpHsrlxDOZugF6ljt9y5vD9U+HhlTuZRmNCLoz92YMj3j+I1kcClA/JAjRz1UD
 kSDhSKsPTTf8xkemdZCp
 =7yKy
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kraxel/tags/pull-fw-cfg-20151217-1' into staging

fw_cfg: doc updates, various optimizations.

# gpg: Signature made Thu 17 Dec 2015 08:59:32 GMT using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/kraxel/tags/pull-fw-cfg-20151217-1:
  fw_cfg: replace ioport data read with generic method
  fw_cfg: add generic non-DMA read method
  fw_cfg: avoid calculating invalid current entry pointer
  fw_cfg: remove offset argument from callback prototype
  fw_cfg: amend callback behavior spec to once per select
  fw_cfg: move internal function call docs to header file

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-12-17 12:40:07 +00:00
commit 98557acf92
6 changed files with 166 additions and 128 deletions

View File

@ -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

View File

@ -631,7 +631,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;

View File

@ -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;

View File

@ -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,41 +262,45 @@ 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);
}
}
trace_fw_cfg_select(s, key, ret);
return ret;
}
static uint8_t fw_cfg_read(FWCfgState *s)
{
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 {
if (e->read_callback) {
e->read_callback(e->callback_opaque, s->cur_offset);
}
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)
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->cur_entry == FW_CFG_INVALID) ? NULL :
&s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
uint64_t value = 0;
unsigned i;
for (i = 0; i < size; ++i) {
value = (value << 8) | fw_cfg_read(s);
assert(size > 0 && size <= sizeof(value));
if (s->cur_entry != FW_CFG_INVALID && e->data && s->cur_offset < e->len) {
/* The least significant 'size' bytes of the return value are
* expected to contain a string preserving portion of the item
* data, padded with zeros on the right in case we run out early.
* In technical terms, we're composing the host-endian representation
* of the big endian interpretation of the fw_cfg string.
*/
do {
value = (value << 8) | e->data[s->cur_offset++];
} while (--size && s->cur_offset < e->len);
/* If size is still not zero, we *did* run out early, so continue
* left-shifting, to add the appropriate number of padding zeros
* on the right.
*/
value <<= 8 * size;
}
trace_fw_cfg_read(s, value);
return value;
}
@ -338,7 +343,8 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
}
arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
e = (s->cur_entry == FW_CFG_INVALID) ? NULL :
&s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
if (dma.control & FW_CFG_DMA_CTL_READ) {
read = 1;
@ -371,10 +377,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.
*/
@ -451,12 +453,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 +479,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 +490,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,
@ -513,7 +509,8 @@ static void fw_cfg_reset(DeviceState *d)
{
FWCfgState *s = FW_CFG(d);
fw_cfg_select(s, 0);
/* we never register a read callback for FW_CFG_SIGNATURE */
fw_cfg_select(s, FW_CFG_SIGNATURE);
}
/* Save restore 32 bit int as uint16_t

View File

@ -70,22 +70,146 @@ 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:
* @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 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).
*/
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
* to 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);

View File

@ -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