diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2015-02-10 23:45:11 -0500 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2015-02-11 01:17:36 -0500 |
commit | d7fbf6e95e2c5e7ef97c463a97499d7a2341fb09 (patch) | |
tree | eb883c2c3178fa297cfa473b9dd572e88dd0534a /tools/lguest | |
parent | 6a54f9ab0d65a2095de50160b8ca7ce6469aaac0 (diff) |
lguest: add PCI config space emulation to example launcher.
This handles ioport 0xCF8 and 0xCFC accesses, which are used to
read/write PCI device config space.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'tools/lguest')
-rw-r--r-- | tools/lguest/lguest.c | 216 |
1 files changed, 211 insertions, 5 deletions
diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c index e52a3571076a..0f29657fc065 100644 --- a/tools/lguest/lguest.c +++ b/tools/lguest/lguest.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <pwd.h> | 42 | #include <pwd.h> |
43 | #include <grp.h> | 43 | #include <grp.h> |
44 | #include <sys/user.h> | 44 | #include <sys/user.h> |
45 | #include <linux/pci_regs.h> | ||
45 | 46 | ||
46 | #ifndef VIRTIO_F_ANY_LAYOUT | 47 | #ifndef VIRTIO_F_ANY_LAYOUT |
47 | #define VIRTIO_F_ANY_LAYOUT 27 | 48 | #define VIRTIO_F_ANY_LAYOUT 27 |
@@ -125,6 +126,21 @@ struct device_list { | |||
125 | /* The list of Guest devices, based on command line arguments. */ | 126 | /* The list of Guest devices, based on command line arguments. */ |
126 | static struct device_list devices; | 127 | static struct device_list devices; |
127 | 128 | ||
129 | /* This is the layout (little-endian) of the PCI config space. */ | ||
130 | struct pci_config { | ||
131 | u16 vendor_id, device_id; | ||
132 | u16 command, status; | ||
133 | u8 revid, prog_if, subclass, class; | ||
134 | u8 cacheline_size, lat_timer, header_type, bist; | ||
135 | u32 bar[6]; | ||
136 | u32 cardbus_cis_ptr; | ||
137 | u16 subsystem_vendor_id, subsystem_device_id; | ||
138 | u32 expansion_rom_addr; | ||
139 | u8 capabilities, reserved1[3]; | ||
140 | u32 reserved2; | ||
141 | u8 irq_line, irq_pin, min_grant, max_latency; | ||
142 | }; | ||
143 | |||
128 | /* The device structure describes a single device. */ | 144 | /* The device structure describes a single device. */ |
129 | struct device { | 145 | struct device { |
130 | /* The linked-list pointer. */ | 146 | /* The linked-list pointer. */ |
@@ -146,6 +162,15 @@ struct device { | |||
146 | /* Is it operational */ | 162 | /* Is it operational */ |
147 | bool running; | 163 | bool running; |
148 | 164 | ||
165 | /* PCI configuration */ | ||
166 | union { | ||
167 | struct pci_config config; | ||
168 | u32 config_words[sizeof(struct pci_config) / sizeof(u32)]; | ||
169 | }; | ||
170 | |||
171 | /* Device-specific config hangs off the end of this. */ | ||
172 | struct virtio_pci_mmio *mmio; | ||
173 | |||
149 | /* PCI MMIO resources (all in BAR0) */ | 174 | /* PCI MMIO resources (all in BAR0) */ |
150 | size_t mmio_size; | 175 | size_t mmio_size; |
151 | u32 mmio_addr; | 176 | u32 mmio_addr; |
@@ -1173,6 +1198,169 @@ static void handle_output(unsigned long addr) | |||
1173 | strnlen(from_guest_phys(addr), guest_limit - addr)); | 1198 | strnlen(from_guest_phys(addr), guest_limit - addr)); |
1174 | } | 1199 | } |
1175 | 1200 | ||
1201 | /*L:217 | ||
1202 | * We do PCI. This is mainly done to let us test the kernel virtio PCI | ||
1203 | * code. | ||
1204 | */ | ||
1205 | |||
1206 | /* The IO ports used to read the PCI config space. */ | ||
1207 | #define PCI_CONFIG_ADDR 0xCF8 | ||
1208 | #define PCI_CONFIG_DATA 0xCFC | ||
1209 | |||
1210 | /* | ||
1211 | * Not really portable, but does help readability: this is what the Guest | ||
1212 | * writes to the PCI_CONFIG_ADDR IO port. | ||
1213 | */ | ||
1214 | union pci_config_addr { | ||
1215 | struct { | ||
1216 | unsigned mbz: 2; | ||
1217 | unsigned offset: 6; | ||
1218 | unsigned funcnum: 3; | ||
1219 | unsigned devnum: 5; | ||
1220 | unsigned busnum: 8; | ||
1221 | unsigned reserved: 7; | ||
1222 | unsigned enabled : 1; | ||
1223 | } bits; | ||
1224 | u32 val; | ||
1225 | }; | ||
1226 | |||
1227 | /* | ||
1228 | * We cache what they wrote to the address port, so we know what they're | ||
1229 | * talking about when they access the data port. | ||
1230 | */ | ||
1231 | static union pci_config_addr pci_config_addr; | ||
1232 | |||
1233 | static struct device *find_pci_device(unsigned int index) | ||
1234 | { | ||
1235 | return devices.pci[index]; | ||
1236 | } | ||
1237 | |||
1238 | /* PCI can do 1, 2 and 4 byte reads; we handle that here. */ | ||
1239 | static void ioread(u16 off, u32 v, u32 mask, u32 *val) | ||
1240 | { | ||
1241 | assert(off < 4); | ||
1242 | assert(mask == 0xFF || mask == 0xFFFF || mask == 0xFFFFFFFF); | ||
1243 | *val = (v >> (off * 8)) & mask; | ||
1244 | } | ||
1245 | |||
1246 | /* PCI can do 1, 2 and 4 byte writes; we handle that here. */ | ||
1247 | static void iowrite(u16 off, u32 v, u32 mask, u32 *dst) | ||
1248 | { | ||
1249 | assert(off < 4); | ||
1250 | assert(mask == 0xFF || mask == 0xFFFF || mask == 0xFFFFFFFF); | ||
1251 | *dst &= ~(mask << (off * 8)); | ||
1252 | *dst |= (v & mask) << (off * 8); | ||
1253 | } | ||
1254 | |||
1255 | /* | ||
1256 | * Where PCI_CONFIG_DATA accesses depends on the previous write to | ||
1257 | * PCI_CONFIG_ADDR. | ||
1258 | */ | ||
1259 | static struct device *dev_and_reg(u32 *reg) | ||
1260 | { | ||
1261 | if (!pci_config_addr.bits.enabled) | ||
1262 | return NULL; | ||
1263 | |||
1264 | if (pci_config_addr.bits.funcnum != 0) | ||
1265 | return NULL; | ||
1266 | |||
1267 | if (pci_config_addr.bits.busnum != 0) | ||
1268 | return NULL; | ||
1269 | |||
1270 | if (pci_config_addr.bits.offset * 4 >= sizeof(struct pci_config)) | ||
1271 | return NULL; | ||
1272 | |||
1273 | *reg = pci_config_addr.bits.offset; | ||
1274 | return find_pci_device(pci_config_addr.bits.devnum); | ||
1275 | } | ||
1276 | |||
1277 | /* Is this accessing the PCI config address port?. */ | ||
1278 | static bool is_pci_addr_port(u16 port) | ||
1279 | { | ||
1280 | return port >= PCI_CONFIG_ADDR && port < PCI_CONFIG_ADDR + 4; | ||
1281 | } | ||
1282 | |||
1283 | static bool pci_addr_iowrite(u16 port, u32 mask, u32 val) | ||
1284 | { | ||
1285 | iowrite(port - PCI_CONFIG_ADDR, val, mask, | ||
1286 | &pci_config_addr.val); | ||
1287 | verbose("PCI%s: %#x/%x: bus %u dev %u func %u reg %u\n", | ||
1288 | pci_config_addr.bits.enabled ? "" : " DISABLED", | ||
1289 | val, mask, | ||
1290 | pci_config_addr.bits.busnum, | ||
1291 | pci_config_addr.bits.devnum, | ||
1292 | pci_config_addr.bits.funcnum, | ||
1293 | pci_config_addr.bits.offset); | ||
1294 | return true; | ||
1295 | } | ||
1296 | |||
1297 | static void pci_addr_ioread(u16 port, u32 mask, u32 *val) | ||
1298 | { | ||
1299 | ioread(port - PCI_CONFIG_ADDR, pci_config_addr.val, mask, val); | ||
1300 | } | ||
1301 | |||
1302 | /* Is this accessing the PCI config data port?. */ | ||
1303 | static bool is_pci_data_port(u16 port) | ||
1304 | { | ||
1305 | return port >= PCI_CONFIG_DATA && port < PCI_CONFIG_DATA + 4; | ||
1306 | } | ||
1307 | |||
1308 | static bool pci_data_iowrite(u16 port, u32 mask, u32 val) | ||
1309 | { | ||
1310 | u32 reg, portoff; | ||
1311 | struct device *d = dev_and_reg(®); | ||
1312 | |||
1313 | /* Complain if they don't belong to a device. */ | ||
1314 | if (!d) | ||
1315 | return false; | ||
1316 | |||
1317 | /* They can do 1 byte writes, etc. */ | ||
1318 | portoff = port - PCI_CONFIG_DATA; | ||
1319 | |||
1320 | /* | ||
1321 | * PCI uses a weird way to determine the BAR size: the OS | ||
1322 | * writes all 1's, and sees which ones stick. | ||
1323 | */ | ||
1324 | if (&d->config_words[reg] == &d->config.bar[0]) { | ||
1325 | int i; | ||
1326 | |||
1327 | iowrite(portoff, val, mask, &d->config.bar[0]); | ||
1328 | for (i = 0; (1 << i) < d->mmio_size; i++) | ||
1329 | d->config.bar[0] &= ~(1 << i); | ||
1330 | return true; | ||
1331 | } else if ((&d->config_words[reg] > &d->config.bar[0] | ||
1332 | && &d->config_words[reg] <= &d->config.bar[6]) | ||
1333 | || &d->config_words[reg] == &d->config.expansion_rom_addr) { | ||
1334 | /* Allow writing to any other BAR, or expansion ROM */ | ||
1335 | iowrite(portoff, val, mask, &d->config_words[reg]); | ||
1336 | return true; | ||
1337 | /* We let them overide latency timer and cacheline size */ | ||
1338 | } else if (&d->config_words[reg] == (void *)&d->config.cacheline_size) { | ||
1339 | /* Only let them change the first two fields. */ | ||
1340 | if (mask == 0xFFFFFFFF) | ||
1341 | mask = 0xFFFF; | ||
1342 | iowrite(portoff, val, mask, &d->config_words[reg]); | ||
1343 | return true; | ||
1344 | } else if (&d->config_words[reg] == (void *)&d->config.command | ||
1345 | && mask == 0xFFFF) { | ||
1346 | /* Ignore command writes. */ | ||
1347 | return true; | ||
1348 | } | ||
1349 | |||
1350 | /* Complain about other writes. */ | ||
1351 | return false; | ||
1352 | } | ||
1353 | |||
1354 | static void pci_data_ioread(u16 port, u32 mask, u32 *val) | ||
1355 | { | ||
1356 | u32 reg; | ||
1357 | struct device *d = dev_and_reg(®); | ||
1358 | |||
1359 | if (!d) | ||
1360 | return; | ||
1361 | ioread(port - PCI_CONFIG_DATA, d->config_words[reg], mask, val); | ||
1362 | } | ||
1363 | |||
1176 | /*L:216 | 1364 | /*L:216 |
1177 | * This is where we emulate a handful of Guest instructions. It's ugly | 1365 | * This is where we emulate a handful of Guest instructions. It's ugly |
1178 | * and we used to do it in the kernel but it grew over time. | 1366 | * and we used to do it in the kernel but it grew over time. |
@@ -1284,7 +1472,7 @@ static void emulate_insn(const u8 insn[]) | |||
1284 | unsigned int insnlen = 0, in = 0, small_operand = 0, byte_access; | 1472 | unsigned int insnlen = 0, in = 0, small_operand = 0, byte_access; |
1285 | unsigned int eax, port, mask; | 1473 | unsigned int eax, port, mask; |
1286 | /* | 1474 | /* |
1287 | * We always return all-ones on IO port reads, which traditionally | 1475 | * Default is to return all-ones on IO port reads, which traditionally |
1288 | * means "there's nothing there". | 1476 | * means "there's nothing there". |
1289 | */ | 1477 | */ |
1290 | u32 val = 0xFFFFFFFF; | 1478 | u32 val = 0xFFFFFFFF; |
@@ -1359,10 +1547,6 @@ static void emulate_insn(const u8 insn[]) | |||
1359 | else | 1547 | else |
1360 | mask = 0xFFFFFFFF; | 1548 | mask = 0xFFFFFFFF; |
1361 | 1549 | ||
1362 | /* This is the PS/2 keyboard status; 1 means ready for output */ | ||
1363 | if (port == 0x64) | ||
1364 | val = 1; | ||
1365 | |||
1366 | /* | 1550 | /* |
1367 | * If it was an "IN" instruction, they expect the result to be read | 1551 | * If it was an "IN" instruction, they expect the result to be read |
1368 | * into %eax, so we change %eax. | 1552 | * into %eax, so we change %eax. |
@@ -1370,12 +1554,30 @@ static void emulate_insn(const u8 insn[]) | |||
1370 | eax = getreg(eax); | 1554 | eax = getreg(eax); |
1371 | 1555 | ||
1372 | if (in) { | 1556 | if (in) { |
1557 | /* This is the PS/2 keyboard status; 1 means ready for output */ | ||
1558 | if (port == 0x64) | ||
1559 | val = 1; | ||
1560 | else if (is_pci_addr_port(port)) | ||
1561 | pci_addr_ioread(port, mask, &val); | ||
1562 | else if (is_pci_data_port(port)) | ||
1563 | pci_data_ioread(port, mask, &val); | ||
1564 | |||
1373 | /* Clear the bits we're about to read */ | 1565 | /* Clear the bits we're about to read */ |
1374 | eax &= ~mask; | 1566 | eax &= ~mask; |
1375 | /* Copy bits in from val. */ | 1567 | /* Copy bits in from val. */ |
1376 | eax |= val & mask; | 1568 | eax |= val & mask; |
1377 | /* Now update the register. */ | 1569 | /* Now update the register. */ |
1378 | setreg(eax, eax); | 1570 | setreg(eax, eax); |
1571 | } else { | ||
1572 | if (is_pci_addr_port(port)) { | ||
1573 | if (!pci_addr_iowrite(port, mask, eax)) | ||
1574 | goto bad_io; | ||
1575 | } else if (is_pci_data_port(port)) { | ||
1576 | if (!pci_data_iowrite(port, mask, eax)) | ||
1577 | goto bad_io; | ||
1578 | } | ||
1579 | /* There are many other ports, eg. CMOS clock, serial | ||
1580 | * and parallel ports, so we ignore them all. */ | ||
1379 | } | 1581 | } |
1380 | 1582 | ||
1381 | verbose("IO %s of %x to %u: %#08x\n", | 1583 | verbose("IO %s of %x to %u: %#08x\n", |
@@ -1385,6 +1587,10 @@ skip_insn: | |||
1385 | setreg(eip, getreg(eip) + insnlen); | 1587 | setreg(eip, getreg(eip) + insnlen); |
1386 | return; | 1588 | return; |
1387 | 1589 | ||
1590 | bad_io: | ||
1591 | warnx("Attempt to %s port %u (%#x mask)", | ||
1592 | in ? "read from" : "write to", port, mask); | ||
1593 | |||
1388 | no_emulate: | 1594 | no_emulate: |
1389 | /* Inject trap into Guest. */ | 1595 | /* Inject trap into Guest. */ |
1390 | if (write(lguest_fd, args, sizeof(args)) < 0) | 1596 | if (write(lguest_fd, args, sizeof(args)) < 0) |