qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 1/3] loader: add support for resizeable blobs


From: Michael S. Tsirkin
Subject: [Qemu-devel] [PATCH 1/3] loader: add support for resizeable blobs
Date: Mon, 28 Jul 2014 17:35:04 +0200

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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]