Support resizeable blobs: we allocate more memory than currently available in the blob, which can later be filled in.
Signed-off-by: Michael S. Tsirkin <m...@redhat.com> --- include/hw/loader.h | 14 +++++++-- include/hw/nvram/fw_cfg.h | 2 +- hw/core/loader.c | 15 +++++---- hw/nvram/fw_cfg.c | 79 ++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 96 insertions(+), 14 deletions(-) diff --git a/include/hw/loader.h b/include/hw/loader.h index 796cbf9..ecce654 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -55,9 +55,19 @@ extern bool rom_file_has_mr; int rom_add_file(const char *file, const char *fw_dir, hwaddr addr, int32_t bootindex, bool option_rom); -void *rom_add_blob(const char *name, const void *blob, size_t len, +void *rom_add_blob_resizeable(const char *name, const void *blob, + size_t len, size_t max_len, + hwaddr addr, const char *fw_file_name, + FWCfgReadCallback fw_callback, + void *callback_opaque); +static inline void *rom_add_blob(const char *name, const void *blob, size_t len, hwaddr addr, const char *fw_file_name, - FWCfgReadCallback fw_callback, void *callback_opaque); + FWCfgReadCallback fw_callback, void *callback_opaque) +{ + return rom_add_blob_resizeable(name, blob, len, len, addr, + fw_file_name, fw_callback, callback_opaque); +} + int rom_add_elf_program(const char *name, void *data, size_t datasize, size_t romsize, hwaddr addr); int rom_load_all(void); diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index 72b1549..da4f5c5 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -75,7 +75,7 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data, size_t len); void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, FWCfgReadCallback callback, void *callback_opaque, - void *data, size_t len); + void *data, size_t len, size_t max_len); FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, hwaddr crl_addr, hwaddr data_addr); diff --git a/hw/core/loader.c b/hw/core/loader.c index 2bf6b8f..ad6ec67 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -720,9 +720,11 @@ err: return -1; } -void *rom_add_blob(const char *name, const void *blob, size_t len, - hwaddr addr, const char *fw_file_name, - FWCfgReadCallback fw_callback, void *callback_opaque) +void *rom_add_blob_resizeable(const char *name, const void *blob, + size_t len, size_t max_len, + hwaddr addr, const char *fw_file_name, + FWCfgReadCallback fw_callback, + void *callback_opaque) { Rom *rom; void *data = NULL; @@ -730,9 +732,10 @@ void *rom_add_blob(const char *name, const void *blob, size_t len, rom = g_malloc0(sizeof(*rom)); rom->name = g_strdup(name); rom->addr = addr; - rom->romsize = len; - rom->datasize = len; + rom->romsize = max_len; + rom->datasize = max_len; rom->data = g_malloc0(rom->datasize); + assert(len <= rom->datasize); memcpy(rom->data, blob, len); rom_insert(rom); if (fw_file_name && fw_cfg) { @@ -748,7 +751,7 @@ void *rom_add_blob(const char *name, const void *blob, size_t len, fw_cfg_add_file_callback(fw_cfg, fw_file_name, fw_callback, callback_opaque, - data, rom->romsize); + data, rom->romsize, rom->datasize); } return data; } diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index b71d251..65f233e 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -38,6 +38,8 @@ #define FW_CFG(obj) OBJECT_CHECK(FWCfgState, (obj), TYPE_FW_CFG) typedef struct FWCfgEntry { + uint32_t max_len; + uint32_t reset_len; uint32_t len; uint8_t *data; void *callback_opaque; @@ -57,6 +59,9 @@ struct FWCfgState { uint16_t cur_entry; uint32_t cur_offset; Notifier machine_ready; + /* Entry length: used for migration */ +#define FW_CFG_LEN_ENTRIES (2 * FW_CFG_MAX_ENTRY) + uint32_t len[FW_CFG_LEN_ENTRIES]; }; #define JPG_FILE 0 @@ -336,6 +341,13 @@ static const MemoryRegionOps fw_cfg_comb_mem_ops = { static void fw_cfg_reset(DeviceState *d) { FWCfgState *s = FW_CFG(d); + int i, j; + + for (i = 0; i < ARRAY_SIZE(s->entries); ++i) { + for (j = 0; j < ARRAY_SIZE(s->entries[0]); ++j) { + s->entries[i][j].len = s->entries[i][j].reset_len; + } + } fw_cfg_select(s, 0); } @@ -373,14 +385,63 @@ static bool is_version_1(void *opaque, int version_id) return version_id == 1; } +static void fw_cfg_pre_save(void *opaque) +{ + FWCfgState *s = FW_CFG(opaque); + int i, j; + + for (i = 0; i < ARRAY_SIZE(s->entries); ++i) { + for (j = 0; j < ARRAY_SIZE(s->entries[0]); ++j) { + s->len[i * j] = s->entries[i][j].len; + } + } +} + +static int fw_cfg_post_load(void *opaque, int version_id) +{ + FWCfgState *s = FW_CFG(opaque); + int i, j; + + for (i = 0; i < ARRAY_SIZE(s->entries); ++i) { + for (j = 0; j < ARRAY_SIZE(s->entries[0]); ++j) { + if (s->entries[i][j].max_len < s->len[i * j]) { + return -1; + } + s->entries[i][j].len = s->len[i * j]; + } + } + return 0; +} + +static bool fw_cfg_len_needed(void *opaque, int version_id) +{ + FWCfgState *s = FW_CFG(opaque); + int i, j; + + for (i = 0; i < ARRAY_SIZE(s->entries); ++i) { + for (j = 0; j < ARRAY_SIZE(s->entries[0]); ++j) { + if (s->entries[i][j].len != s->entries[i][j].max_len) { + return true; + } + } + } + + return false; +} + static const VMStateDescription vmstate_fw_cfg = { .name = "fw_cfg", .version_id = 2, .minimum_version_id = 1, + .post_load = fw_cfg_post_load, + .pre_save = fw_cfg_pre_save, .fields = (VMStateField[]) { VMSTATE_UINT16(cur_entry, FWCfgState), VMSTATE_UINT16_HACK(cur_offset, FWCfgState, is_version_1), VMSTATE_UINT32_V(cur_offset, FWCfgState, 2), + VMSTATE_ARRAY_TEST(len, FWCfgState, FW_CFG_LEN_ENTRIES, + fw_cfg_len_needed, + vmstate_info_uint32, uint32_t), VMSTATE_END_OF_LIST() } }; @@ -388,23 +449,28 @@ static const VMStateDescription vmstate_fw_cfg = { static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key, FWCfgReadCallback callback, void *callback_opaque, - void *data, size_t len) + void *data, size_t len, + size_t max_len) { int arch = !!(key & FW_CFG_ARCH_LOCAL); + assert(len <= max_len); + key &= FW_CFG_ENTRY_MASK; assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX); s->entries[arch][key].data = data; s->entries[arch][key].len = (uint32_t)len; + s->entries[arch][key].reset_len = (uint32_t)len; + s->entries[arch][key].max_len = (uint32_t)max_len; s->entries[arch][key].read_callback = callback; s->entries[arch][key].callback_opaque = callback_opaque; } void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len) { - fw_cfg_add_bytes_read_callback(s, key, NULL, NULL, data, len); + fw_cfg_add_bytes_read_callback(s, key, NULL, NULL, data, len, len); } void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value) @@ -454,13 +520,15 @@ void fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback, s->entries[arch][key].data = data; s->entries[arch][key].len = (uint32_t)len; + s->entries[arch][key].reset_len = (uint32_t)len; + s->entries[arch][key].max_len = (uint32_t)len; s->entries[arch][key].callback_opaque = callback_opaque; s->entries[arch][key].callback = callback; } void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, FWCfgReadCallback callback, void *callback_opaque, - void *data, size_t len) + void *data, size_t len, size_t max_len) { int i, index; size_t dsize; @@ -475,7 +543,8 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, assert(index < FW_CFG_FILE_SLOTS); fw_cfg_add_bytes_read_callback(s, FW_CFG_FILE_FIRST + index, - callback, callback_opaque, data, len); + callback, callback_opaque, data, len, + max_len); pstrcpy(s->files->f[index].name, sizeof(s->files->f[index].name), filename); @@ -496,7 +565,7 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data, size_t len) { - fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len); + fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len, len); } static void fw_cfg_machine_ready(struct Notifier *n, void *data) -- MST