mirror of https://github.com/xemu-project/xemu.git
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:
commit
98557acf92
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue