1 /** @file 2 3 Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR> 4 This program and the accompanying materials 5 are licensed and made available under the terms and conditions of the BSD License 6 which accompanies this distribution. The full text of the license may be found at 7 http://opensource.org/licenses/bsd-license.php. 8 9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12 **/ 13 14 #include "DxeIpl.h" 15 16 17 // 18 // Module Globals used in the DXE to PEI hand off 19 // These must be module globals, so the stack can be switched 20 // 21 CONST EFI_DXE_IPL_PPI mDxeIplPpi = { 22 DxeLoadCore 23 }; 24 25 CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomGuidedSectionExtractionPpi = { 26 CustomGuidedSectionExtract 27 }; 28 29 CONST EFI_PEI_DECOMPRESS_PPI mDecompressPpi = { 30 Decompress 31 }; 32 33 CONST EFI_PEI_PPI_DESCRIPTOR mPpiList[] = { 34 { 35 EFI_PEI_PPI_DESCRIPTOR_PPI, 36 &gEfiDxeIplPpiGuid, 37 (VOID *) &mDxeIplPpi 38 }, 39 { 40 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), 41 &gEfiPeiDecompressPpiGuid, 42 (VOID *) &mDecompressPpi 43 } 44 }; 45 46 CONST EFI_PEI_PPI_DESCRIPTOR gEndOfPeiSignalPpi = { 47 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), 48 &gEfiEndOfPeiSignalPpiGuid, 49 NULL 50 }; 51 52 /** 53 Entry point of DXE IPL PEIM. 54 55 This function installs DXE IPL PPI and Decompress PPI. It also reloads 56 itself to memory on non-S3 resume boot path. 57 58 @param[in] FileHandle Handle of the file being invoked. 59 @param[in] PeiServices Describes the list of possible PEI Services. 60 61 @retval EFI_SUCESS The entry point of DXE IPL PEIM executes successfully. 62 @retval Others Some error occurs during the execution of this function. 63 64 **/ 65 EFI_STATUS 66 EFIAPI 67 PeimInitializeDxeIpl ( 68 IN EFI_PEI_FILE_HANDLE FileHandle, 69 IN CONST EFI_PEI_SERVICES **PeiServices 70 ) 71 { 72 EFI_STATUS Status; 73 EFI_GUID *ExtractHandlerGuidTable; 74 UINTN ExtractHandlerNumber; 75 EFI_PEI_PPI_DESCRIPTOR *GuidPpi; 76 77 // 78 // Get custom extract guided section method guid list 79 // 80 ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable); 81 82 // 83 // Install custom extraction guid PPI 84 // 85 if (ExtractHandlerNumber > 0) { 86 GuidPpi = (EFI_PEI_PPI_DESCRIPTOR *) AllocatePool (ExtractHandlerNumber * sizeof (EFI_PEI_PPI_DESCRIPTOR)); 87 ASSERT (GuidPpi != NULL); 88 while (ExtractHandlerNumber-- > 0) { 89 GuidPpi->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST; 90 GuidPpi->Ppi = (VOID *) &mCustomGuidedSectionExtractionPpi; 91 GuidPpi->Guid = &ExtractHandlerGuidTable[ExtractHandlerNumber]; 92 Status = PeiServicesInstallPpi (GuidPpi++); 93 ASSERT_EFI_ERROR(Status); 94 } 95 } 96 97 // 98 // Install DxeIpl and Decompress PPIs. 99 // 100 Status = PeiServicesInstallPpi (mPpiList); 101 ASSERT_EFI_ERROR(Status); 102 103 return Status; 104 } 105 106 /** 107 The ExtractSection() function processes the input section and 108 returns a pointer to the section contents. If the section being 109 extracted does not require processing (if the section 110 GuidedSectionHeader.Attributes has the 111 EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then 112 OutputBuffer is just updated to point to the start of the 113 section's contents. Otherwise, *Buffer must be allocated 114 from PEI permanent memory. 115 116 @param[in] This Indicates the 117 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance. 118 Buffer containing the input GUIDed section to be 119 processed. OutputBuffer OutputBuffer is 120 allocated from PEI permanent memory and contains 121 the new section stream. 122 @param[in] InputSection A pointer to the input buffer, which contains 123 the input section to be processed. 124 @param[out] OutputBuffer A pointer to a caller-allocated buffer, whose 125 size is specified by the contents of OutputSize. 126 @param[out] OutputSize A pointer to a caller-allocated 127 UINTN in which the size of *OutputBuffer 128 allocation is stored. If the function 129 returns anything other than EFI_SUCCESS, 130 the value of OutputSize is undefined. 131 @param[out] AuthenticationStatus A pointer to a caller-allocated 132 UINT32 that indicates the 133 authentication status of the 134 output buffer. If the input 135 section's GuidedSectionHeader. 136 Attributes field has the 137 EFI_GUIDED_SECTION_AUTH_STATUS_VALID 138 bit as clear, 139 AuthenticationStatus must return 140 zero. These bits reflect the 141 status of the extraction 142 operation. If the function 143 returns anything other than 144 EFI_SUCCESS, the value of 145 AuthenticationStatus is 146 undefined. 147 148 @retval EFI_SUCCESS The InputSection was 149 successfully processed and the 150 section contents were returned. 151 152 @retval EFI_OUT_OF_RESOURCES The system has insufficient 153 resources to process the request. 154 155 @retval EFI_INVALID_PARAMETER The GUID in InputSection does 156 not match this instance of the 157 GUIDed Section Extraction PPI. 158 159 **/ 160 EFI_STATUS 161 EFIAPI 162 CustomGuidedSectionExtract ( 163 IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This, 164 IN CONST VOID *InputSection, 165 OUT VOID **OutputBuffer, 166 OUT UINTN *OutputSize, 167 OUT UINT32 *AuthenticationStatus 168 ) 169 { 170 EFI_STATUS Status; 171 UINT8 *ScratchBuffer; 172 UINT32 ScratchBufferSize; 173 UINT32 OutputBufferSize; 174 UINT16 SectionAttribute; 175 176 // 177 // Init local variable 178 // 179 ScratchBuffer = NULL; 180 181 // 182 // Call GetInfo to get the size and attribute of input guided section data. 183 // 184 Status = ExtractGuidedSectionGetInfo ( 185 InputSection, 186 &OutputBufferSize, 187 &ScratchBufferSize, 188 &SectionAttribute 189 ); 190 191 if (EFI_ERROR (Status)) { 192 DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status)); 193 return Status; 194 } 195 196 if (ScratchBufferSize != 0) { 197 // 198 // Allocate scratch buffer 199 // 200 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize)); 201 if (ScratchBuffer == NULL) { 202 return EFI_OUT_OF_RESOURCES; 203 } 204 } 205 206 if (((SectionAttribute & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) && OutputBufferSize > 0) { 207 // 208 // Allocate output buffer 209 // 210 *OutputBuffer = AllocatePages (EFI_SIZE_TO_PAGES (OutputBufferSize) + 1); 211 if (*OutputBuffer == NULL) { 212 return EFI_OUT_OF_RESOURCES; 213 } 214 DEBUG ((DEBUG_INFO, "Customized Guided section Memory Size required is 0x%x and address is 0x%p\n", OutputBufferSize, *OutputBuffer)); 215 // 216 // *OutputBuffer still is one section. Adjust *OutputBuffer offset, 217 // skip EFI section header to make section data at page alignment. 218 // 219 *OutputBuffer = (VOID *)((UINT8 *) *OutputBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER)); 220 } 221 222 Status = ExtractGuidedSectionDecode ( 223 InputSection, 224 OutputBuffer, 225 ScratchBuffer, 226 AuthenticationStatus 227 ); 228 if (EFI_ERROR (Status)) { 229 // 230 // Decode failed 231 // 232 DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status)); 233 return Status; 234 } 235 236 *OutputSize = (UINTN) OutputBufferSize; 237 238 return EFI_SUCCESS; 239 } 240 241 242 243 /** 244 Decompresses a section to the output buffer. 245 246 This function looks up the compression type field in the input section and 247 applies the appropriate compression algorithm to compress the section to a 248 callee allocated buffer. 249 250 @param[in] This Points to this instance of the 251 EFI_PEI_DECOMPRESS_PEI PPI. 252 @param[in] CompressionSection Points to the compressed section. 253 @param[out] OutputBuffer Holds the returned pointer to the decompressed 254 sections. 255 @param[out] OutputSize Holds the returned size of the decompress 256 section streams. 257 258 @retval EFI_SUCCESS The section was decompressed successfully. 259 OutputBuffer contains the resulting data and 260 OutputSize contains the resulting size. 261 262 **/ 263 EFI_STATUS 264 EFIAPI 265 Decompress ( 266 IN CONST EFI_PEI_DECOMPRESS_PPI *This, 267 IN CONST EFI_COMPRESSION_SECTION *CompressionSection, 268 OUT VOID **OutputBuffer, 269 OUT UINTN *OutputSize 270 ) 271 { 272 EFI_STATUS Status; 273 UINT8 *DstBuffer; 274 UINT8 *ScratchBuffer; 275 UINT32 DstBufferSize; 276 UINT32 ScratchBufferSize; 277 VOID *CompressionSource; 278 UINT32 CompressionSourceSize; 279 UINT32 UncompressedLength; 280 UINT8 CompressionType; 281 282 if (CompressionSection->CommonHeader.Type != EFI_SECTION_COMPRESSION) { 283 ASSERT (FALSE); 284 return EFI_INVALID_PARAMETER; 285 } 286 287 if (IS_SECTION2 (CompressionSection)) { 288 CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION2)); 289 CompressionSourceSize = (UINT32) (SECTION2_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION2)); 290 UncompressedLength = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->UncompressedLength; 291 CompressionType = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->CompressionType; 292 } else { 293 CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION)); 294 CompressionSourceSize = (UINT32) (SECTION_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION)); 295 UncompressedLength = CompressionSection->UncompressedLength; 296 CompressionType = CompressionSection->CompressionType; 297 } 298 299 // 300 // This is a compression set, expand it 301 // 302 switch (CompressionType) { 303 case EFI_STANDARD_COMPRESSION: 304 // 305 // Load EFI standard compression. 306 // For compressed data, decompress them to destination buffer. 307 // 308 Status = UefiDecompressGetInfo ( 309 CompressionSource, 310 CompressionSourceSize, 311 &DstBufferSize, 312 &ScratchBufferSize 313 ); 314 if (EFI_ERROR (Status)) { 315 // 316 // GetInfo failed 317 // 318 DEBUG ((DEBUG_ERROR, "Decompress GetInfo Failed - %r\n", Status)); 319 return EFI_NOT_FOUND; 320 } 321 // 322 // Allocate scratch buffer 323 // 324 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize)); 325 if (ScratchBuffer == NULL) { 326 return EFI_OUT_OF_RESOURCES; 327 } 328 // 329 // Allocate destination buffer, extra one page for adjustment 330 // 331 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1); 332 if (DstBuffer == NULL) { 333 return EFI_OUT_OF_RESOURCES; 334 } 335 // 336 // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header 337 // to make section data at page alignment. 338 // 339 DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER); 340 // 341 // Call decompress function 342 // 343 Status = UefiDecompress ( 344 CompressionSource, 345 DstBuffer, 346 ScratchBuffer 347 ); 348 if (EFI_ERROR (Status)) { 349 // 350 // Decompress failed 351 // 352 DEBUG ((DEBUG_ERROR, "Decompress Failed - %r\n", Status)); 353 return EFI_NOT_FOUND; 354 } 355 break; 356 357 case EFI_NOT_COMPRESSED: 358 // 359 // Allocate destination buffer 360 // 361 DstBufferSize = UncompressedLength; 362 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1); 363 if (DstBuffer == NULL) { 364 return EFI_OUT_OF_RESOURCES; 365 } 366 // 367 // Adjust DstBuffer offset, skip EFI section header 368 // to make section data at page alignment. 369 // 370 DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER); 371 // 372 // stream is not actually compressed, just encapsulated. So just copy it. 373 // 374 CopyMem (DstBuffer, CompressionSource, DstBufferSize); 375 break; 376 377 default: 378 // 379 // Don't support other unknown compression type. 380 // 381 ASSERT (FALSE); 382 return EFI_NOT_FOUND; 383 } 384 385 *OutputSize = DstBufferSize; 386 *OutputBuffer = DstBuffer; 387 388 return EFI_SUCCESS; 389 } 390 391 /** 392 Main entry point to last PEIM. 393 394 This function finds DXE Core in the firmware volume and transfer the control to 395 DXE core. 396 397 @param[in] This Entry point for DXE IPL PPI. 398 @param[in] PeiServices General purpose services available to every PEIM. 399 @param[in] HobList Address to the Pei HOB list. 400 401 @return EFI_SUCCESS DXE core was successfully loaded. 402 @return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core. 403 404 **/ 405 EFI_STATUS 406 EFIAPI 407 DxeLoadCore ( 408 IN CONST EFI_DXE_IPL_PPI *This, 409 IN EFI_PEI_SERVICES **PeiServices, 410 IN EFI_PEI_HOB_POINTERS HobList 411 ) 412 { 413 EFI_STATUS Status; 414 415 DEBUG ((DEBUG_INFO | DEBUG_INIT, "FSP HOB is located at 0x%08X\n", HobList)); 416 417 // 418 // End of PEI phase signal 419 // 420 Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi); 421 ASSERT_EFI_ERROR (Status); 422 423 // 424 // Give control back to BootLoader after FspInit 425 // 426 DEBUG ((DEBUG_INFO | DEBUG_INIT, "FSP is waiting for NOTIFY\n")); 427 FspInitDone (); 428 429 // 430 // BootLoader called FSP again through NotifyPhase 431 // 432 FspWaitForNotify (); 433 434 435 // 436 // Give control back to the boot loader framework caller 437 // 438 DEBUG ((DEBUG_INFO | DEBUG_INIT, "============= PEIM FSP is Completed =============\n\n")); 439 440 SetFspApiReturnStatus(EFI_SUCCESS); 441 442 SetFspMeasurePoint (FSP_PERF_ID_API_NOTIFY_RDYBOOT_EXIT); 443 444 Pei2LoaderSwitchStack(); 445 446 // 447 // Should not come here 448 // 449 while (TRUE) { 450 DEBUG ((DEBUG_ERROR, "No FSP API should be called after FSP is DONE!\n")); 451 SetFspApiReturnStatus(EFI_UNSUPPORTED); 452 Pei2LoaderSwitchStack(); 453 } 454 455 return EFI_SUCCESS; 456 } 457