summaryrefslogtreecommitdiff
path: root/hw/nvram/fw_cfg.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/nvram/fw_cfg.c')
-rw-r--r--hw/nvram/fw_cfg.c177
1 files changed, 122 insertions, 55 deletions
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index c4b78ed36c..ab7bfffae2 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)