xen_pt.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  1. /*
  2. * Copyright (c) 2007, Neocleus Corporation.
  3. * Copyright (c) 2007, Intel Corporation.
  4. *
  5. * This work is licensed under the terms of the GNU GPL, version 2. See
  6. * the COPYING file in the top-level directory.
  7. *
  8. * Alex Novik <alex@neocleus.com>
  9. * Allen Kay <allen.m.kay@intel.com>
  10. * Guy Zana <guy@neocleus.com>
  11. *
  12. * This file implements direct PCI assignment to a HVM guest
  13. */
  14. /*
  15. * Interrupt Disable policy:
  16. *
  17. * INTx interrupt:
  18. * Initialize(register_real_device)
  19. * Map INTx(xc_physdev_map_pirq):
  20. * <fail>
  21. * - Set real Interrupt Disable bit to '1'.
  22. * - Set machine_irq and assigned_device->machine_irq to '0'.
  23. * * Don't bind INTx.
  24. *
  25. * Bind INTx(xc_domain_bind_pt_pci_irq):
  26. * <fail>
  27. * - Set real Interrupt Disable bit to '1'.
  28. * - Unmap INTx.
  29. * - Decrement xen_pt_mapped_machine_irq[machine_irq]
  30. * - Set assigned_device->machine_irq to '0'.
  31. *
  32. * Write to Interrupt Disable bit by guest software(xen_pt_cmd_reg_write)
  33. * Write '0'
  34. * - Set real bit to '0' if assigned_device->machine_irq isn't '0'.
  35. *
  36. * Write '1'
  37. * - Set real bit to '1'.
  38. *
  39. * MSI interrupt:
  40. * Initialize MSI register(xen_pt_msi_setup, xen_pt_msi_update)
  41. * Bind MSI(xc_domain_update_msi_irq)
  42. * <fail>
  43. * - Unmap MSI.
  44. * - Set dev->msi->pirq to '-1'.
  45. *
  46. * MSI-X interrupt:
  47. * Initialize MSI-X register(xen_pt_msix_update_one)
  48. * Bind MSI-X(xc_domain_update_msi_irq)
  49. * <fail>
  50. * - Unmap MSI-X.
  51. * - Set entry->pirq to '-1'.
  52. */
  53. #include <sys/ioctl.h>
  54. #include "pci.h"
  55. #include "xen.h"
  56. #include "xen_backend.h"
  57. #include "xen_pt.h"
  58. #include "range.h"
  59. #define XEN_PT_NR_IRQS (256)
  60. static uint8_t xen_pt_mapped_machine_irq[XEN_PT_NR_IRQS] = {0};
  61. void xen_pt_log(const PCIDevice *d, const char *f, ...)
  62. {
  63. va_list ap;
  64. va_start(ap, f);
  65. if (d) {
  66. fprintf(stderr, "[%02x:%02x.%d] ", pci_bus_num(d->bus),
  67. PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));
  68. }
  69. vfprintf(stderr, f, ap);
  70. va_end(ap);
  71. }
  72. /* Config Space */
  73. static int xen_pt_pci_config_access_check(PCIDevice *d, uint32_t addr, int len)
  74. {
  75. /* check offset range */
  76. if (addr >= 0xFF) {
  77. XEN_PT_ERR(d, "Failed to access register with offset exceeding 0xFF. "
  78. "(addr: 0x%02x, len: %d)\n", addr, len);
  79. return -1;
  80. }
  81. /* check read size */
  82. if ((len != 1) && (len != 2) && (len != 4)) {
  83. XEN_PT_ERR(d, "Failed to access register with invalid access length. "
  84. "(addr: 0x%02x, len: %d)\n", addr, len);
  85. return -1;
  86. }
  87. /* check offset alignment */
  88. if (addr & (len - 1)) {
  89. XEN_PT_ERR(d, "Failed to access register with invalid access size "
  90. "alignment. (addr: 0x%02x, len: %d)\n", addr, len);
  91. return -1;
  92. }
  93. return 0;
  94. }
  95. int xen_pt_bar_offset_to_index(uint32_t offset)
  96. {
  97. int index = 0;
  98. /* check Exp ROM BAR */
  99. if (offset == PCI_ROM_ADDRESS) {
  100. return PCI_ROM_SLOT;
  101. }
  102. /* calculate BAR index */
  103. index = (offset - PCI_BASE_ADDRESS_0) >> 2;
  104. if (index >= PCI_NUM_REGIONS) {
  105. return -1;
  106. }
  107. return index;
  108. }
  109. static uint32_t xen_pt_pci_read_config(PCIDevice *d, uint32_t addr, int len)
  110. {
  111. XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
  112. uint32_t val = 0;
  113. XenPTRegGroup *reg_grp_entry = NULL;
  114. XenPTReg *reg_entry = NULL;
  115. int rc = 0;
  116. int emul_len = 0;
  117. uint32_t find_addr = addr;
  118. if (xen_pt_pci_config_access_check(d, addr, len)) {
  119. goto exit;
  120. }
  121. /* find register group entry */
  122. reg_grp_entry = xen_pt_find_reg_grp(s, addr);
  123. if (reg_grp_entry) {
  124. /* check 0-Hardwired register group */
  125. if (reg_grp_entry->reg_grp->grp_type == XEN_PT_GRP_TYPE_HARDWIRED) {
  126. /* no need to emulate, just return 0 */
  127. val = 0;
  128. goto exit;
  129. }
  130. }
  131. /* read I/O device register value */
  132. rc = xen_host_pci_get_block(&s->real_device, addr, (uint8_t *)&val, len);
  133. if (rc < 0) {
  134. XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc);
  135. memset(&val, 0xff, len);
  136. }
  137. /* just return the I/O device register value for
  138. * passthrough type register group */
  139. if (reg_grp_entry == NULL) {
  140. goto exit;
  141. }
  142. /* adjust the read value to appropriate CFC-CFF window */
  143. val <<= (addr & 3) << 3;
  144. emul_len = len;
  145. /* loop around the guest requested size */
  146. while (emul_len > 0) {
  147. /* find register entry to be emulated */
  148. reg_entry = xen_pt_find_reg(reg_grp_entry, find_addr);
  149. if (reg_entry) {
  150. XenPTRegInfo *reg = reg_entry->reg;
  151. uint32_t real_offset = reg_grp_entry->base_offset + reg->offset;
  152. uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3);
  153. uint8_t *ptr_val = NULL;
  154. valid_mask <<= (find_addr - real_offset) << 3;
  155. ptr_val = (uint8_t *)&val + (real_offset & 3);
  156. /* do emulation based on register size */
  157. switch (reg->size) {
  158. case 1:
  159. if (reg->u.b.read) {
  160. rc = reg->u.b.read(s, reg_entry, ptr_val, valid_mask);
  161. }
  162. break;
  163. case 2:
  164. if (reg->u.w.read) {
  165. rc = reg->u.w.read(s, reg_entry,
  166. (uint16_t *)ptr_val, valid_mask);
  167. }
  168. break;
  169. case 4:
  170. if (reg->u.dw.read) {
  171. rc = reg->u.dw.read(s, reg_entry,
  172. (uint32_t *)ptr_val, valid_mask);
  173. }
  174. break;
  175. }
  176. if (rc < 0) {
  177. xen_shutdown_fatal_error("Internal error: Invalid read "
  178. "emulation. (%s, rc: %d)\n",
  179. __func__, rc);
  180. return 0;
  181. }
  182. /* calculate next address to find */
  183. emul_len -= reg->size;
  184. if (emul_len > 0) {
  185. find_addr = real_offset + reg->size;
  186. }
  187. } else {
  188. /* nothing to do with passthrough type register,
  189. * continue to find next byte */
  190. emul_len--;
  191. find_addr++;
  192. }
  193. }
  194. /* need to shift back before returning them to pci bus emulator */
  195. val >>= ((addr & 3) << 3);
  196. exit:
  197. XEN_PT_LOG_CONFIG(d, addr, val, len);
  198. return val;
  199. }
  200. static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
  201. uint32_t val, int len)
  202. {
  203. XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
  204. int index = 0;
  205. XenPTRegGroup *reg_grp_entry = NULL;
  206. int rc = 0;
  207. uint32_t read_val = 0;
  208. int emul_len = 0;
  209. XenPTReg *reg_entry = NULL;
  210. uint32_t find_addr = addr;
  211. XenPTRegInfo *reg = NULL;
  212. if (xen_pt_pci_config_access_check(d, addr, len)) {
  213. return;
  214. }
  215. XEN_PT_LOG_CONFIG(d, addr, val, len);
  216. /* check unused BAR register */
  217. index = xen_pt_bar_offset_to_index(addr);
  218. if ((index >= 0) && (val > 0 && val < XEN_PT_BAR_ALLF) &&
  219. (s->bases[index].bar_flag == XEN_PT_BAR_FLAG_UNUSED)) {
  220. XEN_PT_WARN(d, "Guest attempt to set address to unused Base Address "
  221. "Register. (addr: 0x%02x, len: %d)\n", addr, len);
  222. }
  223. /* find register group entry */
  224. reg_grp_entry = xen_pt_find_reg_grp(s, addr);
  225. if (reg_grp_entry) {
  226. /* check 0-Hardwired register group */
  227. if (reg_grp_entry->reg_grp->grp_type == XEN_PT_GRP_TYPE_HARDWIRED) {
  228. /* ignore silently */
  229. XEN_PT_WARN(d, "Access to 0-Hardwired register. "
  230. "(addr: 0x%02x, len: %d)\n", addr, len);
  231. return;
  232. }
  233. }
  234. rc = xen_host_pci_get_block(&s->real_device, addr,
  235. (uint8_t *)&read_val, len);
  236. if (rc < 0) {
  237. XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc);
  238. memset(&read_val, 0xff, len);
  239. }
  240. /* pass directly to the real device for passthrough type register group */
  241. if (reg_grp_entry == NULL) {
  242. goto out;
  243. }
  244. memory_region_transaction_begin();
  245. pci_default_write_config(d, addr, val, len);
  246. /* adjust the read and write value to appropriate CFC-CFF window */
  247. read_val <<= (addr & 3) << 3;
  248. val <<= (addr & 3) << 3;
  249. emul_len = len;
  250. /* loop around the guest requested size */
  251. while (emul_len > 0) {
  252. /* find register entry to be emulated */
  253. reg_entry = xen_pt_find_reg(reg_grp_entry, find_addr);
  254. if (reg_entry) {
  255. reg = reg_entry->reg;
  256. uint32_t real_offset = reg_grp_entry->base_offset + reg->offset;
  257. uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3);
  258. uint8_t *ptr_val = NULL;
  259. valid_mask <<= (find_addr - real_offset) << 3;
  260. ptr_val = (uint8_t *)&val + (real_offset & 3);
  261. /* do emulation based on register size */
  262. switch (reg->size) {
  263. case 1:
  264. if (reg->u.b.write) {
  265. rc = reg->u.b.write(s, reg_entry, ptr_val,
  266. read_val >> ((real_offset & 3) << 3),
  267. valid_mask);
  268. }
  269. break;
  270. case 2:
  271. if (reg->u.w.write) {
  272. rc = reg->u.w.write(s, reg_entry, (uint16_t *)ptr_val,
  273. (read_val >> ((real_offset & 3) << 3)),
  274. valid_mask);
  275. }
  276. break;
  277. case 4:
  278. if (reg->u.dw.write) {
  279. rc = reg->u.dw.write(s, reg_entry, (uint32_t *)ptr_val,
  280. (read_val >> ((real_offset & 3) << 3)),
  281. valid_mask);
  282. }
  283. break;
  284. }
  285. if (rc < 0) {
  286. xen_shutdown_fatal_error("Internal error: Invalid write"
  287. " emulation. (%s, rc: %d)\n",
  288. __func__, rc);
  289. return;
  290. }
  291. /* calculate next address to find */
  292. emul_len -= reg->size;
  293. if (emul_len > 0) {
  294. find_addr = real_offset + reg->size;
  295. }
  296. } else {
  297. /* nothing to do with passthrough type register,
  298. * continue to find next byte */
  299. emul_len--;
  300. find_addr++;
  301. }
  302. }
  303. /* need to shift back before passing them to xen_host_pci_device */
  304. val >>= (addr & 3) << 3;
  305. memory_region_transaction_commit();
  306. out:
  307. if (!(reg && reg->no_wb)) {
  308. /* unknown regs are passed through */
  309. rc = xen_host_pci_set_block(&s->real_device, addr,
  310. (uint8_t *)&val, len);
  311. if (rc < 0) {
  312. XEN_PT_ERR(d, "pci_write_block failed. return value: %d.\n", rc);
  313. }
  314. }
  315. }
  316. /* register regions */
  317. static uint64_t xen_pt_bar_read(void *o, target_phys_addr_t addr,
  318. unsigned size)
  319. {
  320. PCIDevice *d = o;
  321. /* if this function is called, that probably means that there is a
  322. * misconfiguration of the IOMMU. */
  323. XEN_PT_ERR(d, "Should not read BAR through QEMU. @0x"TARGET_FMT_plx"\n",
  324. addr);
  325. return 0;
  326. }
  327. static void xen_pt_bar_write(void *o, target_phys_addr_t addr, uint64_t val,
  328. unsigned size)
  329. {
  330. PCIDevice *d = o;
  331. /* Same comment as xen_pt_bar_read function */
  332. XEN_PT_ERR(d, "Should not write BAR through QEMU. @0x"TARGET_FMT_plx"\n",
  333. addr);
  334. }
  335. static const MemoryRegionOps ops = {
  336. .endianness = DEVICE_NATIVE_ENDIAN,
  337. .read = xen_pt_bar_read,
  338. .write = xen_pt_bar_write,
  339. };
  340. static int xen_pt_register_regions(XenPCIPassthroughState *s)
  341. {
  342. int i = 0;
  343. XenHostPCIDevice *d = &s->real_device;
  344. /* Register PIO/MMIO BARs */
  345. for (i = 0; i < PCI_ROM_SLOT; i++) {
  346. XenHostPCIIORegion *r = &d->io_regions[i];
  347. uint8_t type;
  348. if (r->base_addr == 0 || r->size == 0) {
  349. continue;
  350. }
  351. s->bases[i].access.u = r->base_addr;
  352. if (r->type & XEN_HOST_PCI_REGION_TYPE_IO) {
  353. type = PCI_BASE_ADDRESS_SPACE_IO;
  354. } else {
  355. type = PCI_BASE_ADDRESS_SPACE_MEMORY;
  356. if (r->type & XEN_HOST_PCI_REGION_TYPE_PREFETCH) {
  357. type |= PCI_BASE_ADDRESS_MEM_PREFETCH;
  358. }
  359. }
  360. memory_region_init_io(&s->bar[i], &ops, &s->dev,
  361. "xen-pci-pt-bar", r->size);
  362. pci_register_bar(&s->dev, i, type, &s->bar[i]);
  363. XEN_PT_LOG(&s->dev, "IO region %i registered (size=0x%08"PRIx64
  364. " base_addr=0x%08"PRIx64" type: %#x)\n",
  365. i, r->size, r->base_addr, type);
  366. }
  367. /* Register expansion ROM address */
  368. if (d->rom.base_addr && d->rom.size) {
  369. uint32_t bar_data = 0;
  370. /* Re-set BAR reported by OS, otherwise ROM can't be read. */
  371. if (xen_host_pci_get_long(d, PCI_ROM_ADDRESS, &bar_data)) {
  372. return 0;
  373. }
  374. if ((bar_data & PCI_ROM_ADDRESS_MASK) == 0) {
  375. bar_data |= d->rom.base_addr & PCI_ROM_ADDRESS_MASK;
  376. xen_host_pci_set_long(d, PCI_ROM_ADDRESS, bar_data);
  377. }
  378. s->bases[PCI_ROM_SLOT].access.maddr = d->rom.base_addr;
  379. memory_region_init_rom_device(&s->rom, NULL, NULL,
  380. "xen-pci-pt-rom", d->rom.size);
  381. pci_register_bar(&s->dev, PCI_ROM_SLOT, PCI_BASE_ADDRESS_MEM_PREFETCH,
  382. &s->rom);
  383. XEN_PT_LOG(&s->dev, "Expansion ROM registered (size=0x%08"PRIx64
  384. " base_addr=0x%08"PRIx64")\n",
  385. d->rom.size, d->rom.base_addr);
  386. }
  387. return 0;
  388. }
  389. static void xen_pt_unregister_regions(XenPCIPassthroughState *s)
  390. {
  391. XenHostPCIDevice *d = &s->real_device;
  392. int i;
  393. for (i = 0; i < PCI_NUM_REGIONS - 1; i++) {
  394. XenHostPCIIORegion *r = &d->io_regions[i];
  395. if (r->base_addr == 0 || r->size == 0) {
  396. continue;
  397. }
  398. memory_region_destroy(&s->bar[i]);
  399. }
  400. if (d->rom.base_addr && d->rom.size) {
  401. memory_region_destroy(&s->rom);
  402. }
  403. }
  404. /* region mapping */
  405. static int xen_pt_bar_from_region(XenPCIPassthroughState *s, MemoryRegion *mr)
  406. {
  407. int i = 0;
  408. for (i = 0; i < PCI_NUM_REGIONS - 1; i++) {
  409. if (mr == &s->bar[i]) {
  410. return i;
  411. }
  412. }
  413. if (mr == &s->rom) {
  414. return PCI_ROM_SLOT;
  415. }
  416. return -1;
  417. }
  418. /*
  419. * This function checks if an io_region overlaps an io_region from another
  420. * device. The io_region to check is provided with (addr, size and type)
  421. * A callback can be provided and will be called for every region that is
  422. * overlapped.
  423. * The return value indicates if the region is overlappsed */
  424. struct CheckBarArgs {
  425. XenPCIPassthroughState *s;
  426. pcibus_t addr;
  427. pcibus_t size;
  428. uint8_t type;
  429. bool rc;
  430. };
  431. static void xen_pt_check_bar_overlap(PCIBus *bus, PCIDevice *d, void *opaque)
  432. {
  433. struct CheckBarArgs *arg = opaque;
  434. XenPCIPassthroughState *s = arg->s;
  435. uint8_t type = arg->type;
  436. int i;
  437. if (d->devfn == s->dev.devfn) {
  438. return;
  439. }
  440. /* xxx: This ignores bridges. */
  441. for (i = 0; i < PCI_NUM_REGIONS; i++) {
  442. const PCIIORegion *r = &d->io_regions[i];
  443. if (!r->size) {
  444. continue;
  445. }
  446. if ((type & PCI_BASE_ADDRESS_SPACE_IO)
  447. != (r->type & PCI_BASE_ADDRESS_SPACE_IO)) {
  448. continue;
  449. }
  450. if (ranges_overlap(arg->addr, arg->size, r->addr, r->size)) {
  451. XEN_PT_WARN(&s->dev,
  452. "Overlapped to device [%02x:%02x.%d] Region: %i"
  453. " (addr: %#"FMT_PCIBUS", len: %#"FMT_PCIBUS")\n",
  454. pci_bus_num(bus), PCI_SLOT(d->devfn),
  455. PCI_FUNC(d->devfn), i, r->addr, r->size);
  456. arg->rc = true;
  457. }
  458. }
  459. }
  460. static void xen_pt_region_update(XenPCIPassthroughState *s,
  461. MemoryRegionSection *sec, bool adding)
  462. {
  463. PCIDevice *d = &s->dev;
  464. MemoryRegion *mr = sec->mr;
  465. int bar = -1;
  466. int rc;
  467. int op = adding ? DPCI_ADD_MAPPING : DPCI_REMOVE_MAPPING;
  468. struct CheckBarArgs args = {
  469. .s = s,
  470. .addr = sec->offset_within_address_space,
  471. .size = sec->size,
  472. .rc = false,
  473. };
  474. bar = xen_pt_bar_from_region(s, mr);
  475. if (bar == -1 && (!s->msix || &s->msix->mmio != mr)) {
  476. return;
  477. }
  478. if (s->msix && &s->msix->mmio == mr) {
  479. if (adding) {
  480. s->msix->mmio_base_addr = sec->offset_within_address_space;
  481. rc = xen_pt_msix_update_remap(s, s->msix->bar_index);
  482. }
  483. return;
  484. }
  485. args.type = d->io_regions[bar].type;
  486. pci_for_each_device(d->bus, pci_bus_num(d->bus),
  487. xen_pt_check_bar_overlap, &args);
  488. if (args.rc) {
  489. XEN_PT_WARN(d, "Region: %d (addr: %#"FMT_PCIBUS
  490. ", len: %#"FMT_PCIBUS") is overlapped.\n",
  491. bar, sec->offset_within_address_space, sec->size);
  492. }
  493. if (d->io_regions[bar].type & PCI_BASE_ADDRESS_SPACE_IO) {
  494. uint32_t guest_port = sec->offset_within_address_space;
  495. uint32_t machine_port = s->bases[bar].access.pio_base;
  496. uint32_t size = sec->size;
  497. rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
  498. guest_port, machine_port, size,
  499. op);
  500. if (rc) {
  501. XEN_PT_ERR(d, "%s ioport mapping failed! (rc: %i)\n",
  502. adding ? "create new" : "remove old", rc);
  503. }
  504. } else {
  505. pcibus_t guest_addr = sec->offset_within_address_space;
  506. pcibus_t machine_addr = s->bases[bar].access.maddr
  507. + sec->offset_within_region;
  508. pcibus_t size = sec->size;
  509. rc = xc_domain_memory_mapping(xen_xc, xen_domid,
  510. XEN_PFN(guest_addr + XC_PAGE_SIZE - 1),
  511. XEN_PFN(machine_addr + XC_PAGE_SIZE - 1),
  512. XEN_PFN(size + XC_PAGE_SIZE - 1),
  513. op);
  514. if (rc) {
  515. XEN_PT_ERR(d, "%s mem mapping failed! (rc: %i)\n",
  516. adding ? "create new" : "remove old", rc);
  517. }
  518. }
  519. }
  520. static void xen_pt_begin(MemoryListener *l)
  521. {
  522. }
  523. static void xen_pt_commit(MemoryListener *l)
  524. {
  525. }
  526. static void xen_pt_region_add(MemoryListener *l, MemoryRegionSection *sec)
  527. {
  528. XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
  529. memory_listener);
  530. xen_pt_region_update(s, sec, true);
  531. }
  532. static void xen_pt_region_del(MemoryListener *l, MemoryRegionSection *sec)
  533. {
  534. XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
  535. memory_listener);
  536. xen_pt_region_update(s, sec, false);
  537. }
  538. static void xen_pt_region_nop(MemoryListener *l, MemoryRegionSection *s)
  539. {
  540. }
  541. static void xen_pt_log_fns(MemoryListener *l, MemoryRegionSection *s)
  542. {
  543. }
  544. static void xen_pt_log_global_fns(MemoryListener *l)
  545. {
  546. }
  547. static void xen_pt_eventfd_fns(MemoryListener *l, MemoryRegionSection *s,
  548. bool match_data, uint64_t data, EventNotifier *n)
  549. {
  550. }
  551. static const MemoryListener xen_pt_memory_listener = {
  552. .begin = xen_pt_begin,
  553. .commit = xen_pt_commit,
  554. .region_add = xen_pt_region_add,
  555. .region_nop = xen_pt_region_nop,
  556. .region_del = xen_pt_region_del,
  557. .log_start = xen_pt_log_fns,
  558. .log_stop = xen_pt_log_fns,
  559. .log_sync = xen_pt_log_fns,
  560. .log_global_start = xen_pt_log_global_fns,
  561. .log_global_stop = xen_pt_log_global_fns,
  562. .eventfd_add = xen_pt_eventfd_fns,
  563. .eventfd_del = xen_pt_eventfd_fns,
  564. .priority = 10,
  565. };
  566. /* init */
  567. static int xen_pt_initfn(PCIDevice *d)
  568. {
  569. XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
  570. int rc = 0;
  571. uint8_t machine_irq = 0;
  572. int pirq = XEN_PT_UNASSIGNED_PIRQ;
  573. /* register real device */
  574. XEN_PT_LOG(d, "Assigning real physical device %02x:%02x.%d"
  575. " to devfn %#x\n",
  576. s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function,
  577. s->dev.devfn);
  578. rc = xen_host_pci_device_get(&s->real_device,
  579. s->hostaddr.domain, s->hostaddr.bus,
  580. s->hostaddr.slot, s->hostaddr.function);
  581. if (rc) {
  582. XEN_PT_ERR(d, "Failed to \"open\" the real pci device. rc: %i\n", rc);
  583. return -1;
  584. }
  585. s->is_virtfn = s->real_device.is_virtfn;
  586. if (s->is_virtfn) {
  587. XEN_PT_LOG(d, "%04x:%02x:%02x.%d is a SR-IOV Virtual Function\n",
  588. s->real_device.domain, bus, slot, func);
  589. }
  590. /* Initialize virtualized PCI configuration (Extended 256 Bytes) */
  591. if (xen_host_pci_get_block(&s->real_device, 0, d->config,
  592. PCI_CONFIG_SPACE_SIZE) == -1) {
  593. xen_host_pci_device_put(&s->real_device);
  594. return -1;
  595. }
  596. s->memory_listener = xen_pt_memory_listener;
  597. /* Handle real device's MMIO/PIO BARs */
  598. xen_pt_register_regions(s);
  599. /* reinitialize each config register to be emulated */
  600. if (xen_pt_config_init(s)) {
  601. XEN_PT_ERR(d, "PCI Config space initialisation failed.\n");
  602. xen_host_pci_device_put(&s->real_device);
  603. return -1;
  604. }
  605. /* Bind interrupt */
  606. if (!s->dev.config[PCI_INTERRUPT_PIN]) {
  607. XEN_PT_LOG(d, "no pin interrupt\n");
  608. goto out;
  609. }
  610. machine_irq = s->real_device.irq;
  611. rc = xc_physdev_map_pirq(xen_xc, xen_domid, machine_irq, &pirq);
  612. if (rc < 0) {
  613. XEN_PT_ERR(d, "Mapping machine irq %u to pirq %i failed, (rc: %d)\n",
  614. machine_irq, pirq, rc);
  615. /* Disable PCI intx assertion (turn on bit10 of devctl) */
  616. xen_host_pci_set_word(&s->real_device,
  617. PCI_COMMAND,
  618. pci_get_word(s->dev.config + PCI_COMMAND)
  619. | PCI_COMMAND_INTX_DISABLE);
  620. machine_irq = 0;
  621. s->machine_irq = 0;
  622. } else {
  623. machine_irq = pirq;
  624. s->machine_irq = pirq;
  625. xen_pt_mapped_machine_irq[machine_irq]++;
  626. }
  627. /* bind machine_irq to device */
  628. if (machine_irq != 0) {
  629. uint8_t e_intx = xen_pt_pci_intx(s);
  630. rc = xc_domain_bind_pt_pci_irq(xen_xc, xen_domid, machine_irq,
  631. pci_bus_num(d->bus),
  632. PCI_SLOT(d->devfn),
  633. e_intx);
  634. if (rc < 0) {
  635. XEN_PT_ERR(d, "Binding of interrupt %i failed! (rc: %d)\n",
  636. e_intx, rc);
  637. /* Disable PCI intx assertion (turn on bit10 of devctl) */
  638. xen_host_pci_set_word(&s->real_device, PCI_COMMAND,
  639. *(uint16_t *)(&s->dev.config[PCI_COMMAND])
  640. | PCI_COMMAND_INTX_DISABLE);
  641. xen_pt_mapped_machine_irq[machine_irq]--;
  642. if (xen_pt_mapped_machine_irq[machine_irq] == 0) {
  643. if (xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq)) {
  644. XEN_PT_ERR(d, "Unmapping of machine interrupt %i failed!"
  645. " (rc: %d)\n", machine_irq, rc);
  646. }
  647. }
  648. s->machine_irq = 0;
  649. }
  650. }
  651. out:
  652. memory_listener_register(&s->memory_listener, NULL);
  653. XEN_PT_LOG(d, "Real physical device %02x:%02x.%d registered successfuly!\n",
  654. bus, slot, func);
  655. return 0;
  656. }
  657. static void xen_pt_unregister_device(PCIDevice *d)
  658. {
  659. XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
  660. uint8_t machine_irq = s->machine_irq;
  661. uint8_t intx = xen_pt_pci_intx(s);
  662. int rc;
  663. if (machine_irq) {
  664. rc = xc_domain_unbind_pt_irq(xen_xc, xen_domid, machine_irq,
  665. PT_IRQ_TYPE_PCI,
  666. pci_bus_num(d->bus),
  667. PCI_SLOT(s->dev.devfn),
  668. intx,
  669. 0 /* isa_irq */);
  670. if (rc < 0) {
  671. XEN_PT_ERR(d, "unbinding of interrupt INT%c failed."
  672. " (machine irq: %i, rc: %d)"
  673. " But bravely continuing on..\n",
  674. 'a' + intx, machine_irq, rc);
  675. }
  676. }
  677. if (s->msi) {
  678. xen_pt_msi_disable(s);
  679. }
  680. if (s->msix) {
  681. xen_pt_msix_disable(s);
  682. }
  683. if (machine_irq) {
  684. xen_pt_mapped_machine_irq[machine_irq]--;
  685. if (xen_pt_mapped_machine_irq[machine_irq] == 0) {
  686. rc = xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq);
  687. if (rc < 0) {
  688. XEN_PT_ERR(d, "unmapping of interrupt %i failed. (rc: %d)"
  689. " But bravely continuing on..\n",
  690. machine_irq, rc);
  691. }
  692. }
  693. }
  694. /* delete all emulated config registers */
  695. xen_pt_config_delete(s);
  696. xen_pt_unregister_regions(s);
  697. memory_listener_unregister(&s->memory_listener);
  698. xen_host_pci_device_put(&s->real_device);
  699. }
  700. static Property xen_pci_passthrough_properties[] = {
  701. DEFINE_PROP_PCI_HOST_DEVADDR("hostaddr", XenPCIPassthroughState, hostaddr),
  702. DEFINE_PROP_END_OF_LIST(),
  703. };
  704. static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data)
  705. {
  706. DeviceClass *dc = DEVICE_CLASS(klass);
  707. PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
  708. k->init = xen_pt_initfn;
  709. k->exit = xen_pt_unregister_device;
  710. k->config_read = xen_pt_pci_read_config;
  711. k->config_write = xen_pt_pci_write_config;
  712. dc->desc = "Assign an host PCI device with Xen";
  713. dc->props = xen_pci_passthrough_properties;
  714. };
  715. static TypeInfo xen_pci_passthrough_info = {
  716. .name = "xen-pci-passthrough",
  717. .parent = TYPE_PCI_DEVICE,
  718. .instance_size = sizeof(XenPCIPassthroughState),
  719. .class_init = xen_pci_passthrough_class_init,
  720. };
  721. static void xen_pci_passthrough_register_types(void)
  722. {
  723. type_register_static(&xen_pci_passthrough_info);
  724. }
  725. type_init(xen_pci_passthrough_register_types)