Pool.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  1. /** @file
  2. UEFI Memory pool management functions.
  3. Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "DxeMain.h"
  7. #include "Imem.h"
  8. #include "HeapGuard.h"
  9. STATIC EFI_LOCK mPoolMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
  10. #define POOL_FREE_SIGNATURE SIGNATURE_32('p','f','r','0')
  11. typedef struct {
  12. UINT32 Signature;
  13. UINT32 Index;
  14. LIST_ENTRY Link;
  15. } POOL_FREE;
  16. #define POOL_HEAD_SIGNATURE SIGNATURE_32('p','h','d','0')
  17. #define POOLPAGE_HEAD_SIGNATURE SIGNATURE_32('p','h','d','1')
  18. typedef struct {
  19. UINT32 Signature;
  20. UINT32 Reserved;
  21. EFI_MEMORY_TYPE Type;
  22. UINTN Size;
  23. CHAR8 Data[1];
  24. } POOL_HEAD;
  25. #define SIZE_OF_POOL_HEAD OFFSET_OF(POOL_HEAD,Data)
  26. #define POOL_TAIL_SIGNATURE SIGNATURE_32('p','t','a','l')
  27. typedef struct {
  28. UINT32 Signature;
  29. UINT32 Reserved;
  30. UINTN Size;
  31. } POOL_TAIL;
  32. #define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))
  33. #define HEAD_TO_TAIL(a) \
  34. ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));
  35. //
  36. // Each element is the sum of the 2 previous ones: this allows us to migrate
  37. // blocks between bins by splitting them up, while not wasting too much memory
  38. // as we would in a strict power-of-2 sequence
  39. //
  40. STATIC CONST UINT16 mPoolSizeTable[] = {
  41. 128, 256, 384, 640, 1024, 1664, 2688, 4352, 7040, 11392, 18432, 29824
  42. };
  43. #define SIZE_TO_LIST(a) (GetPoolIndexFromSize (a))
  44. #define LIST_TO_SIZE(a) (mPoolSizeTable [a])
  45. #define MAX_POOL_LIST (ARRAY_SIZE (mPoolSizeTable))
  46. #define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)
  47. //
  48. // Globals
  49. //
  50. #define POOL_SIGNATURE SIGNATURE_32('p','l','s','t')
  51. typedef struct {
  52. INTN Signature;
  53. UINTN Used;
  54. EFI_MEMORY_TYPE MemoryType;
  55. LIST_ENTRY FreeList[MAX_POOL_LIST];
  56. LIST_ENTRY Link;
  57. } POOL;
  58. //
  59. // Pool header for each memory type.
  60. //
  61. POOL mPoolHead[EfiMaxMemoryType];
  62. //
  63. // List of pool header to search for the appropriate memory type.
  64. //
  65. LIST_ENTRY mPoolHeadList = INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList);
  66. /**
  67. Get pool size table index from the specified size.
  68. @param Size The specified size to get index from pool table.
  69. @return The index of pool size table.
  70. **/
  71. STATIC
  72. UINTN
  73. GetPoolIndexFromSize (
  74. UINTN Size
  75. )
  76. {
  77. UINTN Index;
  78. for (Index = 0; Index < MAX_POOL_LIST; Index++) {
  79. if (mPoolSizeTable[Index] >= Size) {
  80. return Index;
  81. }
  82. }
  83. return MAX_POOL_LIST;
  84. }
  85. /**
  86. Called to initialize the pool.
  87. **/
  88. VOID
  89. CoreInitializePool (
  90. VOID
  91. )
  92. {
  93. UINTN Type;
  94. UINTN Index;
  95. for (Type = 0; Type < EfiMaxMemoryType; Type++) {
  96. mPoolHead[Type].Signature = 0;
  97. mPoolHead[Type].Used = 0;
  98. mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE)Type;
  99. for (Index = 0; Index < MAX_POOL_LIST; Index++) {
  100. InitializeListHead (&mPoolHead[Type].FreeList[Index]);
  101. }
  102. }
  103. }
  104. /**
  105. Look up pool head for specified memory type.
  106. @param MemoryType Memory type of which pool head is looked for
  107. @return Pointer of Corresponding pool head.
  108. **/
  109. POOL *
  110. LookupPoolHead (
  111. IN EFI_MEMORY_TYPE MemoryType
  112. )
  113. {
  114. LIST_ENTRY *Link;
  115. POOL *Pool;
  116. UINTN Index;
  117. if ((UINT32)MemoryType < EfiMaxMemoryType) {
  118. return &mPoolHead[MemoryType];
  119. }
  120. //
  121. // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI
  122. // OS loaders that are provided by operating system vendors.
  123. // MemoryType values in the range 0x70000000..0x7FFFFFFF are reserved for OEM use.
  124. //
  125. if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
  126. for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {
  127. Pool = CR (Link, POOL, Link, POOL_SIGNATURE);
  128. if (Pool->MemoryType == MemoryType) {
  129. return Pool;
  130. }
  131. }
  132. Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL), FALSE);
  133. if (Pool == NULL) {
  134. return NULL;
  135. }
  136. Pool->Signature = POOL_SIGNATURE;
  137. Pool->Used = 0;
  138. Pool->MemoryType = MemoryType;
  139. for (Index = 0; Index < MAX_POOL_LIST; Index++) {
  140. InitializeListHead (&Pool->FreeList[Index]);
  141. }
  142. InsertHeadList (&mPoolHeadList, &Pool->Link);
  143. return Pool;
  144. }
  145. return NULL;
  146. }
  147. /**
  148. Allocate pool of a particular type.
  149. @param PoolType Type of pool to allocate
  150. @param Size The amount of pool to allocate
  151. @param Buffer The address to return a pointer to the allocated
  152. pool
  153. @retval EFI_INVALID_PARAMETER Buffer is NULL.
  154. PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.
  155. PoolType is EfiPersistentMemory.
  156. @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
  157. @retval EFI_SUCCESS Pool successfully allocated.
  158. **/
  159. EFI_STATUS
  160. EFIAPI
  161. CoreInternalAllocatePool (
  162. IN EFI_MEMORY_TYPE PoolType,
  163. IN UINTN Size,
  164. OUT VOID **Buffer
  165. )
  166. {
  167. EFI_STATUS Status;
  168. BOOLEAN NeedGuard;
  169. //
  170. // If it's not a valid type, fail it
  171. //
  172. if (((PoolType >= EfiMaxMemoryType) && (PoolType < MEMORY_TYPE_OEM_RESERVED_MIN)) ||
  173. (PoolType == EfiConventionalMemory) || (PoolType == EfiPersistentMemory) || (PoolType == EfiUnacceptedMemoryType))
  174. {
  175. return EFI_INVALID_PARAMETER;
  176. }
  177. if (Buffer == NULL) {
  178. return EFI_INVALID_PARAMETER;
  179. }
  180. *Buffer = NULL;
  181. //
  182. // If size is too large, fail it
  183. // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES
  184. //
  185. if (Size > MAX_POOL_SIZE) {
  186. return EFI_OUT_OF_RESOURCES;
  187. }
  188. NeedGuard = IsPoolTypeToGuard (PoolType) && !mOnGuarding;
  189. //
  190. // Acquire the memory lock and make the allocation
  191. //
  192. Status = CoreAcquireLockOrFail (&mPoolMemoryLock);
  193. if (EFI_ERROR (Status)) {
  194. return EFI_OUT_OF_RESOURCES;
  195. }
  196. *Buffer = CoreAllocatePoolI (PoolType, Size, NeedGuard);
  197. CoreReleaseLock (&mPoolMemoryLock);
  198. return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
  199. }
  200. /**
  201. Allocate pool of a particular type.
  202. @param PoolType Type of pool to allocate
  203. @param Size The amount of pool to allocate
  204. @param Buffer The address to return a pointer to the allocated
  205. pool
  206. @retval EFI_INVALID_PARAMETER Buffer is NULL.
  207. PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.
  208. PoolType is EfiPersistentMemory.
  209. @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
  210. @retval EFI_SUCCESS Pool successfully allocated.
  211. **/
  212. EFI_STATUS
  213. EFIAPI
  214. CoreAllocatePool (
  215. IN EFI_MEMORY_TYPE PoolType,
  216. IN UINTN Size,
  217. OUT VOID **Buffer
  218. )
  219. {
  220. EFI_STATUS Status;
  221. Status = CoreInternalAllocatePool (PoolType, Size, Buffer);
  222. if (!EFI_ERROR (Status)) {
  223. CoreUpdateProfile (
  224. (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
  225. MemoryProfileActionAllocatePool,
  226. PoolType,
  227. Size,
  228. *Buffer,
  229. NULL
  230. );
  231. InstallMemoryAttributesTableOnMemoryAllocation (PoolType);
  232. }
  233. return Status;
  234. }
  235. /**
  236. Internal function. Used by the pool functions to allocate pages
  237. to back pool allocation requests.
  238. @param PoolType The type of memory for the new pool pages
  239. @param NoPages No of pages to allocate
  240. @param Granularity Bits to align.
  241. @param NeedGuard Flag to indicate Guard page is needed or not
  242. @return The allocated memory, or NULL
  243. **/
  244. STATIC
  245. VOID *
  246. CoreAllocatePoolPagesI (
  247. IN EFI_MEMORY_TYPE PoolType,
  248. IN UINTN NoPages,
  249. IN UINTN Granularity,
  250. IN BOOLEAN NeedGuard
  251. )
  252. {
  253. VOID *Buffer;
  254. EFI_STATUS Status;
  255. Status = CoreAcquireLockOrFail (&gMemoryLock);
  256. if (EFI_ERROR (Status)) {
  257. return NULL;
  258. }
  259. Buffer = CoreAllocatePoolPages (PoolType, NoPages, Granularity, NeedGuard);
  260. CoreReleaseMemoryLock ();
  261. if (Buffer != NULL) {
  262. if (NeedGuard) {
  263. SetGuardForMemory ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, NoPages);
  264. }
  265. ApplyMemoryProtectionPolicy (
  266. EfiConventionalMemory,
  267. PoolType,
  268. (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer,
  269. EFI_PAGES_TO_SIZE (NoPages)
  270. );
  271. }
  272. return Buffer;
  273. }
  274. /**
  275. Internal function to allocate pool of a particular type.
  276. Caller must have the memory lock held
  277. @param PoolType Type of pool to allocate
  278. @param Size The amount of pool to allocate
  279. @param NeedGuard Flag to indicate Guard page is needed or not
  280. @return The allocate pool, or NULL
  281. **/
  282. VOID *
  283. CoreAllocatePoolI (
  284. IN EFI_MEMORY_TYPE PoolType,
  285. IN UINTN Size,
  286. IN BOOLEAN NeedGuard
  287. )
  288. {
  289. POOL *Pool;
  290. POOL_FREE *Free;
  291. POOL_HEAD *Head;
  292. POOL_TAIL *Tail;
  293. CHAR8 *NewPage;
  294. VOID *Buffer;
  295. UINTN Index;
  296. UINTN FSize;
  297. UINTN Offset, MaxOffset;
  298. UINTN NoPages;
  299. UINTN Granularity;
  300. BOOLEAN HasPoolTail;
  301. BOOLEAN PageAsPool;
  302. ASSERT_LOCKED (&mPoolMemoryLock);
  303. if ((PoolType == EfiACPIReclaimMemory) ||
  304. (PoolType == EfiACPIMemoryNVS) ||
  305. (PoolType == EfiRuntimeServicesCode) ||
  306. (PoolType == EfiRuntimeServicesData))
  307. {
  308. Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
  309. } else {
  310. Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
  311. }
  312. //
  313. // Adjust the size by the pool header & tail overhead
  314. //
  315. HasPoolTail = !(NeedGuard &&
  316. ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
  317. PageAsPool = (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) && !mOnGuarding);
  318. //
  319. // Adjusting the Size to be of proper alignment so that
  320. // we don't get an unaligned access fault later when
  321. // pool_Tail is being initialized
  322. //
  323. Size = ALIGN_VARIABLE (Size);
  324. Size += POOL_OVERHEAD;
  325. Index = SIZE_TO_LIST (Size);
  326. Pool = LookupPoolHead (PoolType);
  327. if (Pool == NULL) {
  328. return NULL;
  329. }
  330. Head = NULL;
  331. //
  332. // If allocation is over max size, just allocate pages for the request
  333. // (slow)
  334. //
  335. if ((Index >= SIZE_TO_LIST (Granularity)) || NeedGuard || PageAsPool) {
  336. if (!HasPoolTail) {
  337. Size -= sizeof (POOL_TAIL);
  338. }
  339. NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;
  340. NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);
  341. Head = CoreAllocatePoolPagesI (PoolType, NoPages, Granularity, NeedGuard);
  342. if (NeedGuard) {
  343. Head = AdjustPoolHeadA ((EFI_PHYSICAL_ADDRESS)(UINTN)Head, NoPages, Size);
  344. }
  345. goto Done;
  346. }
  347. //
  348. // If there's no free pool in the proper list size, go get some more pages
  349. //
  350. if (IsListEmpty (&Pool->FreeList[Index])) {
  351. Offset = LIST_TO_SIZE (Index);
  352. MaxOffset = Granularity;
  353. //
  354. // Check the bins holding larger blocks, and carve one up if needed
  355. //
  356. while (++Index < SIZE_TO_LIST (Granularity)) {
  357. if (!IsListEmpty (&Pool->FreeList[Index])) {
  358. Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);
  359. RemoveEntryList (&Free->Link);
  360. NewPage = (VOID *)Free;
  361. MaxOffset = LIST_TO_SIZE (Index);
  362. goto Carve;
  363. }
  364. }
  365. //
  366. // Get another page
  367. //
  368. NewPage = CoreAllocatePoolPagesI (
  369. PoolType,
  370. EFI_SIZE_TO_PAGES (Granularity),
  371. Granularity,
  372. NeedGuard
  373. );
  374. if (NewPage == NULL) {
  375. goto Done;
  376. }
  377. //
  378. // Serve the allocation request from the head of the allocated block
  379. //
  380. Carve:
  381. Head = (POOL_HEAD *)NewPage;
  382. //
  383. // Carve up remaining space into free pool blocks
  384. //
  385. Index--;
  386. while (Offset < MaxOffset) {
  387. ASSERT (Index < MAX_POOL_LIST);
  388. FSize = LIST_TO_SIZE (Index);
  389. while (Offset + FSize <= MaxOffset) {
  390. Free = (POOL_FREE *)&NewPage[Offset];
  391. Free->Signature = POOL_FREE_SIGNATURE;
  392. Free->Index = (UINT32)Index;
  393. InsertHeadList (&Pool->FreeList[Index], &Free->Link);
  394. Offset += FSize;
  395. }
  396. Index -= 1;
  397. }
  398. ASSERT (Offset == MaxOffset);
  399. goto Done;
  400. }
  401. //
  402. // Remove entry from free pool list
  403. //
  404. Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);
  405. RemoveEntryList (&Free->Link);
  406. Head = (POOL_HEAD *)Free;
  407. Done:
  408. Buffer = NULL;
  409. if (Head != NULL) {
  410. //
  411. // Account the allocation
  412. //
  413. Pool->Used += Size;
  414. //
  415. // If we have a pool buffer, fill in the header & tail info
  416. //
  417. Head->Signature = (PageAsPool) ? POOLPAGE_HEAD_SIGNATURE : POOL_HEAD_SIGNATURE;
  418. Head->Size = Size;
  419. Head->Type = (EFI_MEMORY_TYPE)PoolType;
  420. Buffer = Head->Data;
  421. if (HasPoolTail) {
  422. Tail = HEAD_TO_TAIL (Head);
  423. Tail->Signature = POOL_TAIL_SIGNATURE;
  424. Tail->Size = Size;
  425. Size -= POOL_OVERHEAD;
  426. } else {
  427. Size -= SIZE_OF_POOL_HEAD;
  428. }
  429. DEBUG_CLEAR_MEMORY (Buffer, Size);
  430. DEBUG ((
  431. DEBUG_POOL,
  432. "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n",
  433. PoolType,
  434. Buffer,
  435. (UINT64)Size,
  436. (UINT64)Pool->Used
  437. ));
  438. } else {
  439. DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64)Size));
  440. }
  441. return Buffer;
  442. }
  443. /**
  444. Frees pool.
  445. @param Buffer The allocated pool entry to free
  446. @param PoolType Pointer to pool type
  447. @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
  448. @retval EFI_SUCCESS Pool successfully freed.
  449. **/
  450. EFI_STATUS
  451. EFIAPI
  452. CoreInternalFreePool (
  453. IN VOID *Buffer,
  454. OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
  455. )
  456. {
  457. EFI_STATUS Status;
  458. if (Buffer == NULL) {
  459. return EFI_INVALID_PARAMETER;
  460. }
  461. CoreAcquireLock (&mPoolMemoryLock);
  462. Status = CoreFreePoolI (Buffer, PoolType);
  463. CoreReleaseLock (&mPoolMemoryLock);
  464. return Status;
  465. }
  466. /**
  467. Frees pool.
  468. @param Buffer The allocated pool entry to free
  469. @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
  470. @retval EFI_SUCCESS Pool successfully freed.
  471. **/
  472. EFI_STATUS
  473. EFIAPI
  474. CoreFreePool (
  475. IN VOID *Buffer
  476. )
  477. {
  478. EFI_STATUS Status;
  479. EFI_MEMORY_TYPE PoolType;
  480. Status = CoreInternalFreePool (Buffer, &PoolType);
  481. if (!EFI_ERROR (Status)) {
  482. CoreUpdateProfile (
  483. (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
  484. MemoryProfileActionFreePool,
  485. PoolType,
  486. 0,
  487. Buffer,
  488. NULL
  489. );
  490. InstallMemoryAttributesTableOnMemoryAllocation (PoolType);
  491. }
  492. return Status;
  493. }
  494. /**
  495. Internal function. Frees pool pages allocated via CoreAllocatePoolPagesI().
  496. @param PoolType The type of memory for the pool pages
  497. @param Memory The base address to free
  498. @param NoPages The number of pages to free
  499. **/
  500. STATIC
  501. VOID
  502. CoreFreePoolPagesI (
  503. IN EFI_MEMORY_TYPE PoolType,
  504. IN EFI_PHYSICAL_ADDRESS Memory,
  505. IN UINTN NoPages
  506. )
  507. {
  508. CoreAcquireMemoryLock ();
  509. CoreFreePoolPages (Memory, NoPages);
  510. CoreReleaseMemoryLock ();
  511. GuardFreedPagesChecked (Memory, NoPages);
  512. ApplyMemoryProtectionPolicy (
  513. PoolType,
  514. EfiConventionalMemory,
  515. (EFI_PHYSICAL_ADDRESS)(UINTN)Memory,
  516. EFI_PAGES_TO_SIZE (NoPages)
  517. );
  518. }
  519. /**
  520. Internal function. Frees guarded pool pages.
  521. @param PoolType The type of memory for the pool pages
  522. @param Memory The base address to free
  523. @param NoPages The number of pages to free
  524. **/
  525. STATIC
  526. VOID
  527. CoreFreePoolPagesWithGuard (
  528. IN EFI_MEMORY_TYPE PoolType,
  529. IN EFI_PHYSICAL_ADDRESS Memory,
  530. IN UINTN NoPages
  531. )
  532. {
  533. EFI_PHYSICAL_ADDRESS MemoryGuarded;
  534. UINTN NoPagesGuarded;
  535. MemoryGuarded = Memory;
  536. NoPagesGuarded = NoPages;
  537. AdjustMemoryF (&Memory, &NoPages);
  538. //
  539. // It's safe to unset Guard page inside memory lock because there should
  540. // be no memory allocation occurred in updating memory page attribute at
  541. // this point. And unsetting Guard page before free will prevent Guard
  542. // page just freed back to pool from being allocated right away before
  543. // marking it usable (from non-present to present).
  544. //
  545. UnsetGuardForMemory (MemoryGuarded, NoPagesGuarded);
  546. if (NoPages > 0) {
  547. CoreFreePoolPagesI (PoolType, Memory, NoPages);
  548. }
  549. }
  550. /**
  551. Internal function to free a pool entry.
  552. Caller must have the memory lock held
  553. @param Buffer The allocated pool entry to free
  554. @param PoolType Pointer to pool type
  555. @retval EFI_INVALID_PARAMETER Buffer not valid
  556. @retval EFI_SUCCESS Buffer successfully freed.
  557. **/
  558. EFI_STATUS
  559. CoreFreePoolI (
  560. IN VOID *Buffer,
  561. OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
  562. )
  563. {
  564. POOL *Pool;
  565. POOL_HEAD *Head;
  566. POOL_TAIL *Tail;
  567. POOL_FREE *Free;
  568. UINTN Index;
  569. UINTN NoPages;
  570. UINTN Size;
  571. CHAR8 *NewPage;
  572. UINTN Offset;
  573. BOOLEAN AllFree;
  574. UINTN Granularity;
  575. BOOLEAN IsGuarded;
  576. BOOLEAN HasPoolTail;
  577. BOOLEAN PageAsPool;
  578. ASSERT (Buffer != NULL);
  579. //
  580. // Get the head & tail of the pool entry
  581. //
  582. Head = BASE_CR (Buffer, POOL_HEAD, Data);
  583. ASSERT (Head != NULL);
  584. if ((Head->Signature != POOL_HEAD_SIGNATURE) &&
  585. (Head->Signature != POOLPAGE_HEAD_SIGNATURE))
  586. {
  587. ASSERT (
  588. Head->Signature == POOL_HEAD_SIGNATURE ||
  589. Head->Signature == POOLPAGE_HEAD_SIGNATURE
  590. );
  591. return EFI_INVALID_PARAMETER;
  592. }
  593. IsGuarded = IsPoolTypeToGuard (Head->Type) &&
  594. IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);
  595. HasPoolTail = !(IsGuarded &&
  596. ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
  597. PageAsPool = (Head->Signature == POOLPAGE_HEAD_SIGNATURE);
  598. if (HasPoolTail) {
  599. Tail = HEAD_TO_TAIL (Head);
  600. ASSERT (Tail != NULL);
  601. //
  602. // Debug
  603. //
  604. ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);
  605. ASSERT (Head->Size == Tail->Size);
  606. if (Tail->Signature != POOL_TAIL_SIGNATURE) {
  607. return EFI_INVALID_PARAMETER;
  608. }
  609. if (Head->Size != Tail->Size) {
  610. return EFI_INVALID_PARAMETER;
  611. }
  612. }
  613. ASSERT_LOCKED (&mPoolMemoryLock);
  614. //
  615. // Determine the pool type and account for it
  616. //
  617. Size = Head->Size;
  618. Pool = LookupPoolHead (Head->Type);
  619. if (Pool == NULL) {
  620. return EFI_INVALID_PARAMETER;
  621. }
  622. Pool->Used -= Size;
  623. DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64)Pool->Used));
  624. if ((Head->Type == EfiACPIReclaimMemory) ||
  625. (Head->Type == EfiACPIMemoryNVS) ||
  626. (Head->Type == EfiRuntimeServicesCode) ||
  627. (Head->Type == EfiRuntimeServicesData))
  628. {
  629. Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
  630. } else {
  631. Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
  632. }
  633. if (PoolType != NULL) {
  634. *PoolType = Head->Type;
  635. }
  636. //
  637. // Determine the pool list
  638. //
  639. Index = SIZE_TO_LIST (Size);
  640. DEBUG_CLEAR_MEMORY (Head, Size);
  641. //
  642. // If it's not on the list, it must be pool pages
  643. //
  644. if ((Index >= SIZE_TO_LIST (Granularity)) || IsGuarded || PageAsPool) {
  645. //
  646. // Return the memory pages back to free memory
  647. //
  648. NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;
  649. NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);
  650. if (IsGuarded) {
  651. Head = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);
  652. CoreFreePoolPagesWithGuard (
  653. Pool->MemoryType,
  654. (EFI_PHYSICAL_ADDRESS)(UINTN)Head,
  655. NoPages
  656. );
  657. } else {
  658. CoreFreePoolPagesI (
  659. Pool->MemoryType,
  660. (EFI_PHYSICAL_ADDRESS)(UINTN)Head,
  661. NoPages
  662. );
  663. }
  664. } else {
  665. //
  666. // Put the pool entry onto the free pool list
  667. //
  668. Free = (POOL_FREE *)Head;
  669. ASSERT (Free != NULL);
  670. Free->Signature = POOL_FREE_SIGNATURE;
  671. Free->Index = (UINT32)Index;
  672. InsertHeadList (&Pool->FreeList[Index], &Free->Link);
  673. //
  674. // See if all the pool entries in the same page as Free are freed pool
  675. // entries
  676. //
  677. NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));
  678. Free = (POOL_FREE *)&NewPage[0];
  679. ASSERT (Free != NULL);
  680. if (Free->Signature == POOL_FREE_SIGNATURE) {
  681. AllFree = TRUE;
  682. Offset = 0;
  683. while ((Offset < Granularity) && (AllFree)) {
  684. Free = (POOL_FREE *)&NewPage[Offset];
  685. ASSERT (Free != NULL);
  686. if (Free->Signature != POOL_FREE_SIGNATURE) {
  687. AllFree = FALSE;
  688. }
  689. Offset += LIST_TO_SIZE (Free->Index);
  690. }
  691. if (AllFree) {
  692. //
  693. // All of the pool entries in the same page as Free are free pool
  694. // entries
  695. // Remove all of these pool entries from the free loop lists.
  696. //
  697. Free = (POOL_FREE *)&NewPage[0];
  698. ASSERT (Free != NULL);
  699. Offset = 0;
  700. while (Offset < Granularity) {
  701. Free = (POOL_FREE *)&NewPage[Offset];
  702. ASSERT (Free != NULL);
  703. RemoveEntryList (&Free->Link);
  704. Offset += LIST_TO_SIZE (Free->Index);
  705. }
  706. //
  707. // Free the page
  708. //
  709. CoreFreePoolPagesI (
  710. Pool->MemoryType,
  711. (EFI_PHYSICAL_ADDRESS)(UINTN)NewPage,
  712. EFI_SIZE_TO_PAGES (Granularity)
  713. );
  714. }
  715. }
  716. }
  717. //
  718. // If this is an OS/OEM specific memory type, then check to see if the last
  719. // portion of that memory type has been freed. If it has, then free the
  720. // list entry for that memory type
  721. //
  722. if (((UINT32)Pool->MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) && (Pool->Used == 0)) {
  723. RemoveEntryList (&Pool->Link);
  724. CoreFreePoolI (Pool, NULL);
  725. }
  726. return EFI_SUCCESS;
  727. }