/** Ready to Boot Event notification handler. Sequence of OS boot events is measured in this event notification handler. @param[in] Event Event whose notification function is being invoked @param[in] Context Pointer to the notification function's context **/ VOID EFIAPI OnReadyToBoot ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; UINTN DataSize; if (MOR_CLEAR_MEMORY_VALUE (mMorControl) == 0x0) { // // MorControl is expected, directly return to avoid unnecessary variable operation // return ; } // // Clear MOR_CLEAR_MEMORY_BIT // DEBUG ((EFI_D_INFO, "TcgMor: Clear MorClearMemory bit\n")); mMorControl &= 0xFE; DataSize = sizeof (mMorControl); Status = gRT->SetVariable ( MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, &gEfiMemoryOverwriteControlDataGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, DataSize, &mMorControl ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "TcgMor: Clear MOR_CLEAR_MEMORY_BIT failure, Status = %r\n")); } }
/** Software SMI callback for MemoryClear which is called from ACPI method. Caution: This function may receive untrusted input. Variable and ACPINvs are external input, so this function will validate its data structure to be valid value. @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). @param[in] Context Points to an optional handler context which was specified when the handler was registered. @param[in, out] CommBuffer A pointer to a collection of data in memory that will be conveyed from a non-SMM environment into an SMM environment. @param[in, out] CommBufferSize The size of the CommBuffer. @retval EFI_SUCCESS The interrupt was handled successfully. **/ EFI_STATUS EFIAPI MemoryClearCallback ( IN EFI_HANDLE DispatchHandle, IN CONST VOID *Context, IN OUT VOID *CommBuffer, IN OUT UINTN *CommBufferSize ) { EFI_STATUS Status; UINTN DataSize; UINT8 MorControl; mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS; if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) { MorControl = (UINT8) mTcgNvs->MemoryClear.Request; } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) { DataSize = sizeof (UINT8); Status = mSmmVariable->SmmGetVariable ( MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, &gEfiMemoryOverwriteControlDataGuid, NULL, &DataSize, &MorControl ); if (EFI_ERROR (Status)) { mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE; DEBUG ((EFI_D_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status)); return EFI_SUCCESS; } if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) { return EFI_SUCCESS; } MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK; } DataSize = sizeof (UINT8); Status = mSmmVariable->SmmSetVariable ( MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, &gEfiMemoryOverwriteControlDataGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, DataSize, &MorControl ); if (EFI_ERROR (Status)) { mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE; DEBUG ((EFI_D_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", Status)); } return EFI_SUCCESS; }
/** This function will be called when MRC is done. @param PeiServices General purpose services available to every PEIM. @param NotifyDescriptor Information about the notify event.. @param Ppi The notify context. @retval EFI_SUCCESS If the function completed successfully. **/ EFI_STATUS EFIAPI MemoryDiscoveredPpiNotifyCallback ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi ) { EFI_STATUS Status; EFI_BOOT_MODE BootMode; UINT64 MemoryLength; EFI_SMRAM_DESCRIPTOR *SmramDescriptor; UINTN NumSmramRegions; UINT32 RmuMainBaseAddress; UINT32 RegData32; UINT8 CpuAddressWidth; UINT32 RegEax; MTRR_SETTINGS MtrrSettings; EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices; UINT8 MorControl; UINTN DataSize; DEBUG ((EFI_D_INFO, "Platform PEIM Memory Callback\n")); NumSmramRegions = 0; SmramDescriptor = NULL; RmuMainBaseAddress = 0; PERF_START (NULL, "SetCache", NULL, 0); InfoPostInstallMemory (&RmuMainBaseAddress, &SmramDescriptor, &NumSmramRegions); ASSERT (SmramDescriptor != NULL); ASSERT (RmuMainBaseAddress != 0); MemoryLength = ((UINT64) RmuMainBaseAddress) + 0x10000; Status = PeiServicesGetBootMode (&BootMode); ASSERT_EFI_ERROR (Status); // // Get current MTRR settings // MtrrGetAllMtrrs (&MtrrSettings); // // Set all DRAM cachability to CacheWriteBack // Status = MtrrSetMemoryAttributeInMtrrSettings (&MtrrSettings, 0, MemoryLength, CacheWriteBack); ASSERT_EFI_ERROR (Status); // // RTC:28208 - System hang/crash when entering probe mode(ITP) when relocating SMBASE // Workaround to make default SMRAM UnCachable // Status = MtrrSetMemoryAttributeInMtrrSettings (&MtrrSettings, 0x30000, SIZE_64KB, CacheUncacheable); ASSERT_EFI_ERROR (Status); // // Set new MTRR settings // MtrrSetAllMtrrs (&MtrrSettings); PERF_END (NULL, "SetCache", NULL, 0); // // Get necessary PPI // Status = PeiServicesLocatePpi ( &gEfiPeiReadOnlyVariable2PpiGuid, // GUID 0, // INSTANCE NULL, // EFI_PEI_PPI_DESCRIPTOR (VOID **)&VariableServices // PPI ); ASSERT_EFI_ERROR (Status); // // Detect MOR request by the OS. // MorControl = 0; DataSize = sizeof (MorControl); Status = VariableServices->GetVariable ( VariableServices, MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, &gEfiMemoryOverwriteControlDataGuid, NULL, &DataSize, &MorControl ); // // If OS requested a memory overwrite perform it now for Embedded SRAM // if (MOR_CLEAR_MEMORY_VALUE (MorControl)) { DEBUG ((EFI_D_INFO, "Clear Embedded SRAM per MOR request.\n")); if (PcdGet32 (PcdESramMemorySize) > 0) { if (PcdGet32 (PcdEsramStage1Base) == 0) { // // ZeroMem() generates an ASSERT() if Buffer parameter is NULL. // Clear byte at 0 and start clear operation at address 1. // *(UINT8 *)(0) = 0; ZeroMem ((VOID *)1, (UINTN)PcdGet32 (PcdESramMemorySize) - 1); } else { ZeroMem ( (VOID *)(UINTN)PcdGet32 (PcdEsramStage1Base), (UINTN)PcdGet32 (PcdESramMemorySize) ); } } } // // Install PeiReset for PeiResetSystem service // Status = PeiServicesInstallPpi (&mPpiList[0]); ASSERT_EFI_ERROR (Status); // // Do QNC initialization after MRC // PeiQNCPostMemInit (); Status = PeiServicesInstallPpi (&mPpiStall[0]); ASSERT_EFI_ERROR (Status); // // Set E000/F000 Routing // RegData32 = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC); RegData32 |= (BIT2|BIT1); QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, RegData32); if (BootMode == BOOT_IN_RECOVERY_MODE) { // Do nothing here. A generic RecoveryModule will handle it. } else if (BootMode == BOOT_ON_S3_RESUME) { return EFI_SUCCESS; } else { PeiServicesInstallFvInfoPpi ( NULL, (VOID *) (UINTN) PcdGet32 (PcdFlashFvMainBase), PcdGet32 (PcdFlashFvMainSize), NULL, NULL ); // // Publish the FVMAIN FV so the DXE Phase can dispatch drivers from this FV // and produce Load File Protocols for UEFI Applications in this FV. // BuildFvHob ( PcdGet32 (PcdFlashFvMainBase), PcdGet32 (PcdFlashFvMainSize) ); // // Publish the Payload FV so the DXE Phase can dispatch drivers from this FV // and produce Load File Protocols for UEFI Applications in this FV. // BuildFvHob ( PcdGet32 (PcdFlashFvPayloadBase), PcdGet32 (PcdFlashFvPayloadSize) ); } // // Build flash HOB, it's going to be used by GCD and E820 building // Map full SPI flash decode range (regardless of smaller SPI flash parts installed) // BuildResourceDescriptorHob ( EFI_RESOURCE_FIRMWARE_DEVICE, (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE), (SIZE_4GB - SIZE_8MB), SIZE_8MB ); // // Create a CPU hand-off information // CpuAddressWidth = 32; AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL); if (RegEax >= CPUID_VIR_PHY_ADDRESS_SIZE) { AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &RegEax, NULL, NULL, NULL); CpuAddressWidth = (UINT8) (RegEax & 0xFF); } DEBUG ((EFI_D_INFO, "CpuAddressWidth: %d\n", CpuAddressWidth)); BuildCpuHob (CpuAddressWidth, 16); ASSERT_EFI_ERROR (Status); return Status; }