ivshmem.c 23 KB

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