Pool.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /** @file
  2. SMM Memory pool management functions.
  3. Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
  4. Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include "StandaloneMmCore.h"
  8. LIST_ENTRY mMmPoolLists[MAX_POOL_INDEX];
  9. //
  10. // To cache the MMRAM base since when Loading modules At fixed address feature is enabled,
  11. // all module is assigned an offset relative the MMRAM base in build time.
  12. //
  13. GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressMmramBase = 0;
  14. /**
  15. Called to initialize the memory service.
  16. @param MmramRangeCount Number of MMRAM Regions
  17. @param MmramRanges Pointer to MMRAM Descriptors
  18. **/
  19. VOID
  20. MmInitializeMemoryServices (
  21. IN UINTN MmramRangeCount,
  22. IN EFI_MMRAM_DESCRIPTOR *MmramRanges
  23. )
  24. {
  25. UINTN Index;
  26. //
  27. // Initialize Pool list
  28. //
  29. for (Index = sizeof (mMmPoolLists) / sizeof (*mMmPoolLists); Index > 0;) {
  30. InitializeListHead (&mMmPoolLists[--Index]);
  31. }
  32. //
  33. // Initialize free MMRAM regions
  34. //
  35. for (Index = 0; Index < MmramRangeCount; Index++) {
  36. //
  37. // BUGBUG: Add legacy MMRAM region is buggy.
  38. //
  39. if (MmramRanges[Index].CpuStart < BASE_1MB) {
  40. continue;
  41. }
  42. DEBUG ((
  43. DEBUG_INFO,
  44. "MmAddMemoryRegion %d : 0x%016lx - 0x%016lx\n",
  45. Index,
  46. MmramRanges[Index].CpuStart,
  47. MmramRanges[Index].PhysicalSize
  48. ));
  49. MmAddMemoryRegion (
  50. MmramRanges[Index].CpuStart,
  51. MmramRanges[Index].PhysicalSize,
  52. EfiConventionalMemory,
  53. MmramRanges[Index].RegionState
  54. );
  55. }
  56. }
  57. /**
  58. Internal Function. Allocate a pool by specified PoolIndex.
  59. @param PoolIndex Index which indicate the Pool size.
  60. @param FreePoolHdr The returned Free pool.
  61. @retval EFI_OUT_OF_RESOURCES Allocation failed.
  62. @retval EFI_SUCCESS Pool successfully allocated.
  63. **/
  64. EFI_STATUS
  65. InternalAllocPoolByIndex (
  66. IN UINTN PoolIndex,
  67. OUT FREE_POOL_HEADER **FreePoolHdr
  68. )
  69. {
  70. EFI_STATUS Status;
  71. FREE_POOL_HEADER *Hdr;
  72. EFI_PHYSICAL_ADDRESS Address;
  73. ASSERT (PoolIndex <= MAX_POOL_INDEX);
  74. Status = EFI_SUCCESS;
  75. Hdr = NULL;
  76. if (PoolIndex == MAX_POOL_INDEX) {
  77. Status = MmInternalAllocatePages (
  78. AllocateAnyPages,
  79. EfiRuntimeServicesData,
  80. EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1),
  81. &Address
  82. );
  83. if (EFI_ERROR (Status)) {
  84. return EFI_OUT_OF_RESOURCES;
  85. }
  86. Hdr = (FREE_POOL_HEADER *)(UINTN)Address;
  87. } else if (!IsListEmpty (&mMmPoolLists[PoolIndex])) {
  88. Hdr = BASE_CR (GetFirstNode (&mMmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);
  89. RemoveEntryList (&Hdr->Link);
  90. } else {
  91. Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);
  92. if (!EFI_ERROR (Status)) {
  93. Hdr->Header.Size >>= 1;
  94. Hdr->Header.Available = TRUE;
  95. InsertHeadList (&mMmPoolLists[PoolIndex], &Hdr->Link);
  96. Hdr = (FREE_POOL_HEADER *)((UINT8 *)Hdr + Hdr->Header.Size);
  97. }
  98. }
  99. if (!EFI_ERROR (Status)) {
  100. Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;
  101. Hdr->Header.Available = FALSE;
  102. }
  103. *FreePoolHdr = Hdr;
  104. return Status;
  105. }
  106. /**
  107. Internal Function. Free a pool by specified PoolIndex.
  108. @param FreePoolHdr The pool to free.
  109. @retval EFI_SUCCESS Pool successfully freed.
  110. **/
  111. EFI_STATUS
  112. InternalFreePoolByIndex (
  113. IN FREE_POOL_HEADER *FreePoolHdr
  114. )
  115. {
  116. UINTN PoolIndex;
  117. ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);
  118. ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);
  119. ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);
  120. PoolIndex = (UINTN)(HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);
  121. FreePoolHdr->Header.Available = TRUE;
  122. ASSERT (PoolIndex < MAX_POOL_INDEX);
  123. InsertHeadList (&mMmPoolLists[PoolIndex], &FreePoolHdr->Link);
  124. return EFI_SUCCESS;
  125. }
  126. /**
  127. Allocate pool of a particular type.
  128. @param PoolType Type of pool to allocate.
  129. @param Size The amount of pool to allocate.
  130. @param Buffer The address to return a pointer to the allocated
  131. pool.
  132. @retval EFI_INVALID_PARAMETER PoolType not valid.
  133. @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
  134. @retval EFI_SUCCESS Pool successfully allocated.
  135. **/
  136. EFI_STATUS
  137. EFIAPI
  138. MmInternalAllocatePool (
  139. IN EFI_MEMORY_TYPE PoolType,
  140. IN UINTN Size,
  141. OUT VOID **Buffer
  142. )
  143. {
  144. POOL_HEADER *PoolHdr;
  145. FREE_POOL_HEADER *FreePoolHdr;
  146. EFI_STATUS Status;
  147. EFI_PHYSICAL_ADDRESS Address;
  148. UINTN PoolIndex;
  149. if ((PoolType != EfiRuntimeServicesCode) &&
  150. (PoolType != EfiRuntimeServicesData))
  151. {
  152. return EFI_INVALID_PARAMETER;
  153. }
  154. Size += sizeof (*PoolHdr);
  155. if (Size > MAX_POOL_SIZE) {
  156. Size = EFI_SIZE_TO_PAGES (Size);
  157. Status = MmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);
  158. if (EFI_ERROR (Status)) {
  159. return Status;
  160. }
  161. PoolHdr = (POOL_HEADER *)(UINTN)Address;
  162. PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);
  163. PoolHdr->Available = FALSE;
  164. *Buffer = PoolHdr + 1;
  165. return Status;
  166. }
  167. Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;
  168. PoolIndex = (UINTN)HighBitSet32 ((UINT32)Size);
  169. if ((Size & (Size - 1)) != 0) {
  170. PoolIndex++;
  171. }
  172. Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);
  173. if (!EFI_ERROR (Status)) {
  174. *Buffer = &FreePoolHdr->Header + 1;
  175. }
  176. return Status;
  177. }
  178. /**
  179. Allocate pool of a particular type.
  180. @param PoolType Type of pool to allocate.
  181. @param Size The amount of pool to allocate.
  182. @param Buffer The address to return a pointer to the allocated
  183. pool.
  184. @retval EFI_INVALID_PARAMETER PoolType not valid.
  185. @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
  186. @retval EFI_SUCCESS Pool successfully allocated.
  187. **/
  188. EFI_STATUS
  189. EFIAPI
  190. MmAllocatePool (
  191. IN EFI_MEMORY_TYPE PoolType,
  192. IN UINTN Size,
  193. OUT VOID **Buffer
  194. )
  195. {
  196. EFI_STATUS Status;
  197. Status = MmInternalAllocatePool (PoolType, Size, Buffer);
  198. return Status;
  199. }
  200. /**
  201. Frees pool.
  202. @param Buffer The allocated pool entry to free.
  203. @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
  204. @retval EFI_SUCCESS Pool successfully freed.
  205. **/
  206. EFI_STATUS
  207. EFIAPI
  208. MmInternalFreePool (
  209. IN VOID *Buffer
  210. )
  211. {
  212. FREE_POOL_HEADER *FreePoolHdr;
  213. if (Buffer == NULL) {
  214. return EFI_INVALID_PARAMETER;
  215. }
  216. FreePoolHdr = (FREE_POOL_HEADER *)((POOL_HEADER *)Buffer - 1);
  217. ASSERT (!FreePoolHdr->Header.Available);
  218. if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {
  219. ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);
  220. ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);
  221. return MmInternalFreePages (
  222. (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,
  223. EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)
  224. );
  225. }
  226. return InternalFreePoolByIndex (FreePoolHdr);
  227. }
  228. /**
  229. Frees pool.
  230. @param Buffer The allocated pool entry to free.
  231. @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
  232. @retval EFI_SUCCESS Pool successfully freed.
  233. **/
  234. EFI_STATUS
  235. EFIAPI
  236. MmFreePool (
  237. IN VOID *Buffer
  238. )
  239. {
  240. EFI_STATUS Status;
  241. Status = MmInternalFreePool (Buffer);
  242. return Status;
  243. }