123c98c9417908188207408afa3f6901b8aca826aqhuang/** @file
2504214c4870e9183418014634268ce630eb5332algao  UEFI Memory pool management functions.
3504214c4870e9183418014634268ce630eb5332algao
4a671a0120a2fd8e8cb402741cf5e8652e27f38b5Liming GaoCopyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5cd5ebaa06dca3e6ef3c464081e6defe00d358c69hhtianThis program and the accompanying materials
623c98c9417908188207408afa3f6901b8aca826aqhuangare licensed and made available under the terms and conditions of the BSD License
723c98c9417908188207408afa3f6901b8aca826aqhuangwhich accompanies this distribution.  The full text of the license may be found at
823c98c9417908188207408afa3f6901b8aca826aqhuanghttp://opensource.org/licenses/bsd-license.php
923c98c9417908188207408afa3f6901b8aca826aqhuang
1023c98c9417908188207408afa3f6901b8aca826aqhuangTHE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
1123c98c9417908188207408afa3f6901b8aca826aqhuangWITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
1228a00297189c323096aae8e2975de94e8549613cyshang
13504214c4870e9183418014634268ce630eb5332algao**/
1428a00297189c323096aae8e2975de94e8549613cyshang
159c4ac31cca01b4a503c36616770ea3157bf3bb9eqhuang#include "DxeMain.h"
16ec90508b3d3ff22a698a0446cb09d551d7466045eric_tian#include "Imem.h"
1728a00297189c323096aae8e2975de94e8549613cyshang
18f3f2e05db8c89628498ec4efdb16184747824c63qhuang#define POOL_FREE_SIGNATURE   SIGNATURE_32('p','f','r','0')
1928a00297189c323096aae8e2975de94e8549613cyshangtypedef struct {
2028a00297189c323096aae8e2975de94e8549613cyshang  UINT32          Signature;
2128a00297189c323096aae8e2975de94e8549613cyshang  UINT32          Index;
2228a00297189c323096aae8e2975de94e8549613cyshang  LIST_ENTRY      Link;
2328a00297189c323096aae8e2975de94e8549613cyshang} POOL_FREE;
2428a00297189c323096aae8e2975de94e8549613cyshang
2528a00297189c323096aae8e2975de94e8549613cyshang
26f3f2e05db8c89628498ec4efdb16184747824c63qhuang#define POOL_HEAD_SIGNATURE   SIGNATURE_32('p','h','d','0')
2728a00297189c323096aae8e2975de94e8549613cyshangtypedef struct {
2828a00297189c323096aae8e2975de94e8549613cyshang  UINT32          Signature;
29bb683bf4656730be2210fe3964e20d8c36d19eb5Star Zeng  UINT32          Reserved;
3028a00297189c323096aae8e2975de94e8549613cyshang  EFI_MEMORY_TYPE Type;
31bb683bf4656730be2210fe3964e20d8c36d19eb5Star Zeng  UINTN           Size;
3228a00297189c323096aae8e2975de94e8549613cyshang  CHAR8           Data[1];
3328a00297189c323096aae8e2975de94e8549613cyshang} POOL_HEAD;
3428a00297189c323096aae8e2975de94e8549613cyshang
35f3f2e05db8c89628498ec4efdb16184747824c63qhuang#define SIZE_OF_POOL_HEAD OFFSET_OF(POOL_HEAD,Data)
3628a00297189c323096aae8e2975de94e8549613cyshang
37f3f2e05db8c89628498ec4efdb16184747824c63qhuang#define POOL_TAIL_SIGNATURE   SIGNATURE_32('p','t','a','l')
3828a00297189c323096aae8e2975de94e8549613cyshangtypedef struct {
3928a00297189c323096aae8e2975de94e8549613cyshang  UINT32      Signature;
40bb683bf4656730be2210fe3964e20d8c36d19eb5Star Zeng  UINT32      Reserved;
41bb683bf4656730be2210fe3964e20d8c36d19eb5Star Zeng  UINTN       Size;
4228a00297189c323096aae8e2975de94e8549613cyshang} POOL_TAIL;
4328a00297189c323096aae8e2975de94e8549613cyshang
4428a00297189c323096aae8e2975de94e8549613cyshang#define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))
4528a00297189c323096aae8e2975de94e8549613cyshang
4628a00297189c323096aae8e2975de94e8549613cyshang#define HEAD_TO_TAIL(a)   \
4728a00297189c323096aae8e2975de94e8549613cyshang  ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));
4828a00297189c323096aae8e2975de94e8549613cyshang
49f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel//
50f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel// Each element is the sum of the 2 previous ones: this allows us to migrate
51f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel// blocks between bins by splitting them up, while not wasting too much memory
52f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel// as we would in a strict power-of-2 sequence
53f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel//
54f2c7daf675d246261bd5e034b78e200017057df6Ard BiesheuvelSTATIC CONST UINT16 mPoolSizeTable[] = {
55f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel  64, 128, 192, 320, 512, 832, 1344, 2176, 3520, 5696, 9216, 14912, 24128
56f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel};
5728a00297189c323096aae8e2975de94e8549613cyshang
58f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel#define SIZE_TO_LIST(a)   (GetPoolIndexFromSize (a))
59f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel#define LIST_TO_SIZE(a)   (mPoolSizeTable [a])
6028a00297189c323096aae8e2975de94e8549613cyshang
61f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel#define MAX_POOL_LIST     (sizeof (mPoolSizeTable) / sizeof (mPoolSizeTable[0]))
6228a00297189c323096aae8e2975de94e8549613cyshang
6328a00297189c323096aae8e2975de94e8549613cyshang#define MAX_POOL_SIZE     (MAX_ADDRESS - POOL_OVERHEAD)
6428a00297189c323096aae8e2975de94e8549613cyshang
6528a00297189c323096aae8e2975de94e8549613cyshang//
6628a00297189c323096aae8e2975de94e8549613cyshang// Globals
6728a00297189c323096aae8e2975de94e8549613cyshang//
6828a00297189c323096aae8e2975de94e8549613cyshang
69f3f2e05db8c89628498ec4efdb16184747824c63qhuang#define POOL_SIGNATURE  SIGNATURE_32('p','l','s','t')
7028a00297189c323096aae8e2975de94e8549613cyshangtypedef struct {
7128a00297189c323096aae8e2975de94e8549613cyshang    INTN             Signature;
7228a00297189c323096aae8e2975de94e8549613cyshang    UINTN            Used;
7328a00297189c323096aae8e2975de94e8549613cyshang    EFI_MEMORY_TYPE  MemoryType;
7428a00297189c323096aae8e2975de94e8549613cyshang    LIST_ENTRY       FreeList[MAX_POOL_LIST];
7528a00297189c323096aae8e2975de94e8549613cyshang    LIST_ENTRY       Link;
76022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang} POOL;
7728a00297189c323096aae8e2975de94e8549613cyshang
7828a00297189c323096aae8e2975de94e8549613cyshang//
79e94a9ff7271367e649ee4f9a86da1f1bea6d112eqhuang// Pool header for each memory type.
80e94a9ff7271367e649ee4f9a86da1f1bea6d112eqhuang//
81e94a9ff7271367e649ee4f9a86da1f1bea6d112eqhuangPOOL            mPoolHead[EfiMaxMemoryType];
82e94a9ff7271367e649ee4f9a86da1f1bea6d112eqhuang
8328a00297189c323096aae8e2975de94e8549613cyshang//
84e94a9ff7271367e649ee4f9a86da1f1bea6d112eqhuang// List of pool header to search for the appropriate memory type.
8528a00297189c323096aae8e2975de94e8549613cyshang//
8657b4ecb94bceac2484dd9367b2ad111b05e17d97qhuangLIST_ENTRY      mPoolHeadList = INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList);
8728a00297189c323096aae8e2975de94e8549613cyshang
88dd51e45b6fc28b5240d37dd941aea5231f14db90Shumin Qiu/**
89dd51e45b6fc28b5240d37dd941aea5231f14db90Shumin Qiu  Get pool size table index from the specified size.
90dd51e45b6fc28b5240d37dd941aea5231f14db90Shumin Qiu
91dd51e45b6fc28b5240d37dd941aea5231f14db90Shumin Qiu  @param  Size          The specified size to get index from pool table.
92dd51e45b6fc28b5240d37dd941aea5231f14db90Shumin Qiu
93dd51e45b6fc28b5240d37dd941aea5231f14db90Shumin Qiu  @return               The index of pool size table.
94dd51e45b6fc28b5240d37dd941aea5231f14db90Shumin Qiu
95dd51e45b6fc28b5240d37dd941aea5231f14db90Shumin Qiu**/
96f2c7daf675d246261bd5e034b78e200017057df6Ard BiesheuvelSTATIC
97f2c7daf675d246261bd5e034b78e200017057df6Ard BiesheuvelUINTN
98f2c7daf675d246261bd5e034b78e200017057df6Ard BiesheuvelGetPoolIndexFromSize (
99f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel  UINTN   Size
100f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel  )
101f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel{
102f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel  UINTN   Index;
103f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel
104f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel  for (Index = 0; Index < MAX_POOL_LIST; Index++) {
105f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel    if (mPoolSizeTable [Index] >= Size) {
106f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel      return Index;
107f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel    }
108f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel  }
109f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel  return MAX_POOL_LIST;
110f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel}
111162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang
112162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang/**
113162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang  Called to initialize the pool.
114162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang
115162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang**/
11628a00297189c323096aae8e2975de94e8549613cyshangVOID
11728a00297189c323096aae8e2975de94e8549613cyshangCoreInitializePool (
11828a00297189c323096aae8e2975de94e8549613cyshang  VOID
11928a00297189c323096aae8e2975de94e8549613cyshang  )
12028a00297189c323096aae8e2975de94e8549613cyshang{
12128a00297189c323096aae8e2975de94e8549613cyshang  UINTN  Type;
12228a00297189c323096aae8e2975de94e8549613cyshang  UINTN  Index;
12328a00297189c323096aae8e2975de94e8549613cyshang
12428a00297189c323096aae8e2975de94e8549613cyshang  for (Type=0; Type < EfiMaxMemoryType; Type++) {
125e94a9ff7271367e649ee4f9a86da1f1bea6d112eqhuang    mPoolHead[Type].Signature  = 0;
126e94a9ff7271367e649ee4f9a86da1f1bea6d112eqhuang    mPoolHead[Type].Used       = 0;
127e94a9ff7271367e649ee4f9a86da1f1bea6d112eqhuang    mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;
12828a00297189c323096aae8e2975de94e8549613cyshang    for (Index=0; Index < MAX_POOL_LIST; Index++) {
129bb683bf4656730be2210fe3964e20d8c36d19eb5Star Zeng      InitializeListHead (&mPoolHead[Type].FreeList[Index]);
13028a00297189c323096aae8e2975de94e8549613cyshang    }
13128a00297189c323096aae8e2975de94e8549613cyshang  }
13228a00297189c323096aae8e2975de94e8549613cyshang}
13328a00297189c323096aae8e2975de94e8549613cyshang
13428a00297189c323096aae8e2975de94e8549613cyshang
135162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang/**
13628a00297189c323096aae8e2975de94e8549613cyshang  Look up pool head for specified memory type.
13728a00297189c323096aae8e2975de94e8549613cyshang
138022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang  @param  MemoryType             Memory type of which pool head is looked for
13928a00297189c323096aae8e2975de94e8549613cyshang
140162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang  @return Pointer of Corresponding pool head.
14128a00297189c323096aae8e2975de94e8549613cyshang
142162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang**/
143162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuangPOOL *
144162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuangLookupPoolHead (
145162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang  IN EFI_MEMORY_TYPE  MemoryType
146162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang  )
14728a00297189c323096aae8e2975de94e8549613cyshang{
14828a00297189c323096aae8e2975de94e8549613cyshang  LIST_ENTRY      *Link;
14928a00297189c323096aae8e2975de94e8549613cyshang  POOL            *Pool;
15028a00297189c323096aae8e2975de94e8549613cyshang  UINTN           Index;
15128a00297189c323096aae8e2975de94e8549613cyshang
1523d78c020d22023d35d27b48817d73ff31a361ac7rsun  if ((UINT32)MemoryType < EfiMaxMemoryType) {
153e94a9ff7271367e649ee4f9a86da1f1bea6d112eqhuang    return &mPoolHead[MemoryType];
15428a00297189c323096aae8e2975de94e8549613cyshang  }
15528a00297189c323096aae8e2975de94e8549613cyshang
156dc8d93ca0c9a798fe4e23f68b5b5adc032bf5509eric_tian  //
1578ee25f48770dcb139b2313f57bd1449465149f7dStar Zeng  // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI
1588ee25f48770dcb139b2313f57bd1449465149f7dStar Zeng  // OS loaders that are provided by operating system vendors.
1598ee25f48770dcb139b2313f57bd1449465149f7dStar Zeng  // MemoryType values in the range 0x70000000..0x7FFFFFFF are reserved for OEM use.
160dc8d93ca0c9a798fe4e23f68b5b5adc032bf5509eric_tian  //
1618ee25f48770dcb139b2313f57bd1449465149f7dStar Zeng  if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
16228a00297189c323096aae8e2975de94e8549613cyshang
163e94a9ff7271367e649ee4f9a86da1f1bea6d112eqhuang    for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {
16428a00297189c323096aae8e2975de94e8549613cyshang      Pool = CR(Link, POOL, Link, POOL_SIGNATURE);
16528a00297189c323096aae8e2975de94e8549613cyshang      if (Pool->MemoryType == MemoryType) {
16628a00297189c323096aae8e2975de94e8549613cyshang        return Pool;
16728a00297189c323096aae8e2975de94e8549613cyshang      }
16828a00297189c323096aae8e2975de94e8549613cyshang    }
16928a00297189c323096aae8e2975de94e8549613cyshang
17028a00297189c323096aae8e2975de94e8549613cyshang    Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL));
17128a00297189c323096aae8e2975de94e8549613cyshang    if (Pool == NULL) {
17228a00297189c323096aae8e2975de94e8549613cyshang      return NULL;
17328a00297189c323096aae8e2975de94e8549613cyshang    }
17428a00297189c323096aae8e2975de94e8549613cyshang
17528a00297189c323096aae8e2975de94e8549613cyshang    Pool->Signature = POOL_SIGNATURE;
17628a00297189c323096aae8e2975de94e8549613cyshang    Pool->Used      = 0;
17728a00297189c323096aae8e2975de94e8549613cyshang    Pool->MemoryType = MemoryType;
17828a00297189c323096aae8e2975de94e8549613cyshang    for (Index=0; Index < MAX_POOL_LIST; Index++) {
17928a00297189c323096aae8e2975de94e8549613cyshang      InitializeListHead (&Pool->FreeList[Index]);
18028a00297189c323096aae8e2975de94e8549613cyshang    }
18128a00297189c323096aae8e2975de94e8549613cyshang
182e94a9ff7271367e649ee4f9a86da1f1bea6d112eqhuang    InsertHeadList (&mPoolHeadList, &Pool->Link);
18328a00297189c323096aae8e2975de94e8549613cyshang
18428a00297189c323096aae8e2975de94e8549613cyshang    return Pool;
18528a00297189c323096aae8e2975de94e8549613cyshang  }
18628a00297189c323096aae8e2975de94e8549613cyshang
18728a00297189c323096aae8e2975de94e8549613cyshang  return NULL;
18828a00297189c323096aae8e2975de94e8549613cyshang}
18928a00297189c323096aae8e2975de94e8549613cyshang
190022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang
19128a00297189c323096aae8e2975de94e8549613cyshang
192162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang/**
193162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang  Allocate pool of a particular type.
194162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang
195022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang  @param  PoolType               Type of pool to allocate
196022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang  @param  Size                   The amount of pool to allocate
197022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang  @param  Buffer                 The address to return a pointer to the allocated
198022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang                                 pool
199162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang
2003e0587010e36d36d6374c8ca9956e9bfbc8da7a8ydong  @retval EFI_INVALID_PARAMETER  PoolType not valid or Buffer is NULL.
201a671a0120a2fd8e8cb402741cf5e8652e27f38b5Liming Gao                                 PoolType was EfiPersistentMemory.
202022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang  @retval EFI_OUT_OF_RESOURCES   Size exceeds max pool size or allocation failed.
203162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang  @retval EFI_SUCCESS            Pool successfully allocated.
204162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang
205162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang**/
20628a00297189c323096aae8e2975de94e8549613cyshangEFI_STATUS
20728a00297189c323096aae8e2975de94e8549613cyshangEFIAPI
20884edd20bd0756ef5719835498d4283435d6b5e77Star ZengCoreInternalAllocatePool (
20928a00297189c323096aae8e2975de94e8549613cyshang  IN EFI_MEMORY_TYPE  PoolType,
21028a00297189c323096aae8e2975de94e8549613cyshang  IN UINTN            Size,
21128a00297189c323096aae8e2975de94e8549613cyshang  OUT VOID            **Buffer
21228a00297189c323096aae8e2975de94e8549613cyshang  )
21328a00297189c323096aae8e2975de94e8549613cyshang{
21428a00297189c323096aae8e2975de94e8549613cyshang  EFI_STATUS    Status;
21528a00297189c323096aae8e2975de94e8549613cyshang
21628a00297189c323096aae8e2975de94e8549613cyshang  //
21728a00297189c323096aae8e2975de94e8549613cyshang  // If it's not a valid type, fail it
21828a00297189c323096aae8e2975de94e8549613cyshang  //
2198ee25f48770dcb139b2313f57bd1449465149f7dStar Zeng  if ((PoolType >= EfiMaxMemoryType && PoolType < MEMORY_TYPE_OEM_RESERVED_MIN) ||
220a671a0120a2fd8e8cb402741cf5e8652e27f38b5Liming Gao       (PoolType == EfiConventionalMemory) || (PoolType == EfiPersistentMemory)) {
22128a00297189c323096aae8e2975de94e8549613cyshang    return EFI_INVALID_PARAMETER;
22228a00297189c323096aae8e2975de94e8549613cyshang  }
223022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang
2243e0587010e36d36d6374c8ca9956e9bfbc8da7a8ydong  if (Buffer == NULL) {
2253e0587010e36d36d6374c8ca9956e9bfbc8da7a8ydong    return EFI_INVALID_PARAMETER;
2263e0587010e36d36d6374c8ca9956e9bfbc8da7a8ydong  }
2273e0587010e36d36d6374c8ca9956e9bfbc8da7a8ydong
22828a00297189c323096aae8e2975de94e8549613cyshang  *Buffer = NULL;
229022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang
23028a00297189c323096aae8e2975de94e8549613cyshang  //
23128a00297189c323096aae8e2975de94e8549613cyshang  // If size is too large, fail it
23228a00297189c323096aae8e2975de94e8549613cyshang  // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES
23328a00297189c323096aae8e2975de94e8549613cyshang  //
23428a00297189c323096aae8e2975de94e8549613cyshang  if (Size > MAX_POOL_SIZE) {
23528a00297189c323096aae8e2975de94e8549613cyshang    return EFI_OUT_OF_RESOURCES;
23628a00297189c323096aae8e2975de94e8549613cyshang  }
23728a00297189c323096aae8e2975de94e8549613cyshang
23828a00297189c323096aae8e2975de94e8549613cyshang  //
23928a00297189c323096aae8e2975de94e8549613cyshang  // Acquire the memory lock and make the allocation
24028a00297189c323096aae8e2975de94e8549613cyshang  //
24128a00297189c323096aae8e2975de94e8549613cyshang  Status = CoreAcquireLockOrFail (&gMemoryLock);
24228a00297189c323096aae8e2975de94e8549613cyshang  if (EFI_ERROR (Status)) {
24328a00297189c323096aae8e2975de94e8549613cyshang    return EFI_OUT_OF_RESOURCES;
24428a00297189c323096aae8e2975de94e8549613cyshang  }
24528a00297189c323096aae8e2975de94e8549613cyshang
24628a00297189c323096aae8e2975de94e8549613cyshang  *Buffer = CoreAllocatePoolI (PoolType, Size);
24728a00297189c323096aae8e2975de94e8549613cyshang  CoreReleaseMemoryLock ();
24828a00297189c323096aae8e2975de94e8549613cyshang  return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
24928a00297189c323096aae8e2975de94e8549613cyshang}
25028a00297189c323096aae8e2975de94e8549613cyshang
25184edd20bd0756ef5719835498d4283435d6b5e77Star Zeng/**
25284edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  Allocate pool of a particular type.
25384edd20bd0756ef5719835498d4283435d6b5e77Star Zeng
25484edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  @param  PoolType               Type of pool to allocate
25584edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  @param  Size                   The amount of pool to allocate
25684edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  @param  Buffer                 The address to return a pointer to the allocated
25784edd20bd0756ef5719835498d4283435d6b5e77Star Zeng                                 pool
25884edd20bd0756ef5719835498d4283435d6b5e77Star Zeng
25984edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  @retval EFI_INVALID_PARAMETER  PoolType not valid or Buffer is NULL.
26084edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  @retval EFI_OUT_OF_RESOURCES   Size exceeds max pool size or allocation failed.
26184edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  @retval EFI_SUCCESS            Pool successfully allocated.
26284edd20bd0756ef5719835498d4283435d6b5e77Star Zeng
26384edd20bd0756ef5719835498d4283435d6b5e77Star Zeng**/
26484edd20bd0756ef5719835498d4283435d6b5e77Star ZengEFI_STATUS
26584edd20bd0756ef5719835498d4283435d6b5e77Star ZengEFIAPI
26684edd20bd0756ef5719835498d4283435d6b5e77Star ZengCoreAllocatePool (
26784edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  IN EFI_MEMORY_TYPE  PoolType,
26884edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  IN UINTN            Size,
26984edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  OUT VOID            **Buffer
27084edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  )
27184edd20bd0756ef5719835498d4283435d6b5e77Star Zeng{
27284edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  EFI_STATUS  Status;
27328a00297189c323096aae8e2975de94e8549613cyshang
27484edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  Status = CoreInternalAllocatePool (PoolType, Size, Buffer);
27584edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  if (!EFI_ERROR (Status)) {
27684edd20bd0756ef5719835498d4283435d6b5e77Star Zeng    CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionAllocatePool, PoolType, Size, *Buffer);
27784edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  }
27884edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  return Status;
27984edd20bd0756ef5719835498d4283435d6b5e77Star Zeng}
28028a00297189c323096aae8e2975de94e8549613cyshang
281162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang/**
28228a00297189c323096aae8e2975de94e8549613cyshang  Internal function to allocate pool of a particular type.
28328a00297189c323096aae8e2975de94e8549613cyshang  Caller must have the memory lock held
28428a00297189c323096aae8e2975de94e8549613cyshang
285022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang  @param  PoolType               Type of pool to allocate
286022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang  @param  Size                   The amount of pool to allocate
28728a00297189c323096aae8e2975de94e8549613cyshang
288162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang  @return The allocate pool, or NULL
28928a00297189c323096aae8e2975de94e8549613cyshang
290162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang**/
291162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuangVOID *
292162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuangCoreAllocatePoolI (
293162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang  IN EFI_MEMORY_TYPE  PoolType,
294162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang  IN UINTN            Size
295162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang  )
29628a00297189c323096aae8e2975de94e8549613cyshang{
29728a00297189c323096aae8e2975de94e8549613cyshang  POOL        *Pool;
29828a00297189c323096aae8e2975de94e8549613cyshang  POOL_FREE   *Free;
29928a00297189c323096aae8e2975de94e8549613cyshang  POOL_HEAD   *Head;
30028a00297189c323096aae8e2975de94e8549613cyshang  POOL_TAIL   *Tail;
30128a00297189c323096aae8e2975de94e8549613cyshang  CHAR8       *NewPage;
30228a00297189c323096aae8e2975de94e8549613cyshang  VOID        *Buffer;
30328a00297189c323096aae8e2975de94e8549613cyshang  UINTN       Index;
30428a00297189c323096aae8e2975de94e8549613cyshang  UINTN       FSize;
3056860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel  UINTN       Offset, MaxOffset;
30628a00297189c323096aae8e2975de94e8549613cyshang  UINTN       NoPages;
3077970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel  UINTN       Granularity;
30828a00297189c323096aae8e2975de94e8549613cyshang
30928a00297189c323096aae8e2975de94e8549613cyshang  ASSERT_LOCKED (&gMemoryLock);
31028a00297189c323096aae8e2975de94e8549613cyshang
3117970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel  if  (PoolType == EfiACPIReclaimMemory   ||
3127970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel       PoolType == EfiACPIMemoryNVS       ||
3137970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel       PoolType == EfiRuntimeServicesCode ||
3147970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel       PoolType == EfiRuntimeServicesData) {
3157970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel
3167970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel    Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
3177970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel  } else {
3187970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel    Granularity = DEFAULT_PAGE_ALLOCATION;
3197970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel  }
3207970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel
32128a00297189c323096aae8e2975de94e8549613cyshang  //
32228a00297189c323096aae8e2975de94e8549613cyshang  // Adjust the size by the pool header & tail overhead
32328a00297189c323096aae8e2975de94e8549613cyshang  //
324022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang
32528a00297189c323096aae8e2975de94e8549613cyshang  //
32628a00297189c323096aae8e2975de94e8549613cyshang  // Adjusting the Size to be of proper alignment so that
32728a00297189c323096aae8e2975de94e8549613cyshang  // we don't get an unaligned access fault later when
32828a00297189c323096aae8e2975de94e8549613cyshang  // pool_Tail is being initialized
32928a00297189c323096aae8e2975de94e8549613cyshang  //
330f0d5cbb66aa222e3eb0777d0d4b0d70a03d49188qhuang  Size = ALIGN_VARIABLE (Size);
33128a00297189c323096aae8e2975de94e8549613cyshang
33228a00297189c323096aae8e2975de94e8549613cyshang  Size += POOL_OVERHEAD;
33328a00297189c323096aae8e2975de94e8549613cyshang  Index = SIZE_TO_LIST(Size);
33428a00297189c323096aae8e2975de94e8549613cyshang  Pool = LookupPoolHead (PoolType);
33528a00297189c323096aae8e2975de94e8549613cyshang  if (Pool== NULL) {
33628a00297189c323096aae8e2975de94e8549613cyshang    return NULL;
33728a00297189c323096aae8e2975de94e8549613cyshang  }
33828a00297189c323096aae8e2975de94e8549613cyshang  Head = NULL;
33928a00297189c323096aae8e2975de94e8549613cyshang
34028a00297189c323096aae8e2975de94e8549613cyshang  //
34128a00297189c323096aae8e2975de94e8549613cyshang  // If allocation is over max size, just allocate pages for the request
34228a00297189c323096aae8e2975de94e8549613cyshang  // (slow)
34328a00297189c323096aae8e2975de94e8549613cyshang  //
344f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel  if (Index >= SIZE_TO_LIST (Granularity)) {
3457970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel    NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;
3467970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel    NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);
3477970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel    Head = CoreAllocatePoolPages (PoolType, NoPages, Granularity);
34828a00297189c323096aae8e2975de94e8549613cyshang    goto Done;
34928a00297189c323096aae8e2975de94e8549613cyshang  }
35028a00297189c323096aae8e2975de94e8549613cyshang
35128a00297189c323096aae8e2975de94e8549613cyshang  //
35228a00297189c323096aae8e2975de94e8549613cyshang  // If there's no free pool in the proper list size, go get some more pages
35328a00297189c323096aae8e2975de94e8549613cyshang  //
35428a00297189c323096aae8e2975de94e8549613cyshang  if (IsListEmpty (&Pool->FreeList[Index])) {
35528a00297189c323096aae8e2975de94e8549613cyshang
3566860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel    Offset = LIST_TO_SIZE (Index);
3576860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel    MaxOffset = Granularity;
3586860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel
3596860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel    //
3606860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel    // Check the bins holding larger blocks, and carve one up if needed
3616860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel    //
3626860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel    while (++Index < SIZE_TO_LIST (Granularity)) {
3636860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel      if (!IsListEmpty (&Pool->FreeList[Index])) {
3646860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel        Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);
3656860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel        RemoveEntryList (&Free->Link);
3666860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel        NewPage = (VOID *) Free;
3676860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel        MaxOffset = LIST_TO_SIZE (Index);
3686860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel        goto Carve;
3696860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel      }
3706860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel    }
3716860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel
37228a00297189c323096aae8e2975de94e8549613cyshang    //
37328a00297189c323096aae8e2975de94e8549613cyshang    // Get another page
37428a00297189c323096aae8e2975de94e8549613cyshang    //
3757970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel    NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (Granularity), Granularity);
37628a00297189c323096aae8e2975de94e8549613cyshang    if (NewPage == NULL) {
37728a00297189c323096aae8e2975de94e8549613cyshang      goto Done;
37828a00297189c323096aae8e2975de94e8549613cyshang    }
37928a00297189c323096aae8e2975de94e8549613cyshang
38028a00297189c323096aae8e2975de94e8549613cyshang    //
381f8aabf6e4c199e92498512e1d0cf9a347b62e491Ard Biesheuvel    // Serve the allocation request from the head of the allocated block
38228a00297189c323096aae8e2975de94e8549613cyshang    //
3836860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd BiesheuvelCarve:
384f8aabf6e4c199e92498512e1d0cf9a347b62e491Ard Biesheuvel    Head = (POOL_HEAD *) NewPage;
385f8aabf6e4c199e92498512e1d0cf9a347b62e491Ard Biesheuvel
386f8aabf6e4c199e92498512e1d0cf9a347b62e491Ard Biesheuvel    //
387f8aabf6e4c199e92498512e1d0cf9a347b62e491Ard Biesheuvel    // Carve up remaining space into free pool blocks
388f8aabf6e4c199e92498512e1d0cf9a347b62e491Ard Biesheuvel    //
3896860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel    Index--;
3906860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel    while (Offset < MaxOffset) {
39128a00297189c323096aae8e2975de94e8549613cyshang      ASSERT (Index < MAX_POOL_LIST);
39228a00297189c323096aae8e2975de94e8549613cyshang      FSize = LIST_TO_SIZE(Index);
39328a00297189c323096aae8e2975de94e8549613cyshang
3946860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel      while (Offset + FSize <= MaxOffset) {
395022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang        Free = (POOL_FREE *) &NewPage[Offset];
39628a00297189c323096aae8e2975de94e8549613cyshang        Free->Signature = POOL_FREE_SIGNATURE;
39728a00297189c323096aae8e2975de94e8549613cyshang        Free->Index     = (UINT32)Index;
39828a00297189c323096aae8e2975de94e8549613cyshang        InsertHeadList (&Pool->FreeList[Index], &Free->Link);
399162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang        Offset += FSize;
40028a00297189c323096aae8e2975de94e8549613cyshang      }
40128a00297189c323096aae8e2975de94e8549613cyshang      Index -= 1;
40228a00297189c323096aae8e2975de94e8549613cyshang    }
40328a00297189c323096aae8e2975de94e8549613cyshang
4046860b92c847caff16b8cbc58ca31e3dbf9c5e5ccArd Biesheuvel    ASSERT (Offset == MaxOffset);
405f8aabf6e4c199e92498512e1d0cf9a347b62e491Ard Biesheuvel    goto Done;
40628a00297189c323096aae8e2975de94e8549613cyshang  }
40728a00297189c323096aae8e2975de94e8549613cyshang
40828a00297189c323096aae8e2975de94e8549613cyshang  //
40928a00297189c323096aae8e2975de94e8549613cyshang  // Remove entry from free pool list
41028a00297189c323096aae8e2975de94e8549613cyshang  //
41128a00297189c323096aae8e2975de94e8549613cyshang  Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);
41228a00297189c323096aae8e2975de94e8549613cyshang  RemoveEntryList (&Free->Link);
41328a00297189c323096aae8e2975de94e8549613cyshang
41428a00297189c323096aae8e2975de94e8549613cyshang  Head = (POOL_HEAD *) Free;
41528a00297189c323096aae8e2975de94e8549613cyshang
41628a00297189c323096aae8e2975de94e8549613cyshangDone:
41728a00297189c323096aae8e2975de94e8549613cyshang  Buffer = NULL;
41828a00297189c323096aae8e2975de94e8549613cyshang
41928a00297189c323096aae8e2975de94e8549613cyshang  if (Head != NULL) {
420022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang
42128a00297189c323096aae8e2975de94e8549613cyshang    //
42228a00297189c323096aae8e2975de94e8549613cyshang    // If we have a pool buffer, fill in the header & tail info
42328a00297189c323096aae8e2975de94e8549613cyshang    //
42428a00297189c323096aae8e2975de94e8549613cyshang    Head->Signature = POOL_HEAD_SIGNATURE;
425bb683bf4656730be2210fe3964e20d8c36d19eb5Star Zeng    Head->Size      = Size;
42628a00297189c323096aae8e2975de94e8549613cyshang    Head->Type      = (EFI_MEMORY_TYPE) PoolType;
42728a00297189c323096aae8e2975de94e8549613cyshang    Tail            = HEAD_TO_TAIL (Head);
42828a00297189c323096aae8e2975de94e8549613cyshang    Tail->Signature = POOL_TAIL_SIGNATURE;
429bb683bf4656730be2210fe3964e20d8c36d19eb5Star Zeng    Tail->Size      = Size;
43028a00297189c323096aae8e2975de94e8549613cyshang    Buffer          = Head->Data;
43128a00297189c323096aae8e2975de94e8549613cyshang    DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);
43228a00297189c323096aae8e2975de94e8549613cyshang
433e94a9ff7271367e649ee4f9a86da1f1bea6d112eqhuang    DEBUG ((
434e94a9ff7271367e649ee4f9a86da1f1bea6d112eqhuang      DEBUG_POOL,
43557b4ecb94bceac2484dd9367b2ad111b05e17d97qhuang      "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,
436022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang      Buffer,
43757b4ecb94bceac2484dd9367b2ad111b05e17d97qhuang      (UINT64)(Size - POOL_OVERHEAD),
43857b4ecb94bceac2484dd9367b2ad111b05e17d97qhuang      (UINT64) Pool->Used
439e94a9ff7271367e649ee4f9a86da1f1bea6d112eqhuang      ));
44028a00297189c323096aae8e2975de94e8549613cyshang
44128a00297189c323096aae8e2975de94e8549613cyshang    //
44228a00297189c323096aae8e2975de94e8549613cyshang    // Account the allocation
44328a00297189c323096aae8e2975de94e8549613cyshang    //
44428a00297189c323096aae8e2975de94e8549613cyshang    Pool->Used += Size;
44528a00297189c323096aae8e2975de94e8549613cyshang
44628a00297189c323096aae8e2975de94e8549613cyshang  } else {
44757b4ecb94bceac2484dd9367b2ad111b05e17d97qhuang    DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));
44828a00297189c323096aae8e2975de94e8549613cyshang  }
44928a00297189c323096aae8e2975de94e8549613cyshang
45028a00297189c323096aae8e2975de94e8549613cyshang  return Buffer;
45128a00297189c323096aae8e2975de94e8549613cyshang}
452022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang
45328a00297189c323096aae8e2975de94e8549613cyshang
45428a00297189c323096aae8e2975de94e8549613cyshang
455162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang/**
45628a00297189c323096aae8e2975de94e8549613cyshang  Frees pool.
45728a00297189c323096aae8e2975de94e8549613cyshang
458022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang  @param  Buffer                 The allocated pool entry to free
45928a00297189c323096aae8e2975de94e8549613cyshang
460022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang  @retval EFI_INVALID_PARAMETER  Buffer is not a valid value.
461162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang  @retval EFI_SUCCESS            Pool successfully freed.
46228a00297189c323096aae8e2975de94e8549613cyshang
463162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang**/
464162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuangEFI_STATUS
465162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuangEFIAPI
46684edd20bd0756ef5719835498d4283435d6b5e77Star ZengCoreInternalFreePool (
467162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang  IN VOID        *Buffer
468162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang  )
46928a00297189c323096aae8e2975de94e8549613cyshang{
47028a00297189c323096aae8e2975de94e8549613cyshang  EFI_STATUS Status;
47128a00297189c323096aae8e2975de94e8549613cyshang
472e94a9ff7271367e649ee4f9a86da1f1bea6d112eqhuang  if (Buffer == NULL) {
47328a00297189c323096aae8e2975de94e8549613cyshang    return EFI_INVALID_PARAMETER;
47428a00297189c323096aae8e2975de94e8549613cyshang  }
47528a00297189c323096aae8e2975de94e8549613cyshang
47628a00297189c323096aae8e2975de94e8549613cyshang  CoreAcquireMemoryLock ();
47728a00297189c323096aae8e2975de94e8549613cyshang  Status = CoreFreePoolI (Buffer);
47828a00297189c323096aae8e2975de94e8549613cyshang  CoreReleaseMemoryLock ();
47928a00297189c323096aae8e2975de94e8549613cyshang  return Status;
48028a00297189c323096aae8e2975de94e8549613cyshang}
48128a00297189c323096aae8e2975de94e8549613cyshang
48284edd20bd0756ef5719835498d4283435d6b5e77Star Zeng/**
48384edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  Frees pool.
48484edd20bd0756ef5719835498d4283435d6b5e77Star Zeng
48584edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  @param  Buffer                 The allocated pool entry to free
48684edd20bd0756ef5719835498d4283435d6b5e77Star Zeng
48784edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  @retval EFI_INVALID_PARAMETER  Buffer is not a valid value.
48884edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  @retval EFI_SUCCESS            Pool successfully freed.
48984edd20bd0756ef5719835498d4283435d6b5e77Star Zeng
49084edd20bd0756ef5719835498d4283435d6b5e77Star Zeng**/
49184edd20bd0756ef5719835498d4283435d6b5e77Star ZengEFI_STATUS
49284edd20bd0756ef5719835498d4283435d6b5e77Star ZengEFIAPI
49384edd20bd0756ef5719835498d4283435d6b5e77Star ZengCoreFreePool (
49484edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  IN VOID  *Buffer
49584edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  )
49684edd20bd0756ef5719835498d4283435d6b5e77Star Zeng{
49784edd20bd0756ef5719835498d4283435d6b5e77Star Zeng  EFI_STATUS  Status;
498736a692e7c0210eb71c01c39731ef97383d606ebHot Tian
499736a692e7c0210eb71c01c39731ef97383d606ebHot Tian  Status = CoreInternalFreePool (Buffer);
500736a692e7c0210eb71c01c39731ef97383d606ebHot Tian  if (!EFI_ERROR (Status)) {
501736a692e7c0210eb71c01c39731ef97383d606ebHot Tian    CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionFreePool, (EFI_MEMORY_TYPE) 0, 0, Buffer);
502736a692e7c0210eb71c01c39731ef97383d606ebHot Tian  }
503736a692e7c0210eb71c01c39731ef97383d606ebHot Tian  return Status;
504736a692e7c0210eb71c01c39731ef97383d606ebHot Tian}
50528a00297189c323096aae8e2975de94e8549613cyshang
506162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang/**
50728a00297189c323096aae8e2975de94e8549613cyshang  Internal function to free a pool entry.
50828a00297189c323096aae8e2975de94e8549613cyshang  Caller must have the memory lock held
50928a00297189c323096aae8e2975de94e8549613cyshang
510022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang  @param  Buffer                 The allocated pool entry to free
51128a00297189c323096aae8e2975de94e8549613cyshang
512022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang  @retval EFI_INVALID_PARAMETER  Buffer not valid
513162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang  @retval EFI_SUCCESS            Buffer successfully freed.
51428a00297189c323096aae8e2975de94e8549613cyshang
515162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang**/
516162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuangEFI_STATUS
517162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuangCoreFreePoolI (
518162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang  IN VOID       *Buffer
519162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang  )
52028a00297189c323096aae8e2975de94e8549613cyshang{
52128a00297189c323096aae8e2975de94e8549613cyshang  POOL        *Pool;
52228a00297189c323096aae8e2975de94e8549613cyshang  POOL_HEAD   *Head;
52328a00297189c323096aae8e2975de94e8549613cyshang  POOL_TAIL   *Tail;
52428a00297189c323096aae8e2975de94e8549613cyshang  POOL_FREE   *Free;
52528a00297189c323096aae8e2975de94e8549613cyshang  UINTN       Index;
52628a00297189c323096aae8e2975de94e8549613cyshang  UINTN       NoPages;
52728a00297189c323096aae8e2975de94e8549613cyshang  UINTN       Size;
52828a00297189c323096aae8e2975de94e8549613cyshang  CHAR8       *NewPage;
529162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang  UINTN       Offset;
53028a00297189c323096aae8e2975de94e8549613cyshang  BOOLEAN     AllFree;
5317970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel  UINTN       Granularity;
53228a00297189c323096aae8e2975de94e8549613cyshang
53357b4ecb94bceac2484dd9367b2ad111b05e17d97qhuang  ASSERT(Buffer != NULL);
53428a00297189c323096aae8e2975de94e8549613cyshang  //
53528a00297189c323096aae8e2975de94e8549613cyshang  // Get the head & tail of the pool entry
53628a00297189c323096aae8e2975de94e8549613cyshang  //
53728a00297189c323096aae8e2975de94e8549613cyshang  Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);
53857b4ecb94bceac2484dd9367b2ad111b05e17d97qhuang  ASSERT(Head != NULL);
53928a00297189c323096aae8e2975de94e8549613cyshang
54028a00297189c323096aae8e2975de94e8549613cyshang  if (Head->Signature != POOL_HEAD_SIGNATURE) {
54128a00297189c323096aae8e2975de94e8549613cyshang    return EFI_INVALID_PARAMETER;
54228a00297189c323096aae8e2975de94e8549613cyshang  }
54328a00297189c323096aae8e2975de94e8549613cyshang
54428a00297189c323096aae8e2975de94e8549613cyshang  Tail = HEAD_TO_TAIL (Head);
54557b4ecb94bceac2484dd9367b2ad111b05e17d97qhuang  ASSERT(Tail != NULL);
54628a00297189c323096aae8e2975de94e8549613cyshang
54728a00297189c323096aae8e2975de94e8549613cyshang  //
54828a00297189c323096aae8e2975de94e8549613cyshang  // Debug
54928a00297189c323096aae8e2975de94e8549613cyshang  //
55028a00297189c323096aae8e2975de94e8549613cyshang  ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);
55128a00297189c323096aae8e2975de94e8549613cyshang  ASSERT (Head->Size == Tail->Size);
55228a00297189c323096aae8e2975de94e8549613cyshang  ASSERT_LOCKED (&gMemoryLock);
55328a00297189c323096aae8e2975de94e8549613cyshang
55428a00297189c323096aae8e2975de94e8549613cyshang  if (Tail->Signature != POOL_TAIL_SIGNATURE) {
55528a00297189c323096aae8e2975de94e8549613cyshang    return EFI_INVALID_PARAMETER;
55628a00297189c323096aae8e2975de94e8549613cyshang  }
55728a00297189c323096aae8e2975de94e8549613cyshang
55828a00297189c323096aae8e2975de94e8549613cyshang  if (Head->Size != Tail->Size) {
55928a00297189c323096aae8e2975de94e8549613cyshang    return EFI_INVALID_PARAMETER;
56028a00297189c323096aae8e2975de94e8549613cyshang  }
56128a00297189c323096aae8e2975de94e8549613cyshang
56228a00297189c323096aae8e2975de94e8549613cyshang  //
56328a00297189c323096aae8e2975de94e8549613cyshang  // Determine the pool type and account for it
56428a00297189c323096aae8e2975de94e8549613cyshang  //
56528a00297189c323096aae8e2975de94e8549613cyshang  Size = Head->Size;
56628a00297189c323096aae8e2975de94e8549613cyshang  Pool = LookupPoolHead (Head->Type);
56728a00297189c323096aae8e2975de94e8549613cyshang  if (Pool == NULL) {
56828a00297189c323096aae8e2975de94e8549613cyshang    return EFI_INVALID_PARAMETER;
56928a00297189c323096aae8e2975de94e8549613cyshang  }
57028a00297189c323096aae8e2975de94e8549613cyshang  Pool->Used -= Size;
57157b4ecb94bceac2484dd9367b2ad111b05e17d97qhuang  DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));
57228a00297189c323096aae8e2975de94e8549613cyshang
5737970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel  if  (Head->Type == EfiACPIReclaimMemory   ||
5747970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel       Head->Type == EfiACPIMemoryNVS       ||
5757970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel       Head->Type == EfiRuntimeServicesCode ||
5767970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel       Head->Type == EfiRuntimeServicesData) {
5777970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel
5787970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel    Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
5797970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel  } else {
5807970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel    Granularity = DEFAULT_PAGE_ALLOCATION;
5817970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel  }
5827970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel
58328a00297189c323096aae8e2975de94e8549613cyshang  //
584022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang  // Determine the pool list
58528a00297189c323096aae8e2975de94e8549613cyshang  //
58628a00297189c323096aae8e2975de94e8549613cyshang  Index = SIZE_TO_LIST(Size);
58728a00297189c323096aae8e2975de94e8549613cyshang  DEBUG_CLEAR_MEMORY (Head, Size);
58828a00297189c323096aae8e2975de94e8549613cyshang
58928a00297189c323096aae8e2975de94e8549613cyshang  //
59028a00297189c323096aae8e2975de94e8549613cyshang  // If it's not on the list, it must be pool pages
59128a00297189c323096aae8e2975de94e8549613cyshang  //
592f2c7daf675d246261bd5e034b78e200017057df6Ard Biesheuvel  if (Index >= SIZE_TO_LIST (Granularity)) {
59328a00297189c323096aae8e2975de94e8549613cyshang
59428a00297189c323096aae8e2975de94e8549613cyshang    //
59528a00297189c323096aae8e2975de94e8549613cyshang    // Return the memory pages back to free memory
59628a00297189c323096aae8e2975de94e8549613cyshang    //
5977970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel    NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;
5987970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel    NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);
59928a00297189c323096aae8e2975de94e8549613cyshang    CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);
60028a00297189c323096aae8e2975de94e8549613cyshang
60128a00297189c323096aae8e2975de94e8549613cyshang  } else {
60228a00297189c323096aae8e2975de94e8549613cyshang
60328a00297189c323096aae8e2975de94e8549613cyshang    //
60428a00297189c323096aae8e2975de94e8549613cyshang    // Put the pool entry onto the free pool list
60528a00297189c323096aae8e2975de94e8549613cyshang    //
60628a00297189c323096aae8e2975de94e8549613cyshang    Free = (POOL_FREE *) Head;
60757b4ecb94bceac2484dd9367b2ad111b05e17d97qhuang    ASSERT(Free != NULL);
60828a00297189c323096aae8e2975de94e8549613cyshang    Free->Signature = POOL_FREE_SIGNATURE;
60928a00297189c323096aae8e2975de94e8549613cyshang    Free->Index     = (UINT32)Index;
61028a00297189c323096aae8e2975de94e8549613cyshang    InsertHeadList (&Pool->FreeList[Index], &Free->Link);
61128a00297189c323096aae8e2975de94e8549613cyshang
61228a00297189c323096aae8e2975de94e8549613cyshang    //
613022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang    // See if all the pool entries in the same page as Free are freed pool
61428a00297189c323096aae8e2975de94e8549613cyshang    // entries
61528a00297189c323096aae8e2975de94e8549613cyshang    //
6167970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel    NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));
61728a00297189c323096aae8e2975de94e8549613cyshang    Free = (POOL_FREE *) &NewPage[0];
618e94a9ff7271367e649ee4f9a86da1f1bea6d112eqhuang    ASSERT(Free != NULL);
61928a00297189c323096aae8e2975de94e8549613cyshang
62028a00297189c323096aae8e2975de94e8549613cyshang    if (Free->Signature == POOL_FREE_SIGNATURE) {
62128a00297189c323096aae8e2975de94e8549613cyshang
62228a00297189c323096aae8e2975de94e8549613cyshang      AllFree = TRUE;
623162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang      Offset = 0;
624022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang
6257970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel      while ((Offset < Granularity) && (AllFree)) {
6267e8e22056b721203f29b3ee982a64e98b0cbc22aArd Biesheuvel        Free = (POOL_FREE *) &NewPage[Offset];
6277e8e22056b721203f29b3ee982a64e98b0cbc22aArd Biesheuvel        ASSERT(Free != NULL);
6287e8e22056b721203f29b3ee982a64e98b0cbc22aArd Biesheuvel        if (Free->Signature != POOL_FREE_SIGNATURE) {
6297e8e22056b721203f29b3ee982a64e98b0cbc22aArd Biesheuvel          AllFree = FALSE;
63028a00297189c323096aae8e2975de94e8549613cyshang        }
6317e8e22056b721203f29b3ee982a64e98b0cbc22aArd Biesheuvel        Offset += LIST_TO_SIZE(Free->Index);
63228a00297189c323096aae8e2975de94e8549613cyshang      }
63328a00297189c323096aae8e2975de94e8549613cyshang
63428a00297189c323096aae8e2975de94e8549613cyshang      if (AllFree) {
63528a00297189c323096aae8e2975de94e8549613cyshang
63628a00297189c323096aae8e2975de94e8549613cyshang        //
637022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang        // All of the pool entries in the same page as Free are free pool
63828a00297189c323096aae8e2975de94e8549613cyshang        // entries
63928a00297189c323096aae8e2975de94e8549613cyshang        // Remove all of these pool entries from the free loop lists.
64028a00297189c323096aae8e2975de94e8549613cyshang        //
64128a00297189c323096aae8e2975de94e8549613cyshang        Free = (POOL_FREE *) &NewPage[0];
64257b4ecb94bceac2484dd9367b2ad111b05e17d97qhuang        ASSERT(Free != NULL);
643162ed594438ab8d39f89b43e6d645ca24e1e1e65qhuang        Offset = 0;
644022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang
6457970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel        while (Offset < Granularity) {
6467e8e22056b721203f29b3ee982a64e98b0cbc22aArd Biesheuvel          Free = (POOL_FREE *) &NewPage[Offset];
6477e8e22056b721203f29b3ee982a64e98b0cbc22aArd Biesheuvel          ASSERT(Free != NULL);
6487e8e22056b721203f29b3ee982a64e98b0cbc22aArd Biesheuvel          RemoveEntryList (&Free->Link);
6497e8e22056b721203f29b3ee982a64e98b0cbc22aArd Biesheuvel          Offset += LIST_TO_SIZE(Free->Index);
65028a00297189c323096aae8e2975de94e8549613cyshang        }
65128a00297189c323096aae8e2975de94e8549613cyshang
65228a00297189c323096aae8e2975de94e8549613cyshang        //
65328a00297189c323096aae8e2975de94e8549613cyshang        // Free the page
65428a00297189c323096aae8e2975de94e8549613cyshang        //
6557970100ccbd48e6f931b078cb8e615eabee26141Ard Biesheuvel        CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (Granularity));
65628a00297189c323096aae8e2975de94e8549613cyshang      }
65728a00297189c323096aae8e2975de94e8549613cyshang    }
65828a00297189c323096aae8e2975de94e8549613cyshang  }
65928a00297189c323096aae8e2975de94e8549613cyshang
66028a00297189c323096aae8e2975de94e8549613cyshang  //
661022c6d45ef78605c173023f53984e4dfaf7b11f4qhuang  // If this is an OS specific memory type, then check to see if the last
66228a00297189c323096aae8e2975de94e8549613cyshang  // portion of that memory type has been freed.  If it has, then free the
66328a00297189c323096aae8e2975de94e8549613cyshang  // list entry for that memory type
66428a00297189c323096aae8e2975de94e8549613cyshang  //
6653d78c020d22023d35d27b48817d73ff31a361ac7rsun  if ((INT32)Pool->MemoryType < 0 && Pool->Used == 0) {
66628a00297189c323096aae8e2975de94e8549613cyshang    RemoveEntryList (&Pool->Link);
66728a00297189c323096aae8e2975de94e8549613cyshang    CoreFreePoolI (Pool);
66828a00297189c323096aae8e2975de94e8549613cyshang  }
66928a00297189c323096aae8e2975de94e8549613cyshang
67028a00297189c323096aae8e2975de94e8549613cyshang  return EFI_SUCCESS;
67128a00297189c323096aae8e2975de94e8549613cyshang}
67284edd20bd0756ef5719835498d4283435d6b5e77Star Zeng
673