qp_host_kernel.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. /*
  2. * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support
  3. *
  4. * Copyright (C) 2010-2013 VMware, Inc. All rights reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License version 2 as published by
  8. * the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful, but WITHOUT
  11. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13. * more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along with
  16. * this program; see the file COPYING. If not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. */
  19. #line 5
  20. /**
  21. * @file
  22. *
  23. * @brief MVP host kernel implementation of the queue pairs API
  24. *
  25. */
  26. #include <linux/module.h>
  27. #include <linux/slab.h>
  28. #include <linux/mm.h>
  29. #include <linux/vmalloc.h>
  30. #include <linux/highmem.h>
  31. #include <linux/slab.h>
  32. #include "mvp.h"
  33. #include "mvpkm_kernel.h"
  34. #include "qp.h"
  35. #include "qp_host_kernel.h"
  36. static QPHandle queuePairs[QP_MAX_QUEUE_PAIRS];
  37. static QPListener listeners[QP_MAX_LISTENERS];
  38. /*
  39. * Protect listeners and queuePairs.
  40. */
  41. static DEFINE_MUTEX(qpLock);
  42. #define QPLock() mutex_lock(&qpLock)
  43. #define QPUnlock() mutex_unlock(&qpLock)
  44. /**
  45. * @brief Map a vector of pages into virtually contiguous kernel space
  46. * @param vm this vm's vm struct
  47. * @param base base machine page number that lists pages to map
  48. * @param nrPages number of pages to map
  49. * @param[out] qp handle to qp to set up
  50. * @param[out] hkva virtual address mapping
  51. * @return QP_SUCCESS on success, error code otherwise. Mapped address
  52. * is returned in hkva
  53. */
  54. static int32
  55. MapPages(struct MvpkmVM *vm,
  56. MPN base,
  57. uint32 nrPages,
  58. QPHandle *qp,
  59. HKVA *hkva)
  60. {
  61. HKVA *va;
  62. uint32 i;
  63. uint32 rc;
  64. struct page *basepfn = pfn_to_page(base);
  65. struct page **pages;
  66. BUG_ON(!vm); /* this would be very bad. */
  67. if (!hkva)
  68. return QP_ERROR_INVALID_ARGS;
  69. pages = kmalloc(nrPages * sizeof(MPN), GFP_KERNEL);
  70. if (!pages)
  71. return QP_ERROR_NO_MEM;
  72. /*
  73. * Map in the first page, read out the MPN vector
  74. */
  75. down_write(&vm->lockedSem);
  76. va = kmap(basepfn);
  77. if (!va) {
  78. rc = QP_ERROR_INVALID_ARGS;
  79. kfree(pages);
  80. qp->pages = NULL;
  81. goto out;
  82. }
  83. /*
  84. * Grab references and translate MPNs->PFNs
  85. */
  86. for (i = 0; i < nrPages; i++) {
  87. pages[i] = pfn_to_page(((MPN *)va)[i]);
  88. get_page(pages[i]);
  89. }
  90. /*
  91. * Clean up the first mapping and remap the entire vector
  92. */
  93. kunmap(basepfn);
  94. va = vmap(pages, nrPages, VM_MAP, PAGE_KERNEL);
  95. if (!va) {
  96. rc = QP_ERROR_NO_MEM;
  97. for (i = 0; i < nrPages; i++)
  98. put_page(pages[i]);
  99. kfree(pages);
  100. qp->pages = NULL;
  101. goto out;
  102. } else {
  103. *hkva = (HKVA)va;
  104. qp->pages = pages;
  105. }
  106. /*
  107. * Let's not leak mpns..
  108. */
  109. memset(va, 0x0, nrPages * PAGE_SIZE);
  110. rc = QP_SUCCESS;
  111. out:
  112. up_write(&vm->lockedSem);
  113. return rc;
  114. }
  115. /**
  116. * @brief Initialize all free queue pair entries and listeners
  117. */
  118. void
  119. QP_HostInit(void)
  120. {
  121. uint32 i;
  122. for (i = 0; i < QP_MAX_QUEUE_PAIRS; i++)
  123. QP_MakeInvalidQPHandle(&queuePairs[i]);
  124. for (i = 0; i < QP_MAX_LISTENERS; i++)
  125. listeners[i] = NULL;
  126. }
  127. /**
  128. * @brief Detaches a guest from a queue pair and notifies
  129. * any registered listeners through the detach callback
  130. * @param id id that guest requested a detach from, detaches all
  131. * queue pairs associated with a VM if the resource id == QP_INVALID_ID
  132. * @return QP_SUCCESS on success, appropriate error code otherwise
  133. */
  134. int32
  135. QP_GuestDetachRequest(QPId id)
  136. {
  137. QPHandle *qp;
  138. uint32 i;
  139. if (id.resource >= QP_MAX_ID && id.resource != QP_INVALID_ID)
  140. return QP_ERROR_INVALID_ARGS;
  141. QPLock();
  142. /*
  143. * Invalidate all queue pairs associated with this VM if
  144. * resource == QP_INVALID_ID
  145. */
  146. if (id.resource == QP_INVALID_ID) {
  147. for (i = 0; i < QP_MAX_QUEUE_PAIRS; i++) {
  148. qp = &queuePairs[i];
  149. if (qp->id.context == id.context && qp->peerDetachCB)
  150. qp->peerDetachCB(qp->detachData);
  151. }
  152. } else {
  153. qp = &queuePairs[id.resource];
  154. if (qp->peerDetachCB)
  155. qp->peerDetachCB(qp->detachData);
  156. }
  157. QPUnlock();
  158. return QP_SUCCESS;
  159. }
  160. /**
  161. * @brief Attaches a guest to shared memory region
  162. * @param vm guest to attach
  163. * @param args queue pair args structure:
  164. * - args->id: id of the region to attach to;
  165. * if id.resource == QP_INVALID_ID, then an id is assigned.
  166. * - args->capacity: total size of the region in bytes
  167. * - args->type: type of queue pair (e.g PVTCP)
  168. * @param base base machine page number that lists pages to map
  169. * @param nrPages number of pages to map
  170. * @return QP_SUCCESS on success, appropriate error code otherwise.
  171. */
  172. int32
  173. QP_GuestAttachRequest(struct MvpkmVM *vm,
  174. QPInitArgs *args,
  175. MPN base,
  176. uint32 nrPages)
  177. {
  178. int32 rc;
  179. HKVA hkva = 0;
  180. QPHandle *qp;
  181. uint32 i;
  182. if ((!QP_CheckArgs(args)) ||
  183. (vm->wsp->guestId != (Mksck_VmId)args->id.context) ||
  184. (args->capacity != (nrPages * PAGE_SIZE)))
  185. return QP_ERROR_INVALID_ARGS;
  186. QP_DBG("%s: Guest requested attach to [%u:%u] capacity: %u " \
  187. "type: %x base: %x nrPages: %u\n",
  188. __func__, args->id.context, args->id.resource, args->capacity,
  189. args->type, base, nrPages);
  190. QPLock();
  191. /*
  192. * Assign a resource id if id == QP_INVALID_ID
  193. */
  194. if (args->id.resource == QP_INVALID_ID) {
  195. for (i = 0; i < QP_MAX_QUEUE_PAIRS; i++)
  196. if (queuePairs[i].state == QP_STATE_FREE) {
  197. args->id.resource = i;
  198. QP_DBG("%s: Guest requested anonymous region," \
  199. " assigning resource id %u\n",
  200. __func__, args->id.resource);
  201. goto found;
  202. }
  203. rc = QP_ERROR_NO_MEM;
  204. goto out;
  205. }
  206. found:
  207. qp = queuePairs + args->id.resource;
  208. if (qp->state != QP_STATE_FREE) {
  209. rc = QP_ERROR_ALREADY_ATTACHED;
  210. goto out;
  211. }
  212. /*
  213. * Brand new queue pair, allocate some memory to back it and
  214. * initialize the entry.
  215. */
  216. rc = MapPages(vm, base, nrPages, qp, &hkva);
  217. if (rc != QP_SUCCESS)
  218. goto out;
  219. /* NB: reversed from the guest */
  220. qp->id = args->id;
  221. qp->capacity = args->capacity;
  222. qp->produceQ = (QHandle *)hkva;
  223. qp->consumeQ = (QHandle *)(hkva + args->capacity/2);
  224. qp->queueSize = args->capacity/2 - sizeof(QHandle);
  225. qp->type = args->type;
  226. qp->state = QP_STATE_GUEST_ATTACHED;
  227. /*
  228. * The qp is now assumed to be well-formed
  229. */
  230. QP_DBG("%s: Guest attached to region [%u:%u] capacity: %u HKVA: %x\n",
  231. __func__, args->id.context, args->id.resource,
  232. args->capacity, (uint32)hkva);
  233. rc = QP_SUCCESS;
  234. out:
  235. QPUnlock();
  236. if (rc != QP_SUCCESS)
  237. QP_DBG("%s: Failed to attach: %u\n", __func__, rc);
  238. return rc;
  239. }
  240. /**
  241. * @brief Attaches the host to the shared memory region. The guest
  242. * MUST have allocated the shmem region already or else this will fail.
  243. * @param args structure with the shared memory region id to attach to,
  244. * total size of the region in bytes, and type of queue pair (e.g PVTCP)
  245. * @param[in, out] qp handle to the queue pair to return
  246. * @return QP_SUCCESS on success, appropriate error code otherwise
  247. */
  248. int32
  249. QP_Attach(QPInitArgs *args,
  250. QPHandle **qp)
  251. {
  252. uint32 rc;
  253. if (!qp || !QP_CheckArgs(args))
  254. return QP_ERROR_INVALID_ARGS;
  255. QP_DBG("%s: Attaching to id: [%u:%u] capacity: %u\n",
  256. __func__, args->id.context, args->id.resource, args->capacity);
  257. QPLock();
  258. *qp = queuePairs + args->id.resource;
  259. if (!QP_CheckHandle(*qp)) {
  260. *qp = NULL;
  261. rc = QP_ERROR_INVALID_HANDLE;
  262. goto out;
  263. }
  264. if ((*qp)->state == QP_STATE_CONNECTED) {
  265. rc = QP_ERROR_ALREADY_ATTACHED;
  266. goto out;
  267. }
  268. if ((*qp)->state != QP_STATE_GUEST_ATTACHED) {
  269. rc = QP_ERROR_INVALID_HANDLE;
  270. goto out;
  271. }
  272. (*qp)->state = QP_STATE_CONNECTED;
  273. QP_DBG("%s: Attached!\n", __func__);
  274. rc = QP_SUCCESS;
  275. out:
  276. QPUnlock();
  277. return rc;
  278. }
  279. EXPORT_SYMBOL(QP_Attach);
  280. /**
  281. * @brief Detaches the host to the shared memory region.
  282. * @param[in, out] qp handle to the queue pair
  283. * @return QP_SUCCESS on success, appropriate error code otherwise
  284. * @sideeffects Frees memory
  285. */
  286. int32
  287. QP_Detach(QPHandle *qp)
  288. {
  289. uint32 rc;
  290. uint32 i;
  291. QPLock();
  292. if (!QP_CheckHandle(qp)) {
  293. rc = QP_ERROR_INVALID_HANDLE;
  294. goto out;
  295. }
  296. QP_DBG("%s: Freeing queue pair [%u:%u]\n",
  297. __func__, qp->id.context, qp->id.resource);
  298. BUG_ON(!qp->produceQ);
  299. BUG_ON(!qp->pages);
  300. BUG_ON((qp->state != QP_STATE_CONNECTED) &&
  301. (qp->state != QP_STATE_GUEST_ATTACHED));
  302. vunmap(qp->produceQ);
  303. for (i = 0; i < qp->capacity/PAGE_SIZE; i++)
  304. put_page(qp->pages[i]);
  305. kfree(qp->pages);
  306. QP_DBG("%s: Host detached from [%u:%u]\n",
  307. __func__, qp->id.context, qp->id.resource);
  308. QP_MakeInvalidQPHandle(qp);
  309. rc = QP_SUCCESS;
  310. out:
  311. QPUnlock();
  312. return rc;
  313. }
  314. /**
  315. * @brief Detaches and destroys all queue pairs associated with a given guest
  316. * @param vmID which VM to clean up
  317. * @sideeffects Destroys all queue pairs for guest vmID
  318. */
  319. void QP_DetachAll(Mksck_VmId vmID)
  320. {
  321. QPId id = {
  322. .context = (uint32)vmID,
  323. .resource = QP_INVALID_ID
  324. };
  325. QP_DBG("%s: Detaching all queue pairs from vmId context %u\n",
  326. __func__, vmID);
  327. QP_GuestDetachRequest(id);
  328. }
  329. /**
  330. * @brief Registers a listener into the queue pair system. Callbacks are
  331. * called with interrupts disabled and must not sleep.
  332. * @param listener listener to be called
  333. * @return QP_SUCCESS on success, QP_ERROR_NO_MEM if no more
  334. * listeners can be registered
  335. */
  336. int32
  337. QP_RegisterListener(const QPListener listener)
  338. {
  339. uint32 i;
  340. int32 rc = QP_ERROR_NO_MEM;
  341. QPLock();
  342. for (i = 0; i < QP_MAX_LISTENERS; i++)
  343. if (!listeners[i]) {
  344. listeners[i] = listener;
  345. QP_DBG("%s: Registered listener\n", __func__);
  346. rc = QP_SUCCESS;
  347. break;
  348. }
  349. QPUnlock();
  350. return rc;
  351. }
  352. EXPORT_SYMBOL(QP_RegisterListener);
  353. /**
  354. * @brief Unregister a listener service from the queue pair system.
  355. * @param listener listener to unregister
  356. * @return QP_SUCCESS on success, appropriate error code otherwise
  357. */
  358. int32
  359. QP_UnregisterListener(const QPListener listener)
  360. {
  361. uint32 i;
  362. int32 rc = QP_ERROR_INVALID_HANDLE;
  363. QPLock();
  364. for (i = 0; i < QP_MAX_LISTENERS; i++)
  365. if (listeners[i] == listener) {
  366. listeners[i] = NULL;
  367. QP_DBG("%s: Unregistered listener\n", __func__);
  368. rc = QP_SUCCESS;
  369. break;
  370. }
  371. QPUnlock();
  372. return rc;
  373. }
  374. EXPORT_SYMBOL(QP_UnregisterListener);
  375. /**
  376. * @brief Registers a callback to be called when the guest detaches
  377. * from a queue pair. Callbacks are called with interrupts and
  378. * must not sleep.
  379. * @param qp handle to the queue pair
  380. * @param callback callback to be called
  381. * @param data data to deliver to the callback
  382. * @return QP_SUCCESS on success, appropriate error code otherwise
  383. */
  384. int32
  385. QP_RegisterDetachCB(QPHandle *qp,
  386. void (*callback)(void *),
  387. void *data)
  388. {
  389. if (!QP_CheckHandle(qp))
  390. return QP_ERROR_INVALID_HANDLE;
  391. if (!callback)
  392. return QP_ERROR_INVALID_ARGS;
  393. qp->peerDetachCB = callback;
  394. qp->detachData = data;
  395. QP_DBG("%s: Registered detach callback\n", __func__);
  396. return QP_SUCCESS;
  397. }
  398. EXPORT_SYMBOL(QP_RegisterDetachCB);
  399. /**
  400. * @brief Noop on the host, only guests can initiate a notify
  401. * @param args noop
  402. * @return QP_SUCCESS
  403. */
  404. int32 QP_Notify(QPInitArgs *args)
  405. {
  406. return QP_SUCCESS;
  407. }
  408. EXPORT_SYMBOL(QP_Notify);
  409. /**
  410. * @brief Notify any registered listeners for the given queue pair
  411. * @param args initialization arguments used by the guest
  412. * @return QP_SUCCESS on success, error otherwise
  413. */
  414. int32 QP_NotifyListener(QPInitArgs *args)
  415. {
  416. int32 i;
  417. QPHandle *qp = NULL;
  418. if (!QP_CheckArgs(args))
  419. return QP_ERROR_INVALID_ARGS;
  420. /*
  421. * Iterate over listeners until one of them reports they handled it
  422. */
  423. QPLock();
  424. for (i = 0; i < QP_MAX_LISTENERS; i++)
  425. if (listeners[i]) {
  426. QP_DBG("Delivering attach event to listener...\n");
  427. if (listeners[i](args) == QP_SUCCESS)
  428. break;
  429. }
  430. if (i == QP_MAX_LISTENERS) {
  431. /*
  432. * No listener successfully probed this QP.
  433. * The guest DETACH HVC isn't implemented; we need compensate
  434. * for it by deallocating the QP here.
  435. * This is a workaround which assumes, more-or-less correctly,
  436. * that unsuccessful QP probes never lead to subsequent
  437. * host-attaching.
  438. */
  439. qp = &queuePairs[args->id.resource];
  440. }
  441. QPUnlock();
  442. if (qp)
  443. QP_Detach(qp);
  444. return QP_SUCCESS;
  445. }
  446. EXPORT_SYMBOL(QP_Detach);