Commit aae9460e244c7abe70b72ff374b3aa102bb09691

Authored by Paul Brook
1 parent 019d6b8f

Basic qdev infrastructure.

Signed-off-by: Paul Brook <paul@codesourcery.com>
Makefile
... ... @@ -101,6 +101,7 @@ OBJS+=bt-hci-csr.o
101 101 OBJS+=buffered_file.o migration.o migration-tcp.o net.o qemu-sockets.o
102 102 OBJS+=qemu-char.o aio.o net-checksum.o savevm.o cache-utils.o
103 103 OBJS+=msmouse.o ps2.o
  104 +OBJS+=qdev.o
104 105  
105 106 ifdef CONFIG_BRLAPI
106 107 OBJS+= baum.o
... ...
Makefile.target
... ... @@ -486,7 +486,7 @@ endif #CONFIG_BSD_USER
486 486 ifndef CONFIG_USER_ONLY
487 487  
488 488 OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o dma-helpers.o \
489   - gdbstub.o gdbstub-xml.o
  489 + gdbstub.o gdbstub-xml.o sysbus.o
490 490 # virtio has to be here due to weird dependency between PCI and virtio-net.
491 491 # need to fix this properly
492 492 OBJS+=virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o
... ...
hw/qdev.c 0 → 100644
  1 +/*
  2 + * Dynamic device configuration and creation.
  3 + *
  4 + * Copyright (c) 2009 CodeSourcery
  5 + *
  6 + * This library is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU Lesser General Public
  8 + * License as published by the Free Software Foundation; either
  9 + * version 2 of the License, or (at your option) any later version.
  10 + *
  11 + * This library is distributed in the hope that it will be useful,
  12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14 + * Lesser General Public License for more details.
  15 + *
  16 + * You should have received a copy of the GNU Lesser General Public
  17 + * License along with this library; if not, write to the Free Software
  18 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
  19 + */
  20 +
  21 +/* The theory here is that it should be possible to create a machine without
  22 + knowledge of specific devices. Historically board init routines have
  23 + passed a bunch of arguments to each device, requiring the board know
  24 + exactly which device it is dealing with. This file provides an abstract
  25 + API for device configuration and initialization. Devices will generally
  26 + inherit from a particular bus (e.g. PCI or I2C) rather than
  27 + this API directly. */
  28 +
  29 +#include "qdev.h"
  30 +#include "sysemu.h"
  31 +
  32 +struct DeviceProperty {
  33 + const char *name;
  34 + union {
  35 + int i;
  36 + void *ptr;
  37 + } value;
  38 + DeviceProperty *next;
  39 +};
  40 +
  41 +struct DeviceType {
  42 + const char *name;
  43 + qdev_initfn init;
  44 + void *opaque;
  45 + int size;
  46 + DeviceType *next;
  47 +};
  48 +
  49 +static DeviceType *device_type_list;
  50 +
  51 +/* Register a new device type. */
  52 +DeviceType *qdev_register(const char *name, int size, qdev_initfn init,
  53 + void *opaque)
  54 +{
  55 + DeviceType *t;
  56 +
  57 + assert(size >= sizeof(DeviceState));
  58 +
  59 + t = qemu_mallocz(sizeof(DeviceType));
  60 + t->next = device_type_list;
  61 + device_type_list = t;
  62 + t->name = qemu_strdup(name);
  63 + t->size = size;
  64 + t->init = init;
  65 + t->opaque = opaque;
  66 +
  67 + return t;
  68 +}
  69 +
  70 +/* Create a new device. This only initializes the device state structure
  71 + and allows properties to be set. qdev_init should be called to
  72 + initialize the actual device emulation. */
  73 +DeviceState *qdev_create(void *bus, const char *name)
  74 +{
  75 + DeviceType *t;
  76 + DeviceState *dev;
  77 +
  78 + for (t = device_type_list; t; t = t->next) {
  79 + if (strcmp(t->name, name) == 0) {
  80 + break;
  81 + }
  82 + }
  83 + if (!t) {
  84 + fprintf(stderr, "Unknown device '%s'\n", name);
  85 + exit(1);
  86 + }
  87 +
  88 + dev = qemu_mallocz(t->size);
  89 + dev->name = name;
  90 + dev->type = t;
  91 + dev->bus = bus;
  92 + return dev;
  93 +}
  94 +
  95 +/* Initialize a device. Device properties should be set before calling
  96 + this function. IRQs and MMIO regions should be connected/mapped after
  97 + calling this function. */
  98 +void qdev_init(DeviceState *dev)
  99 +{
  100 + dev->type->init(dev, dev->type->opaque);
  101 +}
  102 +
  103 +static DeviceProperty *create_prop(DeviceState *dev, const char *name)
  104 +{
  105 + DeviceProperty *prop;
  106 +
  107 + /* TODO: Check for duplicate properties. */
  108 + prop = qemu_mallocz(sizeof(*prop));
  109 + prop->name = qemu_strdup(name);
  110 + prop->next = dev->props;
  111 + dev->props = prop;
  112 +
  113 + return prop;
  114 +}
  115 +
  116 +void qdev_set_prop_int(DeviceState *dev, const char *name, int value)
  117 +{
  118 + DeviceProperty *prop;
  119 +
  120 + prop = create_prop(dev, name);
  121 + prop->value.i = value;
  122 +}
  123 +
  124 +void qdev_set_prop_ptr(DeviceState *dev, const char *name, void *value)
  125 +{
  126 + DeviceProperty *prop;
  127 +
  128 + prop = create_prop(dev, name);
  129 + prop->value.ptr = value;
  130 +}
  131 +
  132 +
  133 +qemu_irq qdev_get_irq_sink(DeviceState *dev, int n)
  134 +{
  135 + assert(n >= 0 && n < dev->num_irq_sink);
  136 + return dev->irq_sink[n];
  137 +}
  138 +
  139 +/* Register device IRQ sinks. */
  140 +void qdev_init_irq_sink(DeviceState *dev, qemu_irq_handler handler, int nirq)
  141 +{
  142 + dev->num_irq_sink = nirq;
  143 + dev->irq_sink = qemu_allocate_irqs(handler, dev, nirq);
  144 +}
  145 +
  146 +/* Get a character (serial) device interface. */
  147 +CharDriverState *qdev_init_chardev(DeviceState *dev)
  148 +{
  149 + static int next_serial;
  150 + static int next_virtconsole;
  151 + /* FIXME: This is a nasty hack that needs to go away. */
  152 + if (strncmp(dev->name, "virtio", 6) == 0) {
  153 + return virtcon_hds[next_virtconsole++];
  154 + } else {
  155 + return serial_hds[next_serial++];
  156 + }
  157 +}
  158 +
  159 +void *qdev_get_bus(DeviceState *dev)
  160 +{
  161 + return dev->bus;
  162 +}
  163 +
  164 +static DeviceProperty *find_prop(DeviceState *dev, const char *name)
  165 +{
  166 + DeviceProperty *prop;
  167 +
  168 + for (prop = dev->props; prop; prop = prop->next) {
  169 + if (strcmp(prop->name, name) == 0) {
  170 + return prop;
  171 + }
  172 + }
  173 + return NULL;
  174 +}
  175 +
  176 +uint64_t qdev_get_prop_int(DeviceState *dev, const char *name, uint64_t def)
  177 +{
  178 + DeviceProperty *prop;
  179 +
  180 + prop = find_prop(dev, name);
  181 + if (!prop)
  182 + return def;
  183 +
  184 + return prop->value.i;
  185 +}
  186 +
  187 +void *qdev_get_prop_ptr(DeviceState *dev, const char *name)
  188 +{
  189 + DeviceProperty *prop;
  190 +
  191 + prop = find_prop(dev, name);
  192 + assert(prop);
  193 + return prop->value.ptr;
  194 +}
  195 +
  196 +void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
  197 +{
  198 + assert(dev->num_gpio_in == 0);
  199 + dev->num_gpio_in = n;
  200 + dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
  201 +}
  202 +
  203 +void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
  204 +{
  205 + assert(dev->num_gpio_out == 0);
  206 + dev->num_gpio_out = n;
  207 + dev->gpio_out = pins;
  208 +}
  209 +
  210 +qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
  211 +{
  212 + assert(n >= 0 && n < dev->num_gpio_in);
  213 + return dev->gpio_in[n];
  214 +}
  215 +
  216 +void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
  217 +{
  218 + assert(n >= 0 && n < dev->num_gpio_out);
  219 + dev->gpio_out[n] = pin;
  220 +}
  221 +
  222 +static int next_block_unit[IF_COUNT];
  223 +
  224 +/* Get a block device. This should only be used for single-drive devices
  225 + (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
  226 + appropriate bus. */
  227 +BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
  228 +{
  229 + int unit = next_block_unit[type]++;
  230 + int index;
  231 +
  232 + index = drive_get_index(type, 0, unit);
  233 + if (index == -1) {
  234 + return NULL;
  235 + }
  236 + return drives_table[index].bdrv;
  237 +}
... ...
hw/qdev.h 0 → 100644
  1 +#ifndef QDEV_H
  2 +#define QDEV_H
  3 +
  4 +#include "hw.h"
  5 +
  6 +typedef struct DeviceType DeviceType;
  7 +
  8 +typedef struct DeviceProperty DeviceProperty;
  9 +
  10 +/* This structure should not be accessed directly. We declare it here
  11 + so that it can be embedded in individual device state structures. */
  12 +struct DeviceState
  13 +{
  14 + const char *name;
  15 + DeviceType *type;
  16 + void *bus;
  17 + DeviceProperty *props;
  18 + int num_irq_sink;
  19 + qemu_irq *irq_sink;
  20 + int num_gpio_out;
  21 + qemu_irq *gpio_out;
  22 + int num_gpio_in;
  23 + qemu_irq *gpio_in;
  24 +};
  25 +
  26 +/*** Board API. This should go away once we have a machine config file. ***/
  27 +
  28 +DeviceState *qdev_create(void *bus, const char *name);
  29 +void qdev_init(DeviceState *dev);
  30 +
  31 +/* Set properties between creation and init. */
  32 +void qdev_set_prop_int(DeviceState *dev, const char *name, int value);
  33 +void qdev_set_prop_ptr(DeviceState *dev, const char *name, void *value);
  34 +
  35 +qemu_irq qdev_get_irq_sink(DeviceState *dev, int n);
  36 +qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
  37 +void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
  38 +
  39 +/*** Device API. ***/
  40 +
  41 +typedef void (*qdev_initfn)(DeviceState *dev, void *opaque);
  42 +
  43 +DeviceType *qdev_register(const char *name, int size, qdev_initfn init,
  44 + void *opaque);
  45 +
  46 +/* Register device properties. */
  47 +void qdev_init_irq_sink(DeviceState *dev, qemu_irq_handler handler, int nirq);
  48 +void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
  49 +void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
  50 +
  51 +CharDriverState *qdev_init_chardev(DeviceState *dev);
  52 +
  53 +void *qdev_get_bus(DeviceState *dev);
  54 +uint64_t qdev_get_prop_int(DeviceState *dev, const char *name, uint64_t def);
  55 +void *qdev_get_prop_ptr(DeviceState *dev, const char *name);
  56 +
  57 +/* Convery from a base type to a parent type, with compile time checking. */
  58 +#ifdef __GNUC__
  59 +#define DO_UPCAST(type, field, dev) ( __extension__ ( { \
  60 + char __attribute__((unused)) offset_must_be_zero[ \
  61 + -offsetof(type, field)]; \
  62 + container_of(dev, type, field);}))
  63 +#else
  64 +#define DO_UPCAST(type, field, dev) container_of(dev, type, field)
  65 +#endif
  66 +
  67 +#endif
... ...
hw/sysbus.c 0 → 100644
  1 +/*
  2 + * System (CPU) Bus device support code
  3 + *
  4 + * Copyright (c) 2009 CodeSourcery
  5 + *
  6 + * This library is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU Lesser General Public
  8 + * License as published by the Free Software Foundation; either
  9 + * version 2 of the License, or (at your option) any later version.
  10 + *
  11 + * This library is distributed in the hope that it will be useful,
  12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14 + * Lesser General Public License for more details.
  15 + *
  16 + * You should have received a copy of the GNU Lesser General Public
  17 + * License along with this library; if not, write to the Free Software
  18 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
  19 + */
  20 +
  21 +#include "sysbus.h"
  22 +#include "sysemu.h"
  23 +
  24 +void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
  25 +{
  26 + assert(n >= 0 && n < dev->num_irq);
  27 + dev->irqs[n] = 0;
  28 + if (dev->irqp[n]) {
  29 + *dev->irqp[n] = irq;
  30 + }
  31 +}
  32 +
  33 +void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr)
  34 +{
  35 + assert(n >= 0 && n < dev->num_mmio);
  36 +
  37 + if (dev->mmio[n].addr == addr) {
  38 + /* ??? region already mapped here. */
  39 + return;
  40 + }
  41 + if (dev->mmio[n].addr != (target_phys_addr_t)-1) {
  42 + /* Unregister previous mapping. */
  43 + cpu_register_physical_memory(dev->mmio[n].addr, dev->mmio[n].size,
  44 + IO_MEM_UNASSIGNED);
  45 + }
  46 + dev->mmio[n].addr = addr;
  47 + if (dev->mmio[n].cb) {
  48 + dev->mmio[n].cb(dev, addr);
  49 + } else {
  50 + cpu_register_physical_memory(addr, dev->mmio[n].size,
  51 + dev->mmio[n].iofunc);
  52 + }
  53 +}
  54 +
  55 +
  56 +/* Request an IRQ source. The actual IRQ object may be populated later. */
  57 +void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p)
  58 +{
  59 + int n;
  60 +
  61 + assert(dev->num_irq < QDEV_MAX_IRQ);
  62 + n = dev->num_irq++;
  63 + dev->irqp[n] = p;
  64 +}
  65 +
  66 +/* Pass IRQs from a target device. */
  67 +void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target)
  68 +{
  69 + int i;
  70 + assert(dev->num_irq == 0);
  71 + dev->num_irq = target->num_irq;
  72 + for (i = 0; i < dev->num_irq; i++) {
  73 + dev->irqp[i] = target->irqp[i];
  74 + }
  75 +}
  76 +
  77 +void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size, int iofunc)
  78 +{
  79 + int n;
  80 +
  81 + assert(dev->num_mmio < QDEV_MAX_MMIO);
  82 + n = dev->num_mmio++;
  83 + dev->mmio[n].addr = -1;
  84 + dev->mmio[n].size = size;
  85 + dev->mmio[n].iofunc = iofunc;
  86 +}
  87 +
  88 +void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
  89 + mmio_mapfunc cb)
  90 +{
  91 + int n;
  92 +
  93 + assert(dev->num_mmio < QDEV_MAX_MMIO);
  94 + n = dev->num_mmio++;
  95 + dev->mmio[n].addr = -1;
  96 + dev->mmio[n].size = size;
  97 + dev->mmio[n].cb = cb;
  98 +}
  99 +
  100 +static void sysbus_device_init(DeviceState *dev, void *opaque)
  101 +{
  102 + sysbus_initfn init = (sysbus_initfn)opaque;
  103 +
  104 + init(sysbus_from_qdev(dev));
  105 +}
  106 +
  107 +void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init)
  108 +{
  109 + assert(size >= sizeof(SysBusDevice));
  110 + qdev_register(name, size, sysbus_device_init, init);
  111 +}
  112 +
  113 +DeviceState *sysbus_create_varargs(const char *name,
  114 + target_phys_addr_t addr, ...)
  115 +{
  116 + DeviceState *dev;
  117 + SysBusDevice *s;
  118 + va_list va;
  119 + qemu_irq irq;
  120 + int n;
  121 +
  122 + dev = qdev_create(NULL, name);
  123 + s = sysbus_from_qdev(dev);
  124 + qdev_init(dev);
  125 + if (addr != (target_phys_addr_t)-1) {
  126 + sysbus_mmio_map(s, 0, addr);
  127 + }
  128 + va_start(va, addr);
  129 + n = 0;
  130 + while (1) {
  131 + irq = va_arg(va, qemu_irq);
  132 + if (!irq) {
  133 + break;
  134 + }
  135 + sysbus_connect_irq(s, n, irq);
  136 + n++;
  137 + }
  138 + return dev;
  139 +}
... ...
hw/sysbus.h 0 → 100644
  1 +#ifndef HW_SYSBUS_H
  2 +#define HW_SYSBUS_H 1
  3 +
  4 +/* Devices attached directly to the main system bus. */
  5 +
  6 +#include "qdev.h"
  7 +
  8 +#define QDEV_MAX_MMIO 5
  9 +#define QDEV_MAX_IRQ 32
  10 +
  11 +typedef struct SysBusDevice SysBusDevice;
  12 +typedef void (*mmio_mapfunc)(SysBusDevice *dev, target_phys_addr_t addr);
  13 +
  14 +struct SysBusDevice {
  15 + DeviceState qdev;
  16 + int num_irq;
  17 + qemu_irq irqs[QDEV_MAX_IRQ];
  18 + qemu_irq *irqp[QDEV_MAX_IRQ];
  19 + int num_mmio;
  20 + struct {
  21 + target_phys_addr_t addr;
  22 + target_phys_addr_t size;
  23 + mmio_mapfunc cb;
  24 + int iofunc;
  25 + } mmio[QDEV_MAX_MMIO];
  26 +};
  27 +
  28 +typedef void (*sysbus_initfn)(SysBusDevice *dev);
  29 +
  30 +/* Macros to compensate for lack of type inheritance in C. */
  31 +#define sysbus_from_qdev(dev) ((SysBusDevice *)(dev))
  32 +#define FROM_SYSBUS(type, dev) DO_UPCAST(type, busdev, dev)
  33 +
  34 +void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init);
  35 +void *sysbus_new(void);
  36 +void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size, int iofunc);
  37 +void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
  38 + mmio_mapfunc cb);
  39 +void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p);
  40 +void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target);
  41 +
  42 +
  43 +void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq);
  44 +void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr);
  45 +
  46 +/* Legacy helper function for creating devices. */
  47 +DeviceState *sysbus_create_varargs(const char *name,
  48 + target_phys_addr_t addr, ...);
  49 +static inline DeviceState *sysbus_create_simple(const char *name,
  50 + target_phys_addr_t addr,
  51 + qemu_irq irq)
  52 +{
  53 + return sysbus_create_varargs(name, addr, irq, NULL);
  54 +}
  55 +
  56 +#endif /* !HW_SYSBUS_H */
... ...
qemu-common.h
... ... @@ -182,6 +182,7 @@ typedef struct PCMCIACardState PCMCIACardState;
182 182 typedef struct MouseTransformInfo MouseTransformInfo;
183 183 typedef struct uWireSlave uWireSlave;
184 184 typedef struct I2SCodec I2SCodec;
  185 +typedef struct DeviceState DeviceState;
185 186  
186 187 /* CPU save/load. */
187 188 void cpu_save(QEMUFile *f, void *opaque);
... ...
sysemu.h
... ... @@ -132,7 +132,8 @@ extern unsigned int nb_prom_envs;
132 132 #endif
133 133  
134 134 typedef enum {
135   - IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_XEN
  135 + IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_XEN,
  136 + IF_COUNT
136 137 } BlockInterfaceType;
137 138  
138 139 typedef enum {
... ... @@ -165,6 +166,8 @@ extern void drive_remove(int index);
165 166 extern const char *drive_get_serial(BlockDriverState *bdrv);
166 167 extern BlockInterfaceErrorAction drive_get_onerror(BlockDriverState *bdrv);
167 168  
  169 +BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type);
  170 +
168 171 struct drive_opt {
169 172 const char *file;
170 173 char opt[1024];
... ... @@ -259,4 +262,6 @@ int get_param_value(char *buf, int buf_size,
259 262 const char *tag, const char *str);
260 263 int check_params(const char * const *params, const char *str);
261 264  
  265 +void register_devices(void);
  266 +
262 267 #endif
... ...
... ... @@ -2565,6 +2565,8 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
2565 2565 case IF_MTD:
2566 2566 case IF_VIRTIO:
2567 2567 break;
  2568 + case IF_COUNT:
  2569 + abort();
2568 2570 }
2569 2571 if (!file[0])
2570 2572 return -2;
... ... @@ -5896,6 +5898,8 @@ int main(int argc, char **argv, char **envp)
5896 5898 }
5897 5899 }
5898 5900  
  5901 + module_call_init(MODULE_INIT_DEVICE);
  5902 +
5899 5903 machine->init(ram_size, boot_devices,
5900 5904 kernel_filename, kernel_cmdline, initrd_filename, cpu_model);
5901 5905  
... ...