+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, " ");
+
+ 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 %04" PRId64, qdict_get_int(qdict, "class"));
+ }
+
+ 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"));
+ }
+
+ /* TODO: PCI bridge info */
+
+ 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",
+ 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", 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 QObject *pci_get_dev_class(const PCIDevice *dev)
+{
+ int class;
+ const char *str = "";
+ 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) {
- monitor_printf(mon, "%s", desc->desc);
- } else {
- monitor_printf(mon, "Class %04x", 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]);
- }
- 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]);
-
- base = pci_bridge_get_base(d, PCI_BASE_ADDRESS_SPACE_IO);
- limit = pci_bridge_get_limit(d, PCI_BASE_ADDRESS_SPACE_IO);
- monitor_printf(mon, " IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
- base, limit);
-
- base = pci_bridge_get_base(d, PCI_BASE_ADDRESS_SPACE_MEMORY);
- limit= pci_bridge_get_limit(d, PCI_BASE_ADDRESS_SPACE_MEMORY);
- monitor_printf(mon,
- " memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
- base, 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);
- monitor_printf(mon, " prefetchable memory range "
- "[0x%08"PRIx64", 0x%08"PRIx64"]\n", base, limit);
- }
- for(i = 0;i< PCI_NUM_REGIONS; i++) {
- r =&d->io_regions[i];
+ str = desc->desc;
+ }
+
+ return qobject_from_jsonf("{ 'desc': %s, 'class': %d }", str, 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++) {
+ const PCIIORegion *r =&dev->io_regions[i];
if (r->size != 0) {
- monitor_printf(mon, " BAR%d: ", i);
+ QObject *obj;
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);
+ obj = qobject_from_jsonf("{ 'BAR': %d, 'type': 'io', "
+ "'address': %" PRId64 ", "
+ "'size': %" PRId64 " }",
+ i, r->addr, r->size);
} 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
- " [0x%08"FMT_PCIBUS"].\n",
- type, prefetch,
- r->addr, r->addr + r->size - 1);
+ 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);
}
}
- 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);
+
+ return QOBJECT(regions_list);
+}
+
+static QObject *pci_get_dev_dict(const PCIDevice *dev, int bus_num)
+{
+ 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]));
}
+
+ return obj;
}
-static void pci_for_each_device_under_bus(PCIBus *bus,
- void (*fn)(PCIBus *b, PCIDevice *d))
+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": bus number
+ * - "slot": slot number
+ * - "function": function number
+ * - "class_info": a QDict containing:
+ * - "desc": device class description
+ * - "class": device class number
+ * - "id": a QDict containing:
+ * - "device": device ID
+ * - "vendor": vendor ID
+ * - "qdev_id": qdev id string
+ * - "regions": a QList of QDicts, each QDict represents a
+ * memory region of this device
+ *
+ * The region QDict can be an I/O region or a memory region,
+ * the I/O region contains the following:
+ *
+ * - "type": "io"
+ * - "BAR": BAR number
+ * - "address": memory address
+ * - "size": memory size
+ *
+ * The 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 fd16460..e1e6d29 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"
@@ -300,7 +301,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 3af1d5c..3fe7aa9 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2436,7 +2436,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)
{