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