pool.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. /*++
  2. Copyright (c) 2014 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. pool.c
  9. Abstract:
  10. This module implements support for core UEFI pool allocations.
  11. Author:
  12. Evan Green 28-Feb-2014
  13. Environment:
  14. Firmware
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include "ueficore.h"
  20. //
  21. // --------------------------------------------------------------------- Macros
  22. //
  23. //
  24. // This macro gets the pointer to the pool tail structure from the header.
  25. //
  26. #define POOL_HEADER_TO_TAIL(_Header) \
  27. ((PPOOL_TAIL)(((CHAR8 *)(_Header)) + (_Header)->Size - sizeof(POOL_TAIL)))
  28. //
  29. // This macro converts the given size in bytes to a pool bucket number.
  30. //
  31. #define POOL_SIZE_TO_LIST(_Size) ((_Size) >> POOL_SHIFT)
  32. //
  33. // This macro converts a bucket index conservatively back into a byte size.
  34. //
  35. #define POOL_LIST_TO_SIZE(_List) (((_List) + 1) << POOL_SHIFT)
  36. //
  37. // ---------------------------------------------------------------- Definitions
  38. //
  39. //
  40. // Define the constants put in pool structures to verify validity.
  41. //
  42. #define POOL_MAGIC 0x6C6F6F50 // 'looP'
  43. #define POOL_HEADER_MAGIC 0x6C6F6F50 // 'looP'
  44. #define POOL_FREE_MAGIC 0x65657246 // 'eerF'
  45. #define POOL_TAIL_MAGIC 0x6C696154 // 'liaT'
  46. //
  47. // Define the granularity of the pool buckets.
  48. //
  49. #define POOL_SHIFT 7
  50. //
  51. // Define the total size of the pool overhead.
  52. //
  53. #define POOL_OVERHEAD (sizeof(POOL_HEADER) + sizeof(POOL_TAIL))
  54. //
  55. // Define the number of pool buckets to store before it makes sense to just
  56. // start allocating pages directly.
  57. //
  58. #define MAX_POOL_LIST POOL_SIZE_TO_LIST(EFI_PAGE_SIZE)
  59. //
  60. // Define the level that pool raises to.
  61. //
  62. #define POOL_TPL TPL_NOTIFY
  63. //
  64. // ------------------------------------------------------ Data Type Definitions
  65. //
  66. typedef struct _POOL_FREE_ENTRY {
  67. LIST_ENTRY ListEntry;
  68. UINT32 Magic;
  69. UINT32 Index;
  70. } POOL_FREE_ENTRY, *PPOOL_FREE_ENTRY;
  71. typedef struct _POOL_HEADER {
  72. UINT32 Magic;
  73. UINT32 Padding;
  74. EFI_MEMORY_TYPE MemoryType;
  75. UINTN Size;
  76. } POOL_HEADER, *PPOOL_HEADER;
  77. typedef struct _POOL_TAIL {
  78. UINT32 Magic;
  79. UINT32 Padding;
  80. UINTN Size;
  81. } POOL_TAIL, *PPOOL_TAIL;
  82. typedef struct _POOL {
  83. LIST_ENTRY ListEntry;
  84. UINTN Magic;
  85. UINTN UsedSize;
  86. EFI_MEMORY_TYPE MemoryType;
  87. LIST_ENTRY FreeList[MAX_POOL_LIST];
  88. } POOL, *PPOOL;
  89. //
  90. // ----------------------------------------------- Internal Function Prototypes
  91. //
  92. VOID *
  93. EfipCoreAllocatePool (
  94. EFI_MEMORY_TYPE PoolType,
  95. UINTN Size
  96. );
  97. EFI_STATUS
  98. EfipCoreFreePool (
  99. VOID *Buffer
  100. );
  101. PPOOL
  102. EfipCoreLookupPool (
  103. EFI_MEMORY_TYPE PoolType
  104. );
  105. //
  106. // -------------------------------------------------------------------- Globals
  107. //
  108. //
  109. // Store the builtin pools for each memory type.
  110. //
  111. POOL EfiPool[EfiMaxMemoryType];
  112. //
  113. // Store the list of pools to search.
  114. //
  115. LIST_ENTRY EfiPoolList;
  116. //
  117. // ------------------------------------------------------------------ Functions
  118. //
  119. EFI_STATUS
  120. EfiCoreInitializePool (
  121. VOID
  122. )
  123. /*++
  124. Routine Description:
  125. This routine initializes EFI core pool services.
  126. Arguments:
  127. None.
  128. Return Value:
  129. EFI status code.
  130. --*/
  131. {
  132. PPOOL Pool;
  133. UINTN PoolIndex;
  134. UINTN PoolListIndex;
  135. INITIALIZE_LIST_HEAD(&EfiPoolList);
  136. for (PoolIndex = 0; PoolIndex < EfiMaxMemoryType; PoolIndex += 1) {
  137. Pool = &(EfiPool[PoolIndex]);
  138. Pool->Magic = POOL_MAGIC;
  139. Pool->UsedSize = 0;
  140. Pool->MemoryType = (EFI_MEMORY_TYPE)PoolIndex;
  141. for (PoolListIndex = 0;
  142. PoolListIndex < MAX_POOL_LIST;
  143. PoolListIndex += 1) {
  144. INITIALIZE_LIST_HEAD(&(Pool->FreeList[PoolListIndex]));
  145. }
  146. }
  147. return EFI_SUCCESS;
  148. }
  149. EFIAPI
  150. EFI_STATUS
  151. EfiCoreAllocatePool (
  152. EFI_MEMORY_TYPE PoolType,
  153. UINTN Size,
  154. VOID **Buffer
  155. )
  156. /*++
  157. Routine Description:
  158. This routine allocates memory from the heap.
  159. Arguments:
  160. PoolType - Supplies the type of pool to allocate.
  161. Size - Supplies the number of bytes to allocate from the pool.
  162. Buffer - Supplies a pointer where a pointer to the allocated buffer will
  163. be returned on success.
  164. Return Value:
  165. EFI_SUCCESS on success.
  166. EFI_OUT_OF_RESOURCES if memory could not be allocated.
  167. EFI_INVALID_PARAMETER if the pool type was invalid or the buffer is NULL.
  168. --*/
  169. {
  170. EFI_STATUS Status;
  171. //
  172. // Fail invalid types.
  173. //
  174. if ((((UINT32)PoolType >= EfiMaxMemoryType) &&
  175. ((UINT32)PoolType < 0x7FFFFFFF)) ||
  176. (PoolType == EfiConventionalMemory)) {
  177. return EFI_INVALID_PARAMETER;
  178. }
  179. if (Buffer == NULL) {
  180. return EFI_INVALID_PARAMETER;
  181. }
  182. Status = EfiCoreAcquireLockOrFail(&EfiMemoryLock);
  183. if (EFI_ERROR(Status)) {
  184. return EFI_OUT_OF_RESOURCES;
  185. }
  186. *Buffer = EfipCoreAllocatePool(PoolType, Size);
  187. EfiCoreReleaseLock(&EfiMemoryLock);
  188. if (*Buffer == NULL) {
  189. return EFI_OUT_OF_RESOURCES;
  190. }
  191. return EFI_SUCCESS;
  192. }
  193. EFIAPI
  194. EFI_STATUS
  195. EfiCoreFreePool (
  196. VOID *Buffer
  197. )
  198. /*++
  199. Routine Description:
  200. This routine frees heap allocated memory.
  201. Arguments:
  202. Buffer - Supplies a pointer to the buffer to free.
  203. Return Value:
  204. EFI_SUCCESS on success.
  205. EFI_INVALID_PARAMETER if the buffer was invalid.
  206. --*/
  207. {
  208. EFI_STATUS Status;
  209. if (Buffer == NULL) {
  210. return EFI_INVALID_PARAMETER;
  211. }
  212. EfiCoreAcquireLock(&EfiMemoryLock);
  213. Status = EfipCoreFreePool(Buffer);
  214. EfiCoreReleaseLock(&EfiMemoryLock);
  215. return Status;
  216. }
  217. //
  218. // --------------------------------------------------------- Internal Functions
  219. //
  220. VOID *
  221. EfipCoreAllocatePool (
  222. EFI_MEMORY_TYPE PoolType,
  223. UINTN Size
  224. )
  225. /*++
  226. Routine Description:
  227. This routine allocates memory from a pool.
  228. Arguments:
  229. PoolType - Supplies the type of pool to allocate.
  230. Size - Supplies the number of bytes to allocate from the pool.
  231. Return Value:
  232. Returns a pointer to the allocation on sucess.
  233. NULL on allocation failure.
  234. --*/
  235. {
  236. UINTN BlockSize;
  237. VOID *Buffer;
  238. PPOOL_FREE_ENTRY FreeEntry;
  239. PPOOL_HEADER Header;
  240. UINTN ListIndex;
  241. CHAR8 *NewPage;
  242. UINTN Offset;
  243. UINTN PageCount;
  244. PPOOL Pool;
  245. PPOOL_TAIL Tail;
  246. ASSERT(EfiCoreIsLockHeld(&EfiMemoryLock) != FALSE);
  247. Size = ALIGN_VARIABLE(Size);
  248. Size += POOL_OVERHEAD;
  249. ListIndex = POOL_SIZE_TO_LIST(Size);
  250. Pool = EfipCoreLookupPool(PoolType);
  251. if (Pool == NULL) {
  252. return NULL;
  253. }
  254. Header = NULL;
  255. //
  256. // If the allocation size is big enough, just allocate pages.
  257. //
  258. if (ListIndex >= MAX_POOL_LIST) {
  259. PageCount = ALIGN_VALUE(EFI_SIZE_TO_PAGES(Size),
  260. EFI_SIZE_TO_PAGES(EFI_MEMORY_EXPANSION_SIZE));
  261. Header = EfiCoreAllocatePoolPages(PoolType,
  262. PageCount,
  263. EFI_MEMORY_EXPANSION_SIZE);
  264. goto CoreAllocatePoolEnd;
  265. }
  266. //
  267. // If there's no free pool left in the bucket, allocate more pages.
  268. //
  269. if (LIST_EMPTY(&(Pool->FreeList[ListIndex])) != FALSE) {
  270. NewPage = EfiCoreAllocatePoolPages(
  271. PoolType,
  272. EFI_SIZE_TO_PAGES(EFI_MEMORY_EXPANSION_SIZE),
  273. EFI_MEMORY_EXPANSION_SIZE);
  274. if (NewPage == NULL) {
  275. goto CoreAllocatePoolEnd;
  276. }
  277. //
  278. // Carve up the new page into free pool blocks. Add as many as possible
  279. // to the desired list, then successively add the remainders to the
  280. // smaller lists.
  281. //
  282. Offset = 0;
  283. while (Offset < EFI_MEMORY_EXPANSION_SIZE) {
  284. ASSERT(ListIndex < MAX_POOL_LIST);
  285. BlockSize = POOL_LIST_TO_SIZE(ListIndex);
  286. while (Offset + BlockSize <= EFI_MEMORY_EXPANSION_SIZE) {
  287. FreeEntry = (PPOOL_FREE_ENTRY)(&(NewPage[Offset]));
  288. FreeEntry->Magic = POOL_FREE_MAGIC;
  289. FreeEntry->Index = ListIndex;
  290. INSERT_BEFORE(&(FreeEntry->ListEntry),
  291. &(Pool->FreeList[ListIndex]));
  292. Offset += BlockSize;
  293. }
  294. ListIndex -= 1;
  295. }
  296. ASSERT(Offset == EFI_MEMORY_EXPANSION_SIZE);
  297. ListIndex = POOL_SIZE_TO_LIST(Size);
  298. }
  299. //
  300. // Remove the first free entry from the pool.
  301. //
  302. FreeEntry = LIST_VALUE(Pool->FreeList[ListIndex].Next,
  303. POOL_FREE_ENTRY,
  304. ListEntry);
  305. LIST_REMOVE(&(FreeEntry->ListEntry));
  306. Header = (PPOOL_HEADER)FreeEntry;
  307. CoreAllocatePoolEnd:
  308. Buffer = NULL;
  309. if (Header != NULL) {
  310. //
  311. // Initialize the header and tail information.
  312. //
  313. Header->Magic = POOL_HEADER_MAGIC;
  314. Header->Size = Size;
  315. Header->MemoryType = PoolType;
  316. Tail = POOL_HEADER_TO_TAIL(Header);
  317. Tail->Magic = POOL_TAIL_MAGIC;
  318. Tail->Size = Size;
  319. Buffer = Header + 1;
  320. Pool->UsedSize += Size;
  321. }
  322. return Buffer;
  323. }
  324. EFI_STATUS
  325. EfipCoreFreePool (
  326. VOID *Buffer
  327. )
  328. /*++
  329. Routine Description:
  330. This routine frees heap allocated memory.
  331. Arguments:
  332. Buffer - Supplies a pointer to the buffer to free.
  333. Return Value:
  334. EFI_SUCCESS on success.
  335. EFI_INVALID_PARAMETER if the buffer was invalid.
  336. --*/
  337. {
  338. PPOOL_FREE_ENTRY FreeEntry;
  339. PPOOL_HEADER Header;
  340. UINTN ListIndex;
  341. UINTN PageCount;
  342. PPOOL Pool;
  343. PPOOL_TAIL Tail;
  344. ASSERT(Buffer != NULL);
  345. Header = Buffer;
  346. Header -= 1;
  347. ASSERT(Header != NULL);
  348. if (Header->Magic != POOL_HEADER_MAGIC) {
  349. ASSERT(FALSE);
  350. return EFI_INVALID_PARAMETER;
  351. }
  352. Tail = POOL_HEADER_TO_TAIL(Header);
  353. ASSERT(Tail != NULL);
  354. ASSERT(EfiCoreIsLockHeld(&EfiMemoryLock) != FALSE);
  355. if (Tail->Magic != POOL_TAIL_MAGIC) {
  356. ASSERT(FALSE);
  357. return EFI_INVALID_PARAMETER;
  358. }
  359. if (Tail->Size != Header->Size) {
  360. ASSERT(FALSE);
  361. return EFI_INVALID_PARAMETER;
  362. }
  363. //
  364. // Determine the pool type.
  365. //
  366. Pool = EfipCoreLookupPool(Header->MemoryType);
  367. if (Pool == NULL) {
  368. ASSERT(FALSE);
  369. return EFI_INVALID_PARAMETER;
  370. }
  371. ASSERT(Pool->UsedSize >= Header->Size);
  372. Pool->UsedSize -= Header->Size;
  373. //
  374. // If the pool is not on any list, free the pages directly.
  375. //
  376. ListIndex = POOL_SIZE_TO_LIST(Header->Size);
  377. if (ListIndex >= MAX_POOL_LIST) {
  378. PageCount = ALIGN_VALUE(EFI_SIZE_TO_PAGES(Header->Size),
  379. EFI_SIZE_TO_PAGES(EFI_MEMORY_EXPANSION_SIZE));
  380. EfiCoreFreePoolPages((EFI_PHYSICAL_ADDRESS)(UINTN)Header, PageCount);
  381. //
  382. // Put the pool entry back onto the free list.
  383. //
  384. } else {
  385. FreeEntry = (PPOOL_FREE_ENTRY)Header;
  386. FreeEntry->Magic = POOL_FREE_MAGIC;
  387. FreeEntry->Index = ListIndex;
  388. INSERT_AFTER(&(FreeEntry->ListEntry), &(Pool->FreeList[ListIndex]));
  389. }
  390. return EFI_SUCCESS;
  391. }
  392. PPOOL
  393. EfipCoreLookupPool (
  394. EFI_MEMORY_TYPE PoolType
  395. )
  396. /*++
  397. Routine Description:
  398. This routine finds the pool for the given pool type. If there is none,
  399. it creates one.
  400. Arguments:
  401. PoolType - Supplies the type of pool to allocate.
  402. Return Value:
  403. Returns a pointer to the pool for the specified type on success.
  404. NULL on allocation failure.
  405. --*/
  406. {
  407. PLIST_ENTRY CurrentEntry;
  408. UINTN FreeListIndex;
  409. PPOOL Pool;
  410. //
  411. // If the memory type is a builtin EFI type, then just return the pool
  412. // right quick.
  413. //
  414. if ((UINT32)PoolType < EfiMaxMemoryType) {
  415. return &(EfiPool[PoolType]);
  416. }
  417. //
  418. // Root through the existing pools to try to find it.
  419. //
  420. CurrentEntry = EfiPoolList.Next;
  421. while (CurrentEntry != &EfiPoolList) {
  422. Pool = LIST_VALUE(CurrentEntry, POOL, ListEntry);
  423. if (Pool->MemoryType == PoolType) {
  424. return Pool;
  425. }
  426. CurrentEntry = CurrentEntry->Next;
  427. }
  428. //
  429. // The pool wasn't found, it will need to be created.
  430. //
  431. Pool = EfipCoreAllocatePool(PoolType, sizeof(POOL));
  432. if (Pool == NULL) {
  433. return NULL;
  434. }
  435. Pool->Magic = POOL_MAGIC;
  436. Pool->UsedSize = 0;
  437. Pool->MemoryType = PoolType;
  438. for (FreeListIndex = 0; FreeListIndex < MAX_POOL_LIST; FreeListIndex += 1) {
  439. INITIALIZE_LIST_HEAD(&(Pool->FreeList[FreeListIndex]));
  440. }
  441. INSERT_BEFORE(&(Pool->ListEntry), &EfiPoolList);
  442. return Pool;
  443. }