mksck_shared.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  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. #include "mvp.h"
  21. #include "mksck_shared.h"
  22. /**
  23. * @file
  24. *
  25. * @brief The mksck shared area functions used by the monitor and the
  26. * kernel extension.
  27. *
  28. */
  29. /**
  30. * @brief try to locate a socket using an address.
  31. * @param mksckPage which shared page to look on.
  32. * ASSUMED: locked for shared access
  33. * @param addr address to check
  34. * @return pointer to mksck page with addr.
  35. * NULL if not found
  36. */
  37. Mksck *
  38. MksckPage_GetFromAddr(MksckPage *mksckPage,
  39. Mksck_Address addr)
  40. {
  41. Mksck *mksck = mksckPage->sockets;
  42. uint32 ii;
  43. ASSERT(addr.vmId == mksckPage->vmId);
  44. for (ii = mksckPage->numAllocSocks; ii--; mksck++) {
  45. if ((ATOMIC_GETO(mksck->refCount) != 0) &&
  46. (mksck->addr.addr == addr.addr))
  47. return mksck;
  48. }
  49. return NULL;
  50. }
  51. /**
  52. * @brief Close a monitor socket.
  53. *
  54. * @param mksck pointer to the socket control block
  55. */
  56. void
  57. Mksck_CloseCommon(Mksck *mksck)
  58. {
  59. /*
  60. * If a peer was connected, release the peer.
  61. */
  62. Mksck_DisconnectPeer(mksck);
  63. /*
  64. * Signal senders that this socket won't be read anymore.
  65. */
  66. while (Mutex_Lock(&mksck->mutex, MutexModeEX) < 0)
  67. ;
  68. mksck->shutDown = MKSCK_SHUT_WR | MKSCK_SHUT_RD;
  69. Mutex_UnlWake(&mksck->mutex, MutexModeEX, MKSCK_CVAR_ROOM, true);
  70. /*
  71. * Decrement reference count because it was set to 1 when opened.
  72. * It could still be non-zero after this if some other thread is
  73. * currently sending to this socket.
  74. */
  75. Mksck_DecRefc(mksck);
  76. }
  77. /**
  78. * @brief decrement socket reference count, free if it goes zero. Also do a
  79. * dmb first to make sure all activity on the struct is finished before
  80. * decrementing the ref count.
  81. * @param mksck socket
  82. */
  83. void
  84. Mksck_DecRefc(Mksck *mksck)
  85. {
  86. uint32 oldRefc;
  87. DMB();
  88. do {
  89. while ((oldRefc = ATOMIC_GETO(mksck->refCount)) == 1) {
  90. MksckPage *mksckPage = Mksck_ToSharedPage(mksck);
  91. /*
  92. * Socket refcount is going zero on a socket that locks
  93. * mksckPage in.
  94. * Lock shared page exclusive to make sure no one is
  95. * trying to look for this socket, thus preventing
  96. * socket's refcount from being incremented non-zero
  97. * once we decrement it to zero.
  98. */
  99. /*
  100. * Lock failed probably because of an interrupt.
  101. * Keep trying to lock until we succeed.
  102. */
  103. while (Mutex_Lock(&mksckPage->mutex, MutexModeEX) < 0)
  104. ;
  105. /*
  106. * No one is doing any lookups, so set refcount zero.
  107. */
  108. if (ATOMIC_SETIF(mksck->refCount, 0, 1)) {
  109. #if 0
  110. /**
  111. * @knownjira{MVP-1349}
  112. * The standard Log is not yet implemented in
  113. * kernel space.
  114. */
  115. KNOWN_BUG(MVP-1349);
  116. PRINTK("Mksck_DecRefc: %08X " \
  117. "shutDown %u, foundEmpty %u, " \
  118. "foundFull %u, blocked %u\n",
  119. mksck->addr.addr, mksck->shutDown,
  120. mksck->foundEmpty, mksck->foundFull,
  121. ATOMIC_GETO(mksck->mutex.blocked));
  122. #endif
  123. /*
  124. * Sockets can't have connected peers by the
  125. * time their refc hits 0. The owner should
  126. * have cleaned that up by now.
  127. */
  128. ASSERT(mksck->peer == 0);
  129. /*
  130. * Successfully set to zero, release mutex and
  131. * decrement shared page ref count as it was
  132. * incremented when the socket was opened.
  133. * This may free the shared page.
  134. */
  135. Mutex_Unlock(&mksckPage->mutex, MutexModeEX);
  136. MksckPage_DecRefc(mksckPage);
  137. return;
  138. }
  139. /*
  140. * Someone incremented refcount just before we locked
  141. * the mutex, so try it all again.
  142. */
  143. Mutex_Unlock(&mksckPage->mutex, MutexModeEX);
  144. }
  145. /*
  146. * Not going zero or doesn't lock mksckPage, simple decrement.
  147. */
  148. ASSERT(oldRefc != 0);
  149. } while (!ATOMIC_SETIF(mksck->refCount, oldRefc - 1, oldRefc));
  150. }
  151. /**
  152. * @brief Find an unused port.
  153. * @param mksckPage which shared page to look in.
  154. * Locked for exclusive access
  155. * @param port if not MKSCK_PORT_UNDEF test only this port
  156. * @return port allocated or MKSCK_PORT_UNDEF if none was found
  157. */
  158. Mksck_Port
  159. MksckPage_GetFreePort(MksckPage *mksckPage,
  160. Mksck_Port port)
  161. {
  162. Mksck_Address addr = { .addr = Mksck_AddrInit(mksckPage->vmId, port) };
  163. uint32 ii;
  164. if (port == MKSCK_PORT_UNDEF)
  165. for (ii = 0; ii < MKSCK_SOCKETS_PER_PAGE; ii++) {
  166. /*
  167. * Find an unused local socket number.
  168. */
  169. addr.port = mksckPage->portStore--;
  170. if (!addr.port)
  171. /*
  172. * Wrapped around, reset portStore
  173. */
  174. mksckPage->portStore = MKSCK_PORT_HIGH;
  175. if (!MksckPage_GetFromAddr(mksckPage, addr))
  176. return addr.port;
  177. }
  178. else if (!MksckPage_GetFromAddr(mksckPage, addr))
  179. return addr.port;
  180. return MKSCK_PORT_UNDEF;
  181. }
  182. /**
  183. * @brief Find an unused slot in the sockets[] array and allocate it.
  184. * @param mksckPage which shared page to look in.
  185. * Locked for exclusive access
  186. * @param addr what local address to assign to the socket
  187. * @return NULL: no slots available <br>
  188. * else: pointer to allocated socket
  189. */
  190. Mksck *
  191. MksckPage_AllocSocket(MksckPage *mksckPage,
  192. Mksck_Address addr)
  193. {
  194. Mksck *mksck;
  195. uint32 i;
  196. for (i = 0;
  197. (offsetof(MksckPage, sockets[i+1]) <= MKSCKPAGE_SIZE) &&
  198. (i < 8 * sizeof(mksckPage->wakeHostRecv)) &&
  199. (i < 8 * sizeof(mksckPage->wakeVMMRecv));
  200. i++) {
  201. mksck = &mksckPage->sockets[i];
  202. if (ATOMIC_GETO(mksck->refCount) == 0) {
  203. ATOMIC_SETV(mksck->refCount, 1);
  204. mksck->addr = addr;
  205. mksck->peerAddr.addr = MKSCK_ADDR_UNDEF;
  206. mksck->peer = NULL;
  207. mksck->index = i;
  208. mksck->write = 0;
  209. mksck->read = 0;
  210. mksck->shutDown = 0;
  211. mksck->foundEmpty = 0;
  212. mksck->foundFull = 0;
  213. ATOMIC_SETV(mksck->mutex.blocked, 0);
  214. mksck->rcvCBEntryMVA = 0;
  215. mksck->rcvCBParamMVA = 0;
  216. if (mksckPage->numAllocSocks < ++i)
  217. mksckPage->numAllocSocks = i;
  218. return mksck;
  219. }
  220. }
  221. return NULL;
  222. }
  223. /**
  224. * @brief increment read index over the packet just read
  225. * @param mksck socket packet was read from.
  226. * Locked for exclusive access
  227. * @param read current value of mksck->read
  228. * @param dg datagram at current mksck->read
  229. * @return with mksck->read updated to next packet <br>
  230. * false: buffer not empty <br>
  231. * true: buffer now empty
  232. */
  233. _Bool
  234. Mksck_IncReadIndex(Mksck *mksck,
  235. uint32 read,
  236. Mksck_Datagram *dg)
  237. {
  238. ASSERT(read == mksck->read);
  239. ASSERT((void *)dg == (void *)&mksck->buff[read]);
  240. read += MKSCK_DGSIZE(dg->len);
  241. if ((read > mksck->write) && (read >= mksck->wrap)) {
  242. ASSERT(read == mksck->wrap);
  243. read = 0;
  244. }
  245. mksck->read = read;
  246. return read == mksck->write;
  247. }
  248. /**
  249. * @brief find index in buffer that has enough room for a packet
  250. * @param mksck socket message is being sent to.
  251. * Locked for exclusive access
  252. * @param needed room needed, including dg header and rounded up
  253. * @return MKSCK_FINDSENDROOM_FULL: not enough room available <br>
  254. * else: index in mksck->buff for packet
  255. */
  256. uint32
  257. Mksck_FindSendRoom(Mksck *mksck,
  258. uint32 needed)
  259. {
  260. uint32 read, write;
  261. /*
  262. * We must leave at least one byte unused so receiver can distinguish
  263. * full from empty.
  264. */
  265. read = mksck->read;
  266. write = mksck->write;
  267. if (write == read) {
  268. if (needed < MKSCK_BUFSIZE) {
  269. mksck->read = 0;
  270. mksck->write = 0;
  271. return 0;
  272. }
  273. } else if (write < read) {
  274. if (write + needed < read)
  275. return write;
  276. } else {
  277. if (write + needed < MKSCK_BUFSIZE)
  278. return write;
  279. if ((write + needed == MKSCK_BUFSIZE) && (read > 0))
  280. return write;
  281. if (needed < read) {
  282. mksck->wrap = write;
  283. mksck->write = 0;
  284. return 0;
  285. }
  286. }
  287. return MKSCK_FINDSENDROOM_FULL;
  288. }
  289. /**
  290. * @brief increment read index over the packet just written
  291. * @param mksck socket packet was written to.
  292. * Locked for exclusive access
  293. * @param write as returned by @ref Mksck_FindSendRoom
  294. * @param needed as passed to @ref Mksck_FindSendRoom
  295. * @return with mksck->write updated to next packet
  296. */
  297. void
  298. Mksck_IncWriteIndex(Mksck *mksck,
  299. uint32 write,
  300. uint32 needed)
  301. {
  302. ASSERT(write == mksck->write);
  303. write += needed;
  304. if (write >= MKSCK_BUFSIZE) {
  305. ASSERT(write == MKSCK_BUFSIZE);
  306. mksck->wrap = MKSCK_BUFSIZE;
  307. write = 0;
  308. }
  309. ASSERT(write != mksck->read);
  310. mksck->write = write;
  311. }