* [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt
@ 2014-12-22 12:11 Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 01/11] fw_cfg: hard separation between the MMIO and I/O port mappings Paolo Bonzini
` (12 more replies)
0 siblings, 13 replies; 14+ messages in thread
From: Paolo Bonzini @ 2014-12-22 12:11 UTC (permalink / raw)
To: peter.maydell, qemu-devel, rjones, drjones, lersek, agraf
The only change from v5 to v6 is that sysbus_mmio_map is moved to
fw_cfg_init_mem. (And fw_cfg_init1 returns void because it's now
simpler that way).
This causes changes in patches 1, 5 and 6.
I did not have the ARM firmware built, so I tested on PPC to check
for compatibility, and played with "info mtree" and qtest on ARM
(see also commit message for patch 7).
Paolo
Laszlo Ersek (10):
fw_cfg: hard separation between the MMIO and I/O port mappings
fw_cfg: move boards to fw_cfg_init_io() / fw_cfg_init_mem()
fw_cfg_mem: max access size and region size are the same for data
register
fw_cfg_mem: flip ctl_mem_ops and data_mem_ops to DEVICE_BIG_ENDIAN
fw_cfg_mem: introduce the "data_width" property
fw_cfg_mem: expose the "data_width" property with
fw_cfg_init_mem_wide()
arm: add fw_cfg to "virt" board
hw/loader: split out load_image_gzipped_buffer()
hw/arm: pass pristine kernel image to guest firmware over fw_cfg
hw/arm/virt: enable passing of EFI-stubbed kernel to guest UEFI
firmware
Paolo Bonzini (1):
exec: allows 8-byte accesses in subpage_ops
exec.c | 13 ++-
hw/arm/boot.c | 88 +++++++++++++++-
hw/arm/virt.c | 22 ++++
hw/core/loader.c | 30 ++++--
hw/i386/pc.c | 4 +-
hw/nvram/fw_cfg.c | 250 +++++++++++++++++++++++++++++++++++-----------
hw/ppc/mac_newworld.c | 2 +-
hw/ppc/mac_oldworld.c | 2 +-
hw/sparc/sun4m.c | 2 +-
hw/sparc64/sun4u.c | 2 +-
include/hw/arm/arm.h | 5 +
include/hw/loader.h | 9 ++
include/hw/nvram/fw_cfg.h | 6 +-
include/qemu/typedefs.h | 2 +
14 files changed, 352 insertions(+), 85 deletions(-)
--
2.1.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v6 01/11] fw_cfg: hard separation between the MMIO and I/O port mappings
2014-12-22 12:11 [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt Paolo Bonzini
@ 2014-12-22 12:11 ` Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 02/11] fw_cfg: move boards to fw_cfg_init_io() / fw_cfg_init_mem() Paolo Bonzini
` (11 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Paolo Bonzini @ 2014-12-22 12:11 UTC (permalink / raw)
To: peter.maydell, qemu-devel, rjones, drjones, lersek, agraf
From: Laszlo Ersek <lersek@redhat.com>
We are going to introduce a wide data register for fw_cfg, but only for
the MMIO mapped device. The wide data register will also require the
tightening of endiannesses.
However we don't want to touch the I/O port mapped fw_cfg device at all.
Currently QEMU provides a single fw_cfg device type that can handle both
I/O port and MMIO mapping. This flexibility is not actually exploited by
any board in the tree, but it renders restricting the above changes to
MMIO very hard.
Therefore, let's derive two classes from TYPE_FW_CFG: TYPE_FW_CFG_IO and
TYPE_FW_CFG_MEM.
TYPE_FW_CFG_IO incorporates the base I/O port and the related combined
MemoryRegion. (NB: all boards in the tree that use the I/O port mapped
flavor opt for the combined mapping; that is, when the data port overlays
the high address byte of the selector port. Therefore we can drop the
capability to map those I/O ports separately.)
TYPE_FW_CFG_MEM incorporates the base addresses for the MMIO selector and
data registers, and their respective MemoryRegions.
The "realize" and "props" class members are specific to each new derived
class, and become unused for the base class. The base class retains the
"reset" member and the "vmsd" member, because the reset functionality and
the set of migrated data are not specific to the mapping.
The new functions fw_cfg_init_io() and fw_cfg_init_mem() expose the
possible mappings in separation. For now fw_cfg_init() is retained as a
compatibility shim that enforces the above assumptions.
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/nvram/fw_cfg.c | 177 ++++++++++++++++++++++++++++++++--------------
include/hw/nvram/fw_cfg.h | 2 +
include/qemu/typedefs.h | 2 +
3 files changed, 126 insertions(+), 55 deletions(-)
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index c4b78ed..ab7bfff 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -32,10 +32,16 @@
#define FW_CFG_SIZE 2
#define FW_CFG_DATA_SIZE 1
-#define TYPE_FW_CFG "fw_cfg"
#define FW_CFG_NAME "fw_cfg"
#define FW_CFG_PATH "/machine/" FW_CFG_NAME
-#define FW_CFG(obj) OBJECT_CHECK(FWCfgState, (obj), TYPE_FW_CFG)
+
+#define TYPE_FW_CFG "fw_cfg"
+#define TYPE_FW_CFG_IO "fw_cfg_io"
+#define TYPE_FW_CFG_MEM "fw_cfg_mem"
+
+#define FW_CFG(obj) OBJECT_CHECK(FWCfgState, (obj), TYPE_FW_CFG)
+#define FW_CFG_IO(obj) OBJECT_CHECK(FWCfgIoState, (obj), TYPE_FW_CFG_IO)
+#define FW_CFG_MEM(obj) OBJECT_CHECK(FWCfgMemState, (obj), TYPE_FW_CFG_MEM)
typedef struct FWCfgEntry {
uint32_t len;
@@ -50,8 +56,6 @@ struct FWCfgState {
SysBusDevice parent_obj;
/*< public >*/
- MemoryRegion ctl_iomem, data_iomem, comb_iomem;
- uint32_t ctl_iobase, data_iobase;
FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
FWCfgFiles *files;
uint16_t cur_entry;
@@ -59,6 +63,23 @@ struct FWCfgState {
Notifier machine_ready;
};
+struct FWCfgIoState {
+ /*< private >*/
+ FWCfgState parent_obj;
+ /*< public >*/
+
+ MemoryRegion comb_iomem;
+ uint32_t iobase;
+};
+
+struct FWCfgMemState {
+ /*< private >*/
+ FWCfgState parent_obj;
+ /*< public >*/
+
+ MemoryRegion ctl_iomem, data_iomem;
+};
+
#define JPG_FILE 0
#define BMP_FILE 1
@@ -560,19 +581,11 @@ static void fw_cfg_machine_ready(struct Notifier *n, void *data)
qemu_register_reset(fw_cfg_machine_reset, s);
}
-FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
- hwaddr ctl_addr, hwaddr data_addr)
-{
- DeviceState *dev;
- SysBusDevice *d;
- FWCfgState *s;
- dev = qdev_create(NULL, TYPE_FW_CFG);
- qdev_prop_set_uint32(dev, "ctl_iobase", ctl_port);
- qdev_prop_set_uint32(dev, "data_iobase", data_port);
- d = SYS_BUS_DEVICE(dev);
- s = FW_CFG(dev);
+static void fw_cfg_init1(DeviceState *dev)
+{
+ FWCfgState *s = FW_CFG(dev);
assert(!object_resolve_path(FW_CFG_PATH, NULL));
@@ -580,12 +593,6 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
qdev_init_nofail(dev);
- if (ctl_addr) {
- sysbus_mmio_map(d, 0, ctl_addr);
- }
- if (data_addr) {
- sysbus_mmio_map(d, 1, data_addr);
- }
fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4);
fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16);
fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC));
@@ -596,48 +603,48 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
s->machine_ready.notify = fw_cfg_machine_ready;
qemu_add_machine_init_done_notifier(&s->machine_ready);
-
- return s;
}
-static void fw_cfg_initfn(Object *obj)
+FWCfgState *fw_cfg_init_io(uint32_t iobase)
{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- FWCfgState *s = FW_CFG(obj);
+ DeviceState *dev;
- memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops, s,
- "fwcfg.ctl", FW_CFG_SIZE);
- sysbus_init_mmio(sbd, &s->ctl_iomem);
- memory_region_init_io(&s->data_iomem, OBJECT(s), &fw_cfg_data_mem_ops, s,
- "fwcfg.data", FW_CFG_DATA_SIZE);
- sysbus_init_mmio(sbd, &s->data_iomem);
- /* In case ctl and data overlap: */
- memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops, s,
- "fwcfg", FW_CFG_SIZE);
+ dev = qdev_create(NULL, TYPE_FW_CFG_IO);
+ qdev_prop_set_uint32(dev, "iobase", iobase);
+ fw_cfg_init1(dev);
+
+ return FW_CFG(dev);
}
-static void fw_cfg_realize(DeviceState *dev, Error **errp)
+FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr)
{
- FWCfgState *s = FW_CFG(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ DeviceState *dev;
+ SysBusDevice *sbd;
- if (s->ctl_iobase + 1 == s->data_iobase) {
- sysbus_add_io(sbd, s->ctl_iobase, &s->comb_iomem);
- } else {
- if (s->ctl_iobase) {
- sysbus_add_io(sbd, s->ctl_iobase, &s->ctl_iomem);
- }
- if (s->data_iobase) {
- sysbus_add_io(sbd, s->data_iobase, &s->data_iomem);
- }
+ dev = qdev_create(NULL, TYPE_FW_CFG_MEM);
+ fw_cfg_init1(dev);
+
+ sbd = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(sbd, 0, ctl_addr);
+ sysbus_mmio_map(sbd, 1, data_addr);
+
+ return FW_CFG(dev);
+}
+
+
+FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
+ hwaddr crl_addr, hwaddr data_addr)
+{
+ if (ctl_port + 1 == data_port && crl_addr == 0 && data_addr == 0) {
+ return fw_cfg_init_io(ctl_port);
}
+ if (ctl_port == 0 && data_port == 0 && crl_addr != 0 && data_addr != 0) {
+ return fw_cfg_init_mem(crl_addr, data_addr);
+ }
+ assert(false);
+ return NULL;
}
-static Property fw_cfg_properties[] = {
- DEFINE_PROP_UINT32("ctl_iobase", FWCfgState, ctl_iobase, -1),
- DEFINE_PROP_UINT32("data_iobase", FWCfgState, data_iobase, -1),
- DEFINE_PROP_END_OF_LIST(),
-};
FWCfgState *fw_cfg_find(void)
{
@@ -648,23 +655,83 @@ static void fw_cfg_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->realize = fw_cfg_realize;
dc->reset = fw_cfg_reset;
dc->vmsd = &vmstate_fw_cfg;
- dc->props = fw_cfg_properties;
}
static const TypeInfo fw_cfg_info = {
.name = TYPE_FW_CFG,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(FWCfgState),
- .instance_init = fw_cfg_initfn,
.class_init = fw_cfg_class_init,
};
+
+static Property fw_cfg_io_properties[] = {
+ DEFINE_PROP_UINT32("iobase", FWCfgIoState, iobase, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void fw_cfg_io_realize(DeviceState *dev, Error **errp)
+{
+ FWCfgIoState *s = FW_CFG_IO(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops,
+ FW_CFG(s), "fwcfg", FW_CFG_SIZE);
+ sysbus_add_io(sbd, s->iobase, &s->comb_iomem);
+}
+
+static void fw_cfg_io_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = fw_cfg_io_realize;
+ dc->props = fw_cfg_io_properties;
+}
+
+static const TypeInfo fw_cfg_io_info = {
+ .name = TYPE_FW_CFG_IO,
+ .parent = TYPE_FW_CFG,
+ .instance_size = sizeof(FWCfgIoState),
+ .class_init = fw_cfg_io_class_init,
+};
+
+
+static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
+{
+ FWCfgMemState *s = FW_CFG_MEM(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops,
+ FW_CFG(s), "fwcfg.ctl", FW_CFG_SIZE);
+ sysbus_init_mmio(sbd, &s->ctl_iomem);
+
+ memory_region_init_io(&s->data_iomem, OBJECT(s), &fw_cfg_data_mem_ops,
+ FW_CFG(s), "fwcfg.data", FW_CFG_DATA_SIZE);
+ sysbus_init_mmio(sbd, &s->data_iomem);
+}
+
+static void fw_cfg_mem_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = fw_cfg_mem_realize;
+}
+
+static const TypeInfo fw_cfg_mem_info = {
+ .name = TYPE_FW_CFG_MEM,
+ .parent = TYPE_FW_CFG,
+ .instance_size = sizeof(FWCfgMemState),
+ .class_init = fw_cfg_mem_class_init,
+};
+
+
static void fw_cfg_register_types(void)
{
type_register_static(&fw_cfg_info);
+ type_register_static(&fw_cfg_io_info);
+ type_register_static(&fw_cfg_mem_info);
}
type_init(fw_cfg_register_types)
diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
index 56e1ed7..fcc88ea 100644
--- a/include/hw/nvram/fw_cfg.h
+++ b/include/hw/nvram/fw_cfg.h
@@ -80,6 +80,8 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data,
size_t len);
FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
hwaddr crl_addr, hwaddr data_addr);
+FWCfgState *fw_cfg_init_io(uint32_t iobase);
+FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr);
FWCfgState *fw_cfg_find(void);
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 57ff47f..f2bbaaf 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -22,6 +22,8 @@ typedef struct DisplayState DisplayState;
typedef struct DisplaySurface DisplaySurface;
typedef struct DriveInfo DriveInfo;
typedef struct EventNotifier EventNotifier;
+typedef struct FWCfgIoState FWCfgIoState;
+typedef struct FWCfgMemState FWCfgMemState;
typedef struct FWCfgState FWCfgState;
typedef struct HCIInfo HCIInfo;
typedef struct I2CBus I2CBus;
--
2.1.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v6 02/11] fw_cfg: move boards to fw_cfg_init_io() / fw_cfg_init_mem()
2014-12-22 12:11 [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 01/11] fw_cfg: hard separation between the MMIO and I/O port mappings Paolo Bonzini
@ 2014-12-22 12:11 ` Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 03/11] fw_cfg_mem: max access size and region size are the same for data register Paolo Bonzini
` (10 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Paolo Bonzini @ 2014-12-22 12:11 UTC (permalink / raw)
To: peter.maydell, qemu-devel, rjones, drjones, lersek, agraf
From: Laszlo Ersek <lersek@redhat.com>
This allows us to drop the fw_cfg_init() shim and to enforce the possible
mappings at compile time.
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/i386/pc.c | 4 ++--
hw/nvram/fw_cfg.c | 14 --------------
hw/ppc/mac_newworld.c | 2 +-
hw/ppc/mac_oldworld.c | 2 +-
hw/sparc/sun4m.c | 2 +-
hw/sparc64/sun4u.c | 2 +-
include/hw/nvram/fw_cfg.h | 2 --
7 files changed, 6 insertions(+), 22 deletions(-)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index c0e55a6..21e12ea 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -647,7 +647,7 @@ static FWCfgState *bochs_bios_init(void)
int i, j;
unsigned int apic_id_limit = pc_apic_id_limit(max_cpus);
- fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
+ fw_cfg = fw_cfg_init_io(BIOS_CFG_IOPORT);
/* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
*
* SeaBIOS needs FW_CFG_MAX_CPUS for CPU hotplug, but the CPU hotplug
@@ -1168,7 +1168,7 @@ FWCfgState *xen_load_linux(const char *kernel_filename,
assert(kernel_filename != NULL);
- fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
+ fw_cfg = fw_cfg_init_io(BIOS_CFG_IOPORT);
rom_set_fw(fw_cfg);
load_linux(fw_cfg, kernel_filename, initrd_filename,
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index ab7bfff..c48bc6e 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -632,20 +632,6 @@ FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr)
}
-FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
- hwaddr crl_addr, hwaddr data_addr)
-{
- if (ctl_port + 1 == data_port && crl_addr == 0 && data_addr == 0) {
- return fw_cfg_init_io(ctl_port);
- }
- if (ctl_port == 0 && data_port == 0 && crl_addr != 0 && data_addr != 0) {
- return fw_cfg_init_mem(crl_addr, data_addr);
- }
- assert(false);
- return NULL;
-}
-
-
FWCfgState *fw_cfg_find(void)
{
return FW_CFG(object_resolve_path(FW_CFG_PATH, NULL));
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index 89aee71..5dac389 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -454,7 +454,7 @@ static void ppc_core99_init(MachineState *machine)
pmac_format_nvram_partition(nvr, 0x2000);
/* No PCI init: the BIOS will do it */
- fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
+ fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index 32c21a4..41fefb7 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -314,7 +314,7 @@ static void ppc_heathrow_init(MachineState *machine)
/* No PCI init: the BIOS will do it */
- fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
+ fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index 8273199..a12d3c4 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -1084,7 +1084,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
ecc_init(hwdef->ecc_base, slavio_irq[28],
hwdef->ecc_version);
- fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
+ fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index f42112c..49fb678 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -892,7 +892,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
graphic_width, graphic_height, graphic_depth,
(uint8_t *)&nd_table[0].macaddr);
- fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
+ fw_cfg = fw_cfg_init_io(BIOS_CFG_IOPORT);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
index fcc88ea..a99586e 100644
--- a/include/hw/nvram/fw_cfg.h
+++ b/include/hw/nvram/fw_cfg.h
@@ -78,8 +78,6 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
void *data, size_t len);
void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data,
size_t len);
-FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
- hwaddr crl_addr, hwaddr data_addr);
FWCfgState *fw_cfg_init_io(uint32_t iobase);
FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr);
--
2.1.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v6 03/11] fw_cfg_mem: max access size and region size are the same for data register
2014-12-22 12:11 [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 01/11] fw_cfg: hard separation between the MMIO and I/O port mappings Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 02/11] fw_cfg: move boards to fw_cfg_init_io() / fw_cfg_init_mem() Paolo Bonzini
@ 2014-12-22 12:11 ` Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 04/11] fw_cfg_mem: flip ctl_mem_ops and data_mem_ops to DEVICE_BIG_ENDIAN Paolo Bonzini
` (9 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Paolo Bonzini @ 2014-12-22 12:11 UTC (permalink / raw)
To: peter.maydell, qemu-devel, rjones, drjones, lersek, agraf
From: Laszlo Ersek <lersek@redhat.com>
Make it clear that the maximum access size to the MMIO data register
determines the full size of the memory region.
Currently the max access size is 1.
This patch doesn't change behavior.
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/nvram/fw_cfg.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index c48bc6e..8deb860 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -31,7 +31,6 @@
#include "qemu/config-file.h"
#define FW_CFG_SIZE 2
-#define FW_CFG_DATA_SIZE 1
#define FW_CFG_NAME "fw_cfg"
#define FW_CFG_PATH "/machine/" FW_CFG_NAME
@@ -694,7 +693,8 @@ static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->ctl_iomem);
memory_region_init_io(&s->data_iomem, OBJECT(s), &fw_cfg_data_mem_ops,
- FW_CFG(s), "fwcfg.data", FW_CFG_DATA_SIZE);
+ FW_CFG(s), "fwcfg.data",
+ fw_cfg_data_mem_ops.valid.max_access_size);
sysbus_init_mmio(sbd, &s->data_iomem);
}
--
2.1.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v6 04/11] fw_cfg_mem: flip ctl_mem_ops and data_mem_ops to DEVICE_BIG_ENDIAN
2014-12-22 12:11 [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt Paolo Bonzini
` (2 preceding siblings ...)
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 03/11] fw_cfg_mem: max access size and region size are the same for data register Paolo Bonzini
@ 2014-12-22 12:11 ` Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 05/11] exec: allows 8-byte accesses in subpage_ops Paolo Bonzini
` (8 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Paolo Bonzini @ 2014-12-22 12:11 UTC (permalink / raw)
To: peter.maydell, qemu-devel, rjones, drjones, lersek, agraf
From: Laszlo Ersek <lersek@redhat.com>
The standalone selector port (fw_cfg_ctl_mem_ops) is only used by big
endian guests to date (*), hence this change doesn't regress them. Paolo
and Alex have suggested / requested an explicit DEVICE_BIG_ENDIAN setting
here, for clarity.
(*) git grep -l fw_cfg_init_mem
hw/nvram/fw_cfg.c
hw/ppc/mac_newworld.c
hw/ppc/mac_oldworld.c
hw/sparc/sun4m.c
include/hw/nvram/fw_cfg.h
The standalone data port (fw_cfg_data_mem_ops) has max_access_size 1 (for
now), hence changing its endianness doesn't change behavior for existing
guest code.
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/nvram/fw_cfg.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 8deb860..910ae14 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -332,14 +332,14 @@ static bool fw_cfg_comb_valid(void *opaque, hwaddr addr,
static const MemoryRegionOps fw_cfg_ctl_mem_ops = {
.write = fw_cfg_ctl_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_BIG_ENDIAN,
.valid.accepts = fw_cfg_ctl_mem_valid,
};
static const MemoryRegionOps fw_cfg_data_mem_ops = {
.read = fw_cfg_data_mem_read,
.write = fw_cfg_data_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_BIG_ENDIAN,
.valid = {
.min_access_size = 1,
.max_access_size = 1,
--
2.1.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v6 05/11] exec: allows 8-byte accesses in subpage_ops
2014-12-22 12:11 [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt Paolo Bonzini
` (3 preceding siblings ...)
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 04/11] fw_cfg_mem: flip ctl_mem_ops and data_mem_ops to DEVICE_BIG_ENDIAN Paolo Bonzini
@ 2014-12-22 12:11 ` Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 06/11] fw_cfg_mem: introduce the "data_width" property Paolo Bonzini
` (7 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Paolo Bonzini @ 2014-12-22 12:11 UTC (permalink / raw)
To: peter.maydell, qemu-devel, rjones, drjones, lersek, agraf
Otherwise fw_cfg accesses are split into 4-byte ones before they reach the
fw_cfg ops / handlers.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
exec.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/exec.c b/exec.c
index c2ed10a..9c3f304 100644
--- a/exec.c
+++ b/exec.c
@@ -1768,7 +1768,7 @@ static uint64_t subpage_read(void *opaque, hwaddr addr,
unsigned len)
{
subpage_t *subpage = opaque;
- uint8_t buf[4];
+ uint8_t buf[8];
#if defined(DEBUG_SUBPAGE)
printf("%s: subpage %p len %u addr " TARGET_FMT_plx "\n", __func__,
@@ -1782,6 +1782,8 @@ static uint64_t subpage_read(void *opaque, hwaddr addr,
return lduw_p(buf);
case 4:
return ldl_p(buf);
+ case 8:
+ return ldq_p(buf);
default:
abort();
}
@@ -1791,7 +1793,7 @@ static void subpage_write(void *opaque, hwaddr addr,
uint64_t value, unsigned len)
{
subpage_t *subpage = opaque;
- uint8_t buf[4];
+ uint8_t buf[8];
#if defined(DEBUG_SUBPAGE)
printf("%s: subpage %p len %u addr " TARGET_FMT_plx
@@ -1808,6 +1810,9 @@ static void subpage_write(void *opaque, hwaddr addr,
case 4:
stl_p(buf, value);
break;
+ case 8:
+ stq_p(buf, value);
+ break;
default:
abort();
}
@@ -1830,6 +1835,10 @@ static bool subpage_accepts(void *opaque, hwaddr addr,
static const MemoryRegionOps subpage_ops = {
.read = subpage_read,
.write = subpage_write,
+ .impl.min_access_size = 1,
+ .impl.max_access_size = 8,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 8,
.valid.accepts = subpage_accepts,
.endianness = DEVICE_NATIVE_ENDIAN,
};
--
2.1.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v6 06/11] fw_cfg_mem: introduce the "data_width" property
2014-12-22 12:11 [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt Paolo Bonzini
` (4 preceding siblings ...)
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 05/11] exec: allows 8-byte accesses in subpage_ops Paolo Bonzini
@ 2014-12-22 12:11 ` Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 07/11] fw_cfg_mem: expose the "data_width" property with fw_cfg_init_mem_wide() Paolo Bonzini
` (6 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Paolo Bonzini @ 2014-12-22 12:11 UTC (permalink / raw)
To: peter.maydell, qemu-devel, rjones, drjones, lersek, agraf
From: Laszlo Ersek <lersek@redhat.com>
The "data_width" property is capable of changing the maximum valid access
size to the MMIO data register, and resizes the memory region similarly,
at device realization time.
The default value of "data_memwidth" is set so that we don't yet diverge
from "fw_cfg_data_mem_ops".
Most of the fw_cfg_mem users will stick with the default, and for them we
should continue using the statically allocated "fw_cfg_data_mem_ops". This
is beneficial for debugging because gdb can resolve pointers referencing
static objects to the names of those objects.
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/nvram/fw_cfg.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 74 insertions(+), 5 deletions(-)
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 910ae14..2950d68 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -77,6 +77,8 @@ struct FWCfgMemState {
/*< public >*/
MemoryRegion ctl_iomem, data_iomem;
+ uint32_t data_width;
+ MemoryRegionOps wide_data_ops;
};
#define JPG_FILE 0
@@ -284,13 +286,58 @@ static uint8_t fw_cfg_read(FWCfgState *s)
static uint64_t fw_cfg_data_mem_read(void *opaque, hwaddr addr,
unsigned size)
{
- return fw_cfg_read(opaque);
+ FWCfgState *s = opaque;
+ uint8_t buf[8];
+ unsigned i;
+
+ for (i = 0; i < size; ++i) {
+ buf[i] = fw_cfg_read(s);
+ }
+ switch (size) {
+ case 1:
+ return buf[0];
+ case 2:
+ return lduw_he_p(buf);
+ case 4:
+ return (uint32_t)ldl_he_p(buf);
+ case 8:
+ return ldq_he_p(buf);
+ }
+ abort();
}
static void fw_cfg_data_mem_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
- fw_cfg_write(opaque, (uint8_t)value);
+ FWCfgState *s = opaque;
+ uint8_t buf[8];
+ unsigned i;
+
+ switch (size) {
+ case 1:
+ buf[0] = value;
+ break;
+ case 2:
+ stw_he_p(buf, value);
+ break;
+ case 4:
+ stl_he_p(buf, value);
+ break;
+ case 8:
+ stq_he_p(buf, value);
+ break;
+ default:
+ abort();
+ }
+ for (i = 0; i < size; ++i) {
+ fw_cfg_write(s, buf[i]);
+ }
+}
+
+static bool fw_cfg_data_mem_valid(void *opaque, hwaddr addr,
+ unsigned size, bool is_write)
+{
+ return addr == 0;
}
static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr,
@@ -343,6 +390,7 @@ static const MemoryRegionOps fw_cfg_data_mem_ops = {
.valid = {
.min_access_size = 1,
.max_access_size = 1,
+ .accepts = fw_cfg_data_mem_valid,
},
};
@@ -621,6 +669,9 @@ FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr)
SysBusDevice *sbd;
dev = qdev_create(NULL, TYPE_FW_CFG_MEM);
+ qdev_prop_set_uint32(dev, "data_width",
+ fw_cfg_data_mem_ops.valid.max_access_size);
+
fw_cfg_init1(dev);
sbd = SYS_BUS_DEVICE(dev);
@@ -683,18 +734,35 @@ static const TypeInfo fw_cfg_io_info = {
};
+static Property fw_cfg_mem_properties[] = {
+ DEFINE_PROP_UINT32("data_width", FWCfgMemState, data_width, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
{
FWCfgMemState *s = FW_CFG_MEM(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ const MemoryRegionOps *data_ops = &fw_cfg_data_mem_ops;
memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops,
FW_CFG(s), "fwcfg.ctl", FW_CFG_SIZE);
sysbus_init_mmio(sbd, &s->ctl_iomem);
- memory_region_init_io(&s->data_iomem, OBJECT(s), &fw_cfg_data_mem_ops,
- FW_CFG(s), "fwcfg.data",
- fw_cfg_data_mem_ops.valid.max_access_size);
+ if (s->data_width > data_ops->valid.max_access_size) {
+ /* memberwise copy because the "old_mmio" member is const */
+ s->wide_data_ops.read = data_ops->read;
+ s->wide_data_ops.write = data_ops->write;
+ s->wide_data_ops.endianness = data_ops->endianness;
+ s->wide_data_ops.valid = data_ops->valid;
+ s->wide_data_ops.impl = data_ops->impl;
+
+ s->wide_data_ops.valid.max_access_size = s->data_width;
+ s->wide_data_ops.impl.max_access_size = s->data_width;
+ data_ops = &s->wide_data_ops;
+ }
+ memory_region_init_io(&s->data_iomem, OBJECT(s), data_ops, FW_CFG(s),
+ "fwcfg.data", data_ops->valid.max_access_size);
sysbus_init_mmio(sbd, &s->data_iomem);
}
@@ -703,6 +771,7 @@ static void fw_cfg_mem_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = fw_cfg_mem_realize;
+ dc->props = fw_cfg_mem_properties;
}
static const TypeInfo fw_cfg_mem_info = {
--
2.1.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v6 07/11] fw_cfg_mem: expose the "data_width" property with fw_cfg_init_mem_wide()
2014-12-22 12:11 [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt Paolo Bonzini
` (5 preceding siblings ...)
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 06/11] fw_cfg_mem: introduce the "data_width" property Paolo Bonzini
@ 2014-12-22 12:11 ` Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 08/11] arm: add fw_cfg to "virt" board Paolo Bonzini
` (5 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Paolo Bonzini @ 2014-12-22 12:11 UTC (permalink / raw)
To: peter.maydell, qemu-devel, rjones, drjones, lersek, agraf
From: Laszlo Ersek <lersek@redhat.com>
We rebase fw_cfg_init_mem() to the new function for compatibility with
current callers.
The behavior of the (big endian) multi-byte data reads is best shown
with a qtest session. Here, we are reading the first six bytes of
the UUID
$ arm-softmmu/qemu-system-arm -M virt -machine accel=qtest \
-qtest stdio -uuid 4600cb32-38ec-4b2f-8acb-81c6ea54f2d8
>>> writew 0x9020008 0x0200
<<< OK
>>> readl 0x9020000
<<< OK 0x000000004600cb32
Remember this is big endian. On big endian machines, it is stored
directly as 0x46 0x00 0xcb 0x32.
On a little endian machine, we have to first swap it, so that it becomes
0x32cb0046. When written to memory, it becomes 0x46 0x00 0xcb 0x32
again.
Reading byte-by-byte works too, of course:
>>> readb 0x9020000
<<< OK 0x0000000000000038
>>> readb 0x9020000
<<< OK 0x00000000000000ec
Here only a single byte is read at a time, so they are read in order
similar to the 1-byte data port that is already in PPC and SPARC
machines.
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/nvram/fw_cfg.c | 12 +++++++++---
include/hw/nvram/fw_cfg.h | 2 ++
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 2950d68..fcdf821 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -663,14 +663,14 @@ FWCfgState *fw_cfg_init_io(uint32_t iobase)
return FW_CFG(dev);
}
-FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr)
+FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr, hwaddr data_addr,
+ uint32_t data_width)
{
DeviceState *dev;
SysBusDevice *sbd;
dev = qdev_create(NULL, TYPE_FW_CFG_MEM);
- qdev_prop_set_uint32(dev, "data_width",
- fw_cfg_data_mem_ops.valid.max_access_size);
+ qdev_prop_set_uint32(dev, "data_width", data_width);
fw_cfg_init1(dev);
@@ -681,6 +681,12 @@ FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr)
return FW_CFG(dev);
}
+FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr)
+{
+ return fw_cfg_init_mem_wide(ctl_addr, data_addr,
+ fw_cfg_data_mem_ops.valid.max_access_size);
+}
+
FWCfgState *fw_cfg_find(void)
{
diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
index a99586e..6d8a8ac 100644
--- a/include/hw/nvram/fw_cfg.h
+++ b/include/hw/nvram/fw_cfg.h
@@ -80,6 +80,8 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data,
size_t len);
FWCfgState *fw_cfg_init_io(uint32_t iobase);
FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr);
+FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr, hwaddr data_addr,
+ uint32_t data_width);
FWCfgState *fw_cfg_find(void);
--
2.1.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v6 08/11] arm: add fw_cfg to "virt" board
2014-12-22 12:11 [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt Paolo Bonzini
` (6 preceding siblings ...)
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 07/11] fw_cfg_mem: expose the "data_width" property with fw_cfg_init_mem_wide() Paolo Bonzini
@ 2014-12-22 12:11 ` Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 09/11] hw/loader: split out load_image_gzipped_buffer() Paolo Bonzini
` (4 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Paolo Bonzini @ 2014-12-22 12:11 UTC (permalink / raw)
To: peter.maydell, qemu-devel, rjones, drjones, lersek, agraf
From: Laszlo Ersek <lersek@redhat.com>
fw_cfg already supports exposure over MMIO (used in ppc/mac_newworld.c,
ppc/mac_oldworld.c, sparc/sun4m.c); we can easily add it to the "virt"
board.
Because MMIO access is slow on ARM KVM, we enable the guest, with
fw_cfg_init_mem_wide(), to transfer up to 8 bytes with a single access.
This has been measured to speed up transfers up to 7.5-fold, relative to
single byte data access, on both ARM KVM and x86_64 TCG.
The MMIO register block of fw_cfg is advertized in the device tree. As
base address we pick 0x09020000, which conforms to the comment preceding
"a15memmap": it falls in the miscellaneous device I/O range 128MB..256MB,
and it is aligned at 64KB. The DTB properties follow the documentation in
the Linux source file "Documentation/devicetree/bindings/arm/fw-cfg.txt".
fw_cfg automatically exports a number of files to the guest; for example,
"bootorder" (see fw_cfg_machine_reset()).
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/arm/virt.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 314e55b..8af4aa0 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -68,6 +68,7 @@ enum {
VIRT_UART,
VIRT_MMIO,
VIRT_RTC,
+ VIRT_FW_CFG,
};
typedef struct MemMapEntry {
@@ -107,6 +108,7 @@ static const MemMapEntry a15memmap[] = {
[VIRT_GIC_CPU] = { 0x08010000, 0x00010000 },
[VIRT_UART] = { 0x09000000, 0x00001000 },
[VIRT_RTC] = { 0x09010000, 0x00001000 },
+ [VIRT_FW_CFG] = { 0x09020000, 0x0000000a },
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
/* 0x10000000 .. 0x40000000 reserved for PCI */
@@ -519,6 +521,23 @@ static void create_flash(const VirtBoardInfo *vbi)
g_free(nodename);
}
+static void create_fw_cfg(const VirtBoardInfo *vbi)
+{
+ hwaddr base = vbi->memmap[VIRT_FW_CFG].base;
+ hwaddr size = vbi->memmap[VIRT_FW_CFG].size;
+ char *nodename;
+
+ fw_cfg_init_mem_wide(base + 8, base, 8);
+
+ nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base);
+ qemu_fdt_add_subnode(vbi->fdt, nodename);
+ qemu_fdt_setprop_string(vbi->fdt, nodename,
+ "compatible", "qemu,fw-cfg-mmio");
+ qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
+ 2, base, 2, size);
+ g_free(nodename);
+}
+
static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
{
const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
@@ -604,6 +623,8 @@ static void machvirt_init(MachineState *machine)
*/
create_virtio_devices(vbi, pic);
+ create_fw_cfg(vbi);
+
vbi->bootinfo.ram_size = machine->ram_size;
vbi->bootinfo.kernel_filename = machine->kernel_filename;
vbi->bootinfo.kernel_cmdline = machine->kernel_cmdline;
--
2.1.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v6 09/11] hw/loader: split out load_image_gzipped_buffer()
2014-12-22 12:11 [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt Paolo Bonzini
` (7 preceding siblings ...)
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 08/11] arm: add fw_cfg to "virt" board Paolo Bonzini
@ 2014-12-22 12:11 ` Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 10/11] hw/arm: pass pristine kernel image to guest firmware over fw_cfg Paolo Bonzini
` (3 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Paolo Bonzini @ 2014-12-22 12:11 UTC (permalink / raw)
To: peter.maydell, qemu-devel, rjones, drjones, lersek, agraf
From: Laszlo Ersek <lersek@redhat.com>
In the next patch we'd like to reuse the image decompression facility
without installing the output as a ROM at a specific guest-phys address.
In addition, expose LOAD_IMAGE_MAX_GUNZIP_BYTES, because that's a
straightforward "max_sz" argument for the new load_image_gzipped_buffer().
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/core/loader.c | 30 +++++++++++++++++++++---------
include/hw/loader.h | 9 +++++++++
2 files changed, 30 insertions(+), 9 deletions(-)
diff --git a/hw/core/loader.c b/hw/core/loader.c
index 7527fd3..f2b34da 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -614,14 +614,9 @@ int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz)
NULL, NULL);
}
-/* This simply prevents g_malloc in the function below from allocating
- * a huge amount of memory, by placing a limit on the maximum
- * uncompressed image size that load_image_gzipped will read.
- */
-#define LOAD_IMAGE_MAX_GUNZIP_BYTES (256 << 20)
-
-/* Load a gzip-compressed kernel. */
-int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
+/* Load a gzip-compressed kernel to a dynamically allocated buffer. */
+int load_image_gzipped_buffer(const char *filename, uint64_t max_sz,
+ uint8_t **buffer)
{
uint8_t *compressed_data = NULL;
uint8_t *data = NULL;
@@ -653,8 +648,11 @@ int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
goto out;
}
- rom_add_blob_fixed(filename, data, bytes, addr);
+ /* trim to actual size and return to caller */
+ *buffer = g_realloc(data, bytes);
ret = bytes;
+ /* ownership has been transferred to caller */
+ data = NULL;
out:
g_free(compressed_data);
@@ -662,6 +660,20 @@ int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
return ret;
}
+/* Load a gzip-compressed kernel. */
+int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
+{
+ int bytes;
+ uint8_t *data;
+
+ bytes = load_image_gzipped_buffer(filename, max_sz, &data);
+ if (bytes != -1) {
+ rom_add_blob_fixed(filename, data, bytes, addr);
+ g_free(data);
+ }
+ return bytes;
+}
+
/*
* Functions for reboot-persistent memory regions.
* - used for vga bios and option roms.
diff --git a/include/hw/loader.h b/include/hw/loader.h
index 6481639..8997620 100644
--- a/include/hw/loader.h
+++ b/include/hw/loader.h
@@ -16,6 +16,15 @@ int load_image(const char *filename, uint8_t *addr); /* deprecated */
ssize_t load_image_size(const char *filename, void *addr, size_t size);
int load_image_targphys(const char *filename, hwaddr,
uint64_t max_sz);
+
+/* This is the limit on the maximum uncompressed image size that
+ * load_image_gzipped_buffer() and load_image_gzipped() will read. It prevents
+ * g_malloc() in those functions from allocating a huge amount of memory.
+ */
+#define LOAD_IMAGE_MAX_GUNZIP_BYTES (256 << 20)
+
+int load_image_gzipped_buffer(const char *filename, uint64_t max_sz,
+ uint8_t **buffer);
int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz);
#define ELF_LOAD_FAILED -1
--
2.1.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v6 10/11] hw/arm: pass pristine kernel image to guest firmware over fw_cfg
2014-12-22 12:11 [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt Paolo Bonzini
` (8 preceding siblings ...)
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 09/11] hw/loader: split out load_image_gzipped_buffer() Paolo Bonzini
@ 2014-12-22 12:11 ` Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 11/11] hw/arm/virt: enable passing of EFI-stubbed kernel to guest UEFI firmware Paolo Bonzini
` (2 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Paolo Bonzini @ 2014-12-22 12:11 UTC (permalink / raw)
To: peter.maydell, qemu-devel, rjones, drjones, lersek, agraf
From: Laszlo Ersek <lersek@redhat.com>
Introduce the new boolean field "arm_boot_info.firmware_loaded". When this
field is set, it means that the portion of guest DRAM that the VCPU
normally starts to execute, or the pflash chip that the VCPU normally
starts to execute, has been populated by board-specific code with
full-fledged guest firmware code, before the board calls
arm_load_kernel().
Simultaneously, "arm_boot_info.firmware_loaded" guarantees that the board
code has set up the global firmware config instance, for arm_load_kernel()
to find with fw_cfg_find().
Guest kernel (-kernel) and guest firmware (-bios, -pflash) has always been
possible to specify independently on the command line. The following cases
should be considered:
nr -bios -pflash -kernel description
unit#0
-- ------- ------- ------- -------------------------------------------
1 present present absent Board code rejects this case, -bios and
present present present -pflash unit#0 are exclusive. Left intact
by this patch.
2 absent absent present Traditional kernel loading, with qemu's
minimal board firmware. Left intact by this
patch.
3 absent present absent Preexistent case for booting guest firmware
present absent absent loaded with -bios or -pflash. Left intact
by this patch.
4 absent absent absent Preexistent case for not loading any
firmware or kernel up-front. Left intact by
this patch.
5 present absent present New case introduced by this patch: kernel
absent present present image is passed to externally loaded
firmware in unmodified form, using fw_cfg.
An easy way to see that this patch doesn't interfere with existing cases
is to realize that "info->firmware_loaded" is constant zero at this point.
Which makes the "outer" condition unchanged, and the "inner" condition
(with the fw_cfg-related code) dead.
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/arm/boot.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++---
include/hw/arm/arm.h | 5 +++
2 files changed, 88 insertions(+), 5 deletions(-)
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index e6a3c5b..17bdaee 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -478,6 +478,55 @@ static void do_cpu_reset(void *opaque)
}
}
+/**
+ * load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified
+ * by key.
+ * @fw_cfg: The firmware config instance to store the data in.
+ * @size_key: The firmware config key to store the size of the loaded
+ * data under, with fw_cfg_add_i32().
+ * @data_key: The firmware config key to store the loaded data under,
+ * with fw_cfg_add_bytes().
+ * @image_name: The name of the image file to load. If it is NULL, the
+ * function returns without doing anything.
+ * @try_decompress: Whether the image should be decompressed (gunzipped) before
+ * adding it to fw_cfg. If decompression fails, the image is
+ * loaded as-is.
+ *
+ * In case of failure, the function prints an error message to stderr and the
+ * process exits with status 1.
+ */
+static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
+ uint16_t data_key, const char *image_name,
+ bool try_decompress)
+{
+ size_t size = -1;
+ uint8_t *data;
+
+ if (image_name == NULL) {
+ return;
+ }
+
+ if (try_decompress) {
+ size = load_image_gzipped_buffer(image_name,
+ LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
+ }
+
+ if (size == (size_t)-1) {
+ gchar *contents;
+ gsize length;
+
+ if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
+ fprintf(stderr, "failed to load \"%s\"\n", image_name);
+ exit(1);
+ }
+ size = length;
+ data = (uint8_t *)contents;
+ }
+
+ fw_cfg_add_i32(fw_cfg, size_key, size);
+ fw_cfg_add_bytes(fw_cfg, data_key, data, size);
+}
+
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
{
CPUState *cs;
@@ -500,19 +549,48 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
}
/* Load the kernel. */
- if (!info->kernel_filename) {
+ if (!info->kernel_filename || info->firmware_loaded) {
if (have_dtb(info)) {
- /* If we have a device tree blob, but no kernel to supply it to,
- * copy it to the base of RAM for a bootloader to pick up.
+ /* If we have a device tree blob, but no kernel to supply it to (or
+ * the kernel is supposed to be loaded by the bootloader), copy the
+ * DTB to the base of RAM for the bootloader to pick up.
*/
if (load_dtb(info->loader_start, info, 0) < 0) {
exit(1);
}
}
- /* If no kernel specified, do nothing; we will start from address 0
- * (typically a boot ROM image) in the same way as hardware.
+ if (info->kernel_filename) {
+ FWCfgState *fw_cfg;
+ bool try_decompressing_kernel;
+
+ fw_cfg = fw_cfg_find();
+ try_decompressing_kernel = arm_feature(&cpu->env,
+ ARM_FEATURE_AARCH64);
+
+ /* Expose the kernel, the command line, and the initrd in fw_cfg.
+ * We don't process them here at all, it's all left to the
+ * firmware.
+ */
+ load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
+ info->kernel_filename,
+ try_decompressing_kernel);
+ load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
+ info->initrd_filename, false);
+
+ if (info->kernel_cmdline) {
+ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+ strlen(info->kernel_cmdline) + 1);
+ fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
+ info->kernel_cmdline);
+ }
+ }
+
+ /* We will start from address 0 (typically a boot ROM image) in the
+ * same way as hardware.
*/
return;
}
diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h
index cefc9e6..dd69d66 100644
--- a/include/hw/arm/arm.h
+++ b/include/hw/arm/arm.h
@@ -66,6 +66,11 @@ struct arm_boot_info {
hwaddr initrd_start;
hwaddr initrd_size;
hwaddr entry;
+
+ /* Boot firmware has been loaded, typically at address 0, with -bios or
+ * -pflash. It also implies that fw_cfg_find() will succeed.
+ */
+ bool firmware_loaded;
};
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info);
--
2.1.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v6 11/11] hw/arm/virt: enable passing of EFI-stubbed kernel to guest UEFI firmware
2014-12-22 12:11 [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt Paolo Bonzini
` (9 preceding siblings ...)
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 10/11] hw/arm: pass pristine kernel image to guest firmware over fw_cfg Paolo Bonzini
@ 2014-12-22 12:11 ` Paolo Bonzini
2014-12-22 23:41 ` [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt Peter Maydell
2014-12-23 22:17 ` Laszlo Ersek
12 siblings, 0 replies; 14+ messages in thread
From: Paolo Bonzini @ 2014-12-22 12:11 UTC (permalink / raw)
To: peter.maydell, qemu-devel, rjones, drjones, lersek, agraf
From: Laszlo Ersek <lersek@redhat.com>
The virt board already ensures mutual exclusion between -bios and -pflash
unit#0; we only need to set "bootinfo.firmware_loaded", introduced in the
previous patch, if either of those options was used to load the guest
firmware.
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/arm/virt.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 8af4aa0..29fbdc1 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -633,6 +633,7 @@ static void machvirt_init(MachineState *machine)
vbi->bootinfo.board_id = -1;
vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;
vbi->bootinfo.get_dtb = machvirt_dtb;
+ vbi->bootinfo.firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
}
--
2.1.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt
2014-12-22 12:11 [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt Paolo Bonzini
` (10 preceding siblings ...)
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 11/11] hw/arm/virt: enable passing of EFI-stubbed kernel to guest UEFI firmware Paolo Bonzini
@ 2014-12-22 23:41 ` Peter Maydell
2014-12-23 22:17 ` Laszlo Ersek
12 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2014-12-22 23:41 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: Alexander Graf, Andrew Jones, Laszlo Ersek, QEMU Developers
On 22 December 2014 at 12:11, Paolo Bonzini <pbonzini@redhat.com> wrote:
> The only change from v5 to v6 is that sysbus_mmio_map is moved to
> fw_cfg_init_mem. (And fw_cfg_init1 returns void because it's now
> simpler that way).
>
> This causes changes in patches 1, 5 and 6.
>
> I did not have the ARM firmware built, so I tested on PPC to check
> for compatibility, and played with "info mtree" and qtest on ARM
> (see also commit message for patch 7).
>
> Paolo
>
> Laszlo Ersek (10):
> fw_cfg: hard separation between the MMIO and I/O port mappings
> fw_cfg: move boards to fw_cfg_init_io() / fw_cfg_init_mem()
> fw_cfg_mem: max access size and region size are the same for data
> register
> fw_cfg_mem: flip ctl_mem_ops and data_mem_ops to DEVICE_BIG_ENDIAN
> fw_cfg_mem: introduce the "data_width" property
> fw_cfg_mem: expose the "data_width" property with
> fw_cfg_init_mem_wide()
> arm: add fw_cfg to "virt" board
> hw/loader: split out load_image_gzipped_buffer()
> hw/arm: pass pristine kernel image to guest firmware over fw_cfg
> hw/arm/virt: enable passing of EFI-stubbed kernel to guest UEFI
> firmware
>
> Paolo Bonzini (1):
> exec: allows 8-byte accesses in subpage_ops
Applied to target-arm.next, thanks.
Note for the PPC guys, in case you care -- you'll need a different
device tree binding for your version of the fw_cfg (or a different
compat string or something), because yours has the data and ctrl
registers the opposite way round.
-- PMM
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt
2014-12-22 12:11 [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt Paolo Bonzini
` (11 preceding siblings ...)
2014-12-22 23:41 ` [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt Peter Maydell
@ 2014-12-23 22:17 ` Laszlo Ersek
12 siblings, 0 replies; 14+ messages in thread
From: Laszlo Ersek @ 2014-12-23 22:17 UTC (permalink / raw)
To: Paolo Bonzini, peter.maydell, qemu-devel, rjones, drjones, agraf
On 12/22/14 13:11, Paolo Bonzini wrote:
> The only change from v5 to v6 is that sysbus_mmio_map is moved to
> fw_cfg_init_mem. (And fw_cfg_init1 returns void because it's now
> simpler that way).
>
> This causes changes in patches 1, 5 and 6.
>
> I did not have the ARM firmware built, so I tested on PPC to check
> for compatibility, and played with "info mtree" and qtest on ARM
> (see also commit message for patch 7).
Many thanks, Paolo. I tested the pulled version with the firmware
running on TCG, and it works fine. Also kudos for the qtest bits in the
commit message of patch 7.
(Yes, I'm on vacation; I just couldn't resist checking. :))
Laszlo
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2014-12-23 22:17 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-12-22 12:11 [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 01/11] fw_cfg: hard separation between the MMIO and I/O port mappings Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 02/11] fw_cfg: move boards to fw_cfg_init_io() / fw_cfg_init_mem() Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 03/11] fw_cfg_mem: max access size and region size are the same for data register Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 04/11] fw_cfg_mem: flip ctl_mem_ops and data_mem_ops to DEVICE_BIG_ENDIAN Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 05/11] exec: allows 8-byte accesses in subpage_ops Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 06/11] fw_cfg_mem: introduce the "data_width" property Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 07/11] fw_cfg_mem: expose the "data_width" property with fw_cfg_init_mem_wide() Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 08/11] arm: add fw_cfg to "virt" board Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 09/11] hw/loader: split out load_image_gzipped_buffer() Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 10/11] hw/arm: pass pristine kernel image to guest firmware over fw_cfg Paolo Bonzini
2014-12-22 12:11 ` [Qemu-devel] [PATCH v6 11/11] hw/arm/virt: enable passing of EFI-stubbed kernel to guest UEFI firmware Paolo Bonzini
2014-12-22 23:41 ` [Qemu-devel] [PATCH v6 00/11] fw_cfg, bootorder, and UEFI+'-kernel' on arm/virt Peter Maydell
2014-12-23 22:17 ` Laszlo Ersek
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).