Deleted Added
full compact
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 ---