diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/nvram/fw_cfg.c | 177 |
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) |