• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   EFI PEI Core memory services
3 
4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "PeiMain.h"
16 
17 /**
18 
19   Initialize the memory services.
20 
21   @param PrivateData     Points to PeiCore's private instance data.
22   @param SecCoreData     Points to a data structure containing information about the PEI core's operating
23                          environment, such as the size and location of temporary RAM, the stack location and
24                          the BFV location.
25   @param OldCoreData     Pointer to the PEI Core data.
26                          NULL if being run in non-permament memory mode.
27 
28 **/
29 VOID
InitializeMemoryServices(IN PEI_CORE_INSTANCE * PrivateData,IN CONST EFI_SEC_PEI_HAND_OFF * SecCoreData,IN PEI_CORE_INSTANCE * OldCoreData)30 InitializeMemoryServices (
31   IN PEI_CORE_INSTANCE           *PrivateData,
32   IN CONST EFI_SEC_PEI_HAND_OFF  *SecCoreData,
33   IN PEI_CORE_INSTANCE           *OldCoreData
34   )
35 {
36 
37   PrivateData->SwitchStackSignal    = FALSE;
38 
39   //
40   // First entering PeiCore, following code will initialized some field
41   // in PeiCore's private data according to hand off data from sec core.
42   //
43   if (OldCoreData == NULL) {
44 
45     PrivateData->PeiMemoryInstalled = FALSE;
46     PrivateData->HobList.Raw        = SecCoreData->PeiTemporaryRamBase;
47 
48     PeiCoreBuildHobHandoffInfoTable (
49       BOOT_WITH_FULL_CONFIGURATION,
50       (EFI_PHYSICAL_ADDRESS) (UINTN) SecCoreData->PeiTemporaryRamBase,
51       (UINTN) SecCoreData->PeiTemporaryRamSize
52       );
53 
54     //
55     // Set Ps to point to ServiceTableShadow in Cache
56     //
57     PrivateData->Ps = &(PrivateData->ServiceTableShadow);
58   }
59 
60   return;
61 }
62 
63 /**
64 
65   This function registers the found memory configuration with the PEI Foundation.
66 
67   The usage model is that the PEIM that discovers the permanent memory shall invoke this service.
68   This routine will hold discoveried memory information into PeiCore's private data,
69   and set SwitchStackSignal flag. After PEIM who discovery memory is dispatched,
70   PeiDispatcher will migrate temporary memory to permenement memory.
71 
72   @param PeiServices        An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
73   @param MemoryBegin        Start of memory address.
74   @param MemoryLength       Length of memory.
75 
76   @return EFI_SUCCESS Always success.
77 
78 **/
79 EFI_STATUS
80 EFIAPI
PeiInstallPeiMemory(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_PHYSICAL_ADDRESS MemoryBegin,IN UINT64 MemoryLength)81 PeiInstallPeiMemory (
82   IN CONST EFI_PEI_SERVICES  **PeiServices,
83   IN EFI_PHYSICAL_ADDRESS    MemoryBegin,
84   IN UINT64                  MemoryLength
85   )
86 {
87   PEI_CORE_INSTANCE                     *PrivateData;
88 
89   DEBUG ((EFI_D_INFO, "PeiInstallPeiMemory MemoryBegin 0x%LX, MemoryLength 0x%LX\n", MemoryBegin, MemoryLength));
90   PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
91 
92   //
93   // PEI_SERVICE.InstallPeiMemory should only be called one time during whole PEI phase.
94   // If it is invoked more than one time, ASSERT information is given for developer debugging in debug tip and
95   // simply return EFI_SUCESS in release tip to ignore it.
96   //
97   if (PrivateData->PeiMemoryInstalled) {
98     DEBUG ((EFI_D_ERROR, "ERROR: PeiInstallPeiMemory is called more than once!\n"));
99     ASSERT (FALSE);
100     return EFI_SUCCESS;
101   }
102 
103   PrivateData->PhysicalMemoryBegin   = MemoryBegin;
104   PrivateData->PhysicalMemoryLength  = MemoryLength;
105   PrivateData->FreePhysicalMemoryTop = MemoryBegin + MemoryLength;
106 
107   PrivateData->SwitchStackSignal      = TRUE;
108 
109   return EFI_SUCCESS;
110 }
111 
112 /**
113   The purpose of the service is to publish an interface that allows
114   PEIMs to allocate memory ranges that are managed by the PEI Foundation.
115 
116   @param  PeiServices      An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
117   @param  MemoryType       The type of memory to allocate.
118   @param  Pages            The number of contiguous 4 KB pages to allocate.
119   @param  Memory           Pointer to a physical address. On output, the address is set to the base
120                            of the page range that was allocated.
121 
122   @retval EFI_SUCCESS           The memory range was successfully allocated.
123   @retval EFI_OUT_OF_RESOURCES  The pages could not be allocated.
124   @retval EFI_INVALID_PARAMETER Type is not equal to EfiLoaderCode, EfiLoaderData, EfiRuntimeServicesCode,
125                                 EfiRuntimeServicesData, EfiBootServicesCode, EfiBootServicesData,
126                                 EfiACPIReclaimMemory, EfiReservedMemoryType, or EfiACPIMemoryNVS.
127 
128 **/
129 EFI_STATUS
130 EFIAPI
PeiAllocatePages(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_MEMORY_TYPE MemoryType,IN UINTN Pages,OUT EFI_PHYSICAL_ADDRESS * Memory)131 PeiAllocatePages (
132   IN CONST EFI_PEI_SERVICES     **PeiServices,
133   IN       EFI_MEMORY_TYPE      MemoryType,
134   IN       UINTN                Pages,
135   OUT      EFI_PHYSICAL_ADDRESS *Memory
136   )
137 {
138   PEI_CORE_INSTANCE                       *PrivateData;
139   EFI_PEI_HOB_POINTERS                    Hob;
140   EFI_PHYSICAL_ADDRESS                    *FreeMemoryTop;
141   EFI_PHYSICAL_ADDRESS                    *FreeMemoryBottom;
142   UINTN                                   RemainingPages;
143 
144   if ((MemoryType != EfiLoaderCode) &&
145       (MemoryType != EfiLoaderData) &&
146       (MemoryType != EfiRuntimeServicesCode) &&
147       (MemoryType != EfiRuntimeServicesData) &&
148       (MemoryType != EfiBootServicesCode) &&
149       (MemoryType != EfiBootServicesData) &&
150       (MemoryType != EfiACPIReclaimMemory) &&
151       (MemoryType != EfiReservedMemoryType) &&
152       (MemoryType != EfiACPIMemoryNVS)) {
153     return EFI_INVALID_PARAMETER;
154   }
155 
156   PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
157   Hob.Raw     = PrivateData->HobList.Raw;
158 
159   //
160   // Check if Hob already available
161   //
162   if (!PrivateData->PeiMemoryInstalled) {
163     //
164     // When PeiInstallMemory is called but temporary memory has *not* been moved to temporary memory,
165     // the AllocatePage will depend on the field of PEI_CORE_INSTANCE structure.
166     //
167     if (!PrivateData->SwitchStackSignal) {
168       return EFI_NOT_AVAILABLE_YET;
169     } else {
170       FreeMemoryTop     = &(PrivateData->FreePhysicalMemoryTop);
171       FreeMemoryBottom  = &(PrivateData->PhysicalMemoryBegin);
172     }
173   } else {
174     FreeMemoryTop     = &(Hob.HandoffInformationTable->EfiFreeMemoryTop);
175     FreeMemoryBottom  = &(Hob.HandoffInformationTable->EfiFreeMemoryBottom);
176   }
177 
178   //
179   // Check to see if on 4k boundary, If not aligned, make the allocation aligned.
180   //
181   *(FreeMemoryTop) -= *(FreeMemoryTop) & 0xFFF;
182 
183   //
184   // Verify that there is sufficient memory to satisfy the allocation.
185   // For page allocation, the overhead sizeof (EFI_HOB_MEMORY_ALLOCATION) needs to be considered.
186   //
187   if ((UINTN) (*FreeMemoryTop - *FreeMemoryBottom) < (UINTN) ALIGN_VALUE (sizeof (EFI_HOB_MEMORY_ALLOCATION), 8)) {
188     DEBUG ((EFI_D_ERROR, "AllocatePages failed: No space to build memory allocation hob.\n"));
189     return  EFI_OUT_OF_RESOURCES;
190   }
191   RemainingPages = (UINTN)(*FreeMemoryTop - *FreeMemoryBottom - ALIGN_VALUE (sizeof (EFI_HOB_MEMORY_ALLOCATION), 8)) >> EFI_PAGE_SHIFT;
192   //
193   // The number of remaining pages needs to be greater than or equal to that of the request pages.
194   //
195   if (RemainingPages < Pages) {
196     DEBUG ((EFI_D_ERROR, "AllocatePages failed: No 0x%lx Pages is available.\n", (UINT64) Pages));
197     DEBUG ((EFI_D_ERROR, "There is only left 0x%lx pages memory resource to be allocated.\n", (UINT64) RemainingPages));
198     return  EFI_OUT_OF_RESOURCES;
199   } else {
200     //
201     // Update the PHIT to reflect the memory usage
202     //
203     *(FreeMemoryTop) -= Pages * EFI_PAGE_SIZE;
204 
205     //
206     // Update the value for the caller
207     //
208     *Memory = *(FreeMemoryTop);
209 
210     //
211     // Create a memory allocation HOB.
212     //
213     BuildMemoryAllocationHob (
214       *(FreeMemoryTop),
215       Pages * EFI_PAGE_SIZE,
216       MemoryType
217       );
218 
219     return EFI_SUCCESS;
220   }
221 }
222 
223 /**
224 
225   Pool allocation service. Before permanent memory is discoveried, the pool will
226   be allocated the heap in the temporary memory. Genenrally, the size of heap in temporary
227   memory does not exceed to 64K, so the biggest pool size could be allocated is
228   64K.
229 
230   @param PeiServices               An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
231   @param Size                      Amount of memory required
232   @param Buffer                    Address of pointer to the buffer
233 
234   @retval EFI_SUCCESS              The allocation was successful
235   @retval EFI_OUT_OF_RESOURCES     There is not enough heap to satisfy the requirement
236                                    to allocate the requested size.
237 
238 **/
239 EFI_STATUS
240 EFIAPI
PeiAllocatePool(IN CONST EFI_PEI_SERVICES ** PeiServices,IN UINTN Size,OUT VOID ** Buffer)241 PeiAllocatePool (
242   IN CONST EFI_PEI_SERVICES     **PeiServices,
243   IN       UINTN                Size,
244   OUT      VOID                 **Buffer
245   )
246 {
247   EFI_STATUS               Status;
248   EFI_HOB_MEMORY_POOL      *Hob;
249 
250   //
251   // If some "post-memory" PEIM wishes to allocate larger pool,
252   // it should use AllocatePages service instead.
253   //
254 
255   //
256   // Generally, the size of heap in temporary memory does not exceed to 64K,
257   // HobLength is multiples of 8 bytes, so the maxmium size of pool is 0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL)
258   //
259   if (Size > (0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL))) {
260     return EFI_OUT_OF_RESOURCES;
261   }
262 
263   Status = PeiServicesCreateHob (
264              EFI_HOB_TYPE_MEMORY_POOL,
265              (UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + Size),
266              (VOID **)&Hob
267              );
268   ASSERT_EFI_ERROR (Status);
269   *Buffer = Hob+1;
270 
271   return Status;
272 }
273