/** @file C functions in SEC Copyright (c) 2008 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "SecMain.h" EFI_PEI_TEMPORARY_RAM_DONE_PPI gSecTemporaryRamDonePpi = { SecTemporaryRamDone }; EFI_SEC_PLATFORM_INFORMATION_PPI mSecPlatformInformationPpi = { SecPlatformInformation }; EFI_PEI_PPI_DESCRIPTOR mPeiSecPlatformInformationPpi[] = { { // // SecPerformance PPI notify descriptor. // EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, &gPeiSecPerformancePpiGuid, (VOID *) (UINTN) SecPerformancePpiCallBack }, { EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiTemporaryRamDonePpiGuid, &gSecTemporaryRamDonePpi }, { (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gEfiSecPlatformInformationPpiGuid, &mSecPlatformInformationPpi } }; /** Migrates the Global Descriptor Table (GDT) to permanent memory. @retval EFI_SUCCESS The GDT was migrated successfully. @retval EFI_OUT_OF_RESOURCES The GDT could not be migrated due to lack of available memory. **/ EFI_STATUS MigrateGdt ( VOID ) { EFI_STATUS Status; UINTN GdtBufferSize; IA32_DESCRIPTOR Gdtr; VOID *GdtBuffer; AsmReadGdtr ((IA32_DESCRIPTOR *) &Gdtr); GdtBufferSize = sizeof (IA32_SEGMENT_DESCRIPTOR) -1 + Gdtr.Limit + 1; Status = PeiServicesAllocatePool ( GdtBufferSize, &GdtBuffer ); ASSERT (GdtBuffer != NULL); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } GdtBuffer = ALIGN_POINTER (GdtBuffer, sizeof (IA32_SEGMENT_DESCRIPTOR)); CopyMem (GdtBuffer, (VOID *) Gdtr.Base, Gdtr.Limit + 1); Gdtr.Base = (UINTN) GdtBuffer; AsmWriteGdtr (&Gdtr); return EFI_SUCCESS; } // // These are IDT entries pointing to 10:FFFFFFE4h. // UINT64 mIdtEntryTemplate = 0xffff8e000010ffe4ULL; /** Caller provided function to be invoked at the end of InitializeDebugAgent(). Entry point to the C language phase of SEC. After the SEC assembly code has initialized some temporary memory and set up the stack, the control is transferred to this function. @param[in] Context The first input parameter of InitializeDebugAgent(). **/ VOID NORETURN EFIAPI SecStartupPhase2( IN VOID *Context ); /** Entry point of the notification callback function itself within the PEIM. It is to get SEC performance data and build HOB to convey the SEC performance data to DXE phase. @param PeiServices Indirect reference to the PEI Services Table. @param NotifyDescriptor Address of the notification descriptor data structure. @param Ppi Address of the PPI that was installed. @return Status of the notification. The status code returned from this function is ignored. **/ EFI_STATUS EFIAPI SecPerformancePpiCallBack ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi ) { EFI_STATUS Status; PEI_SEC_PERFORMANCE_PPI *SecPerf; FIRMWARE_SEC_PERFORMANCE Performance; SecPerf = (PEI_SEC_PERFORMANCE_PPI *) Ppi; Status = SecPerf->GetPerformance ((CONST EFI_PEI_SERVICES **) PeiServices, SecPerf, &Performance); if (!EFI_ERROR (Status)) { BuildGuidDataHob ( &gEfiFirmwarePerformanceGuid, &Performance, sizeof (FIRMWARE_SEC_PERFORMANCE) ); DEBUG ((DEBUG_INFO, "FPDT: SEC Performance Hob ResetEnd = %ld\n", Performance.ResetEnd)); } return Status; } /** Entry point to the C language phase of SEC. After the SEC assembly code has initialized some temporary memory and set up the stack, the control is transferred to this function. @param SizeOfRam Size of the temporary memory available for use. @param TempRamBase Base address of temporary ram @param BootFirmwareVolume Base address of the Boot Firmware Volume. **/ VOID NORETURN EFIAPI SecStartup ( IN UINT32 SizeOfRam, IN UINT32 TempRamBase, IN VOID *BootFirmwareVolume ) { EFI_SEC_PEI_HAND_OFF SecCoreData; IA32_DESCRIPTOR IdtDescriptor; SEC_IDT_TABLE IdtTableInStack; UINT32 Index; UINT32 PeiStackSize; EFI_STATUS Status; // // Report Status Code to indicate entering SEC core // REPORT_STATUS_CODE ( EFI_PROGRESS_CODE, EFI_SOFTWARE_SEC | EFI_SW_SEC_PC_ENTRY_POINT ); PeiStackSize = PcdGet32 (PcdPeiTemporaryRamStackSize); if (PeiStackSize == 0) { PeiStackSize = (SizeOfRam >> 1); } ASSERT (PeiStackSize < SizeOfRam); // // Process all libraries constructor function linked to SecCore. // ProcessLibraryConstructorList (); // // Initialize floating point operating environment // to be compliant with UEFI spec. // InitializeFloatingPointUnits (); // |-------------------|----> // |IDT Table | // |-------------------| // |PeiService Pointer | PeiStackSize // |-------------------| // | | // | Stack | // |-------------------|----> // | | // | | // | Heap | PeiTemporayRamSize // | | // | | // |-------------------|----> TempRamBase IdtTableInStack.PeiService = 0; for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index ++) { CopyMem ((VOID*)&IdtTableInStack.IdtTable[Index], (VOID*)&mIdtEntryTemplate, sizeof (UINT64)); } IdtDescriptor.Base = (UINTN) &IdtTableInStack.IdtTable; IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1); AsmWriteIdtr (&IdtDescriptor); // // Setup the default exception handlers // Status = InitializeCpuExceptionHandlers (NULL); ASSERT_EFI_ERROR (Status); // // Update the base address and length of Pei temporary memory // SecCoreData.DataSize = (UINT16) sizeof (EFI_SEC_PEI_HAND_OFF); SecCoreData.BootFirmwareVolumeBase = BootFirmwareVolume; SecCoreData.BootFirmwareVolumeSize = (UINTN)((EFI_FIRMWARE_VOLUME_HEADER *) BootFirmwareVolume)->FvLength; SecCoreData.TemporaryRamBase = (VOID*)(UINTN) TempRamBase; SecCoreData.TemporaryRamSize = SizeOfRam; SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase; SecCoreData.PeiTemporaryRamSize = SizeOfRam - PeiStackSize; SecCoreData.StackBase = (VOID*)(UINTN)(TempRamBase + SecCoreData.PeiTemporaryRamSize); SecCoreData.StackSize = PeiStackSize; // // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready. // InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, &SecCoreData, SecStartupPhase2); // // Should not come here. // UNREACHABLE (); } /** Caller provided function to be invoked at the end of InitializeDebugAgent(). Entry point to the C language phase of SEC. After the SEC assembly code has initialized some temporary memory and set up the stack, the control is transferred to this function. @param[in] Context The first input parameter of InitializeDebugAgent(). **/ VOID NORETURN EFIAPI SecStartupPhase2( IN VOID *Context ) { EFI_SEC_PEI_HAND_OFF *SecCoreData; EFI_PEI_PPI_DESCRIPTOR *PpiList; UINT32 Index; EFI_PEI_PPI_DESCRIPTOR *AllSecPpiList; EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint; PeiCoreEntryPoint = NULL; SecCoreData = (EFI_SEC_PEI_HAND_OFF *) Context; // // Perform platform specific initialization before entering PeiCore. // PpiList = SecPlatformMain (SecCoreData); // // Find Pei Core entry point. It will report SEC and Pei Core debug information if remote debug // is enabled. // if (PpiList != NULL) { Index = 0; do { if (CompareGuid (PpiList[Index].Guid, &gEfiPeiCoreFvLocationPpiGuid) && (((EFI_PEI_CORE_FV_LOCATION_PPI *) PpiList[Index].Ppi)->PeiCoreFvLocation != 0) ) { // // In this case, SecCore is in BFV but PeiCore is in another FV reported by PPI. // FindAndReportEntryPoints ( (EFI_FIRMWARE_VOLUME_HEADER *) SecCoreData->BootFirmwareVolumeBase, (EFI_FIRMWARE_VOLUME_HEADER *) ((EFI_PEI_CORE_FV_LOCATION_PPI *) PpiList[Index].Ppi)->PeiCoreFvLocation, &PeiCoreEntryPoint ); if (PeiCoreEntryPoint != NULL) { break; } else { // // Invalid PeiCore FV provided by platform // CpuDeadLoop (); } } } while ((PpiList[Index++].Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) != EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); } // // If EFI_PEI_CORE_FV_LOCATION_PPI not found, try to locate PeiCore from BFV. // if (PeiCoreEntryPoint == NULL) { // // Both SecCore and PeiCore are in BFV. // FindAndReportEntryPoints ( (EFI_FIRMWARE_VOLUME_HEADER *) SecCoreData->BootFirmwareVolumeBase, (EFI_FIRMWARE_VOLUME_HEADER *) SecCoreData->BootFirmwareVolumeBase, &PeiCoreEntryPoint ); if (PeiCoreEntryPoint == NULL) { CpuDeadLoop (); } } if (PpiList != NULL) { AllSecPpiList = (EFI_PEI_PPI_DESCRIPTOR *) SecCoreData->PeiTemporaryRamBase; // // Remove the terminal flag from the terminal PPI // CopyMem (AllSecPpiList, mPeiSecPlatformInformationPpi, sizeof (mPeiSecPlatformInformationPpi)); Index = sizeof (mPeiSecPlatformInformationPpi) / sizeof (EFI_PEI_PPI_DESCRIPTOR) - 1; AllSecPpiList[Index].Flags = AllSecPpiList[Index].Flags & (~EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); // // Append the platform additional PPI list // Index += 1; while (((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) != EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST)) { CopyMem (&AllSecPpiList[Index], PpiList, sizeof (EFI_PEI_PPI_DESCRIPTOR)); Index++; PpiList++; } // // Add the terminal PPI // CopyMem (&AllSecPpiList[Index ++], PpiList, sizeof (EFI_PEI_PPI_DESCRIPTOR)); // // Set PpiList to the total PPI // PpiList = AllSecPpiList; // // Adjust PEI TEMP RAM Range. // ASSERT (SecCoreData->PeiTemporaryRamSize > Index * sizeof (EFI_PEI_PPI_DESCRIPTOR)); SecCoreData->PeiTemporaryRamBase = (VOID *)((UINTN) SecCoreData->PeiTemporaryRamBase + Index * sizeof (EFI_PEI_PPI_DESCRIPTOR)); SecCoreData->PeiTemporaryRamSize = SecCoreData->PeiTemporaryRamSize - Index * sizeof (EFI_PEI_PPI_DESCRIPTOR); // // Adjust the Base and Size to be 8-byte aligned as HOB which has 8byte aligned requirement // will be built based on them in PEI phase. // SecCoreData->PeiTemporaryRamBase = (VOID *)(((UINTN)SecCoreData->PeiTemporaryRamBase + 7) & ~0x07); SecCoreData->PeiTemporaryRamSize &= ~(UINTN)0x07; } else { // // No addition PPI, PpiList directly point to the common PPI list. // PpiList = &mPeiSecPlatformInformationPpi[0]; } DEBUG (( DEBUG_INFO, "%a() Stack Base: 0x%p, Stack Size: 0x%x\n", __FUNCTION__, SecCoreData->StackBase, (UINT32) SecCoreData->StackSize )); // // Report Status Code to indicate transferring to PEI core // REPORT_STATUS_CODE ( EFI_PROGRESS_CODE, EFI_SOFTWARE_SEC | EFI_SW_SEC_PC_HANDOFF_TO_NEXT ); // // Transfer the control to the PEI core // ASSERT (PeiCoreEntryPoint != NULL); (*PeiCoreEntryPoint) (SecCoreData, PpiList); // // Should not come here. // UNREACHABLE (); } /** TemporaryRamDone() disables the use of Temporary RAM. If present, this service is invoked by the PEI Foundation after the EFI_PEI_PERMANANT_MEMORY_INSTALLED_PPI is installed. @retval EFI_SUCCESS Use of Temporary RAM was disabled. @retval EFI_INVALID_PARAMETER Temporary RAM could not be disabled. **/ EFI_STATUS EFIAPI SecTemporaryRamDone ( VOID ) { EFI_STATUS Status; EFI_STATUS Status2; UINTN Index; BOOLEAN State; EFI_PEI_PPI_DESCRIPTOR *PeiPpiDescriptor; REPUBLISH_SEC_PPI_PPI *RepublishSecPpiPpi; // // Republish Sec Platform Information(2) PPI // RepublishSecPlatformInformationPpi (); // // Re-install SEC PPIs using a PEIM produced service if published // for (Index = 0, Status = EFI_SUCCESS; Status == EFI_SUCCESS; Index++) { Status = PeiServicesLocatePpi ( &gRepublishSecPpiPpiGuid, Index, &PeiPpiDescriptor, (VOID **) &RepublishSecPpiPpi ); if (!EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "Calling RepublishSecPpi instance %d.\n", Index)); Status2 = RepublishSecPpiPpi->RepublishSecPpis (); ASSERT_EFI_ERROR (Status2); } } // // Migrate DebugAgentContext. // InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, NULL, NULL); // // Disable interrupts and save current interrupt state // State = SaveAndDisableInterrupts (); // // Migrate GDT before NEM near down // if (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes)) { Status = MigrateGdt (); ASSERT_EFI_ERROR (Status); } // // Disable Temporary RAM after Stack and Heap have been migrated at this point. // SecPlatformDisableTemporaryMemory (); // // Restore original interrupt state // SetInterruptState (State); return EFI_SUCCESS; }