/** @file Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent Module Name: BootMode.c Abstract: EFI PEIM to provide the platform support functionality on the Thurley. --*/ #include "PlatformEarlyInit.h" #define NORMALMODE 0 #define RECOVERYMODE 1 #define SAFEMODE 2 #define MANUFACTURINGMODE 3 #define GPIO_SSUS_OFFSET 0x2000 #define PMU_PWRBTN_B_OFFSET 0x88 EFI_PEI_PPI_DESCRIPTOR mPpiListRecoveryBootMode = { (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gEfiPeiBootInRecoveryModePpiGuid, NULL }; /** Return the setting of the Bios configuration jumper @param VOID @retval RECOVERYMODE jumper set to recovery mode @retval SAFEMODE jumper set to config mode @retval NORMALMODE jumper in normal mode **/ UINTN GetConfigJumper( IN CONST EFI_PEI_SERVICES **PeiServices, IN OUT EFI_PLATFORM_INFO_HOB *PlatformInfoHob ) { // // Do the Forced recovery detection based on logic chart above // if (IsRecoveryJumper(PeiServices, PlatformInfoHob)) { return RECOVERYMODE; } else { return NORMALMODE; } } BOOLEAN CheckIfRecoveryMode( IN CONST EFI_PEI_SERVICES **PeiServices, IN OUT EFI_PLATFORM_INFO_HOB *PlatformInfoHob ) { if (GetConfigJumper(PeiServices, PlatformInfoHob) == RECOVERYMODE) { return TRUE; } return FALSE; } BOOLEAN CheckIfSafeMode( IN CONST EFI_PEI_SERVICES **PeiServices, IN OUT EFI_PLATFORM_INFO_HOB *PlatformInfoHob ) { if (GetConfigJumper(PeiServices, PlatformInfoHob) == SAFEMODE) { return TRUE; } return FALSE; } BOOLEAN CheckIfManufacturingMode ( IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status; EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable; UINT32 Attributes; UINTN DataSize; CHAR16 VarName[] = MFGMODE_VARIABLE_NAME; UINT8 MfgMode; Status = (*PeiServices)->LocatePpi ( PeiServices, &gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (void **)&Variable ); ASSERT_EFI_ERROR (Status); // // Check if SW MMJ mode // Attributes = (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS); DataSize = sizeof (MFG_MODE_VAR); Status = Variable->GetVariable ( Variable, VarName, &gMfgModeVariableGuid, &Attributes, &DataSize, &MfgMode ); if (!(EFI_ERROR (Status))) { return TRUE; } return FALSE; } EFI_STATUS UpdateBootMode ( IN CONST EFI_PEI_SERVICES **PeiServices, IN OUT EFI_PLATFORM_INFO_HOB *PlatformInfoHob ) { EFI_STATUS Status; EFI_BOOT_MODE BootMode; UINT16 SleepType; CHAR16 *strBootMode; PEI_CAPSULE_PPI *Capsule; EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable; SYSTEM_CONFIGURATION SystemConfiguration; UINTN VarSize; volatile UINT32 GpioValue; BOOLEAN IsFirstBoot; UINT32 Data32; Status = (*PeiServices)->GetBootMode( PeiServices, &BootMode ); ASSERT_EFI_ERROR (Status); if (BootMode == BOOT_IN_RECOVERY_MODE){ return Status; } GetWakeupEventAndSaveToHob (PeiServices); // // Let's assume things are OK if not told otherwise // BootMode = BOOT_WITH_FULL_CONFIGURATION; // // When this boot is WDT reset, the system needs booting with CrashDump function eanbled. // Data32 = IoRead32 (ACPI_BASE_ADDRESS + R_PCH_TCO_STS); // // Check Power Button, click the power button, the system will boot in fast boot mode, // if it is pressed and hold for a second, it will boot in FullConfiguration/setup mode. // GpioValue = MmioRead32 (IO_BASE_ADDRESS + GPIO_SSUS_OFFSET + PMU_PWRBTN_B_OFFSET); // The value of GPIOS_16 (PMU_PWRBTN_B) if (((GpioValue & BIT0) != 0)&&((Data32 & B_PCH_TCO_STS_SECOND_TO) != B_PCH_TCO_STS_SECOND_TO)){ IsFirstBoot = PcdGetBool(PcdBootState); if (!IsFirstBoot){ VarSize = sizeof (SYSTEM_CONFIGURATION); ZeroMem (&SystemConfiguration, sizeof (SYSTEM_CONFIGURATION)); Status = (*PeiServices)->LocatePpi ( PeiServices, &gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (void **)&Variable ); ASSERT_EFI_ERROR (Status); // // Use normal setup default from NVRAM variable, // the Platform Mode (manufacturing/safe/normal) is handle in PeiGetVariable. // VarSize = sizeof(SYSTEM_CONFIGURATION); Status = Variable->GetVariable ( Variable, L"Setup", &gEfiSetupVariableGuid, NULL, &VarSize, &SystemConfiguration ); if (EFI_ERROR (Status) || VarSize != sizeof(SYSTEM_CONFIGURATION)) { //The setup variable is corrupted VarSize = sizeof(SYSTEM_CONFIGURATION); Status = Variable->GetVariable( Variable, L"SetupRecovery", &gEfiSetupVariableGuid, NULL, &VarSize, &SystemConfiguration ); ASSERT_EFI_ERROR (Status); } if (SystemConfiguration.FastBoot == 1) { BootMode = BOOT_WITH_MINIMAL_CONFIGURATION; } } } // // Check if we need to boot in forced recovery mode // if (CheckIfRecoveryMode(PeiServices, PlatformInfoHob)) { BootMode = BOOT_IN_RECOVERY_MODE; } if (BootMode == BOOT_IN_RECOVERY_MODE) { Status = (*PeiServices)->InstallPpi ( PeiServices, &mPpiListRecoveryBootMode ); ASSERT_EFI_ERROR (Status); } else { if (GetSleepTypeAfterWakeup (PeiServices, &SleepType)) { switch (SleepType) { case V_PCH_ACPI_PM1_CNT_S3: BootMode = BOOT_ON_S3_RESUME; // // Determine if we're in capsule update mode // Status = (*PeiServices)->LocatePpi ( PeiServices, &gPeiCapsulePpiGuid, 0, NULL, (void **)&Capsule ); if (Status == EFI_SUCCESS) { if (Capsule->CheckCapsuleUpdate ((EFI_PEI_SERVICES**)PeiServices) == EFI_SUCCESS) { BootMode = BOOT_ON_FLASH_UPDATE; } } break; case V_PCH_ACPI_PM1_CNT_S4: BootMode = BOOT_ON_S4_RESUME; break; case V_PCH_ACPI_PM1_CNT_S5: BootMode = BOOT_ON_S5_RESUME; break; } // switch (SleepType) } // // Check for Safe Mode // } switch (BootMode) { case BOOT_WITH_FULL_CONFIGURATION: strBootMode = L"BOOT_WITH_FULL_CONFIGURATION"; break; case BOOT_WITH_MINIMAL_CONFIGURATION: strBootMode = L"BOOT_WITH_MINIMAL_CONFIGURATION"; break; case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES: strBootMode = L"BOOT_ASSUMING_NO_CONFIGURATION_CHANGES"; break; case BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS: strBootMode = L"BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS"; break; case BOOT_WITH_DEFAULT_SETTINGS: strBootMode = L"BOOT_WITH_DEFAULT_SETTINGS"; break; case BOOT_ON_S4_RESUME: strBootMode = L"BOOT_ON_S4_RESUME"; break; case BOOT_ON_S5_RESUME: strBootMode = L"BOOT_ON_S5_RESUME"; break; case BOOT_ON_S2_RESUME: strBootMode = L"BOOT_ON_S2_RESUME"; break; case BOOT_ON_S3_RESUME: strBootMode = L"BOOT_ON_S3_RESUME"; break; case BOOT_ON_FLASH_UPDATE: strBootMode = L"BOOT_ON_FLASH_UPDATE"; break; case BOOT_IN_RECOVERY_MODE: strBootMode = L"BOOT_IN_RECOVERY_MODE"; break; default: strBootMode = L"Unknown boot mode"; } // switch (BootMode) DEBUG ((EFI_D_ERROR, "Setting BootMode to %s\n", strBootMode)); Status = (*PeiServices)->SetBootMode( PeiServices, BootMode ); ASSERT_EFI_ERROR (Status); return Status; } /** Get sleep type after wakeup @param PeiServices Pointer to the PEI Service Table. @param SleepType Sleep type to be returned. @retval TRUE A wake event occured without power failure. @retval FALSE Power failure occured or not a wakeup. **/ BOOLEAN GetSleepTypeAfterWakeup ( IN CONST EFI_PEI_SERVICES **PeiServices, OUT UINT16 *SleepType ) { UINT16 Pm1Sts; UINT16 Pm1Cnt; UINT16 GenPmCon1; GenPmCon1 = MmioRead16 (PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1); // // Read the ACPI registers // Pm1Sts = IoRead16 (ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_STS); Pm1Cnt = IoRead16 (ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_CNT); if ((GenPmCon1 & (B_PCH_PMC_GEN_PMCON_SUS_PWR_FLR | B_PCH_PMC_GEN_PMCON_GEN_RST_STS)) || (Pm1Sts & B_PCH_ACPI_PM1_STS_PRBTNOR)) { // // If power failure indicator, then don't attempt s3 resume. // Clear PM1_CNT of S3 and set it to S5 as we just had a power failure, and memory has // lost already. This is to make sure no one will use PM1_CNT to check for S3 after // power failure. // if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S3) { Pm1Cnt = ((Pm1Cnt & ~B_PCH_ACPI_PM1_CNT_SLP_TYP) | V_PCH_ACPI_PM1_CNT_S5); IoWrite16 (ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_CNT, Pm1Cnt); } // // Clear Wake Status (WAK_STS) // IoWrite16 ((ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_STS), B_PCH_ACPI_PM1_STS_WAK); } // // Get sleep type if a wake event occurred and there is no power failure // if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S3) { *SleepType = Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP; return TRUE; } else if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S4){ *SleepType = Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP; return TRUE; } return FALSE; } VOID SetPlatformBootMode ( IN CONST EFI_PEI_SERVICES **PeiServices, IN OUT EFI_PLATFORM_INFO_HOB *PlatformInfoHob ) { EFI_PLATFORM_SETUP_ID PlatformSetupId; ZeroMem(&PlatformSetupId, sizeof (EFI_PLATFORM_SETUP_ID)); CopyMem (&PlatformSetupId.SetupGuid, &gEfiNormalSetupGuid, sizeof (EFI_GUID)); if (CheckIfRecoveryMode(PeiServices, PlatformInfoHob)) { // // Recovery mode // CopyMem (&PlatformSetupId.SetupName, &NORMAL_SETUP_NAME, StrSize (NORMAL_SETUP_NAME)); PlatformSetupId.PlatformBootMode = PLATFORM_RECOVERY_MODE; } else if (CheckIfSafeMode(PeiServices, PlatformInfoHob)) { // // Safe mode also called config mode or maintenace mode. // CopyMem (&PlatformSetupId.SetupName, &NORMAL_SETUP_NAME, StrSize (NORMAL_SETUP_NAME)); PlatformSetupId.PlatformBootMode = PLATFORM_SAFE_MODE; } else if(0) { // else if (CheckIfManufacturingMode(PeiServices)) { // // Manufacturing mode // CopyMem (&PlatformSetupId.SetupName, MANUFACTURE_SETUP_NAME, StrSize (MANUFACTURE_SETUP_NAME)); PlatformSetupId.PlatformBootMode = PLATFORM_MANUFACTURING_MODE; } else { // // Default to normal mode. // CopyMem (&PlatformSetupId.SetupName, &NORMAL_SETUP_NAME, StrSize (NORMAL_SETUP_NAME)); PlatformSetupId.PlatformBootMode = PLATFORM_NORMAL_MODE; } BuildGuidDataHob ( &gEfiPlatformBootModeGuid, &PlatformSetupId, sizeof (EFI_PLATFORM_SETUP_ID) ); return; }