|
|
5d360b |
From 1cc1455511ff6ada7f4b3c4e23d8ff82f820f1ff Mon Sep 17 00:00:00 2001
|
|
|
5d360b |
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
|
|
|
5d360b |
Date: Wed, 13 Dec 2017 13:38:38 +0100
|
|
|
5d360b |
Subject: [PATCH 07/41] fw-cfg: support writeable blobs
|
|
|
5d360b |
MIME-Version: 1.0
|
|
|
5d360b |
Content-Type: text/plain; charset=UTF-8
|
|
|
5d360b |
Content-Transfer-Encoding: 8bit
|
|
|
5d360b |
|
|
|
5d360b |
RH-Author: Marc-André Lureau <marcandre.lureau@redhat.com>
|
|
|
5d360b |
Message-id: <20171213133912.26176-8-marcandre.lureau@redhat.com>
|
|
|
5d360b |
Patchwork-id: 78356
|
|
|
5d360b |
O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 07/41] fw-cfg: support writeable blobs
|
|
|
5d360b |
Bugzilla: 1411490
|
|
|
5d360b |
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
5d360b |
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
|
|
|
5d360b |
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
5d360b |
|
|
|
5d360b |
From: "Michael S. Tsirkin" <mst@redhat.com>
|
|
|
5d360b |
|
|
|
5d360b |
Useful to send guest data back to QEMU.
|
|
|
5d360b |
|
|
|
5d360b |
Changes from Laszlo Ersek <lersek@redhat.com>:
|
|
|
5d360b |
- rebase the patch from Michael Tsirkin's original postings at [1] and [2]
|
|
|
5d360b |
to the following patches:
|
|
|
5d360b |
- loader: Allow a custom AddressSpace when loading ROMs
|
|
|
5d360b |
- loader: Add AddressSpace loading support to uImages
|
|
|
5d360b |
- loader: fix handling of custom address spaces when adding ROM blobs
|
|
|
5d360b |
- reject such writes immediately that would exceed the end of the array,
|
|
|
5d360b |
rather than performing a partial write before setting the error bit: see
|
|
|
5d360b |
the (len != dma.length) condition
|
|
|
5d360b |
- document the write interface
|
|
|
5d360b |
|
|
|
5d360b |
[1] http://lists.nongnu.org/archive/html/qemu-devel/2016-02/msg04968.html
|
|
|
5d360b |
[2] http://lists.nongnu.org/archive/html/qemu-devel/2016-03/msg02735.html
|
|
|
5d360b |
|
|
|
5d360b |
Cc: "Gabriel L. Somlo" <somlo@cmu.edu>
|
|
|
5d360b |
Cc: "Michael S. Tsirkin" <mst@redhat.com>
|
|
|
5d360b |
Cc: Gerd Hoffmann <kraxel@redhat.com>
|
|
|
5d360b |
Cc: Igor Mammedov <imammedo@redhat.com>
|
|
|
5d360b |
Cc: Michael Walle <michael@walle.cc>
|
|
|
5d360b |
Cc: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
5d360b |
Cc: Peter Maydell <peter.maydell@linaro.org>
|
|
|
5d360b |
Cc: Shannon Zhao <zhaoshenglong@huawei.com>
|
|
|
5d360b |
Cc: qemu-arm@nongnu.org
|
|
|
5d360b |
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
|
|
5d360b |
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
5d360b |
Reviewed-by: Marcel Apfelbaum <marcel@redhat.com>
|
|
|
5d360b |
Acked-by: Gabriel Somlo <somlo@cmu.edu>
|
|
|
5d360b |
Tested-by: Gabriel Somlo <somlo@cmu.edu>
|
|
|
5d360b |
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
|
|
|
5d360b |
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
|
|
5d360b |
Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>
|
|
|
5d360b |
|
|
|
5d360b |
(cherry picked from commit baf2d5bfbac015b27f4db74feab235e167df0c84)
|
|
|
5d360b |
|
|
|
5d360b |
RHEL: major conflict due to internal API changes, but functional
|
|
|
5d360b |
changes minor.
|
|
|
5d360b |
|
|
|
5d360b |
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
|
|
5d360b |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
5d360b |
---
|
|
|
5d360b |
hw/core/loader.c | 19 ++++++++++++-------
|
|
|
5d360b |
hw/i386/acpi-build.c | 2 +-
|
|
|
5d360b |
hw/lm32/lm32_hwsetup.h | 3 ++-
|
|
|
5d360b |
hw/nvram/fw_cfg.c | 35 +++++++++++++++++++++++++++++------
|
|
|
5d360b |
include/hw/loader.h | 5 +++--
|
|
|
5d360b |
include/hw/nvram/fw_cfg.h | 2 +-
|
|
|
5d360b |
6 files changed, 48 insertions(+), 18 deletions(-)
|
|
|
5d360b |
|
|
|
5d360b |
diff --git a/hw/core/loader.c b/hw/core/loader.c
|
|
|
5d360b |
index 9309b8c..c824bc2 100644
|
|
|
5d360b |
--- a/hw/core/loader.c
|
|
|
5d360b |
+++ b/hw/core/loader.c
|
|
|
5d360b |
@@ -575,13 +575,13 @@ static void rom_insert(Rom *rom)
|
|
|
5d360b |
QTAILQ_INSERT_TAIL(&roms, rom, next);
|
|
|
5d360b |
}
|
|
|
5d360b |
|
|
|
5d360b |
-static void *rom_set_mr(Rom *rom, const char *name)
|
|
|
5d360b |
+static void *rom_set_mr(Rom *rom, const char *name, bool ro)
|
|
|
5d360b |
{
|
|
|
5d360b |
void *data;
|
|
|
5d360b |
|
|
|
5d360b |
rom->mr = g_malloc(sizeof(*rom->mr));
|
|
|
5d360b |
memory_region_init_ram(rom->mr, name, rom->datasize);
|
|
|
5d360b |
- memory_region_set_readonly(rom->mr, true);
|
|
|
5d360b |
+ memory_region_set_readonly(rom->mr, ro);
|
|
|
5d360b |
vmstate_register_ram_global(rom->mr);
|
|
|
5d360b |
|
|
|
5d360b |
data = memory_region_get_ram_ptr(rom->mr);
|
|
|
5d360b |
@@ -645,7 +645,7 @@ int rom_add_file(const char *file, const char *fw_dir,
|
|
|
5d360b |
snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
|
|
|
5d360b |
|
|
|
5d360b |
if ((!option_rom || option_rom_has_mr) && rom_file_has_mr) {
|
|
|
5d360b |
- data = rom_set_mr(rom, devpath);
|
|
|
5d360b |
+ data = rom_set_mr(rom, devpath, true);
|
|
|
5d360b |
} else {
|
|
|
5d360b |
data = rom->data;
|
|
|
5d360b |
}
|
|
|
5d360b |
@@ -670,7 +670,8 @@ err:
|
|
|
5d360b |
|
|
|
5d360b |
void *rom_add_blob(const char *name, const void *blob, size_t len,
|
|
|
5d360b |
hwaddr addr, const char *fw_file_name,
|
|
|
5d360b |
- FWCfgReadCallback fw_callback, void *callback_opaque)
|
|
|
5d360b |
+ FWCfgReadCallback fw_callback, void *callback_opaque,
|
|
|
5d360b |
+ bool read_only)
|
|
|
5d360b |
{
|
|
|
5d360b |
Rom *rom;
|
|
|
5d360b |
void *data = NULL;
|
|
|
5d360b |
@@ -686,17 +687,21 @@ void *rom_add_blob(const char *name, const void *blob, size_t len,
|
|
|
5d360b |
if (fw_file_name && fw_cfg) {
|
|
|
5d360b |
char devpath[100];
|
|
|
5d360b |
|
|
|
5d360b |
- snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
|
|
|
5d360b |
+ if (read_only) {
|
|
|
5d360b |
+ snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
|
|
|
5d360b |
+ } else {
|
|
|
5d360b |
+ snprintf(devpath, sizeof(devpath), "/ram@%s", fw_file_name);
|
|
|
5d360b |
+ }
|
|
|
5d360b |
|
|
|
5d360b |
if (rom_file_has_mr) {
|
|
|
5d360b |
- data = rom_set_mr(rom, devpath);
|
|
|
5d360b |
+ data = rom_set_mr(rom, devpath, read_only);
|
|
|
5d360b |
} else {
|
|
|
5d360b |
data = rom->data;
|
|
|
5d360b |
}
|
|
|
5d360b |
|
|
|
5d360b |
fw_cfg_add_file_callback(fw_cfg, fw_file_name,
|
|
|
5d360b |
fw_callback, callback_opaque,
|
|
|
5d360b |
- data, rom->romsize);
|
|
|
5d360b |
+ data, rom->romsize, read_only);
|
|
|
5d360b |
}
|
|
|
5d360b |
return data;
|
|
|
5d360b |
}
|
|
|
5d360b |
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
|
|
|
5d360b |
index 85291f5..52dd500 100644
|
|
|
5d360b |
--- a/hw/i386/acpi-build.c
|
|
|
5d360b |
+++ b/hw/i386/acpi-build.c
|
|
|
5d360b |
@@ -1182,7 +1182,7 @@ static void *acpi_add_rom_blob(AcpiBuildState *build_state, GArray *blob,
|
|
|
5d360b |
const char *name)
|
|
|
5d360b |
{
|
|
|
5d360b |
return rom_add_blob(name, blob->data, acpi_data_len(blob), -1, name,
|
|
|
5d360b |
- acpi_build_update, build_state);
|
|
|
5d360b |
+ acpi_build_update, build_state, true);
|
|
|
5d360b |
}
|
|
|
5d360b |
|
|
|
5d360b |
static const VMStateDescription vmstate_acpi_build = {
|
|
|
5d360b |
diff --git a/hw/lm32/lm32_hwsetup.h b/hw/lm32/lm32_hwsetup.h
|
|
|
5d360b |
index 9fd5e69..92f952f 100644
|
|
|
5d360b |
--- a/hw/lm32/lm32_hwsetup.h
|
|
|
5d360b |
+++ b/hw/lm32/lm32_hwsetup.h
|
|
|
5d360b |
@@ -73,7 +73,8 @@ static inline void hwsetup_free(HWSetup *hw)
|
|
|
5d360b |
static inline void hwsetup_create_rom(HWSetup *hw,
|
|
|
5d360b |
hwaddr base)
|
|
|
5d360b |
{
|
|
|
5d360b |
- rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE, base, NULL, NULL, NULL);
|
|
|
5d360b |
+ rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE,
|
|
|
5d360b |
+ base, NULL, NULL, NULL, true);
|
|
|
5d360b |
}
|
|
|
5d360b |
|
|
|
5d360b |
static inline void hwsetup_add_u8(HWSetup *hw, uint8_t u)
|
|
|
5d360b |
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
|
|
|
5d360b |
index 1317df7..1789487 100644
|
|
|
5d360b |
--- a/hw/nvram/fw_cfg.c
|
|
|
5d360b |
+++ b/hw/nvram/fw_cfg.c
|
|
|
5d360b |
@@ -46,9 +46,11 @@
|
|
|
5d360b |
#define FW_CFG_DMA_CTL_READ 0x02
|
|
|
5d360b |
#define FW_CFG_DMA_CTL_SKIP 0x04
|
|
|
5d360b |
#define FW_CFG_DMA_CTL_SELECT 0x08
|
|
|
5d360b |
+#define FW_CFG_DMA_CTL_WRITE 0x10
|
|
|
5d360b |
|
|
|
5d360b |
typedef struct FWCfgEntry {
|
|
|
5d360b |
uint32_t len;
|
|
|
5d360b |
+ bool allow_write;
|
|
|
5d360b |
uint8_t *data;
|
|
|
5d360b |
void *callback_opaque;
|
|
|
5d360b |
FWCfgReadCallback read_callback;
|
|
|
5d360b |
@@ -279,7 +281,7 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
|
|
|
5d360b |
FWCfgDmaAccess dma;
|
|
|
5d360b |
int arch;
|
|
|
5d360b |
FWCfgEntry *e;
|
|
|
5d360b |
- int read;
|
|
|
5d360b |
+ int read = 0, write = 0;
|
|
|
5d360b |
dma_addr_t dma_addr;
|
|
|
5d360b |
|
|
|
5d360b |
/* Reset the address before the next access */
|
|
|
5d360b |
@@ -306,8 +308,13 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
|
|
|
5d360b |
|
|
|
5d360b |
if (dma.control & FW_CFG_DMA_CTL_READ) {
|
|
|
5d360b |
read = 1;
|
|
|
5d360b |
+ write = 0;
|
|
|
5d360b |
+ } else if (dma.control & FW_CFG_DMA_CTL_WRITE) {
|
|
|
5d360b |
+ read = 0;
|
|
|
5d360b |
+ write = 1;
|
|
|
5d360b |
} else if (dma.control & FW_CFG_DMA_CTL_SKIP) {
|
|
|
5d360b |
read = 0;
|
|
|
5d360b |
+ write = 0;
|
|
|
5d360b |
} else {
|
|
|
5d360b |
dma.length = 0;
|
|
|
5d360b |
}
|
|
|
5d360b |
@@ -328,6 +335,9 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
|
|
|
5d360b |
}
|
|
|
5d360b |
}
|
|
|
5d360b |
|
|
|
5d360b |
+ if (write) {
|
|
|
5d360b |
+ dma.control |= FW_CFG_DMA_CTL_ERROR;
|
|
|
5d360b |
+ }
|
|
|
5d360b |
} else {
|
|
|
5d360b |
if (dma.length <= (e->len - s->cur_offset)) {
|
|
|
5d360b |
len = dma.length;
|
|
|
5d360b |
@@ -349,6 +359,16 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
|
|
|
5d360b |
}
|
|
|
5d360b |
}
|
|
|
5d360b |
|
|
|
5d360b |
+ if (write) {
|
|
|
5d360b |
+ if (!e->allow_write ||
|
|
|
5d360b |
+ len != dma.length ||
|
|
|
5d360b |
+ dma_memory_read(s->dma, dma.address,
|
|
|
5d360b |
+ &e->data[s->cur_offset], len)) {
|
|
|
5d360b |
+ dma.control |= FW_CFG_DMA_CTL_ERROR;
|
|
|
5d360b |
+ }
|
|
|
5d360b |
+ }
|
|
|
5d360b |
+
|
|
|
5d360b |
+
|
|
|
5d360b |
s->cur_offset += len;
|
|
|
5d360b |
}
|
|
|
5d360b |
|
|
|
5d360b |
@@ -539,7 +559,8 @@ static const VMStateDescription vmstate_fw_cfg = {
|
|
|
5d360b |
static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key,
|
|
|
5d360b |
FWCfgReadCallback callback,
|
|
|
5d360b |
void *callback_opaque,
|
|
|
5d360b |
- void *data, size_t len)
|
|
|
5d360b |
+ void *data, size_t len,
|
|
|
5d360b |
+ bool read_only)
|
|
|
5d360b |
{
|
|
|
5d360b |
int arch = !!(key & FW_CFG_ARCH_LOCAL);
|
|
|
5d360b |
|
|
|
5d360b |
@@ -552,11 +573,12 @@ static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key,
|
|
|
5d360b |
s->entries[arch][key].len = (uint32_t)len;
|
|
|
5d360b |
s->entries[arch][key].read_callback = callback;
|
|
|
5d360b |
s->entries[arch][key].callback_opaque = callback_opaque;
|
|
|
5d360b |
+ s->entries[arch][key].allow_write = !read_only;
|
|
|
5d360b |
}
|
|
|
5d360b |
|
|
|
5d360b |
void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len)
|
|
|
5d360b |
{
|
|
|
5d360b |
- fw_cfg_add_bytes_read_callback(s, key, NULL, NULL, data, len);
|
|
|
5d360b |
+ fw_cfg_add_bytes_read_callback(s, key, NULL, NULL, data, len, true);
|
|
|
5d360b |
}
|
|
|
5d360b |
|
|
|
5d360b |
void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value)
|
|
|
5d360b |
@@ -595,7 +617,7 @@ void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value)
|
|
|
5d360b |
|
|
|
5d360b |
void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
|
|
|
5d360b |
FWCfgReadCallback callback, void *callback_opaque,
|
|
|
5d360b |
- void *data, size_t len)
|
|
|
5d360b |
+ void *data, size_t len, bool read_only)
|
|
|
5d360b |
{
|
|
|
5d360b |
int i, index;
|
|
|
5d360b |
size_t dsize;
|
|
|
5d360b |
@@ -620,7 +642,8 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
|
|
|
5d360b |
}
|
|
|
5d360b |
|
|
|
5d360b |
fw_cfg_add_bytes_read_callback(s, FW_CFG_FILE_FIRST + index,
|
|
|
5d360b |
- callback, callback_opaque, data, len);
|
|
|
5d360b |
+ callback, callback_opaque, data, len,
|
|
|
5d360b |
+ read_only);
|
|
|
5d360b |
|
|
|
5d360b |
s->files->f[index].size = cpu_to_be32(len);
|
|
|
5d360b |
s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index);
|
|
|
5d360b |
@@ -632,7 +655,7 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
|
|
|
5d360b |
void fw_cfg_add_file(FWCfgState *s, const char *filename,
|
|
|
5d360b |
void *data, size_t len)
|
|
|
5d360b |
{
|
|
|
5d360b |
- fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len);
|
|
|
5d360b |
+ fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len, true);
|
|
|
5d360b |
}
|
|
|
5d360b |
|
|
|
5d360b |
static void fw_cfg_machine_ready(struct Notifier *n, void *data)
|
|
|
5d360b |
diff --git a/include/hw/loader.h b/include/hw/loader.h
|
|
|
5d360b |
index a5e02ce..f04a834 100644
|
|
|
5d360b |
--- a/include/hw/loader.h
|
|
|
5d360b |
+++ b/include/hw/loader.h
|
|
|
5d360b |
@@ -31,7 +31,8 @@ int rom_add_file(const char *file, const char *fw_dir,
|
|
|
5d360b |
bool option_rom);
|
|
|
5d360b |
void *rom_add_blob(const char *name, const void *blob, size_t len,
|
|
|
5d360b |
hwaddr addr, const char *fw_file_name,
|
|
|
5d360b |
- FWCfgReadCallback fw_callback, void *callback_opaque);
|
|
|
5d360b |
+ FWCfgReadCallback fw_callback, void *callback_opaque,
|
|
|
5d360b |
+ bool read_only);
|
|
|
5d360b |
int rom_add_elf_program(const char *name, void *data, size_t datasize,
|
|
|
5d360b |
size_t romsize, hwaddr addr);
|
|
|
5d360b |
int rom_load_all(void);
|
|
|
5d360b |
@@ -44,7 +45,7 @@ void do_info_roms(Monitor *mon, const QDict *qdict);
|
|
|
5d360b |
#define rom_add_file_fixed(_f, _a, _i) \
|
|
|
5d360b |
rom_add_file(_f, NULL, _a, _i, false)
|
|
|
5d360b |
#define rom_add_blob_fixed(_f, _b, _l, _a) \
|
|
|
5d360b |
- (rom_add_blob(_f, _b, _l, _a, NULL, NULL, NULL) ? 0 : -1)
|
|
|
5d360b |
+ (rom_add_blob(_f, _b, _l, _a, NULL, NULL, NULL, true) ? 0 : -1)
|
|
|
5d360b |
|
|
|
5d360b |
#define PC_ROM_MIN_VGA 0xc0000
|
|
|
5d360b |
#define PC_ROM_MIN_OPTION 0xc8000
|
|
|
5d360b |
diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
|
|
|
5d360b |
index b193e38..76fc787 100644
|
|
|
5d360b |
--- a/include/hw/nvram/fw_cfg.h
|
|
|
5d360b |
+++ b/include/hw/nvram/fw_cfg.h
|
|
|
5d360b |
@@ -83,7 +83,7 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data,
|
|
|
5d360b |
size_t len);
|
|
|
5d360b |
void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
|
|
|
5d360b |
FWCfgReadCallback callback, void *callback_opaque,
|
|
|
5d360b |
- void *data, size_t len);
|
|
|
5d360b |
+ void *data, size_t len, bool read_only);
|
|
|
5d360b |
FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
|
|
|
5d360b |
hwaddr crl_addr, hwaddr data_addr);
|
|
|
5d360b |
FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
|
|
|
5d360b |
--
|
|
|
5d360b |
1.8.3.1
|
|
|
5d360b |
|