| DeviceState/SysBus in master/qemu: |
| =========================================================================== |
| |
| Defined in <hw/qdev-core.h> |
| |
| Typical sequence to create a new DeviceState instance: |
| |
| DeviceState* dev = qdev_create(parent_bus, device_class_name); |
| qdev_set_prop_int(dev, "<property-name>", value); |
| ... // set other properties. |
| qdev_init(dev); // real initialization / realization here. |
| return dev; |
| |
| Registering a new DeviceState class (a.k.a. DeviceInfo): |
| |
| DeviceInfo info = g_malloc0(sizeof(*info)); |
| info->name = DEVICE_CLASS_NAME; |
| info->size = sizeof(MyDeviceState); |
| info->init = my_device_state_init; |
| info->bus_type = DEVICE_BUS_TYPE; // SYSTEM / PCI / LSI / etc. |
| qdev_register(&info); |
| |
| |
| DeviceState has: |
| |
| type : *DeviceType -> should really be DeviceInfo, see below. |
| parent_bus: *BusState -> parent bus the device is attached to. |
| props: *DeviceProperty -> WHAT ARE THESE ??? |
| num_gpio_out: int -> number of output IRQ pins. |
| gpio_out: *qemu_irq -> array of output IRQ pins. |
| num_gpio_in: int -> number of input IRQ pins. |
| gpio_in: *qemu_irq -> array of input IRQ pins. |
| child_bus: QLIST_HEAD(, BusState) -> optional child bus provided by device? |
| nd: *NICInfo ?? -> WHAT IS THIS ??? |
| sibling: QLIST_ENTRY(DeviceState) -> next device attached to same |parent_bus|. |
| |
| BusState has: |
| parent: *DeviceState -> parent device, if any? |
| name: *char -> bus name. What is used for? |
| type: BusType -> SYSTEM, PCI, SCSI, I2C or SSI. Why? |
| |
| DeviceInfo: -> Really a device class descriptor. |
| name: *const char -> Name of device class. |
| size: size_t -> Size of device instance, must be >= sizeof(DeviceState). |
| props: *DevicePropList -> |
| |
| init: qdev_initfn |
| bus_type: BusType. |
| |
| DeviceType: -> Defined and used by hw/core/qdev.c to to maintain the list of |
| registered DeviceInfo values (added by calling qdev_register()). |
| info: *DeviceInfo -> device class descriptor. |
| next: *DeviceType -> next item in list. |
| |
| DeviceProperty: |
| name: *const_char -> property name. |
| type: DevicePropertyType -> INT, PTR or DEV ??? |
| value: union{uint64_t, void*} -> property value. |
| |
| DevicePropList: Individual array item describing a device property. |
| Used in DeviceInfo to list which properties a given DeviceState |
| supports. |
| name: *const_char -> property name. |
| type: DevicePropertyType -> INT, PTR or DEV ? |
| |
| // Create a new, totally empty, DeviceState instance. |
| // |bus| is the parent bus instance, if NULL, this indicates that the device |
| // will be attached to the main system bus (created internally on demand by |
| // this function). |
| // |name| is the device class name, i.e. must match the |name| field of a |
| // registered DeviceInfo. |
| // Return a new DeviceState instance on success, panic on failure. |
| // |
| // IMPORTANT: The DeviceState is allocated with g_malloc0() but is not |
| // initialized when the function returns!! It is just added |
| // to the parent bus' list. |
| // |
| // Possible failure modes: |
| // - |name| doesn't match a registered DeviceInfo. |
| // - The |bus_type| field of the DeviceInfo does not match the one of |
| // the parent |bus|. |
| DeviceState* qdev_create(BusState* bus, const char* name); |
| |
| // Initialize a given DeviceState. Assumes that all device properties were |
| // set before calling this function, and that IRQs and MMIO regions are also |
| // already connected. This simply calls the |init| function of the device's |
| // DeviceInfo class descriptor. |
| void qdev_init(DeviceState* dev); |
| |
| // Unlink a device from a bus and free the structure. NOTE: This does not |
| // perform any de-initialization. |
| qdev_free(DeviceState* dev); |
| |
| // Sets a device property to a given integer value. |
| // |dev| is the target DeviceState that holds the property value. |
| // |name| is the property name. |
| // |value| is the 64-bit value. |
| // NOTE: This function doesn't check that the property name actually |
| // matches any of the properties listed in the DeviceInfo, or |
| // that their type matches. It also doesn't check for any |
| // previously existing with the same name, it just prepends |
| // to the list. |
| void qdev_set_prop(DeviceState* dev, const char* name, uint64_t value); |
| |
| // Same a qdev_set_prop() for property values of type DEV |
| void qdev_set_prop_dev(DeviceState* dev, const char* name DeviceState* value); |
| |
| // Same a qdev_set_prop() for property values of type PTR |
| void qdev_set_prop_ptr(DeviceState* dev, const char* name, void* value); |
| |
| // Find if the device |dev| has a value for property |name|, and return it |
| // if it does, otherwise return |def|. This assert()s that the property |
| // type is an integer (INT). |
| uint64_t qdev_get_prop_int(DeviceState* dev, const char* name, uint64_t def); |
| |
| // Find if the device |dev| has a pointer value for property |name|, and |
| // return it if it does. Otherwise, assert(NULL). NOTE THE UNEXPECTED ASSERT |
| // HERE! |
| void* qdev_get_prop_ptr(DeviceState* dev, const char* name); |
| |
| // Find if the device |dev| has a DeviceState value for property |name|, |
| // and return it if it does, or NULL if it doesn't. |
| DeviceState* qdev_get_prop_dev(DeviceState* dev, const char* name); |
| |
| // Despite its name, this doesn't do any kind of initialization, this just |
| // returns a new CharDriverState which was previously added to the global |
| // |serial_hds| or |virtcon_hds| arrays. Which one is selected depends |
| // on the device's DeviceInfo |name| field. If it starts with 'virtio' |
| // then it comes from |virtcon_hds|, otherwise from |serial_hds|. |
| // There is a FIXME here to 'get rid of this hack'. |
| CharDriveState* qdev_init_chardev(DeviceState* dev); |
| |
| // Just return device's |parent_bus| field falue. |
| BusState* qdev_get_parent_bus(DeviceState* dev); |
| |
| // Allocate |n| input IRQ pins that all will be handled by the |handler| |
| // callback for device |dev|. |
| void qdev_init_gpio_in(DeviceState* dev, qemu_irq_handler handler, int n); |
| |
| // Allocate |n| output IRQ pins that all will be handled by the |handler| |
| // callback for device |dev|. |
| void qdev_init_gpio_out(DeviceState* dev, qemu_irq_handler handler, int n); |
| |
| // Return IRQ pin indexed by |n| for device |dev|. |
| // The value of |n| must be between 0 (included) and the value passed |
| // to qdev_init_qpio_in() (excluded). |
| qemu_irq qdev_get_gpio_in(DeviceState* dev, int n); |
| |
| // Guess what. |
| qemu_irq qdev_get_gpio_out(DeviceState* dev, int n); |
| |
| // Set the |nd| field of a given DeviceState. Looks like it's network related. |
| void qdev_set_netdev(DeviceState* dev, NICInfo* nd); |
| |
| // Create a new VLANClientState instance using the device's |nd| field |
| // to extract the vlan, model and name to call qemu_new_vlan_client(). |
| // assert that qdev_set_netdev() was called previously on the device. |
| // WHY??? |
| VLANClientState* qdev_get_vlan_client(DeviceState *dev, |
| NetCanReceive* can_receive, |
| NetReceive* receive, |
| NetReceiveIOV* receive_iov, |
| NetCleanup* cleanup, |
| void* opaque); |
| |
| // Return |dev|'s MAC address into |*macaddr| (6 bytes), extracting it from |
| // the device's netdev |nd| field. |
| void qdev_get_macaddr(DeviceState* dev, uint8_t* macaddr); |
| |
| // UNUSED AND PROBABLY MISPLACED, since it completely ignores |dev|. |
| // Used to get the BlockDriverState instance of a given block interface |type|. |
| // This calls drive_get(type, 0, unit), where |unit| is computed internally |
| // by a static type-specific counter. |
| BlockDriverState* qdev_init_bdrv(DeviceState* dev, BlockInterfaceType type); |
| |
| // Return a device's child bus of a given name, or NULL. |
| // |dev| is the device that may provide its own buses. |
| // |name| is the name of the child bus to match. |
| BusState* qdev_get_child_bus(DeviceState* state, const char* name); |
| |
| // Create new bus instance. |
| // |type| is the bus type (SYSTEM, PCI, SCSI, I2C, SSI) |
| // |size| is the instance size, must be >= sizeof(BusState). |
| // |parent| is the parent bbus, can be NULL. |
| // |name| is the bus' name. |
| BusState* qbus_create(BusType type, |
| size_t size, |
| DeviceState* parent, |
| const char* name); |
| |
| // Supposed to return a string describing the device's path from the |
| // main system bus. Currently unimplemented, always return NULL! |
| char* qdev_get_dev_path(DeviceState* dev); |
| |
| SysBusDevice: |
| qdev: DeviceState -> base DeviceState members. |
| num_irq: int -> number of IRQs used by bus? |
| irqs: qemu_irq[32] -> array of pointers to IRQ pins. |
| irqp: (*qemu_irq)[32] -> array of pointers to pointers to IRQ pins? WHAT??? |
| num_mmio: int -> number of MMIO regions. |
| mmio: struct{}[5] -> array of MMIO region descriptor. |
| |
| Each mmio region has: |
| addr: hwaddr |
| size: hwaddr |
| cb: mmio_mapfunc cb -> function used to map I/O memory. |
| iofunc: int |
| |
| SysBusDeviceInfo: |
| qdev: DeviceInfo -> base DeviceInfo class descriptor. |
| init: sysbuf_initfn -> bus initialization function. ??? |
| |
| // Register a new SysBusDevice class. This creates a new SysBusDeviceInfo |
| // instance recording the name, size and initialization function corresponding |
| // to a class of SysBufDevice instances. |
| // |name| is the DeviceInfo class name. |
| // |size| is the instance size, must be >= sizeof(SysBusDevice) |
| // |init| if the sysbus_initfn for instances of this class. |
| sysbus_register_dev(const char* name, size_t size, sysbus_initfn init); |
| |
| // Used internally to set the parent DeviceInfo |bus_type| and |init|. |
| // before calling qdev_register() to register the system bus device class. |
| sysbus_register_withprop(SysBusDeviceInfo* info); |
| |
| // Allocate but do not map a new MMIO region of |size| bytes, using |
| // the |iofunc| MMIO function index. |
| // |dev| points to an existing SysBusDevice. |
| // NOTE: The region can later be mapped by calling sysbus_mmio_map. |
| void sysbus_init_mmio(SysBusDevice* dev, hwaddr size, int iofunc); |
| |
| // REMOVED: Allocate but do not map a new MMIO region of |size| byutes, using |
| // a custom |cb| mapping callback. |
| // |dev| points to an existing SysBusDevice. |
| // NOTE: The region can later be mapped by calling sysbus_mmio_map. |
| void sysbus_init_mmio_cb(SysBusDevice* dev, hwaddr size, mmio_mapfunc cb); |
| |
| // Map a system bus device MMIO region, identified by index |n|, at address |
| // |addr|. The index correspond to the sequence of previous calls to |
| // sysbus_init_mmio() or sysbus_init_mmio_cb(). First call creates index 0. |
| // NOTE: It's possible to call this multiple time to remap the region to |
| // a different address. |
| void sysbus_mmio_map(SysBusDevice* dev, int n, hwaddr addr); |
| |
| // Allocate an IRQ source. The function takes the address of a qemu_irq |
| // value that can be populated/set later, by calling sysbus_connect_irq. |
| // In other words, this function records the pointer in an array for later |
| // user. |
| sysbus_init_irq(SysBusDevice* dev, qemu_irq* p); |
| |
| // Connect an IRQ source to the actual device. |n| is an index corresponding |
| // to the sequence of previous calls to sysbus_init_irq(), and |irq| is the |
| // IRQ to use as the source. This function really writes |irq| to the pointer |
| // that was previously registered with sysbus_init_irq(), and nothing more. |
| sysbus_connect_irq(SysBusDevice* dev, int n, qemu_irq irq); |
| |
| // Pass all |
| sysbus_pass_irq(SysBusDevice* dev, SysBusDevice* target); |
| |
| PCIDevice: |
| qdev: DeviceState -> base DeviceState fields. |
| config: uint8_t[256] -> PCI config space? |
| bus: *PCIBus -> PCI Bus instance this device belongs to. |
| devfn: int -> PCI device function index |
| name: char[64] |
| io_regions: PCIIORegion[PCI_NUM_REGIONS] |
| config_read: *PCIConfigReadFunc |
| config_write: *PCIConfigWriteFunc |
| unregister: *PCIUnregisterFunc |
| |
| irq: *qemu_irq -> IRQ objects for the INTA-INTD pins ??? |
| irq_state: int[4] -> current IRQ levels. ??? |
| |
| PCIIORegion: |
| addr: uint32_t -> PCI mapping address, -1 means not mapped. |
| size: uint32_t |
| type: uint8_t |
| map_func: *PCIMapIORegioFunc |
| |
| PCIBus: |
| qbus: BusState -> base BusState fields. |
| bus_num: int -> ? |
| devfn_min: int -> ? |
| set_irq: pci_set_irq_fn |
| map_irq: pci_map_irq_fn |
| config_reg: uint32_t -> UNUSED |
| low_set_irq: qemu_irq_handler |
| irq_opaque: qemu_irq |
| devices: (*PCIDevice)[256] |
| parent_dev: *PCIDevice |
| next: *PCIBus |
| nirq: int |
| irq_count: int[] |
| |