| /** @file | |
| This file provide the function to detect boot mode | |
| Copyright (c) 2013 Intel Corporation. | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "CommonHeader.h" | |
| #include <Pi/PiFirmwareVolume.h> | |
| EFI_PEI_PPI_DESCRIPTOR mPpiListRecoveryBootMode = { | |
| (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), | |
| &gEfiPeiBootInRecoveryModePpiGuid, | |
| NULL | |
| }; | |
| /** | |
| If the box was opened, it's boot with full config. | |
| If the box is closed, then | |
| 1. If it's first time to boot, it's boot with full config . | |
| 2. If the ChassisIntrution is selected, force to be a boot with full config | |
| 3. Otherwise it's boot with no change. | |
| @param PeiServices General purpose services available to every PEIM. | |
| @retval TRUE If it's boot with no change. | |
| @retval FALSE If boot with no change. | |
| **/ | |
| BOOLEAN | |
| IsBootWithNoChange ( | |
| IN EFI_PEI_SERVICES **PeiServices | |
| ) | |
| { | |
| BOOLEAN IsFirstBoot = FALSE; | |
| BOOLEAN EnableFastBoot = FALSE; | |
| IsFirstBoot = PcdGetBool(PcdBootState); | |
| EnableFastBoot = PcdGetBool (PcdEnableFastBoot); | |
| DEBUG ((EFI_D_INFO, "IsFirstBoot = %x , EnableFastBoot= %x. \n", IsFirstBoot, EnableFastBoot)); | |
| if ((!IsFirstBoot) && EnableFastBoot) { | |
| return TRUE; | |
| } else { | |
| return FALSE; | |
| } | |
| } | |
| /** | |
| Routine Description: | |
| This function is used to verify if the FV header is validate. | |
| @param FwVolHeader - The FV header that to be verified. | |
| @retval EFI_SUCCESS - The Fv header is valid. | |
| @retval EFI_NOT_FOUND - The Fv header is invalid. | |
| **/ | |
| EFI_STATUS | |
| ValidateFvHeader ( | |
| EFI_BOOT_MODE *BootMode | |
| ) | |
| { | |
| UINT16 *Ptr; | |
| UINT16 HeaderLength; | |
| UINT16 Checksum; | |
| EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; | |
| if (BOOT_IN_RECOVERY_MODE == *BootMode) { | |
| DEBUG ((EFI_D_INFO, "Boot mode recovery\n")); | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Let's check whether FvMain header is valid, if not enter into recovery mode | |
| // | |
| // | |
| // Verify the header revision, header signature, length | |
| // Length of FvBlock cannot be 2**64-1 | |
| // HeaderLength cannot be an odd number | |
| // | |
| FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PcdGet32(PcdFlashFvMainBase); | |
| if ((FwVolHeader->Revision != EFI_FVH_REVISION)|| | |
| (FwVolHeader->Signature != EFI_FVH_SIGNATURE) || | |
| (FwVolHeader->FvLength == ((UINT64) -1)) || | |
| ((FwVolHeader->HeaderLength & 0x01) != 0) | |
| ) { | |
| return EFI_NOT_FOUND; | |
| } | |
| // | |
| // Verify the header checksum | |
| // | |
| HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2); | |
| Ptr = (UINT16 *) FwVolHeader; | |
| Checksum = 0; | |
| while (HeaderLength > 0) { | |
| Checksum = Checksum +*Ptr; | |
| Ptr++; | |
| HeaderLength--; | |
| } | |
| if (Checksum != 0) { | |
| return EFI_NOT_FOUND; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Peform the boot mode determination logic | |
| If the box is closed, then | |
| 1. If it's first time to boot, it's boot with full config . | |
| 2. If the ChassisIntrution is selected, force to be a boot with full config | |
| 3. Otherwise it's boot with no change. | |
| @param PeiServices General purpose services available to every PEIM. | |
| @param BootMode The detected boot mode. | |
| @retval EFI_SUCCESS if the boot mode could be set | |
| **/ | |
| EFI_STATUS | |
| UpdateBootMode ( | |
| IN EFI_PEI_SERVICES **PeiServices, | |
| OUT EFI_BOOT_MODE *BootMode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_BOOT_MODE NewBootMode; | |
| PEI_CAPSULE_PPI *Capsule; | |
| UINT32 RegValue; | |
| NewBootMode = *BootMode; | |
| // | |
| // Read Sticky R/W Bits | |
| // | |
| RegValue = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_CFG_STICKY_RW); | |
| DEBUG ((EFI_D_ERROR, "RegValue = %08x\n", RegValue)); | |
| // | |
| // Check if we need to boot in recovery mode | |
| // | |
| if ((RegValue & B_CFG_STICKY_RW_FORCE_RECOVERY) != 0) { | |
| NewBootMode = BOOT_IN_RECOVERY_MODE; | |
| DEBUG ((EFI_D_ERROR, "RECOVERY from sticky bit\n"));; | |
| // | |
| // Clear force recovery sticky bit | |
| // | |
| QNCAltPortWrite ( | |
| QUARK_SCSS_SOC_UNIT_SB_PORT_ID, | |
| QUARK_SCSS_SOC_UNIT_CFG_STICKY_RW, | |
| RegValue &(~B_CFG_STICKY_RW_FORCE_RECOVERY) | |
| ); | |
| } else if (ValidateFvHeader (BootMode) != EFI_SUCCESS) { | |
| NewBootMode = BOOT_IN_RECOVERY_MODE; | |
| DEBUG ((EFI_D_ERROR, "RECOVERY from corrupt FV\n"));; | |
| } else if (QNCCheckS3AndClearState ()) { | |
| // | |
| // Determine if we're in capsule update mode | |
| // | |
| Status = PeiServicesLocatePpi ( | |
| &gPeiCapsulePpiGuid, | |
| 0, | |
| NULL, | |
| (VOID **)&Capsule | |
| ); | |
| if (Status == EFI_SUCCESS) { | |
| Status = Capsule->CheckCapsuleUpdate (PeiServices); | |
| if (Status == EFI_SUCCESS) { | |
| DEBUG ((EFI_D_INFO, "Boot mode Flash Update\n")); | |
| NewBootMode = BOOT_ON_FLASH_UPDATE; | |
| } else { | |
| DEBUG ((EFI_D_INFO, "Boot mode S3 resume\n")); | |
| NewBootMode = BOOT_ON_S3_RESUME; | |
| } | |
| } else { | |
| DEBUG ((EFI_D_INFO, "Boot mode S3 resume\n")); | |
| NewBootMode = BOOT_ON_S3_RESUME; | |
| } | |
| } else { | |
| // | |
| // Check if this is a power on reset | |
| // | |
| if (QNCCheckPowerOnResetAndClearState ()) { | |
| DEBUG ((EFI_D_INFO, "Power On Reset\n")); | |
| } | |
| if (IsBootWithNoChange (PeiServices)) { | |
| DEBUG ((EFI_D_INFO, "Boot with Minimum cfg\n")); | |
| NewBootMode = BOOT_ASSUMING_NO_CONFIGURATION_CHANGES; | |
| } else { | |
| DEBUG ((EFI_D_INFO, "Boot with Full cfg\n")); | |
| NewBootMode = BOOT_WITH_FULL_CONFIGURATION; | |
| } | |
| } | |
| if (NewBootMode == BOOT_IN_RECOVERY_MODE) { | |
| DEBUG ((EFI_D_INFO, "Boot mode recovery\n")); | |
| Status = PeiServicesInstallPpi (&mPpiListRecoveryBootMode); | |
| ASSERT_EFI_ERROR (Status); | |
| } | |
| Status = PeiServicesSetBootMode (NewBootMode); | |
| ASSERT_EFI_ERROR (Status); | |
| *BootMode = NewBootMode; | |
| return EFI_SUCCESS; | |
| } |