ivshmem.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. /*
  2. * Inter-VM Shared Memory PCI device.
  3. *
  4. * Author:
  5. * Cam Macdonell <cam@cs.ualberta.ca>
  6. *
  7. * Based On: cirrus_vga.c
  8. * Copyright (c) 2004 Fabrice Bellard
  9. * Copyright (c) 2004 Makoto Suzuki (suzu)
  10. *
  11. * and rtl8139.c
  12. * Copyright (c) 2006 Igor Kovalenko
  13. *
  14. * This code is licensed under the GNU GPL v2.
  15. */
  16. #include "hw.h"
  17. #include "pc.h"
  18. #include "pci.h"
  19. #include "msix.h"
  20. #include "kvm.h"
  21. #include "migration.h"
  22. #include "qerror.h"
  23. #include <sys/mman.h>
  24. #include <sys/types.h>
  25. #define IVSHMEM_IOEVENTFD 0
  26. #define IVSHMEM_MSI 1
  27. #define IVSHMEM_PEER 0
  28. #define IVSHMEM_MASTER 1
  29. #define IVSHMEM_REG_BAR_SIZE 0x100
  30. //#define DEBUG_IVSHMEM
  31. #ifdef DEBUG_IVSHMEM
  32. #define IVSHMEM_DPRINTF(fmt, ...) \
  33. do {printf("IVSHMEM: " fmt, ## __VA_ARGS__); } while (0)
  34. #else
  35. #define IVSHMEM_DPRINTF(fmt, ...)
  36. #endif
  37. typedef struct Peer {
  38. int nb_eventfds;
  39. int *eventfds;
  40. } Peer;
  41. typedef struct EventfdEntry {
  42. PCIDevice *pdev;
  43. int vector;
  44. } EventfdEntry;
  45. typedef struct IVShmemState {
  46. PCIDevice dev;
  47. uint32_t intrmask;
  48. uint32_t intrstatus;
  49. uint32_t doorbell;
  50. CharDriverState **eventfd_chr;
  51. CharDriverState *server_chr;
  52. MemoryRegion ivshmem_mmio;
  53. pcibus_t mmio_addr;
  54. /* We might need to register the BAR before we actually have the memory.
  55. * So prepare a container MemoryRegion for the BAR immediately and
  56. * add a subregion when we have the memory.
  57. */
  58. MemoryRegion bar;
  59. MemoryRegion ivshmem;
  60. MemoryRegion msix_bar;
  61. uint64_t ivshmem_size; /* size of shared memory region */
  62. int shm_fd; /* shared memory file descriptor */
  63. Peer *peers;
  64. int nb_peers; /* how many guests we have space for */
  65. int max_peer; /* maximum numbered peer */
  66. int vm_id;
  67. uint32_t vectors;
  68. uint32_t features;
  69. EventfdEntry *eventfd_table;
  70. Error *migration_blocker;
  71. char * shmobj;
  72. char * sizearg;
  73. char * role;
  74. int role_val; /* scalar to avoid multiple string comparisons */
  75. } IVShmemState;
  76. /* registers for the Inter-VM shared memory device */
  77. enum ivshmem_registers {
  78. INTRMASK = 0,
  79. INTRSTATUS = 4,
  80. IVPOSITION = 8,
  81. DOORBELL = 12,
  82. };
  83. static inline uint32_t ivshmem_has_feature(IVShmemState *ivs,
  84. unsigned int feature) {
  85. return (ivs->features & (1 << feature));
  86. }
  87. static inline bool is_power_of_two(uint64_t x) {
  88. return (x & (x - 1)) == 0;
  89. }
  90. /* accessing registers - based on rtl8139 */
  91. static void ivshmem_update_irq(IVShmemState *s, int val)
  92. {
  93. int isr;
  94. isr = (s->intrstatus & s->intrmask) & 0xffffffff;
  95. /* don't print ISR resets */
  96. if (isr) {
  97. IVSHMEM_DPRINTF("Set IRQ to %d (%04x %04x)\n",
  98. isr ? 1 : 0, s->intrstatus, s->intrmask);
  99. }
  100. qemu_set_irq(s->dev.irq[0], (isr != 0));
  101. }
  102. static void ivshmem_IntrMask_write(IVShmemState *s, uint32_t val)
  103. {
  104. IVSHMEM_DPRINTF("IntrMask write(w) val = 0x%04x\n", val);
  105. s->intrmask = val;
  106. ivshmem_update_irq(s, val);
  107. }
  108. static uint32_t ivshmem_IntrMask_read(IVShmemState *s)
  109. {
  110. uint32_t ret = s->intrmask;
  111. IVSHMEM_DPRINTF("intrmask read(w) val = 0x%04x\n", ret);
  112. return ret;
  113. }
  114. static void ivshmem_IntrStatus_write(IVShmemState *s, uint32_t val)
  115. {
  116. IVSHMEM_DPRINTF("IntrStatus write(w) val = 0x%04x\n", val);
  117. s->intrstatus = val;
  118. ivshmem_update_irq(s, val);
  119. return;
  120. }
  121. static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
  122. {
  123. uint32_t ret = s->intrstatus;
  124. /* reading ISR clears all interrupts */
  125. s->intrstatus = 0;
  126. ivshmem_update_irq(s, 0);
  127. return ret;
  128. }
  129. static void ivshmem_io_write(void *opaque, target_phys_addr_t addr,
  130. uint64_t val, unsigned size)
  131. {
  132. IVShmemState *s = opaque;
  133. uint64_t write_one = 1;
  134. uint16_t dest = val >> 16;
  135. uint16_t vector = val & 0xff;
  136. addr &= 0xfc;
  137. IVSHMEM_DPRINTF("writing to addr " TARGET_FMT_plx "\n", addr);
  138. switch (addr)
  139. {
  140. case INTRMASK:
  141. ivshmem_IntrMask_write(s, val);
  142. break;
  143. case INTRSTATUS:
  144. ivshmem_IntrStatus_write(s, val);
  145. break;
  146. case DOORBELL:
  147. /* check that dest VM ID is reasonable */
  148. if (dest > s->max_peer) {
  149. IVSHMEM_DPRINTF("Invalid destination VM ID (%d)\n", dest);
  150. break;
  151. }
  152. /* check doorbell range */
  153. if (vector < s->peers[dest].nb_eventfds) {
  154. IVSHMEM_DPRINTF("Writing %" PRId64 " to VM %d on vector %d\n",
  155. write_one, dest, vector);
  156. if (write(s->peers[dest].eventfds[vector],
  157. &(write_one), 8) != 8) {
  158. IVSHMEM_DPRINTF("error writing to eventfd\n");
  159. }
  160. }
  161. break;
  162. default:
  163. IVSHMEM_DPRINTF("Invalid VM Doorbell VM %d\n", dest);
  164. }
  165. }
  166. static uint64_t ivshmem_io_read(void *opaque, target_phys_addr_t addr,
  167. unsigned size)
  168. {
  169. IVShmemState *s = opaque;
  170. uint32_t ret;
  171. switch (addr)
  172. {
  173. case INTRMASK:
  174. ret = ivshmem_IntrMask_read(s);
  175. break;
  176. case INTRSTATUS:
  177. ret = ivshmem_IntrStatus_read(s);
  178. break;
  179. case IVPOSITION:
  180. /* return my VM ID if the memory is mapped */
  181. if (s->shm_fd > 0) {
  182. ret = s->vm_id;
  183. } else {
  184. ret = -1;
  185. }
  186. break;
  187. default:
  188. IVSHMEM_DPRINTF("why are we reading " TARGET_FMT_plx "\n", addr);
  189. ret = 0;
  190. }
  191. return ret;
  192. }
  193. static const MemoryRegionOps ivshmem_mmio_ops = {
  194. .read = ivshmem_io_read,
  195. .write = ivshmem_io_write,
  196. .endianness = DEVICE_NATIVE_ENDIAN,
  197. .impl = {
  198. .min_access_size = 4,
  199. .max_access_size = 4,
  200. },
  201. };
  202. static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
  203. {
  204. IVShmemState *s = opaque;
  205. ivshmem_IntrStatus_write(s, *buf);
  206. IVSHMEM_DPRINTF("ivshmem_receive 0x%02x\n", *buf);
  207. }
  208. static int ivshmem_can_receive(void * opaque)
  209. {
  210. return 8;
  211. }
  212. static void ivshmem_event(void *opaque, int event)
  213. {
  214. IVSHMEM_DPRINTF("ivshmem_event %d\n", event);
  215. }
  216. static void fake_irqfd(void *opaque, const uint8_t *buf, int size) {
  217. EventfdEntry *entry = opaque;
  218. PCIDevice *pdev = entry->pdev;
  219. IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, entry->vector);
  220. msix_notify(pdev, entry->vector);
  221. }
  222. static CharDriverState* create_eventfd_chr_device(void * opaque, int eventfd,
  223. int vector)
  224. {
  225. /* create a event character device based on the passed eventfd */
  226. IVShmemState *s = opaque;
  227. CharDriverState * chr;
  228. chr = qemu_chr_open_eventfd(eventfd);
  229. if (chr == NULL) {
  230. fprintf(stderr, "creating eventfd for eventfd %d failed\n", eventfd);
  231. exit(-1);
  232. }
  233. /* if MSI is supported we need multiple interrupts */
  234. if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
  235. s->eventfd_table[vector].pdev = &s->dev;
  236. s->eventfd_table[vector].vector = vector;
  237. qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd,
  238. ivshmem_event, &s->eventfd_table[vector]);
  239. } else {
  240. qemu_chr_add_handlers(chr, ivshmem_can_receive, ivshmem_receive,
  241. ivshmem_event, s);
  242. }
  243. return chr;
  244. }
  245. static int check_shm_size(IVShmemState *s, int fd) {
  246. /* check that the guest isn't going to try and map more memory than the
  247. * the object has allocated return -1 to indicate error */
  248. struct stat buf;
  249. fstat(fd, &buf);
  250. if (s->ivshmem_size > buf.st_size) {
  251. fprintf(stderr,
  252. "IVSHMEM ERROR: Requested memory size greater"
  253. " than shared object size (%" PRIu64 " > %" PRIu64")\n",
  254. s->ivshmem_size, (uint64_t)buf.st_size);
  255. return -1;
  256. } else {
  257. return 0;
  258. }
  259. }
  260. /* create the shared memory BAR when we are not using the server, so we can
  261. * create the BAR and map the memory immediately */
  262. static void create_shared_memory_BAR(IVShmemState *s, int fd) {
  263. void * ptr;
  264. s->shm_fd = fd;
  265. ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  266. memory_region_init_ram_ptr(&s->ivshmem, &s->dev.qdev, "ivshmem.bar2",
  267. s->ivshmem_size, ptr);
  268. memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
  269. /* region for shared memory */
  270. pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
  271. }
  272. static void close_guest_eventfds(IVShmemState *s, int posn)
  273. {
  274. int i, guest_curr_max;
  275. guest_curr_max = s->peers[posn].nb_eventfds;
  276. for (i = 0; i < guest_curr_max; i++) {
  277. kvm_set_ioeventfd_mmio_long(s->peers[posn].eventfds[i],
  278. s->mmio_addr + DOORBELL, (posn << 16) | i, 0);
  279. close(s->peers[posn].eventfds[i]);
  280. }
  281. g_free(s->peers[posn].eventfds);
  282. s->peers[posn].nb_eventfds = 0;
  283. }
  284. static void setup_ioeventfds(IVShmemState *s) {
  285. int i, j;
  286. for (i = 0; i <= s->max_peer; i++) {
  287. for (j = 0; j < s->peers[i].nb_eventfds; j++) {
  288. memory_region_add_eventfd(&s->ivshmem_mmio,
  289. DOORBELL,
  290. 4,
  291. true,
  292. (i << 16) | j,
  293. s->peers[i].eventfds[j]);
  294. }
  295. }
  296. }
  297. /* this function increase the dynamic storage need to store data about other
  298. * guests */
  299. static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
  300. int j, old_nb_alloc;
  301. old_nb_alloc = s->nb_peers;
  302. while (new_min_size >= s->nb_peers)
  303. s->nb_peers = s->nb_peers * 2;
  304. IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
  305. s->peers = g_realloc(s->peers, s->nb_peers * sizeof(Peer));
  306. /* zero out new pointers */
  307. for (j = old_nb_alloc; j < s->nb_peers; j++) {
  308. s->peers[j].eventfds = NULL;
  309. s->peers[j].nb_eventfds = 0;
  310. }
  311. }
  312. static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
  313. {
  314. IVShmemState *s = opaque;
  315. int incoming_fd, tmp_fd;
  316. int guest_max_eventfd;
  317. long incoming_posn;
  318. memcpy(&incoming_posn, buf, sizeof(long));
  319. /* pick off s->server_chr->msgfd and store it, posn should accompany msg */
  320. tmp_fd = qemu_chr_fe_get_msgfd(s->server_chr);
  321. IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd);
  322. /* make sure we have enough space for this guest */
  323. if (incoming_posn >= s->nb_peers) {
  324. increase_dynamic_storage(s, incoming_posn);
  325. }
  326. if (tmp_fd == -1) {
  327. /* if posn is positive and unseen before then this is our posn*/
  328. if ((incoming_posn >= 0) &&
  329. (s->peers[incoming_posn].eventfds == NULL)) {
  330. /* receive our posn */
  331. s->vm_id = incoming_posn;
  332. return;
  333. } else {
  334. /* otherwise an fd == -1 means an existing guest has gone away */
  335. IVSHMEM_DPRINTF("posn %ld has gone away\n", incoming_posn);
  336. close_guest_eventfds(s, incoming_posn);
  337. return;
  338. }
  339. }
  340. /* because of the implementation of get_msgfd, we need a dup */
  341. incoming_fd = dup(tmp_fd);
  342. if (incoming_fd == -1) {
  343. fprintf(stderr, "could not allocate file descriptor %s\n",
  344. strerror(errno));
  345. return;
  346. }
  347. /* if the position is -1, then it's shared memory region fd */
  348. if (incoming_posn == -1) {
  349. void * map_ptr;
  350. s->max_peer = 0;
  351. if (check_shm_size(s, incoming_fd) == -1) {
  352. exit(-1);
  353. }
  354. /* mmap the region and map into the BAR2 */
  355. map_ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED,
  356. incoming_fd, 0);
  357. memory_region_init_ram_ptr(&s->ivshmem, &s->dev.qdev,
  358. "ivshmem.bar2", s->ivshmem_size, map_ptr);
  359. IVSHMEM_DPRINTF("guest h/w addr = %" PRIu64 ", size = %" PRIu64 "\n",
  360. s->ivshmem_offset, s->ivshmem_size);
  361. memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
  362. /* only store the fd if it is successfully mapped */
  363. s->shm_fd = incoming_fd;
  364. return;
  365. }
  366. /* each guest has an array of eventfds, and we keep track of how many
  367. * guests for each VM */
  368. guest_max_eventfd = s->peers[incoming_posn].nb_eventfds;
  369. if (guest_max_eventfd == 0) {
  370. /* one eventfd per MSI vector */
  371. s->peers[incoming_posn].eventfds = (int *) g_malloc(s->vectors *
  372. sizeof(int));
  373. }
  374. /* this is an eventfd for a particular guest VM */
  375. IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
  376. guest_max_eventfd, incoming_fd);
  377. s->peers[incoming_posn].eventfds[guest_max_eventfd] = incoming_fd;
  378. /* increment count for particular guest */
  379. s->peers[incoming_posn].nb_eventfds++;
  380. /* keep track of the maximum VM ID */
  381. if (incoming_posn > s->max_peer) {
  382. s->max_peer = incoming_posn;
  383. }
  384. if (incoming_posn == s->vm_id) {
  385. s->eventfd_chr[guest_max_eventfd] = create_eventfd_chr_device(s,
  386. s->peers[s->vm_id].eventfds[guest_max_eventfd],
  387. guest_max_eventfd);
  388. }
  389. if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
  390. if (kvm_set_ioeventfd_mmio_long(incoming_fd, s->mmio_addr + DOORBELL,
  391. (incoming_posn << 16) | guest_max_eventfd, 1) < 0) {
  392. fprintf(stderr, "ivshmem: ioeventfd not available\n");
  393. }
  394. }
  395. return;
  396. }
  397. static void ivshmem_reset(DeviceState *d)
  398. {
  399. IVShmemState *s = DO_UPCAST(IVShmemState, dev.qdev, d);
  400. s->intrstatus = 0;
  401. return;
  402. }
  403. static uint64_t ivshmem_get_size(IVShmemState * s) {
  404. uint64_t value;
  405. char *ptr;
  406. value = strtoull(s->sizearg, &ptr, 10);
  407. switch (*ptr) {
  408. case 0: case 'M': case 'm':
  409. value <<= 20;
  410. break;
  411. case 'G': case 'g':
  412. value <<= 30;
  413. break;
  414. default:
  415. fprintf(stderr, "qemu: invalid ram size: %s\n", s->sizearg);
  416. exit(1);
  417. }
  418. /* BARs must be a power of 2 */
  419. if (!is_power_of_two(value)) {
  420. fprintf(stderr, "ivshmem: size must be power of 2\n");
  421. exit(1);
  422. }
  423. return value;
  424. }
  425. static void ivshmem_setup_msi(IVShmemState * s) {
  426. int i;
  427. /* allocate the MSI-X vectors */
  428. memory_region_init(&s->msix_bar, "ivshmem-msix", 4096);
  429. if (!msix_init(&s->dev, s->vectors, &s->msix_bar, 1, 0)) {
  430. pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY,
  431. &s->msix_bar);
  432. IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
  433. } else {
  434. IVSHMEM_DPRINTF("msix initialization failed\n");
  435. exit(1);
  436. }
  437. /* 'activate' the vectors */
  438. for (i = 0; i < s->vectors; i++) {
  439. msix_vector_use(&s->dev, i);
  440. }
  441. /* allocate Qemu char devices for receiving interrupts */
  442. s->eventfd_table = g_malloc0(s->vectors * sizeof(EventfdEntry));
  443. }
  444. static void ivshmem_save(QEMUFile* f, void *opaque)
  445. {
  446. IVShmemState *proxy = opaque;
  447. IVSHMEM_DPRINTF("ivshmem_save\n");
  448. pci_device_save(&proxy->dev, f);
  449. if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
  450. msix_save(&proxy->dev, f);
  451. } else {
  452. qemu_put_be32(f, proxy->intrstatus);
  453. qemu_put_be32(f, proxy->intrmask);
  454. }
  455. }
  456. static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
  457. {
  458. IVSHMEM_DPRINTF("ivshmem_load\n");
  459. IVShmemState *proxy = opaque;
  460. int ret, i;
  461. if (version_id > 0) {
  462. return -EINVAL;
  463. }
  464. if (proxy->role_val == IVSHMEM_PEER) {
  465. fprintf(stderr, "ivshmem: 'peer' devices are not migratable\n");
  466. return -EINVAL;
  467. }
  468. ret = pci_device_load(&proxy->dev, f);
  469. if (ret) {
  470. return ret;
  471. }
  472. if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
  473. msix_load(&proxy->dev, f);
  474. for (i = 0; i < proxy->vectors; i++) {
  475. msix_vector_use(&proxy->dev, i);
  476. }
  477. } else {
  478. proxy->intrstatus = qemu_get_be32(f);
  479. proxy->intrmask = qemu_get_be32(f);
  480. }
  481. return 0;
  482. }
  483. static int pci_ivshmem_init(PCIDevice *dev)
  484. {
  485. IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
  486. uint8_t *pci_conf;
  487. if (s->sizearg == NULL)
  488. s->ivshmem_size = 4 << 20; /* 4 MB default */
  489. else {
  490. s->ivshmem_size = ivshmem_get_size(s);
  491. }
  492. register_savevm(&s->dev.qdev, "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
  493. dev);
  494. /* IRQFD requires MSI */
  495. if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
  496. !ivshmem_has_feature(s, IVSHMEM_MSI)) {
  497. fprintf(stderr, "ivshmem: ioeventfd/irqfd requires MSI\n");
  498. exit(1);
  499. }
  500. /* check that role is reasonable */
  501. if (s->role) {
  502. if (strncmp(s->role, "peer", 5) == 0) {
  503. s->role_val = IVSHMEM_PEER;
  504. } else if (strncmp(s->role, "master", 7) == 0) {
  505. s->role_val = IVSHMEM_MASTER;
  506. } else {
  507. fprintf(stderr, "ivshmem: 'role' must be 'peer' or 'master'\n");
  508. exit(1);
  509. }
  510. } else {
  511. s->role_val = IVSHMEM_MASTER; /* default */
  512. }
  513. if (s->role_val == IVSHMEM_PEER) {
  514. error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION, "ivshmem", "peer mode");
  515. migrate_add_blocker(s->migration_blocker);
  516. }
  517. pci_conf = s->dev.config;
  518. pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
  519. pci_config_set_interrupt_pin(pci_conf, 1);
  520. s->shm_fd = 0;
  521. memory_region_init_io(&s->ivshmem_mmio, &ivshmem_mmio_ops, s,
  522. "ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
  523. if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
  524. setup_ioeventfds(s);
  525. }
  526. /* region for registers*/
  527. pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
  528. &s->ivshmem_mmio);
  529. memory_region_init(&s->bar, "ivshmem-bar2-container", s->ivshmem_size);
  530. if ((s->server_chr != NULL) &&
  531. (strncmp(s->server_chr->filename, "unix:", 5) == 0)) {
  532. /* if we get a UNIX socket as the parameter we will talk
  533. * to the ivshmem server to receive the memory region */
  534. if (s->shmobj != NULL) {
  535. fprintf(stderr, "WARNING: do not specify both 'chardev' "
  536. "and 'shm' with ivshmem\n");
  537. }
  538. IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
  539. s->server_chr->filename);
  540. if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
  541. ivshmem_setup_msi(s);
  542. }
  543. /* we allocate enough space for 16 guests and grow as needed */
  544. s->nb_peers = 16;
  545. s->vm_id = -1;
  546. /* allocate/initialize space for interrupt handling */
  547. s->peers = g_malloc0(s->nb_peers * sizeof(Peer));
  548. pci_register_bar(&s->dev, 2,
  549. PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
  550. s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *));
  551. qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read,
  552. ivshmem_event, s);
  553. } else {
  554. /* just map the file immediately, we're not using a server */
  555. int fd;
  556. if (s->shmobj == NULL) {
  557. fprintf(stderr, "Must specify 'chardev' or 'shm' to ivshmem\n");
  558. }
  559. IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj);
  560. /* try opening with O_EXCL and if it succeeds zero the memory
  561. * by truncating to 0 */
  562. if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR|O_EXCL,
  563. S_IRWXU|S_IRWXG|S_IRWXO)) > 0) {
  564. /* truncate file to length PCI device's memory */
  565. if (ftruncate(fd, s->ivshmem_size) != 0) {
  566. fprintf(stderr, "ivshmem: could not truncate shared file\n");
  567. }
  568. } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR,
  569. S_IRWXU|S_IRWXG|S_IRWXO)) < 0) {
  570. fprintf(stderr, "ivshmem: could not open shared file\n");
  571. exit(-1);
  572. }
  573. if (check_shm_size(s, fd) == -1) {
  574. exit(-1);
  575. }
  576. create_shared_memory_BAR(s, fd);
  577. }
  578. return 0;
  579. }
  580. static int pci_ivshmem_uninit(PCIDevice *dev)
  581. {
  582. IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
  583. if (s->migration_blocker) {
  584. migrate_del_blocker(s->migration_blocker);
  585. error_free(s->migration_blocker);
  586. }
  587. memory_region_destroy(&s->ivshmem_mmio);
  588. memory_region_del_subregion(&s->bar, &s->ivshmem);
  589. memory_region_destroy(&s->ivshmem);
  590. memory_region_destroy(&s->bar);
  591. unregister_savevm(&dev->qdev, "ivshmem", s);
  592. return 0;
  593. }
  594. static PCIDeviceInfo ivshmem_info = {
  595. .qdev.name = "ivshmem",
  596. .qdev.size = sizeof(IVShmemState),
  597. .qdev.reset = ivshmem_reset,
  598. .init = pci_ivshmem_init,
  599. .exit = pci_ivshmem_uninit,
  600. .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
  601. .device_id = 0x1110,
  602. .class_id = PCI_CLASS_MEMORY_RAM,
  603. .qdev.props = (Property[]) {
  604. DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
  605. DEFINE_PROP_STRING("size", IVShmemState, sizearg),
  606. DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
  607. DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, false),
  608. DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true),
  609. DEFINE_PROP_STRING("shm", IVShmemState, shmobj),
  610. DEFINE_PROP_STRING("role", IVShmemState, role),
  611. DEFINE_PROP_END_OF_LIST(),
  612. }
  613. };
  614. static void ivshmem_register_devices(void)
  615. {
  616. pci_qdev_register(&ivshmem_info);
  617. }
  618. device_init(ivshmem_register_devices)