aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/pci.c370
-rw-r--r--hw/pci.h4
-rw-r--r--monitor.c3
3 files changed, 301 insertions, 76 deletions
diff --git a/hw/pci.c b/hw/pci.c
index 2bdf27e04d..ffe4cfef05 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -27,6 +27,7 @@
#include "net.h"
#include "sysemu.h"
#include "loader.h"
+#include "qemu-objects.h"
//#define DEBUG_PCI
#ifdef DEBUG_PCI
@@ -1076,119 +1077,340 @@ static const pci_class_desc pci_class_descriptions[] =
{ 0, NULL}
};
-static void pci_info_device(PCIBus *bus, PCIDevice *d)
+static void pci_for_each_device_under_bus(PCIBus *bus,
+ void (*fn)(PCIBus *b, PCIDevice *d))
{
- Monitor *mon = cur_mon;
- int i, class;
- PCIIORegion *r;
- const pci_class_desc *desc;
+ PCIDevice *d;
+ int devfn;
- monitor_printf(mon, " Bus %2d, device %3d, function %d:\n",
- pci_bus_num(d->bus),
- PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));
- class = pci_get_word(d->config + PCI_CLASS_DEVICE);
+ for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
+ d = bus->devices[devfn];
+ if (d) {
+ fn(bus, d);
+ }
+ }
+}
+
+void pci_for_each_device(PCIBus *bus, int bus_num,
+ void (*fn)(PCIBus *b, PCIDevice *d))
+{
+ bus = pci_find_bus(bus, bus_num);
+
+ if (bus) {
+ pci_for_each_device_under_bus(bus, fn);
+ }
+}
+
+static void pci_device_print(Monitor *mon, QDict *device)
+{
+ QDict *qdict;
+ QListEntry *entry;
+ uint64_t addr, size;
+
+ monitor_printf(mon, " Bus %2" PRId64 ", ", qdict_get_int(device, "bus"));
+ monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n",
+ qdict_get_int(device, "slot"),
+ qdict_get_int(device, "function"));
monitor_printf(mon, " ");
- desc = pci_class_descriptions;
- while (desc->desc && class != desc->class)
- desc++;
- if (desc->desc) {
- monitor_printf(mon, "%s", desc->desc);
+
+ qdict = qdict_get_qdict(device, "class_info");
+ if (qdict_haskey(qdict, "desc")) {
+ monitor_printf(mon, "%s", qdict_get_str(qdict, "desc"));
} else {
- monitor_printf(mon, "Class %04x", class);
+ monitor_printf(mon, "Class %04" PRId64, qdict_get_int(qdict, "class"));
}
- monitor_printf(mon, ": PCI device %04x:%04x\n",
- pci_get_word(d->config + PCI_VENDOR_ID),
- pci_get_word(d->config + PCI_DEVICE_ID));
- if (d->config[PCI_INTERRUPT_PIN] != 0) {
- monitor_printf(mon, " IRQ %d.\n",
- d->config[PCI_INTERRUPT_LINE]);
+ qdict = qdict_get_qdict(device, "id");
+ monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
+ qdict_get_int(qdict, "device"),
+ qdict_get_int(qdict, "vendor"));
+
+ if (qdict_haskey(device, "irq")) {
+ monitor_printf(mon, " IRQ %" PRId64 ".\n",
+ qdict_get_int(device, "irq"));
}
- if (class == 0x0604) {
- uint64_t base;
- uint64_t limit;
- monitor_printf(mon, " BUS %d.\n", d->config[0x19]);
- monitor_printf(mon, " secondary bus %d.\n",
- d->config[PCI_SECONDARY_BUS]);
- monitor_printf(mon, " subordinate bus %d.\n",
- d->config[PCI_SUBORDINATE_BUS]);
+ if (qdict_haskey(device, "pci_bridge")) {
+ QDict *info;
+
+ qdict = qdict_get_qdict(device, "pci_bridge");
+
+ info = qdict_get_qdict(qdict, "bus");
+ monitor_printf(mon, " BUS %" PRId64 ".\n",
+ qdict_get_int(info, "number"));
+ monitor_printf(mon, " secondary bus %" PRId64 ".\n",
+ qdict_get_int(info, "secondary"));
+ monitor_printf(mon, " subordinate bus %" PRId64 ".\n",
+ qdict_get_int(info, "subordinate"));
- base = pci_bridge_get_base(d, PCI_BASE_ADDRESS_SPACE_IO);
- limit = pci_bridge_get_limit(d, PCI_BASE_ADDRESS_SPACE_IO);
+ info = qdict_get_qdict(qdict, "io_range");
monitor_printf(mon, " IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
- base, limit);
+ qdict_get_int(info, "base"),
+ qdict_get_int(info, "limit"));
- base = pci_bridge_get_base(d, PCI_BASE_ADDRESS_SPACE_MEMORY);
- limit= pci_bridge_get_limit(d, PCI_BASE_ADDRESS_SPACE_MEMORY);
+ info = qdict_get_qdict(qdict, "memory_range");
monitor_printf(mon,
" memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
- base, limit);
+ qdict_get_int(info, "base"),
+ qdict_get_int(info, "limit"));
- base = pci_bridge_get_base(d, PCI_BASE_ADDRESS_SPACE_MEMORY |
- PCI_BASE_ADDRESS_MEM_PREFETCH);
- limit = pci_bridge_get_limit(d, PCI_BASE_ADDRESS_SPACE_MEMORY |
- PCI_BASE_ADDRESS_MEM_PREFETCH);
+ info = qdict_get_qdict(qdict, "prefetchable_range");
monitor_printf(mon, " prefetchable memory range "
- "[0x%08"PRIx64", 0x%08"PRIx64"]\n", base, limit);
+ "[0x%08"PRIx64", 0x%08"PRIx64"]\n",
+ qdict_get_int(info, "base"),
+ qdict_get_int(info, "limit"));
}
- for(i = 0;i < PCI_NUM_REGIONS; i++) {
- r = &d->io_regions[i];
- if (r->size != 0) {
- monitor_printf(mon, " BAR%d: ", i);
- if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
- monitor_printf(mon, "I/O at 0x%04"FMT_PCIBUS
- " [0x%04"FMT_PCIBUS"].\n",
- r->addr, r->addr + r->size - 1);
- } else {
- const char *type = r->type & PCI_BASE_ADDRESS_MEM_TYPE_64 ?
- "64 bit" : "32 bit";
- const char *prefetch =
- r->type & PCI_BASE_ADDRESS_MEM_PREFETCH ?
- " prefetchable" : "";
- monitor_printf(mon, "%s%s memory at 0x%08"FMT_PCIBUS
+ QLIST_FOREACH_ENTRY(qdict_get_qlist(device, "regions"), entry) {
+ qdict = qobject_to_qdict(qlist_entry_obj(entry));
+ monitor_printf(mon, " BAR%d: ", (int) qdict_get_int(qdict, "bar"));
+
+ addr = qdict_get_int(qdict, "address");
+ size = qdict_get_int(qdict, "size");
+
+ if (!strcmp(qdict_get_str(qdict, "type"), "io")) {
+ monitor_printf(mon, "I/O at 0x%04"FMT_PCIBUS
+ " [0x%04"FMT_PCIBUS"].\n",
+ addr, addr + size - 1);
+ } else {
+ monitor_printf(mon, "%d bit%s memory at 0x%08"FMT_PCIBUS
" [0x%08"FMT_PCIBUS"].\n",
- type, prefetch,
- r->addr, r->addr + r->size - 1);
- }
+ qdict_get_bool(qdict, "mem_type_64") ? 64 : 32,
+ qdict_get_bool(qdict, "prefetch") ?
+ " prefetchable" : "", addr, addr + size - 1);
}
}
- monitor_printf(mon, " id \"%s\"\n", d->qdev.id ? d->qdev.id : "");
- if (class == 0x0604 && d->config[0x19] != 0) {
- pci_for_each_device(bus, d->config[0x19], pci_info_device);
+
+ monitor_printf(mon, " id \"%s\"\n", qdict_get_str(device, "qdev_id"));
+
+ /* TODO: PCI bridge devices */
+}
+
+void do_pci_info_print(Monitor *mon, const QObject *data)
+{
+ QListEntry *bus, *dev;
+
+ QLIST_FOREACH_ENTRY(qobject_to_qlist(data), bus) {
+ QDict *qdict = qobject_to_qdict(qlist_entry_obj(bus));
+ QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) {
+ pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev)));
+ }
}
}
-static void pci_for_each_device_under_bus(PCIBus *bus,
- void (*fn)(PCIBus *b, PCIDevice *d))
+static QObject *pci_get_dev_class(const PCIDevice *dev)
+{
+ int class;
+ const pci_class_desc *desc;
+
+ class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
+ desc = pci_class_descriptions;
+ while (desc->desc && class != desc->class)
+ desc++;
+
+ if (desc->desc) {
+ return qobject_from_jsonf("{ 'desc': %s, 'class': %d }",
+ desc->desc, class);
+ } else {
+ return qobject_from_jsonf("{ 'class': %d }", class);
+ }
+}
+
+static QObject *pci_get_dev_id(const PCIDevice *dev)
+{
+ return qobject_from_jsonf("{ 'device': %d, 'vendor': %d }",
+ pci_get_word(dev->config + PCI_VENDOR_ID),
+ pci_get_word(dev->config + PCI_DEVICE_ID));
+}
+
+static QObject *pci_get_regions_list(const PCIDevice *dev)
+{
+ int i;
+ QList *regions_list;
+
+ regions_list = qlist_new();
+
+ for (i = 0; i < PCI_NUM_REGIONS; i++) {
+ QObject *obj;
+ const PCIIORegion *r = &dev->io_regions[i];
+
+ if (!r->size) {
+ continue;
+ }
+
+ if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
+ obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'io', "
+ "'address': %" PRId64 ", "
+ "'size': %" PRId64 " }",
+ i, r->addr, r->size);
+ } else {
+ int mem_type_64 = r->type & PCI_BASE_ADDRESS_MEM_TYPE_64;
+
+ obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'memory', "
+ "'mem_type_64': %i, 'prefetch': %i, "
+ "'address': %" PRId64 ", "
+ "'size': %" PRId64 " }",
+ i, mem_type_64,
+ r->type & PCI_BASE_ADDRESS_MEM_PREFETCH,
+ r->addr, r->size);
+ }
+
+ qlist_append_obj(regions_list, obj);
+ }
+
+ return QOBJECT(regions_list);
+}
+
+static QObject *pci_get_dev_dict(PCIDevice *dev, int bus_num)
+{
+ int class;
+ QObject *obj;
+
+ obj = qobject_from_jsonf("{ 'bus': %d, 'slot': %d, 'function': %d," "'class_info': %p, 'id': %p, 'regions': %p,"
+ " 'qdev_id': %s }",
+ bus_num,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+ pci_get_dev_class(dev), pci_get_dev_id(dev),
+ pci_get_regions_list(dev),
+ dev->qdev.id ? dev->qdev.id : "");
+
+ if (dev->config[PCI_INTERRUPT_PIN] != 0) {
+ QDict *qdict = qobject_to_qdict(obj);
+ qdict_put(qdict, "irq", qint_from_int(dev->config[PCI_INTERRUPT_LINE]));
+ }
+
+ class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
+ if (class == 0x0604) {
+ QDict *qdict;
+ QObject *pci_bridge;
+
+ pci_bridge = qobject_from_jsonf("{ 'bus': "
+ "{ 'number': %d, 'secondary': %d, 'subordinate': %d }, "
+ "'io_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "
+ "'memory_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "
+ "'prefetchable_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "} }",
+ dev->config[0x19], dev->config[PCI_SECONDARY_BUS],
+ dev->config[PCI_SUBORDINATE_BUS],
+ pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO),
+ pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO),
+ pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),
+ pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),
+ pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_PREFETCH),
+ pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_PREFETCH));
+
+ qdict = qobject_to_qdict(obj);
+ qdict_put_obj(qdict, "pci_bridge", pci_bridge);
+ }
+
+ return obj;
+}
+
+static QObject *pci_get_devices_list(PCIBus *bus, int bus_num)
{
- PCIDevice *d;
int devfn;
+ PCIDevice *dev;
+ QList *dev_list;
- for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
- d = bus->devices[devfn];
- if (d)
- fn(bus, d);
+ dev_list = qlist_new();
+
+ for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
+ dev = bus->devices[devfn];
+ if (dev) {
+ qlist_append_obj(dev_list, pci_get_dev_dict(dev, bus_num));
+ }
}
+
+ return QOBJECT(dev_list);
}
-void pci_for_each_device(PCIBus *bus, int bus_num,
- void (*fn)(PCIBus *b, PCIDevice *d))
+static QObject *pci_get_bus_dict(PCIBus *bus, int bus_num)
{
bus = pci_find_bus(bus, bus_num);
-
if (bus) {
- pci_for_each_device_under_bus(bus, fn);
+ return qobject_from_jsonf("{ 'bus': %d, 'devices': %p }",
+ bus_num, pci_get_devices_list(bus, bus_num));
}
+
+ return NULL;
}
-void pci_info(Monitor *mon)
+/**
+ * do_pci_info(): PCI buses and devices information
+ *
+ * The returned QObject is a QList of all buses. Each bus is
+ * represented by a QDict, which has a key with a QList of all
+ * PCI devices attached to it. Each device is represented by
+ * a QDict.
+ *
+ * The bus QDict contains the following:
+ *
+ * - "bus": bus number
+ * - "devices": a QList of QDicts, each QDict represents a PCI
+ * device
+ *
+ * The PCI device QDict contains the following:
+ *
+ * - "bus": identical to the parent's bus number
+ * - "slot": slot number
+ * - "function": function number
+ * - "class_info": a QDict containing:
+ * - "desc": device class description (optional)
+ * - "class": device class number
+ * - "id": a QDict containing:
+ * - "device": device ID
+ * - "vendor": vendor ID
+ * - "irq": device's IRQ if assigned (optional)
+ * - "qdev_id": qdev id string
+ * - "pci_bridge": It's a QDict, only present if this device is a
+ * PCI bridge, contains:
+ * - "bus": bus number
+ * - "secondary": secondary bus number
+ * - "subordinate": subordinate bus number
+ * - "io_range": a QDict with memory range information
+ * - "memory_range": a QDict with memory range information
+ * - "prefetchable_range": a QDict with memory range information
+ * - "regions": a QList of QDicts, each QDict represents a
+ * memory region of this device
+ *
+ * The memory range QDict contains the following:
+ *
+ * - "base": base memory address
+ * - "limit": limit value
+ *
+ * The region QDict can be an I/O region or a memory region,
+ * an I/O region QDict contains the following:
+ *
+ * - "type": "io"
+ * - "bar": BAR number
+ * - "address": memory address
+ * - "size": memory size
+ *
+ * A memory region QDict contains the following:
+ *
+ * - "type": "memory"
+ * - "bar": BAR number
+ * - "address": memory address
+ * - "size": memory size
+ * - "mem_type_64": true or false
+ * - "prefetch": true or false
+ */
+void do_pci_info(Monitor *mon, QObject **ret_data)
{
+ QList *bus_list;
struct PCIHostBus *host;
+
+ bus_list = qlist_new();
+
QLIST_FOREACH(host, &host_buses, next) {
- pci_for_each_device(host->bus, 0, pci_info_device);
+ QObject *obj = pci_get_bus_dict(host->bus, 0);
+ if (obj) {
+ qlist_append_obj(bus_list, obj);
+ }
}
+
+ *ret_data = QOBJECT(bus_list);
}
static const char * const pci_nic_models[] = {
diff --git a/hw/pci.h b/hw/pci.h
index c9ee07b75a..8b511d243c 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -2,6 +2,7 @@
#define QEMU_PCI_H
#include "qemu-common.h"
+#include "qobject.h"
#include "qdev.h"
@@ -234,7 +235,8 @@ PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr);
int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
unsigned *slotp);
-void pci_info(Monitor *mon);
+void do_pci_info_print(Monitor *mon, const QObject *data);
+void do_pci_info(Monitor *mon, QObject **ret_data);
PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
pci_map_irq_fn map_irq, const char *name);
PCIDevice *pci_bridge_get_device(PCIBus *bus);
diff --git a/monitor.c b/monitor.c
index 2f38601d65..1cdb0c848f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2445,7 +2445,8 @@ static const mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show PCI info",
- .mhandler.info = pci_info,
+ .user_print = do_pci_info_print,
+ .mhandler.info_new = do_pci_info,
},
#if defined(TARGET_I386) || defined(TARGET_SH4)
{