| 1 | /*++\r |
| 2 | \r |
| 3 | Copyright (c) 2006, Intel Corporation \r |
| 4 | All rights reserved. This program and the accompanying materials \r |
| 5 | are licensed and made available under the terms and conditions of the BSD License \r |
| 6 | which accompanies this distribution. The full text of the license may be found at \r |
| 7 | http://opensource.org/licenses/bsd-license.php \r |
| 8 | \r |
| 9 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r |
| 10 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r |
| 11 | \r |
| 12 | Module Name:\r |
| 13 | \r |
| 14 | MemoryServices.c\r |
| 15 | \r |
| 16 | Abstract:\r |
| 17 | \r |
| 18 | EFI PEI Core memory services\r |
| 19 | \r |
| 20 | --*/\r |
| 21 | \r |
| 22 | //\r |
| 23 | // Include common header file for this module.\r |
| 24 | //\r |
| 25 | #include "CommonHeader.h"\r |
| 26 | \r |
| 27 | #include <PeiMain.h>\r |
| 28 | \r |
| 29 | VOID\r |
| 30 | InitializeMemoryServices (\r |
| 31 | IN EFI_PEI_SERVICES **PeiServices,\r |
| 32 | IN EFI_PEI_STARTUP_DESCRIPTOR *PeiStartupDescriptor,\r |
| 33 | IN PEI_CORE_INSTANCE *OldCoreData\r |
| 34 | )\r |
| 35 | /*++\r |
| 36 | \r |
| 37 | Routine Description:\r |
| 38 | \r |
| 39 | Initialize the memory services.\r |
| 40 | \r |
| 41 | Arguments:\r |
| 42 | \r |
| 43 | PeiServices - The PEI core services table.\r |
| 44 | PeiStartupDescriptor - Information and services provided by SEC phase.\r |
| 45 | OldCoreData - Pointer to the PEI Core data.\r |
| 46 | NULL if being run in non-permament memory mode.\r |
| 47 | \r |
| 48 | Returns:\r |
| 49 | \r |
| 50 | None\r |
| 51 | \r |
| 52 | --*/\r |
| 53 | {\r |
| 54 | PEI_CORE_INSTANCE *PrivateData;\r |
| 55 | UINT64 SizeOfCarHeap;\r |
| 56 | \r |
| 57 | PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);\r |
| 58 | PrivateData->SwitchStackSignal = FALSE;\r |
| 59 | \r |
| 60 | if (OldCoreData == NULL) {\r |
| 61 | \r |
| 62 | PrivateData->PeiMemoryInstalled = FALSE;\r |
| 63 | \r |
| 64 | PrivateData->BottomOfCarHeap = (VOID *) (((UINTN)(VOID *)(&PrivateData))\r |
| 65 | & (~((PeiStartupDescriptor->SizeOfCacheAsRam) - 1))); \r |
| 66 | PrivateData->TopOfCarHeap = (VOID *)((UINTN)(PrivateData->BottomOfCarHeap) + PeiStartupDescriptor->SizeOfCacheAsRam);\r |
| 67 | //\r |
| 68 | // SizeOfCarHeap is 1/2 (arbitrary) of CacheAsRam Size.\r |
| 69 | //\r |
| 70 | SizeOfCarHeap = (UINT64) PeiStartupDescriptor->SizeOfCacheAsRam;\r |
| 71 | SizeOfCarHeap = RShiftU64 (SizeOfCarHeap, 1);\r |
| 72 | \r |
| 73 | DEBUG_CODE_BEGIN ();\r |
| 74 | PrivateData->SizeOfCacheAsRam = PeiStartupDescriptor->SizeOfCacheAsRam;\r |
| 75 | PrivateData->MaxTopOfCarHeap = (VOID *) ((UINTN) PrivateData->BottomOfCarHeap + (UINTN) SizeOfCarHeap);\r |
| 76 | DEBUG_CODE_END ();\r |
| 77 | \r |
| 78 | PrivateData->HobList.Raw = PrivateData->BottomOfCarHeap;\r |
| 79 | \r |
| 80 | PeiCoreBuildHobHandoffInfoTable (\r |
| 81 | BOOT_WITH_FULL_CONFIGURATION,\r |
| 82 | (EFI_PHYSICAL_ADDRESS) (UINTN) PrivateData->BottomOfCarHeap,\r |
| 83 | (UINTN) SizeOfCarHeap\r |
| 84 | );\r |
| 85 | //\r |
| 86 | // Copy PeiServices from ROM to Cache in PrivateData\r |
| 87 | //\r |
| 88 | CopyMem (&(PrivateData->ServiceTableShadow), *PeiServices, sizeof (EFI_PEI_SERVICES));\r |
| 89 | \r |
| 90 | //\r |
| 91 | // Set PS to point to ServiceTableShadow in Cache\r |
| 92 | //\r |
| 93 | PrivateData->PS = &(PrivateData->ServiceTableShadow);\r |
| 94 | } else {\r |
| 95 | // \r |
| 96 | // Set PS to point to ServiceTableShadow in Cache one time after the \r |
| 97 | // stack switched to main memory \r |
| 98 | // \r |
| 99 | PrivateData->PS = &(PrivateData->ServiceTableShadow); \r |
| 100 | } \r |
| 101 | \r |
| 102 | return;\r |
| 103 | }\r |
| 104 | \r |
| 105 | EFI_STATUS\r |
| 106 | EFIAPI\r |
| 107 | PeiInstallPeiMemory (\r |
| 108 | IN EFI_PEI_SERVICES **PeiServices,\r |
| 109 | IN EFI_PHYSICAL_ADDRESS MemoryBegin,\r |
| 110 | IN UINT64 MemoryLength\r |
| 111 | )\r |
| 112 | /*++\r |
| 113 | \r |
| 114 | Routine Description:\r |
| 115 | \r |
| 116 | Install the permanent memory is now available.\r |
| 117 | Creates HOB (PHIT and Stack).\r |
| 118 | \r |
| 119 | Arguments:\r |
| 120 | \r |
| 121 | PeiServices - The PEI core services table.\r |
| 122 | MemoryBegin - Start of memory address.\r |
| 123 | MemoryLength - Length of memory.\r |
| 124 | \r |
| 125 | Returns:\r |
| 126 | \r |
| 127 | Status - EFI_SUCCESS\r |
| 128 | \r |
| 129 | --*/\r |
| 130 | {\r |
| 131 | PEI_CORE_INSTANCE *PrivateData;\r |
| 132 | EFI_HOB_HANDOFF_INFO_TABLE *OldHandOffHob;\r |
| 133 | EFI_HOB_HANDOFF_INFO_TABLE *NewHandOffHob;\r |
| 134 | UINT64 PeiStackSize;\r |
| 135 | UINT64 EfiFreeMemorySize;\r |
| 136 | EFI_PHYSICAL_ADDRESS PhysicalAddressOfOldHob;\r |
| 137 | \r |
| 138 | PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);\r |
| 139 | \r |
| 140 | PrivateData->SwitchStackSignal = TRUE;\r |
| 141 | PrivateData->PeiMemoryInstalled = TRUE;\r |
| 142 | \r |
| 143 | PrivateData->StackBase = MemoryBegin;\r |
| 144 | \r |
| 145 | PeiStackSize = RShiftU64 (MemoryLength, 1);\r |
| 146 | if (PEI_STACK_SIZE > PeiStackSize) {\r |
| 147 | PrivateData->StackSize = PeiStackSize;\r |
| 148 | } else {\r |
| 149 | PrivateData->StackSize = PEI_STACK_SIZE;\r |
| 150 | }\r |
| 151 | \r |
| 152 | OldHandOffHob = PrivateData->HobList.HandoffInformationTable;\r |
| 153 | \r |
| 154 | PrivateData->HobList.Raw = (VOID *)((UINTN)(MemoryBegin + PrivateData->StackSize));\r |
| 155 | NewHandOffHob = PrivateData->HobList.HandoffInformationTable;\r |
| 156 | PhysicalAddressOfOldHob = (EFI_PHYSICAL_ADDRESS) (UINTN) OldHandOffHob;\r |
| 157 | \r |
| 158 | EfiFreeMemorySize = OldHandOffHob->EfiFreeMemoryBottom - PhysicalAddressOfOldHob;\r |
| 159 | \r |
| 160 | DEBUG ((EFI_D_INFO, "HOBLIST address before memory init = 0x%08x\n", OldHandOffHob));\r |
| 161 | DEBUG ((EFI_D_INFO, "HOBLIST address after memory init = 0x%08x\n", NewHandOffHob));\r |
| 162 | \r |
| 163 | CopyMem (\r |
| 164 | NewHandOffHob,\r |
| 165 | OldHandOffHob,\r |
| 166 | (UINTN)EfiFreeMemorySize\r |
| 167 | );\r |
| 168 | \r |
| 169 | NewHandOffHob->EfiMemoryTop = MemoryBegin + MemoryLength;\r |
| 170 | NewHandOffHob->EfiFreeMemoryTop = NewHandOffHob->EfiMemoryTop;\r |
| 171 | NewHandOffHob->EfiMemoryBottom = MemoryBegin;\r |
| 172 | \r |
| 173 | NewHandOffHob->EfiFreeMemoryBottom = (UINTN)NewHandOffHob + EfiFreeMemorySize; \r |
| 174 | \r |
| 175 | NewHandOffHob->EfiEndOfHobList = (UINTN)NewHandOffHob +\r |
| 176 | (OldHandOffHob->EfiEndOfHobList -\r |
| 177 | PhysicalAddressOfOldHob);\r |
| 178 | \r |
| 179 | ConvertPpiPointers (PeiServices, OldHandOffHob, NewHandOffHob);\r |
| 180 | \r |
| 181 | BuildStackHob (PrivateData->StackBase, PrivateData->StackSize);\r |
| 182 | \r |
| 183 | \r |
| 184 | return EFI_SUCCESS; \r |
| 185 | }\r |
| 186 | \r |
| 187 | EFI_STATUS\r |
| 188 | EFIAPI\r |
| 189 | PeiAllocatePages (\r |
| 190 | IN EFI_PEI_SERVICES **PeiServices,\r |
| 191 | IN EFI_MEMORY_TYPE MemoryType,\r |
| 192 | IN UINTN Pages,\r |
| 193 | OUT EFI_PHYSICAL_ADDRESS *Memory\r |
| 194 | )\r |
| 195 | /*++\r |
| 196 | \r |
| 197 | Routine Description:\r |
| 198 | \r |
| 199 | Memory allocation service on permanent memory, \r |
| 200 | not usable prior to the memory installation.\r |
| 201 | \r |
| 202 | Arguments:\r |
| 203 | \r |
| 204 | PeiServices - The PEI core services table.\r |
| 205 | MemoryType - Type of memory to allocate.\r |
| 206 | Pages - Number of pages to allocate.\r |
| 207 | Memory - Pointer of memory allocated.\r |
| 208 | \r |
| 209 | Returns:\r |
| 210 | \r |
| 211 | Status - EFI_SUCCESS The allocation was successful\r |
| 212 | EFI_INVALID_PARAMETER Only AllocateAnyAddress is supported.\r |
| 213 | EFI_NOT_AVAILABLE_YET Called with permanent memory not available\r |
| 214 | EFI_OUT_OF_RESOURCES There is not enough HOB heap to satisfy the requirement\r |
| 215 | to allocate the number of pages.\r |
| 216 | \r |
| 217 | --*/\r |
| 218 | {\r |
| 219 | PEI_CORE_INSTANCE *PrivateData;\r |
| 220 | EFI_PEI_HOB_POINTERS Hob;\r |
| 221 | EFI_PHYSICAL_ADDRESS Offset;\r |
| 222 | \r |
| 223 | PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);\r |
| 224 | \r |
| 225 | //\r |
| 226 | // Check if Hob already available\r |
| 227 | //\r |
| 228 | if (!PrivateData->PeiMemoryInstalled) {\r |
| 229 | return EFI_NOT_AVAILABLE_YET;\r |
| 230 | }\r |
| 231 | \r |
| 232 | Hob.Raw = PrivateData->HobList.Raw;\r |
| 233 | \r |
| 234 | //\r |
| 235 | // Check to see if on 4k boundary\r |
| 236 | //\r |
| 237 | Offset = Hob.HandoffInformationTable->EfiFreeMemoryTop & 0xFFF;\r |
| 238 | \r |
| 239 | //\r |
| 240 | // If not aligned, make the allocation aligned.\r |
| 241 | //\r |
| 242 | if (Offset != 0) {\r |
| 243 | Hob.HandoffInformationTable->EfiFreeMemoryTop -= Offset;\r |
| 244 | }\r |
| 245 | \r |
| 246 | //\r |
| 247 | // Verify that there is sufficient memory to satisfy the allocation\r |
| 248 | //\r |
| 249 | if (Hob.HandoffInformationTable->EfiFreeMemoryTop - ((Pages * EFI_PAGE_SIZE) + sizeof (EFI_HOB_MEMORY_ALLOCATION)) < \r |
| 250 | Hob.HandoffInformationTable->EfiFreeMemoryBottom) {\r |
| 251 | DEBUG ((EFI_D_ERROR, "AllocatePages failed: No 0x%x Pages is available.\n", Pages));\r |
| 252 | DEBUG ((EFI_D_ERROR, "There is only left 0x%x pages memory resource to be allocated.\n", \\r |
| 253 | EFI_SIZE_TO_PAGES ((UINTN) (Hob.HandoffInformationTable->EfiFreeMemoryTop - Hob.HandoffInformationTable->EfiFreeMemoryBottom))));\r |
| 254 | return EFI_OUT_OF_RESOURCES;\r |
| 255 | } else {\r |
| 256 | //\r |
| 257 | // Update the PHIT to reflect the memory usage\r |
| 258 | //\r |
| 259 | Hob.HandoffInformationTable->EfiFreeMemoryTop -= Pages * EFI_PAGE_SIZE;\r |
| 260 | \r |
| 261 | //\r |
| 262 | // Update the value for the caller\r |
| 263 | //\r |
| 264 | *Memory = Hob.HandoffInformationTable->EfiFreeMemoryTop;\r |
| 265 | \r |
| 266 | //\r |
| 267 | // Create a memory allocation HOB.\r |
| 268 | //\r |
| 269 | BuildMemoryAllocationHob (\r |
| 270 | Hob.HandoffInformationTable->EfiFreeMemoryTop,\r |
| 271 | Pages * EFI_PAGE_SIZE + Offset,\r |
| 272 | MemoryType\r |
| 273 | );\r |
| 274 | \r |
| 275 | return EFI_SUCCESS;\r |
| 276 | }\r |
| 277 | }\r |
| 278 | \r |
| 279 | \r |
| 280 | EFI_STATUS\r |
| 281 | EFIAPI\r |
| 282 | PeiAllocatePool (\r |
| 283 | IN EFI_PEI_SERVICES **PeiServices,\r |
| 284 | IN UINTN Size,\r |
| 285 | OUT VOID **Buffer\r |
| 286 | )\r |
| 287 | /*++\r |
| 288 | \r |
| 289 | Routine Description:\r |
| 290 | \r |
| 291 | Memory allocation service on the CAR. \r |
| 292 | \r |
| 293 | Arguments:\r |
| 294 | \r |
| 295 | PeiServices - The PEI core services table.\r |
| 296 | \r |
| 297 | Size - Amount of memory required\r |
| 298 | \r |
| 299 | Buffer - Address of pointer to the buffer\r |
| 300 | \r |
| 301 | Returns:\r |
| 302 | \r |
| 303 | Status - EFI_SUCCESS The allocation was successful\r |
| 304 | EFI_OUT_OF_RESOURCES There is not enough heap to satisfy the requirement\r |
| 305 | to allocate the requested size.\r |
| 306 | \r |
| 307 | --*/\r |
| 308 | {\r |
| 309 | EFI_STATUS Status;\r |
| 310 | EFI_HOB_MEMORY_POOL *Hob;\r |
| 311 | \r |
| 312 | //\r |
| 313 | // If some "post-memory" PEIM wishes to allocate larger pool,\r |
| 314 | // it should use AllocatePages service instead.\r |
| 315 | //\r |
| 316 | ASSERT (Size < 0x10000 - sizeof (EFI_HOB_MEMORY_POOL));\r |
| 317 | Status = PeiServicesCreateHob (\r |
| 318 | EFI_HOB_TYPE_MEMORY_POOL,\r |
| 319 | (UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + Size),\r |
| 320 | (VOID **)&Hob\r |
| 321 | );\r |
| 322 | *Buffer = Hob+1; \r |
| 323 | \r |
| 324 | \r |
| 325 | return Status;\r |
| 326 | }\r |