/** @file Source code file for Platform Init Pre-Memory PEI module Copyright (c) 2017 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include EFI_STATUS EFIAPI MemoryDiscoveredPpiNotifyCallback ( IN CONST EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi ); EFI_STATUS EFIAPI GetPlatformMemorySize ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_PLATFORM_MEMORY_SIZE_PPI *This, IN OUT UINT64 *MemorySize ); /** This function checks the memory range in PEI. @param PeiServices Pointer to PEI Services. @param This Pei memory test PPI pointer. @param BeginAddress Beginning of the memory address to be checked. @param MemoryLength Bytes of memory range to be checked. @param Operation Type of memory check operation to be performed. @param ErrorAddress Return the address of the error memory address. @retval EFI_SUCCESS The operation completed successfully. @retval EFI_DEVICE_ERROR Memory test failed. It's not safe to use this range of memory. **/ EFI_STATUS EFIAPI BaseMemoryTest ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_BASE_MEMORY_TEST_PPI *This, IN EFI_PHYSICAL_ADDRESS BeginAddress, IN UINT64 MemoryLength, IN PEI_MEMORY_TEST_OP Operation, OUT EFI_PHYSICAL_ADDRESS *ErrorAddress ); /** A hook for platform-specific initialization prior to disabling temporary RAM. @retval EFI_SUCCESS The platform initialization was successful. @retval EFI_NOT_READY The platform has not been detected yet. **/ EFI_STATUS EFIAPI PlatformInitBeforeTempRamExit ( VOID ); /** A hook for platform-specific initialization after disabling temporary RAM. @retval EFI_SUCCESS The platform initialization was successful. @retval EFI_NOT_READY The platform has not been detected yet. **/ EFI_STATUS EFIAPI PlatformInitAfterTempRamExit ( VOID ); GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mMemDiscoveredNotifyList = { (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gEfiPeiMemoryDiscoveredPpiGuid, (EFI_PEIM_NOTIFY_ENTRY_POINT) MemoryDiscoveredPpiNotifyCallback }; GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_PPI_DESCRIPTOR mPpiListRecoveryBootMode = { (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gEfiPeiBootInRecoveryModePpiGuid, NULL }; GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_PPI_DESCRIPTOR mPpiBootMode = { (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gEfiPeiMasterBootModePpiGuid, NULL }; GLOBAL_REMOVE_IF_UNREFERENCED PEI_BASE_MEMORY_TEST_PPI mPeiBaseMemoryTestPpi = { BaseMemoryTest }; GLOBAL_REMOVE_IF_UNREFERENCED PEI_PLATFORM_MEMORY_SIZE_PPI mMemoryMemorySizePpi = { GetPlatformMemorySize }; GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_PPI_DESCRIPTOR mMemPpiList[] = { { EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiBaseMemoryTestPpiGuid, &mPeiBaseMemoryTestPpi }, { (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gPeiPlatformMemorySizePpiGuid, &mMemoryMemorySizePpi }, }; GLOBAL_REMOVE_IF_UNREFERENCED PLATFORM_INIT_TEMP_RAM_EXIT_PPI mPlatformInitTempRamExitPpi = { PlatformInitBeforeTempRamExit, PlatformInitAfterTempRamExit }; GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_PPI_DESCRIPTOR mPlatformInitTempRamExitPpiDesc = { (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gPlatformInitTempRamExitPpiGuid, &mPlatformInitTempRamExitPpi }; /// /// Memory Reserved should be between 125% to 150% of the Current required memory /// otherwise BdsMisc.c would do a reset to make it 125% to avoid s4 resume issues. /// GLOBAL_REMOVE_IF_UNREFERENCED EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = { { EfiACPIReclaimMemory, FixedPcdGet32 (PcdPlatformEfiAcpiReclaimMemorySize) }, // ASL { EfiACPIMemoryNVS, FixedPcdGet32 (PcdPlatformEfiAcpiNvsMemorySize) }, // ACPI NVS (including S3 related) { EfiReservedMemoryType, FixedPcdGet32 (PcdPlatformEfiReservedMemorySize) }, // BIOS Reserved (including S3 related) { EfiRuntimeServicesData, FixedPcdGet32 (PcdPlatformEfiRtDataMemorySize) }, // Runtime Service Data { EfiRuntimeServicesCode, FixedPcdGet32 (PcdPlatformEfiRtCodeMemorySize) }, // Runtime Service Code { EfiMaxMemoryType, 0 } }; VOID BuildMemoryTypeInformation ( VOID ) { EFI_STATUS Status; EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices; UINTN DataSize; EFI_MEMORY_TYPE_INFORMATION MemoryData[EfiMaxMemoryType + 1]; // // Locate system configuration variable // Status = PeiServicesLocatePpi( &gEfiPeiReadOnlyVariable2PpiGuid, // GUID 0, // INSTANCE NULL, // EFI_PEI_PPI_DESCRIPTOR (VOID **) &VariableServices // PPI ); ASSERT_EFI_ERROR(Status); DataSize = sizeof (MemoryData); Status = VariableServices->GetVariable ( VariableServices, EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME, &gEfiMemoryTypeInformationGuid, NULL, &DataSize, &MemoryData ); if (EFI_ERROR(Status)) { DataSize = sizeof (mDefaultMemoryTypeInformation); CopyMem(MemoryData, mDefaultMemoryTypeInformation, DataSize); } /// /// Build the GUID'd HOB for DXE /// BuildGuidDataHob ( &gEfiMemoryTypeInformationGuid, MemoryData, DataSize ); } EFI_STATUS EFIAPI GetPlatformMemorySize ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_PLATFORM_MEMORY_SIZE_PPI *This, IN OUT UINT64 *MemorySize ) { EFI_STATUS Status; EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable; UINTN DataSize; EFI_MEMORY_TYPE_INFORMATION MemoryData[EfiMaxMemoryType + 1]; UINTN Index; EFI_BOOT_MODE BootMode; UINTN IndexNumber; #define PEI_MIN_MEMORY_SIZE (EFI_PHYSICAL_ADDRESS) ((320 * 0x100000)) *MemorySize = PEI_MIN_MEMORY_SIZE; Status = PeiServicesLocatePpi ( &gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (VOID **)&Variable ); ASSERT_EFI_ERROR (Status); Status = PeiServicesGetBootMode (&BootMode); ASSERT_EFI_ERROR (Status); DataSize = sizeof (MemoryData); Status = Variable->GetVariable ( Variable, EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME, &gEfiMemoryTypeInformationGuid, NULL, &DataSize, &MemoryData ); IndexNumber = sizeof (mDefaultMemoryTypeInformation) / sizeof (EFI_MEMORY_TYPE_INFORMATION); // // Accumulate maximum amount of memory needed // DEBUG((EFI_D_ERROR, "PEI_MIN_MEMORY_SIZE:%dKB \n", DivU64x32(*MemorySize,1024))); DEBUG((EFI_D_ERROR, "IndexNumber:%d MemoryDataNumber%d \n", IndexNumber,DataSize/ sizeof (EFI_MEMORY_TYPE_INFORMATION))); if (EFI_ERROR (Status)) { // // Start with minimum memory // for (Index = 0; Index < IndexNumber; Index++) { DEBUG((EFI_D_ERROR, "Index[%d].Type = %d .NumberOfPages=0x%x\n", Index,mDefaultMemoryTypeInformation[Index].Type,mDefaultMemoryTypeInformation[Index].NumberOfPages)); *MemorySize += mDefaultMemoryTypeInformation[Index].NumberOfPages * EFI_PAGE_SIZE; } DEBUG((EFI_D_ERROR, "No memory type, Total platform memory:%dKB \n", DivU64x32(*MemorySize,1024))); } else { // // Start with at least 0x200 pages of memory for the DXE Core and the DXE Stack // for (Index = 0; Index < IndexNumber; Index++) { DEBUG((EFI_D_ERROR, "Index[%d].Type = %d .NumberOfPages=0x%x\n", Index,MemoryData[Index].Type,MemoryData[Index].NumberOfPages)); *MemorySize += MemoryData[Index].NumberOfPages * EFI_PAGE_SIZE; } DEBUG((EFI_D_ERROR, "has memory type, Total platform memory:%dKB \n", DivU64x32(*MemorySize,1024))); } return EFI_SUCCESS; } /** This function checks the memory range in PEI. @param PeiServices Pointer to PEI Services. @param This Pei memory test PPI pointer. @param BeginAddress Beginning of the memory address to be checked. @param MemoryLength Bytes of memory range to be checked. @param Operation Type of memory check operation to be performed. @param ErrorAddress Return the address of the error memory address. @retval EFI_SUCCESS The operation completed successfully. @retval EFI_DEVICE_ERROR Memory test failed. It's not safe to use this range of memory. **/ EFI_STATUS EFIAPI BaseMemoryTest ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_BASE_MEMORY_TEST_PPI *This, IN EFI_PHYSICAL_ADDRESS BeginAddress, IN UINT64 MemoryLength, IN PEI_MEMORY_TEST_OP Operation, OUT EFI_PHYSICAL_ADDRESS *ErrorAddress ) { UINT32 TestPattern; UINT32 SpanSize; EFI_PHYSICAL_ADDRESS TempAddress; #define MEMORY_TEST_PATTERN 0x5A5A5A5A #define MEMORY_TEST_COVER_SPAN 0x40000 TestPattern = MEMORY_TEST_PATTERN; SpanSize = 0; // // Make sure we don't try and test anything above the max physical address range // ASSERT (BeginAddress + MemoryLength < MAX_ADDRESS); switch (Operation) { case Extensive: SpanSize = 0x4; break; case Sparse: case Quick: SpanSize = MEMORY_TEST_COVER_SPAN; break; case Ignore: goto Done; break; } // // Write the test pattern into memory range // TempAddress = BeginAddress; while (TempAddress < BeginAddress + MemoryLength) { (*(UINT32 *) (UINTN) TempAddress) = TestPattern; TempAddress += SpanSize; } // // Read pattern from memory and compare it // TempAddress = BeginAddress; while (TempAddress < BeginAddress + MemoryLength) { if ((*(UINT32 *) (UINTN) TempAddress) != TestPattern) { *ErrorAddress = TempAddress; return EFI_DEVICE_ERROR; } TempAddress += SpanSize; } Done: return EFI_SUCCESS; } /** Install Firmware Volume Hob's once there is main memory @param[in] PeiServices General purpose services available to every PEIM. @param[in] NotifyDescriptor Notify that this module published. @param[in] Ppi PPI that was installed. @retval EFI_SUCCESS The function completed successfully. **/ EFI_STATUS EFIAPI MemoryDiscoveredPpiNotifyCallback ( IN CONST EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi ) { EFI_STATUS Status; EFI_BOOT_MODE BootMode; Status = BoardInitAfterMemoryInit (); ASSERT_EFI_ERROR (Status); Status = PeiServicesGetBootMode (&BootMode); ASSERT_EFI_ERROR (Status); SetCacheMtrr (); ReportCpuHob (); TestPointMemoryDiscoveredMtrrFunctional (); TestPointMemoryDiscoveredMemoryResourceFunctional (); /// /// If S3 resume, then we are done /// if (BootMode == BOOT_ON_S3_RESUME) { return EFI_SUCCESS; } TestPointMemoryDiscoveredDmaProtectionEnabled (); if (PcdGetBool (PcdStopAfterMemInit)) { CpuDeadLoop (); } return Status; } /** A hook for platform-specific initialization prior to disabling temporary RAM. @retval EFI_SUCCESS The platform initialization was successful. @retval EFI_NOT_READY The platform has not been detected yet. **/ EFI_STATUS EFIAPI PlatformInitBeforeTempRamExit ( VOID ) { return BoardInitBeforeTempRamExit (); } /** A hook for platform-specific initialization after disabling temporary RAM. @retval EFI_SUCCESS The platform initialization was successful. @retval EFI_NOT_READY The platform has not been detected yet. **/ EFI_STATUS EFIAPI PlatformInitAfterTempRamExit ( VOID ) { return BoardInitAfterTempRamExit (); } /** This function handles PlatformInit task after PeiReadOnlyVariable2 PPI produced @param[in] PeiServices Pointer to PEI Services Table. @retval EFI_SUCCESS The function completes successfully @retval others **/ EFI_STATUS EFIAPI PlatformInitPreMem ( IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status; EFI_BOOT_MODE BootMode; // // Start board detection // BoardDetect (); BoardDebugInit (); TestPointDebugInitDone (); if (PcdGetBool (PcdStopAfterDebugInit)) { CpuDeadLoop (); } BootMode = BoardBootModeDetect (); Status = PeiServicesSetBootMode (BootMode); ASSERT_EFI_ERROR (Status); if (BootMode == BOOT_IN_RECOVERY_MODE) { Status = PeiServicesInstallPpi (&mPpiListRecoveryBootMode); } /// /// Signal possible dependent modules that there has been a /// final boot mode determination, it is used to build BIST /// Hob for Dxe use. /// Status = PeiServicesInstallPpi (&mPpiBootMode); ASSERT_EFI_ERROR (Status); BuildMemoryTypeInformation (); if (!PcdGetBool(PcdFspWrapperBootMode)) { Status = PeiServicesInstallPpi (mMemPpiList); ASSERT_EFI_ERROR (Status); } Status = BoardInitBeforeMemoryInit (); ASSERT_EFI_ERROR (Status); Status = PeiServicesInstallPpi (&mPlatformInitTempRamExitPpiDesc); ASSERT_EFI_ERROR (Status); return Status; } /** Platform Init before memory PEI module entry point @param[in] FileHandle Not used. @param[in] PeiServices General purpose services available to every PEIM. @retval EFI_SUCCESS The function completes successfully @retval EFI_OUT_OF_RESOURCES Insufficient resources to create database **/ EFI_STATUS EFIAPI PlatformInitPreMemEntryPoint ( IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status; Status = PlatformInitPreMem (PeiServices); /// /// After code reorangized, memorycallback will run because the PPI is already /// installed when code run to here, it is supposed that the InstallEfiMemory is /// done before. /// Status = PeiServicesNotifyPpi (&mMemDiscoveredNotifyList); return Status; }