pci_emul.c (248477) | pci_emul.c (249321) |
---|---|
1/*- 2 * Copyright (c) 2011 NetApp, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 9 unchanged lines hidden (view full) --- 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * | 1/*- 2 * Copyright (c) 2011 NetApp, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 9 unchanged lines hidden (view full) --- 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * |
26 * $FreeBSD: head/usr.sbin/bhyve/pci_emul.c 248477 2013-03-18 22:38:30Z neel $ | 26 * $FreeBSD: head/usr.sbin/bhyve/pci_emul.c 249321 2013-04-10 02:12:39Z neel $ |
27 */ 28 29#include <sys/cdefs.h> | 27 */ 28 29#include <sys/cdefs.h> |
30__FBSDID("$FreeBSD: head/usr.sbin/bhyve/pci_emul.c 248477 2013-03-18 22:38:30Z neel $"); | 30__FBSDID("$FreeBSD: head/usr.sbin/bhyve/pci_emul.c 249321 2013-04-10 02:12:39Z neel $"); |
31 32#include <sys/param.h> 33#include <sys/linker_set.h> | 31 32#include <sys/param.h> 33#include <sys/linker_set.h> |
34#include <sys/errno.h> |
|
34 35#include <ctype.h> 36#include <stdio.h> 37#include <stdlib.h> 38#include <string.h> 39#include <strings.h> 40#include <assert.h> | 35 36#include <ctype.h> 37#include <stdio.h> 38#include <stdlib.h> 39#include <string.h> 40#include <strings.h> 41#include <assert.h> |
42#include <stdbool.h> |
|
41 42#include <machine/vmm.h> 43#include <vmmapi.h> 44 45#include "bhyverun.h" 46#include "inout.h" 47#include "mem.h" 48#include "mptbl.h" --- 299 unchanged lines hidden (view full) --- 348int 349pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type, 350 uint64_t size) 351{ 352 353 return (pci_emul_alloc_pbar(pdi, idx, 0, type, size)); 354} 355 | 43 44#include <machine/vmm.h> 45#include <vmmapi.h> 46 47#include "bhyverun.h" 48#include "inout.h" 49#include "mem.h" 50#include "mptbl.h" --- 299 unchanged lines hidden (view full) --- 350int 351pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type, 352 uint64_t size) 353{ 354 355 return (pci_emul_alloc_pbar(pdi, idx, 0, type, size)); 356} 357 |
358/* 359 * Register (or unregister) the MMIO or I/O region associated with the BAR 360 * register 'idx' of an emulated pci device. 361 */ 362static void 363modify_bar_registration(struct pci_devinst *pi, int idx, int registration) 364{ 365 int error; 366 struct inout_port iop; 367 struct mem_range mr; 368 369 switch (pi->pi_bar[idx].type) { 370 case PCIBAR_IO: 371 bzero(&iop, sizeof(struct inout_port)); 372 iop.name = pi->pi_name; 373 iop.port = pi->pi_bar[idx].addr; 374 iop.size = pi->pi_bar[idx].size; 375 if (registration) { 376 iop.flags = IOPORT_F_INOUT; 377 iop.handler = pci_emul_io_handler; 378 iop.arg = pi; 379 error = register_inout(&iop); 380 } else 381 error = unregister_inout(&iop); 382 break; 383 case PCIBAR_MEM32: 384 case PCIBAR_MEM64: 385 bzero(&mr, sizeof(struct mem_range)); 386 mr.name = pi->pi_name; 387 mr.base = pi->pi_bar[idx].addr; 388 mr.size = pi->pi_bar[idx].size; 389 if (registration) { 390 mr.flags = MEM_F_RW; 391 mr.handler = pci_emul_mem_handler; 392 mr.arg1 = pi; 393 mr.arg2 = idx; 394 error = register_mem(&mr); 395 } else 396 error = unregister_mem(&mr); 397 break; 398 default: 399 error = EINVAL; 400 break; 401 } 402 assert(error == 0); 403} 404 405static void 406unregister_bar(struct pci_devinst *pi, int idx) 407{ 408 409 modify_bar_registration(pi, idx, 0); 410} 411 412static void 413register_bar(struct pci_devinst *pi, int idx) 414{ 415 416 modify_bar_registration(pi, idx, 1); 417} 418 419/* Are we decoding i/o port accesses for the emulated pci device? */ 420static int 421porten(struct pci_devinst *pi) 422{ 423 uint16_t cmd; 424 425 cmd = pci_get_cfgdata16(pi, PCIR_COMMAND); 426 427 return (cmd & PCIM_CMD_PORTEN); 428} 429 430/* Are we decoding memory accesses for the emulated pci device? */ 431static int 432memen(struct pci_devinst *pi) 433{ 434 uint16_t cmd; 435 436 cmd = pci_get_cfgdata16(pi, PCIR_COMMAND); 437 438 return (cmd & PCIM_CMD_MEMEN); 439} 440 441/* 442 * Update the MMIO or I/O address that is decoded by the BAR register. 443 * 444 * If the pci device has enabled the address space decoding then intercept 445 * the address range decoded by the BAR register. 446 */ 447static void 448update_bar_address(struct pci_devinst *pi, uint64_t addr, int idx, int type) 449{ 450 int decode; 451 452 if (pi->pi_bar[idx].type == PCIBAR_IO) 453 decode = porten(pi); 454 else 455 decode = memen(pi); 456 457 if (decode) 458 unregister_bar(pi, idx); 459 460 switch (type) { 461 case PCIBAR_IO: 462 case PCIBAR_MEM32: 463 pi->pi_bar[idx].addr = addr; 464 break; 465 case PCIBAR_MEM64: 466 pi->pi_bar[idx].addr &= ~0xffffffffUL; 467 pi->pi_bar[idx].addr |= addr; 468 break; 469 case PCIBAR_MEMHI64: 470 pi->pi_bar[idx].addr &= 0xffffffff; 471 pi->pi_bar[idx].addr |= addr; 472 break; 473 default: 474 assert(0); 475 } 476 477 if (decode) 478 register_bar(pi, idx); 479} 480 |
|
356int 357pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx, uint64_t hostbase, 358 enum pcibar_type type, uint64_t size) 359{ | 481int 482pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx, uint64_t hostbase, 483 enum pcibar_type type, uint64_t size) 484{ |
360 int i, error; | 485 int error; |
361 uint64_t *baseptr, limit, addr, mask, lobits, bar; | 486 uint64_t *baseptr, limit, addr, mask, lobits, bar; |
362 struct inout_port iop; 363 struct mem_range memp; | |
364 365 assert(idx >= 0 && idx <= PCI_BARMAX); 366 367 if ((size & (size - 1)) != 0) 368 size = 1UL << flsl(size); /* round up to a power of 2 */ 369 | 487 488 assert(idx >= 0 && idx <= PCI_BARMAX); 489 490 if ((size & (size - 1)) != 0) 491 size = 1UL << flsl(size); /* round up to a power of 2 */ 492 |
493 /* Enforce minimum BAR sizes required by the PCI standard */ 494 if (type == PCIBAR_IO) { 495 if (size < 4) 496 size = 4; 497 } else { 498 if (size < 16) 499 size = 16; 500 } 501 |
|
370 switch (type) { 371 case PCIBAR_NONE: 372 baseptr = NULL; 373 addr = mask = lobits = 0; 374 break; 375 case PCIBAR_IO: 376 if (hostbase && 377 pci_slotinfo[pdi->pi_slot][pdi->pi_func].si_legacy) { --- 60 unchanged lines hidden (view full) --- 438 pci_set_cfgdata32(pdi, PCIR_BAR(idx), bar); 439 440 if (type == PCIBAR_MEM64) { 441 assert(idx + 1 <= PCI_BARMAX); 442 pdi->pi_bar[idx + 1].type = PCIBAR_MEMHI64; 443 pci_set_cfgdata32(pdi, PCIR_BAR(idx + 1), bar >> 32); 444 } 445 | 502 switch (type) { 503 case PCIBAR_NONE: 504 baseptr = NULL; 505 addr = mask = lobits = 0; 506 break; 507 case PCIBAR_IO: 508 if (hostbase && 509 pci_slotinfo[pdi->pi_slot][pdi->pi_func].si_legacy) { --- 60 unchanged lines hidden (view full) --- 570 pci_set_cfgdata32(pdi, PCIR_BAR(idx), bar); 571 572 if (type == PCIBAR_MEM64) { 573 assert(idx + 1 <= PCI_BARMAX); 574 pdi->pi_bar[idx + 1].type = PCIBAR_MEMHI64; 575 pci_set_cfgdata32(pdi, PCIR_BAR(idx + 1), bar >> 32); 576 } 577 |
446 /* add a handler to intercept accesses to the I/O bar */ 447 if (type == PCIBAR_IO) { 448 iop.name = pdi->pi_name; 449 iop.flags = IOPORT_F_INOUT; 450 iop.handler = pci_emul_io_handler; 451 iop.arg = pdi; | 578 register_bar(pdi, idx); |
452 | 579 |
453 for (i = 0; i < size; i++) { 454 iop.port = addr + i; 455 register_inout(&iop); 456 } 457 } else if (type == PCIBAR_MEM32 || type == PCIBAR_MEM64) { 458 /* add memory bar intercept handler */ 459 memp.name = pdi->pi_name; 460 memp.flags = MEM_F_RW; 461 memp.base = addr; 462 memp.size = size; 463 memp.handler = pci_emul_mem_handler; 464 memp.arg1 = pdi; 465 memp.arg2 = idx; 466 467 error = register_mem(&memp); 468 assert(error == 0); 469 } 470 | |
471 return (0); 472} 473 474#define CAP_START_OFFSET 0x40 475static int 476pci_emul_add_capability(struct pci_devinst *pi, u_char *capdata, int caplen) 477{ 478 int i, capoff, capid, reallen; --- 617 unchanged lines hidden (view full) --- 1096 cfgfunc = (x >> 8) & PCI_FUNCMAX; 1097 cfgslot = (x >> 11) & PCI_SLOTMAX; 1098 cfgbus = (x >> 16) & PCI_BUSMAX; 1099 1100 return (0); 1101} 1102INOUT_PORT(pci_cfgaddr, CONF1_ADDR_PORT, IOPORT_F_OUT, pci_emul_cfgaddr); 1103 | 580 return (0); 581} 582 583#define CAP_START_OFFSET 0x40 584static int 585pci_emul_add_capability(struct pci_devinst *pi, u_char *capdata, int caplen) 586{ 587 int i, capoff, capid, reallen; --- 617 unchanged lines hidden (view full) --- 1205 cfgfunc = (x >> 8) & PCI_FUNCMAX; 1206 cfgslot = (x >> 11) & PCI_SLOTMAX; 1207 cfgbus = (x >> 16) & PCI_BUSMAX; 1208 1209 return (0); 1210} 1211INOUT_PORT(pci_cfgaddr, CONF1_ADDR_PORT, IOPORT_F_OUT, pci_emul_cfgaddr); 1212 |
1213static uint32_t 1214bits_changed(uint32_t old, uint32_t new, uint32_t mask) 1215{ 1216 1217 return ((old ^ new) & mask); 1218} 1219 1220static void 1221pci_emul_cmdwrite(struct pci_devinst *pi, uint32_t new, int bytes) 1222{ 1223 int i; 1224 uint16_t old; 1225 1226 /* 1227 * The command register is at an offset of 4 bytes and thus the 1228 * guest could write 1, 2 or 4 bytes starting at this offset. 1229 */ 1230 1231 old = pci_get_cfgdata16(pi, PCIR_COMMAND); /* stash old value */ 1232 CFGWRITE(pi, PCIR_COMMAND, new, bytes); /* update config */ 1233 new = pci_get_cfgdata16(pi, PCIR_COMMAND); /* get updated value */ 1234 1235 /* 1236 * If the MMIO or I/O address space decoding has changed then 1237 * register/unregister all BARs that decode that address space. 1238 */ 1239 for (i = 0; i < PCI_BARMAX; i++) { 1240 switch (pi->pi_bar[i].type) { 1241 case PCIBAR_NONE: 1242 case PCIBAR_MEMHI64: 1243 break; 1244 case PCIBAR_IO: 1245 /* I/O address space decoding changed? */ 1246 if (bits_changed(old, new, PCIM_CMD_PORTEN)) { 1247 if (porten(pi)) 1248 register_bar(pi, i); 1249 else 1250 unregister_bar(pi, i); 1251 } 1252 break; 1253 case PCIBAR_MEM32: 1254 case PCIBAR_MEM64: 1255 /* MMIO address space decoding changed? */ 1256 if (bits_changed(old, new, PCIM_CMD_MEMEN)) { 1257 if (memen(pi)) 1258 register_bar(pi, i); 1259 else 1260 unregister_bar(pi, i); 1261 } 1262 break; 1263 default: 1264 assert(0); 1265 } 1266 } 1267} 1268 |
|
1104static int 1105pci_emul_cfgdata(struct vmctx *ctx, int vcpu, int in, int port, int bytes, 1106 uint32_t *eax, void *arg) 1107{ 1108 struct pci_devinst *pi; 1109 struct pci_devemu *pe; 1110 int coff, idx, needcfg; | 1269static int 1270pci_emul_cfgdata(struct vmctx *ctx, int vcpu, int in, int port, int bytes, 1271 uint32_t *eax, void *arg) 1272{ 1273 struct pci_devinst *pi; 1274 struct pci_devemu *pe; 1275 int coff, idx, needcfg; |
1111 uint64_t mask, bar; | 1276 uint64_t addr, bar, mask; |
1112 1113 assert(bytes == 1 || bytes == 2 || bytes == 4); 1114 1115 if (cfgbus == 0) 1116 pi = pci_slotinfo[cfgslot][cfgfunc].si_devi; 1117 else 1118 pi = NULL; 1119 --- 50 unchanged lines hidden (view full) --- 1170 if (coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1)) { 1171 /* 1172 * Ignore writes to BAR registers that are not 1173 * 4-byte aligned. 1174 */ 1175 if (bytes != 4 || (coff & 0x3) != 0) 1176 return (0); 1177 idx = (coff - PCIR_BAR(0)) / 4; | 1277 1278 assert(bytes == 1 || bytes == 2 || bytes == 4); 1279 1280 if (cfgbus == 0) 1281 pi = pci_slotinfo[cfgslot][cfgfunc].si_devi; 1282 else 1283 pi = NULL; 1284 --- 50 unchanged lines hidden (view full) --- 1335 if (coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1)) { 1336 /* 1337 * Ignore writes to BAR registers that are not 1338 * 4-byte aligned. 1339 */ 1340 if (bytes != 4 || (coff & 0x3) != 0) 1341 return (0); 1342 idx = (coff - PCIR_BAR(0)) / 4; |
1343 mask = ~(pi->pi_bar[idx].size - 1); |
|
1178 switch (pi->pi_bar[idx].type) { 1179 case PCIBAR_NONE: | 1344 switch (pi->pi_bar[idx].type) { 1345 case PCIBAR_NONE: |
1180 bar = 0; | 1346 pi->pi_bar[idx].addr = bar = 0; |
1181 break; 1182 case PCIBAR_IO: | 1347 break; 1348 case PCIBAR_IO: |
1183 mask = ~(pi->pi_bar[idx].size - 1); 1184 mask &= PCIM_BAR_IO_BASE; 1185 bar = (*eax & mask) | PCIM_BAR_IO_SPACE; | 1349 addr = *eax & mask; 1350 addr &= 0xffff; 1351 bar = addr | PCIM_BAR_IO_SPACE; 1352 /* 1353 * Register the new BAR value for interception 1354 */ 1355 if (addr != pi->pi_bar[idx].addr) { 1356 update_bar_address(pi, addr, idx, 1357 PCIBAR_IO); 1358 } |
1186 break; 1187 case PCIBAR_MEM32: | 1359 break; 1360 case PCIBAR_MEM32: |
1188 mask = ~(pi->pi_bar[idx].size - 1); 1189 mask &= PCIM_BAR_MEM_BASE; 1190 bar = *eax & mask; | 1361 addr = bar = *eax & mask; |
1191 bar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32; | 1362 bar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32; |
1363 if (addr != pi->pi_bar[idx].addr) { 1364 update_bar_address(pi, addr, idx, 1365 PCIBAR_MEM32); 1366 } |
|
1192 break; 1193 case PCIBAR_MEM64: | 1367 break; 1368 case PCIBAR_MEM64: |
1194 mask = ~(pi->pi_bar[idx].size - 1); 1195 mask &= PCIM_BAR_MEM_BASE; 1196 bar = *eax & mask; | 1369 addr = bar = *eax & mask; |
1197 bar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 | 1198 PCIM_BAR_MEM_PREFETCH; | 1370 bar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 | 1371 PCIM_BAR_MEM_PREFETCH; |
1372 if (addr != (uint32_t)pi->pi_bar[idx].addr) { 1373 update_bar_address(pi, addr, idx, 1374 PCIBAR_MEM64); 1375 } |
|
1199 break; 1200 case PCIBAR_MEMHI64: 1201 mask = ~(pi->pi_bar[idx - 1].size - 1); | 1376 break; 1377 case PCIBAR_MEMHI64: 1378 mask = ~(pi->pi_bar[idx - 1].size - 1); |
1202 mask &= PCIM_BAR_MEM_BASE; 1203 bar = ((uint64_t)*eax << 32) & mask; 1204 bar = bar >> 32; | 1379 addr = ((uint64_t)*eax << 32) & mask; 1380 bar = addr >> 32; 1381 if (bar != pi->pi_bar[idx - 1].addr >> 32) { 1382 update_bar_address(pi, addr, idx - 1, 1383 PCIBAR_MEMHI64); 1384 } |
1205 break; 1206 default: 1207 assert(0); 1208 } 1209 pci_set_cfgdata32(pi, coff, bar); 1210 1211 } else if (pci_emul_iscap(pi, coff)) { 1212 pci_emul_capwrite(pi, coff, bytes, *eax); | 1385 break; 1386 default: 1387 assert(0); 1388 } 1389 pci_set_cfgdata32(pi, coff, bar); 1390 1391 } else if (pci_emul_iscap(pi, coff)) { 1392 pci_emul_capwrite(pi, coff, bytes, *eax); |
1393 } else if (coff == PCIR_COMMAND) { 1394 pci_emul_cmdwrite(pi, *eax, bytes); |
|
1213 } else { 1214 CFGWRITE(pi, coff, *eax, bytes); 1215 } 1216 } 1217 1218 return (0); 1219} 1220 --- 188 unchanged lines hidden --- | 1395 } else { 1396 CFGWRITE(pi, coff, *eax, bytes); 1397 } 1398 } 1399 1400 return (0); 1401} 1402 --- 188 unchanged lines hidden --- |