GrantTable.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /** @file
  2. Grant Table function implementation.
  3. Grant Table are used to grant access to certain page of the current
  4. VM to an other VM.
  5. Author: Steven Smith (sos22@cam.ac.uk)
  6. Changes: Grzegorz Milos (gm281@cam.ac.uk)
  7. Copyright (C) 2006, Cambridge University
  8. Copyright (C) 2014, Citrix Ltd.
  9. SPDX-License-Identifier: BSD-2-Clause-Patent
  10. **/
  11. #include "XenBusDxe.h"
  12. #include <IndustryStandard/Xen/memory.h>
  13. #include <Library/XenHypercallLib.h>
  14. #include <Library/SynchronizationLib.h>
  15. #include "GrantTable.h"
  16. #define NR_RESERVED_ENTRIES 8
  17. #define NR_GRANT_FRAMES (FixedPcdGet32 (PcdXenGrantFrames))
  18. #define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * EFI_PAGE_SIZE / sizeof(grant_entry_v1_t))
  19. STATIC grant_entry_v1_t *GrantTable = NULL;
  20. STATIC grant_ref_t GrantList[NR_GRANT_ENTRIES];
  21. STATIC EFI_LOCK mGrantListLock;
  22. #ifdef GNT_DEBUG
  23. STATIC BOOLEAN GrantInUseList[NR_GRANT_ENTRIES];
  24. #endif
  25. STATIC
  26. VOID
  27. XenGrantTablePutFreeEntry (
  28. grant_ref_t Ref
  29. )
  30. {
  31. EfiAcquireLock (&mGrantListLock);
  32. #ifdef GNT_DEBUG
  33. ASSERT (GrantInUseList[Ref]);
  34. GrantInUseList[Ref] = FALSE;
  35. #endif
  36. GrantList[Ref] = GrantList[0];
  37. GrantList[0] = Ref;
  38. EfiReleaseLock (&mGrantListLock);
  39. }
  40. STATIC
  41. grant_ref_t
  42. XenGrantTableGetFreeEntry (
  43. VOID
  44. )
  45. {
  46. grant_ref_t Ref;
  47. EfiAcquireLock (&mGrantListLock);
  48. Ref = GrantList[0];
  49. ASSERT (Ref >= NR_RESERVED_ENTRIES && Ref < NR_GRANT_ENTRIES);
  50. GrantList[0] = GrantList[Ref];
  51. #ifdef GNT_DEBUG
  52. ASSERT (!GrantInUseList[Ref]);
  53. GrantInUseList[Ref] = TRUE;
  54. #endif
  55. EfiReleaseLock (&mGrantListLock);
  56. return Ref;
  57. }
  58. STATIC
  59. grant_ref_t
  60. XenGrantTableGrantAccess (
  61. IN domid_t DomainId,
  62. IN UINTN Frame,
  63. IN BOOLEAN ReadOnly
  64. )
  65. {
  66. grant_ref_t Ref;
  67. UINT16 Flags;
  68. ASSERT (GrantTable != NULL);
  69. Ref = XenGrantTableGetFreeEntry ();
  70. GrantTable[Ref].frame = (UINT32)Frame;
  71. GrantTable[Ref].domid = DomainId;
  72. MemoryFence ();
  73. Flags = GTF_permit_access;
  74. if (ReadOnly) {
  75. Flags |= GTF_readonly;
  76. }
  77. GrantTable[Ref].flags = Flags;
  78. return Ref;
  79. }
  80. STATIC
  81. EFI_STATUS
  82. XenGrantTableEndAccess (
  83. grant_ref_t Ref
  84. )
  85. {
  86. UINT16 Flags, OldFlags;
  87. ASSERT (GrantTable != NULL);
  88. ASSERT (Ref >= NR_RESERVED_ENTRIES && Ref < NR_GRANT_ENTRIES);
  89. OldFlags = GrantTable[Ref].flags;
  90. do {
  91. if ((Flags = OldFlags) & (GTF_reading | GTF_writing)) {
  92. DEBUG ((DEBUG_WARN, "WARNING: g.e. still in use! (%x)\n", Flags));
  93. return EFI_NOT_READY;
  94. }
  95. OldFlags = InterlockedCompareExchange16 (&GrantTable[Ref].flags, Flags, 0);
  96. } while (OldFlags != Flags);
  97. XenGrantTablePutFreeEntry (Ref);
  98. return EFI_SUCCESS;
  99. }
  100. VOID
  101. XenGrantTableInit (
  102. IN XENBUS_DEVICE *Dev
  103. )
  104. {
  105. xen_add_to_physmap_t Parameters;
  106. INTN Index;
  107. INTN ReturnCode;
  108. #ifdef GNT_DEBUG
  109. SetMem (GrantInUseList, sizeof (GrantInUseList), 1);
  110. #endif
  111. EfiInitializeLock (&mGrantListLock, TPL_NOTIFY);
  112. for (Index = NR_RESERVED_ENTRIES; Index < NR_GRANT_ENTRIES; Index++) {
  113. XenGrantTablePutFreeEntry ((grant_ref_t)Index);
  114. }
  115. GrantTable = (VOID *)(UINTN)Dev->XenIo->GrantTableAddress;
  116. for (Index = 0; Index < NR_GRANT_FRAMES; Index++) {
  117. Parameters.domid = DOMID_SELF;
  118. Parameters.idx = Index;
  119. Parameters.space = XENMAPSPACE_grant_table;
  120. Parameters.gpfn = (xen_pfn_t)((UINTN)GrantTable >> EFI_PAGE_SHIFT) + Index;
  121. ReturnCode = XenHypercallMemoryOp (XENMEM_add_to_physmap, &Parameters);
  122. if (ReturnCode != 0) {
  123. DEBUG ((
  124. DEBUG_ERROR,
  125. "Xen GrantTable, add_to_physmap hypercall error: %Ld\n",
  126. (INT64)ReturnCode
  127. ));
  128. }
  129. }
  130. }
  131. VOID
  132. XenGrantTableDeinit (
  133. XENBUS_DEVICE *Dev
  134. )
  135. {
  136. INTN ReturnCode, Index;
  137. xen_remove_from_physmap_t Parameters;
  138. if (GrantTable == NULL) {
  139. return;
  140. }
  141. for (Index = NR_GRANT_FRAMES - 1; Index >= 0; Index--) {
  142. Parameters.domid = DOMID_SELF;
  143. Parameters.gpfn = (xen_pfn_t)((UINTN)GrantTable >> EFI_PAGE_SHIFT) + Index;
  144. DEBUG ((
  145. DEBUG_INFO,
  146. "Xen GrantTable, removing %Lx\n",
  147. (UINT64)Parameters.gpfn
  148. ));
  149. ReturnCode = XenHypercallMemoryOp (XENMEM_remove_from_physmap, &Parameters);
  150. if (ReturnCode != 0) {
  151. DEBUG ((
  152. DEBUG_ERROR,
  153. "Xen GrantTable, remove_from_physmap hypercall error: %Ld\n",
  154. (INT64)ReturnCode
  155. ));
  156. }
  157. }
  158. GrantTable = NULL;
  159. }
  160. EFI_STATUS
  161. EFIAPI
  162. XenBusGrantAccess (
  163. IN XENBUS_PROTOCOL *This,
  164. IN domid_t DomainId,
  165. IN UINTN Frame, // MFN
  166. IN BOOLEAN ReadOnly,
  167. OUT grant_ref_t *RefPtr
  168. )
  169. {
  170. *RefPtr = XenGrantTableGrantAccess (DomainId, Frame, ReadOnly);
  171. return EFI_SUCCESS;
  172. }
  173. EFI_STATUS
  174. EFIAPI
  175. XenBusGrantEndAccess (
  176. IN XENBUS_PROTOCOL *This,
  177. IN grant_ref_t Ref
  178. )
  179. {
  180. return XenGrantTableEndAccess (Ref);
  181. }