Revision 163c8a59 hw/pci.c
b/hw/pci.c | ||
---|---|---|
27 | 27 |
#include "net.h" |
28 | 28 |
#include "sysemu.h" |
29 | 29 |
#include "loader.h" |
30 |
#include "qemu-objects.h" |
|
30 | 31 |
|
31 | 32 |
//#define DEBUG_PCI |
32 | 33 |
#ifdef DEBUG_PCI |
... | ... | |
1076 | 1077 |
{ 0, NULL} |
1077 | 1078 |
}; |
1078 | 1079 |
|
1079 |
static void pci_info_device(PCIBus *bus, PCIDevice *d) |
|
1080 |
static void pci_for_each_device_under_bus(PCIBus *bus, |
|
1081 |
void (*fn)(PCIBus *b, PCIDevice *d)) |
|
1080 | 1082 |
{ |
1081 |
Monitor *mon = cur_mon; |
|
1082 |
int i, class; |
|
1083 |
PCIIORegion *r; |
|
1084 |
const pci_class_desc *desc; |
|
1083 |
PCIDevice *d; |
|
1084 |
int devfn; |
|
1085 | 1085 |
|
1086 |
monitor_printf(mon, " Bus %2d, device %3d, function %d:\n", |
|
1087 |
pci_bus_num(d->bus), |
|
1088 |
PCI_SLOT(d->devfn), PCI_FUNC(d->devfn)); |
|
1089 |
class = pci_get_word(d->config + PCI_CLASS_DEVICE); |
|
1086 |
for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { |
|
1087 |
d = bus->devices[devfn]; |
|
1088 |
if (d) { |
|
1089 |
fn(bus, d); |
|
1090 |
} |
|
1091 |
} |
|
1092 |
} |
|
1093 |
|
|
1094 |
void pci_for_each_device(PCIBus *bus, int bus_num, |
|
1095 |
void (*fn)(PCIBus *b, PCIDevice *d)) |
|
1096 |
{ |
|
1097 |
bus = pci_find_bus(bus, bus_num); |
|
1098 |
|
|
1099 |
if (bus) { |
|
1100 |
pci_for_each_device_under_bus(bus, fn); |
|
1101 |
} |
|
1102 |
} |
|
1103 |
|
|
1104 |
static void pci_device_print(Monitor *mon, QDict *device) |
|
1105 |
{ |
|
1106 |
QDict *qdict; |
|
1107 |
QListEntry *entry; |
|
1108 |
uint64_t addr, size; |
|
1109 |
|
|
1110 |
monitor_printf(mon, " Bus %2" PRId64 ", ", qdict_get_int(device, "bus")); |
|
1111 |
monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n", |
|
1112 |
qdict_get_int(device, "slot"), |
|
1113 |
qdict_get_int(device, "function")); |
|
1090 | 1114 |
monitor_printf(mon, " "); |
1091 |
desc = pci_class_descriptions; |
|
1092 |
while (desc->desc && class != desc->class) |
|
1093 |
desc++; |
|
1094 |
if (desc->desc) { |
|
1095 |
monitor_printf(mon, "%s", desc->desc); |
|
1115 |
|
|
1116 |
qdict = qdict_get_qdict(device, "class_info"); |
|
1117 |
if (qdict_haskey(qdict, "desc")) { |
|
1118 |
monitor_printf(mon, "%s", qdict_get_str(qdict, "desc")); |
|
1096 | 1119 |
} else { |
1097 |
monitor_printf(mon, "Class %04x", class);
|
|
1120 |
monitor_printf(mon, "Class %04" PRId64, qdict_get_int(qdict, "class"));
|
|
1098 | 1121 |
} |
1099 |
monitor_printf(mon, ": PCI device %04x:%04x\n", |
|
1100 |
pci_get_word(d->config + PCI_VENDOR_ID), |
|
1101 |
pci_get_word(d->config + PCI_DEVICE_ID)); |
|
1102 | 1122 |
|
1103 |
if (d->config[PCI_INTERRUPT_PIN] != 0) { |
|
1104 |
monitor_printf(mon, " IRQ %d.\n", |
|
1105 |
d->config[PCI_INTERRUPT_LINE]); |
|
1123 |
qdict = qdict_get_qdict(device, "id"); |
|
1124 |
monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n", |
|
1125 |
qdict_get_int(qdict, "device"), |
|
1126 |
qdict_get_int(qdict, "vendor")); |
|
1127 |
|
|
1128 |
if (qdict_haskey(device, "irq")) { |
|
1129 |
monitor_printf(mon, " IRQ %" PRId64 ".\n", |
|
1130 |
qdict_get_int(device, "irq")); |
|
1106 | 1131 |
} |
1107 |
if (class == 0x0604) { |
|
1108 |
uint64_t base; |
|
1109 |
uint64_t limit; |
|
1110 | 1132 |
|
1111 |
monitor_printf(mon, " BUS %d.\n", d->config[0x19]); |
|
1112 |
monitor_printf(mon, " secondary bus %d.\n", |
|
1113 |
d->config[PCI_SECONDARY_BUS]); |
|
1114 |
monitor_printf(mon, " subordinate bus %d.\n", |
|
1115 |
d->config[PCI_SUBORDINATE_BUS]); |
|
1133 |
if (qdict_haskey(device, "pci_bridge")) { |
|
1134 |
QDict *info; |
|
1135 |
|
|
1136 |
qdict = qdict_get_qdict(device, "pci_bridge"); |
|
1137 |
|
|
1138 |
info = qdict_get_qdict(qdict, "bus"); |
|
1139 |
monitor_printf(mon, " BUS %" PRId64 ".\n", |
|
1140 |
qdict_get_int(info, "number")); |
|
1141 |
monitor_printf(mon, " secondary bus %" PRId64 ".\n", |
|
1142 |
qdict_get_int(info, "secondary")); |
|
1143 |
monitor_printf(mon, " subordinate bus %" PRId64 ".\n", |
|
1144 |
qdict_get_int(info, "subordinate")); |
|
1116 | 1145 |
|
1117 |
base = pci_bridge_get_base(d, PCI_BASE_ADDRESS_SPACE_IO); |
|
1118 |
limit = pci_bridge_get_limit(d, PCI_BASE_ADDRESS_SPACE_IO); |
|
1146 |
info = qdict_get_qdict(qdict, "io_range"); |
|
1119 | 1147 |
monitor_printf(mon, " IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n", |
1120 |
base, limit); |
|
1148 |
qdict_get_int(info, "base"), |
|
1149 |
qdict_get_int(info, "limit")); |
|
1121 | 1150 |
|
1122 |
base = pci_bridge_get_base(d, PCI_BASE_ADDRESS_SPACE_MEMORY); |
|
1123 |
limit= pci_bridge_get_limit(d, PCI_BASE_ADDRESS_SPACE_MEMORY); |
|
1151 |
info = qdict_get_qdict(qdict, "memory_range"); |
|
1124 | 1152 |
monitor_printf(mon, |
1125 | 1153 |
" memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n", |
1126 |
base, limit); |
|
1154 |
qdict_get_int(info, "base"), |
|
1155 |
qdict_get_int(info, "limit")); |
|
1127 | 1156 |
|
1128 |
base = pci_bridge_get_base(d, PCI_BASE_ADDRESS_SPACE_MEMORY | |
|
1129 |
PCI_BASE_ADDRESS_MEM_PREFETCH); |
|
1130 |
limit = pci_bridge_get_limit(d, PCI_BASE_ADDRESS_SPACE_MEMORY | |
|
1131 |
PCI_BASE_ADDRESS_MEM_PREFETCH); |
|
1157 |
info = qdict_get_qdict(qdict, "prefetchable_range"); |
|
1132 | 1158 |
monitor_printf(mon, " prefetchable memory range " |
1133 |
"[0x%08"PRIx64", 0x%08"PRIx64"]\n", base, limit); |
|
1159 |
"[0x%08"PRIx64", 0x%08"PRIx64"]\n", |
|
1160 |
qdict_get_int(info, "base"), |
|
1161 |
qdict_get_int(info, "limit")); |
|
1134 | 1162 |
} |
1135 |
for(i = 0;i < PCI_NUM_REGIONS; i++) { |
|
1136 |
r = &d->io_regions[i]; |
|
1137 |
if (r->size != 0) { |
|
1138 |
monitor_printf(mon, " BAR%d: ", i); |
|
1139 |
if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { |
|
1140 |
monitor_printf(mon, "I/O at 0x%04"FMT_PCIBUS |
|
1141 |
" [0x%04"FMT_PCIBUS"].\n", |
|
1142 |
r->addr, r->addr + r->size - 1); |
|
1143 |
} else { |
|
1144 |
const char *type = r->type & PCI_BASE_ADDRESS_MEM_TYPE_64 ? |
|
1145 |
"64 bit" : "32 bit"; |
|
1146 |
const char *prefetch = |
|
1147 |
r->type & PCI_BASE_ADDRESS_MEM_PREFETCH ? |
|
1148 |
" prefetchable" : ""; |
|
1149 | 1163 |
|
1150 |
monitor_printf(mon, "%s%s memory at 0x%08"FMT_PCIBUS |
|
1164 |
QLIST_FOREACH_ENTRY(qdict_get_qlist(device, "regions"), entry) { |
|
1165 |
qdict = qobject_to_qdict(qlist_entry_obj(entry)); |
|
1166 |
monitor_printf(mon, " BAR%d: ", (int) qdict_get_int(qdict, "bar")); |
|
1167 |
|
|
1168 |
addr = qdict_get_int(qdict, "address"); |
|
1169 |
size = qdict_get_int(qdict, "size"); |
|
1170 |
|
|
1171 |
if (!strcmp(qdict_get_str(qdict, "type"), "io")) { |
|
1172 |
monitor_printf(mon, "I/O at 0x%04"FMT_PCIBUS |
|
1173 |
" [0x%04"FMT_PCIBUS"].\n", |
|
1174 |
addr, addr + size - 1); |
|
1175 |
} else { |
|
1176 |
monitor_printf(mon, "%d bit%s memory at 0x%08"FMT_PCIBUS |
|
1151 | 1177 |
" [0x%08"FMT_PCIBUS"].\n", |
1152 |
type, prefetch,
|
|
1153 |
r->addr, r->addr + r->size - 1);
|
|
1154 |
}
|
|
1178 |
qdict_get_bool(qdict, "mem_type_64") ? 64 : 32,
|
|
1179 |
qdict_get_bool(qdict, "prefetch") ?
|
|
1180 |
" prefetchable" : "", addr, addr + size - 1);
|
|
1155 | 1181 |
} |
1156 | 1182 |
} |
1157 |
monitor_printf(mon, " id \"%s\"\n", d->qdev.id ? d->qdev.id : ""); |
|
1158 |
if (class == 0x0604 && d->config[0x19] != 0) { |
|
1159 |
pci_for_each_device(bus, d->config[0x19], pci_info_device); |
|
1183 |
|
|
1184 |
monitor_printf(mon, " id \"%s\"\n", qdict_get_str(device, "qdev_id")); |
|
1185 |
|
|
1186 |
/* TODO: PCI bridge devices */ |
|
1187 |
} |
|
1188 |
|
|
1189 |
void do_pci_info_print(Monitor *mon, const QObject *data) |
|
1190 |
{ |
|
1191 |
QListEntry *bus, *dev; |
|
1192 |
|
|
1193 |
QLIST_FOREACH_ENTRY(qobject_to_qlist(data), bus) { |
|
1194 |
QDict *qdict = qobject_to_qdict(qlist_entry_obj(bus)); |
|
1195 |
QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) { |
|
1196 |
pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev))); |
|
1197 |
} |
|
1160 | 1198 |
} |
1161 | 1199 |
} |
1162 | 1200 |
|
1163 |
static void pci_for_each_device_under_bus(PCIBus *bus, |
|
1164 |
void (*fn)(PCIBus *b, PCIDevice *d)) |
|
1201 |
static QObject *pci_get_dev_class(const PCIDevice *dev) |
|
1202 |
{ |
|
1203 |
int class; |
|
1204 |
const pci_class_desc *desc; |
|
1205 |
|
|
1206 |
class = pci_get_word(dev->config + PCI_CLASS_DEVICE); |
|
1207 |
desc = pci_class_descriptions; |
|
1208 |
while (desc->desc && class != desc->class) |
|
1209 |
desc++; |
|
1210 |
|
|
1211 |
if (desc->desc) { |
|
1212 |
return qobject_from_jsonf("{ 'desc': %s, 'class': %d }", |
|
1213 |
desc->desc, class); |
|
1214 |
} else { |
|
1215 |
return qobject_from_jsonf("{ 'class': %d }", class); |
|
1216 |
} |
|
1217 |
} |
|
1218 |
|
|
1219 |
static QObject *pci_get_dev_id(const PCIDevice *dev) |
|
1220 |
{ |
|
1221 |
return qobject_from_jsonf("{ 'device': %d, 'vendor': %d }", |
|
1222 |
pci_get_word(dev->config + PCI_VENDOR_ID), |
|
1223 |
pci_get_word(dev->config + PCI_DEVICE_ID)); |
|
1224 |
} |
|
1225 |
|
|
1226 |
static QObject *pci_get_regions_list(const PCIDevice *dev) |
|
1227 |
{ |
|
1228 |
int i; |
|
1229 |
QList *regions_list; |
|
1230 |
|
|
1231 |
regions_list = qlist_new(); |
|
1232 |
|
|
1233 |
for (i = 0; i < PCI_NUM_REGIONS; i++) { |
|
1234 |
QObject *obj; |
|
1235 |
const PCIIORegion *r = &dev->io_regions[i]; |
|
1236 |
|
|
1237 |
if (!r->size) { |
|
1238 |
continue; |
|
1239 |
} |
|
1240 |
|
|
1241 |
if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { |
|
1242 |
obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'io', " |
|
1243 |
"'address': %" PRId64 ", " |
|
1244 |
"'size': %" PRId64 " }", |
|
1245 |
i, r->addr, r->size); |
|
1246 |
} else { |
|
1247 |
int mem_type_64 = r->type & PCI_BASE_ADDRESS_MEM_TYPE_64; |
|
1248 |
|
|
1249 |
obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'memory', " |
|
1250 |
"'mem_type_64': %i, 'prefetch': %i, " |
|
1251 |
"'address': %" PRId64 ", " |
|
1252 |
"'size': %" PRId64 " }", |
|
1253 |
i, mem_type_64, |
|
1254 |
r->type & PCI_BASE_ADDRESS_MEM_PREFETCH, |
|
1255 |
r->addr, r->size); |
|
1256 |
} |
|
1257 |
|
|
1258 |
qlist_append_obj(regions_list, obj); |
|
1259 |
} |
|
1260 |
|
|
1261 |
return QOBJECT(regions_list); |
|
1262 |
} |
|
1263 |
|
|
1264 |
static QObject *pci_get_dev_dict(PCIDevice *dev, int bus_num) |
|
1265 |
{ |
|
1266 |
int class; |
|
1267 |
QObject *obj; |
|
1268 |
|
|
1269 |
obj = qobject_from_jsonf("{ 'bus': %d, 'slot': %d, 'function': %d," "'class_info': %p, 'id': %p, 'regions': %p," |
|
1270 |
" 'qdev_id': %s }", |
|
1271 |
bus_num, |
|
1272 |
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), |
|
1273 |
pci_get_dev_class(dev), pci_get_dev_id(dev), |
|
1274 |
pci_get_regions_list(dev), |
|
1275 |
dev->qdev.id ? dev->qdev.id : ""); |
|
1276 |
|
|
1277 |
if (dev->config[PCI_INTERRUPT_PIN] != 0) { |
|
1278 |
QDict *qdict = qobject_to_qdict(obj); |
|
1279 |
qdict_put(qdict, "irq", qint_from_int(dev->config[PCI_INTERRUPT_LINE])); |
|
1280 |
} |
|
1281 |
|
|
1282 |
class = pci_get_word(dev->config + PCI_CLASS_DEVICE); |
|
1283 |
if (class == 0x0604) { |
|
1284 |
QDict *qdict; |
|
1285 |
QObject *pci_bridge; |
|
1286 |
|
|
1287 |
pci_bridge = qobject_from_jsonf("{ 'bus': " |
|
1288 |
"{ 'number': %d, 'secondary': %d, 'subordinate': %d }, " |
|
1289 |
"'io_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, " |
|
1290 |
"'memory_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, " |
|
1291 |
"'prefetchable_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "} }", |
|
1292 |
dev->config[0x19], dev->config[PCI_SECONDARY_BUS], |
|
1293 |
dev->config[PCI_SUBORDINATE_BUS], |
|
1294 |
pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO), |
|
1295 |
pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO), |
|
1296 |
pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY), |
|
1297 |
pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY), |
|
1298 |
pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY | |
|
1299 |
PCI_BASE_ADDRESS_MEM_PREFETCH), |
|
1300 |
pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY | |
|
1301 |
PCI_BASE_ADDRESS_MEM_PREFETCH)); |
|
1302 |
|
|
1303 |
qdict = qobject_to_qdict(obj); |
|
1304 |
qdict_put_obj(qdict, "pci_bridge", pci_bridge); |
|
1305 |
} |
|
1306 |
|
|
1307 |
return obj; |
|
1308 |
} |
|
1309 |
|
|
1310 |
static QObject *pci_get_devices_list(PCIBus *bus, int bus_num) |
|
1165 | 1311 |
{ |
1166 |
PCIDevice *d; |
|
1167 | 1312 |
int devfn; |
1313 |
PCIDevice *dev; |
|
1314 |
QList *dev_list; |
|
1168 | 1315 |
|
1169 |
for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { |
|
1170 |
d = bus->devices[devfn]; |
|
1171 |
if (d) |
|
1172 |
fn(bus, d); |
|
1316 |
dev_list = qlist_new(); |
|
1317 |
|
|
1318 |
for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { |
|
1319 |
dev = bus->devices[devfn]; |
|
1320 |
if (dev) { |
|
1321 |
qlist_append_obj(dev_list, pci_get_dev_dict(dev, bus_num)); |
|
1322 |
} |
|
1173 | 1323 |
} |
1324 |
|
|
1325 |
return QOBJECT(dev_list); |
|
1174 | 1326 |
} |
1175 | 1327 |
|
1176 |
void pci_for_each_device(PCIBus *bus, int bus_num, |
|
1177 |
void (*fn)(PCIBus *b, PCIDevice *d)) |
|
1328 |
static QObject *pci_get_bus_dict(PCIBus *bus, int bus_num) |
|
1178 | 1329 |
{ |
1179 | 1330 |
bus = pci_find_bus(bus, bus_num); |
1180 |
|
|
1181 | 1331 |
if (bus) { |
1182 |
pci_for_each_device_under_bus(bus, fn); |
|
1332 |
return qobject_from_jsonf("{ 'bus': %d, 'devices': %p }", |
|
1333 |
bus_num, pci_get_devices_list(bus, bus_num)); |
|
1183 | 1334 |
} |
1335 |
|
|
1336 |
return NULL; |
|
1184 | 1337 |
} |
1185 | 1338 |
|
1186 |
void pci_info(Monitor *mon) |
|
1339 |
/** |
|
1340 |
* do_pci_info(): PCI buses and devices information |
|
1341 |
* |
|
1342 |
* The returned QObject is a QList of all buses. Each bus is |
|
1343 |
* represented by a QDict, which has a key with a QList of all |
|
1344 |
* PCI devices attached to it. Each device is represented by |
|
1345 |
* a QDict. |
|
1346 |
* |
|
1347 |
* The bus QDict contains the following: |
|
1348 |
* |
|
1349 |
* - "bus": bus number |
|
1350 |
* - "devices": a QList of QDicts, each QDict represents a PCI |
|
1351 |
* device |
|
1352 |
* |
|
1353 |
* The PCI device QDict contains the following: |
|
1354 |
* |
|
1355 |
* - "bus": identical to the parent's bus number |
|
1356 |
* - "slot": slot number |
|
1357 |
* - "function": function number |
|
1358 |
* - "class_info": a QDict containing: |
|
1359 |
* - "desc": device class description (optional) |
|
1360 |
* - "class": device class number |
|
1361 |
* - "id": a QDict containing: |
|
1362 |
* - "device": device ID |
|
1363 |
* - "vendor": vendor ID |
|
1364 |
* - "irq": device's IRQ if assigned (optional) |
|
1365 |
* - "qdev_id": qdev id string |
|
1366 |
* - "pci_bridge": It's a QDict, only present if this device is a |
|
1367 |
* PCI bridge, contains: |
|
1368 |
* - "bus": bus number |
|
1369 |
* - "secondary": secondary bus number |
|
1370 |
* - "subordinate": subordinate bus number |
|
1371 |
* - "io_range": a QDict with memory range information |
|
1372 |
* - "memory_range": a QDict with memory range information |
|
1373 |
* - "prefetchable_range": a QDict with memory range information |
|
1374 |
* - "regions": a QList of QDicts, each QDict represents a |
|
1375 |
* memory region of this device |
|
1376 |
* |
|
1377 |
* The memory range QDict contains the following: |
|
1378 |
* |
|
1379 |
* - "base": base memory address |
|
1380 |
* - "limit": limit value |
|
1381 |
* |
|
1382 |
* The region QDict can be an I/O region or a memory region, |
|
1383 |
* an I/O region QDict contains the following: |
|
1384 |
* |
|
1385 |
* - "type": "io" |
|
1386 |
* - "bar": BAR number |
|
1387 |
* - "address": memory address |
|
1388 |
* - "size": memory size |
|
1389 |
* |
|
1390 |
* A memory region QDict contains the following: |
|
1391 |
* |
|
1392 |
* - "type": "memory" |
|
1393 |
* - "bar": BAR number |
|
1394 |
* - "address": memory address |
|
1395 |
* - "size": memory size |
|
1396 |
* - "mem_type_64": true or false |
|
1397 |
* - "prefetch": true or false |
|
1398 |
*/ |
|
1399 |
void do_pci_info(Monitor *mon, QObject **ret_data) |
|
1187 | 1400 |
{ |
1401 |
QList *bus_list; |
|
1188 | 1402 |
struct PCIHostBus *host; |
1403 |
|
|
1404 |
bus_list = qlist_new(); |
|
1405 |
|
|
1189 | 1406 |
QLIST_FOREACH(host, &host_buses, next) { |
1190 |
pci_for_each_device(host->bus, 0, pci_info_device); |
|
1407 |
QObject *obj = pci_get_bus_dict(host->bus, 0); |
|
1408 |
if (obj) { |
|
1409 |
qlist_append_obj(bus_list, obj); |
|
1410 |
} |
|
1191 | 1411 |
} |
1412 |
|
|
1413 |
*ret_data = QOBJECT(bus_list); |
|
1192 | 1414 |
} |
1193 | 1415 |
|
1194 | 1416 |
static const char * const pci_nic_models[] = { |
Also available in: Unified diff