1 /** @file 2 This file provide the function to detect boot mode 3 4 Copyright (c) 2013 Intel Corporation. 5 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 17 #include "CommonHeader.h" 18 #include <Pi/PiFirmwareVolume.h> 19 20 EFI_PEI_PPI_DESCRIPTOR mPpiListRecoveryBootMode = { 21 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), 22 &gEfiPeiBootInRecoveryModePpiGuid, 23 NULL 24 }; 25 26 /** 27 If the box was opened, it's boot with full config. 28 If the box is closed, then 29 1. If it's first time to boot, it's boot with full config . 30 2. If the ChassisIntrution is selected, force to be a boot with full config 31 3. Otherwise it's boot with no change. 32 33 @param PeiServices General purpose services available to every PEIM. 34 35 @retval TRUE If it's boot with no change. 36 37 @retval FALSE If boot with no change. 38 **/ 39 BOOLEAN 40 IsBootWithNoChange ( 41 IN EFI_PEI_SERVICES **PeiServices 42 ) 43 { 44 BOOLEAN IsFirstBoot = FALSE; 45 46 BOOLEAN EnableFastBoot = FALSE; 47 IsFirstBoot = PcdGetBool(PcdBootState); 48 EnableFastBoot = PcdGetBool (PcdEnableFastBoot); 49 50 DEBUG ((EFI_D_INFO, "IsFirstBoot = %x , EnableFastBoot= %x. \n", IsFirstBoot, EnableFastBoot)); 51 52 if ((!IsFirstBoot) && EnableFastBoot) { 53 return TRUE; 54 } else { 55 return FALSE; 56 } 57 } 58 59 60 /** 61 62 Routine Description: 63 64 This function is used to verify if the FV header is validate. 65 66 @param FwVolHeader - The FV header that to be verified. 67 68 @retval EFI_SUCCESS - The Fv header is valid. 69 @retval EFI_NOT_FOUND - The Fv header is invalid. 70 71 **/ 72 EFI_STATUS 73 ValidateFvHeader ( 74 EFI_BOOT_MODE *BootMode 75 ) 76 { 77 UINT16 *Ptr; 78 UINT16 HeaderLength; 79 UINT16 Checksum; 80 81 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; 82 83 if (BOOT_IN_RECOVERY_MODE == *BootMode) { 84 DEBUG ((EFI_D_INFO, "Boot mode recovery\n")); 85 return EFI_SUCCESS; 86 } 87 // 88 // Let's check whether FvMain header is valid, if not enter into recovery mode 89 // 90 // 91 // Verify the header revision, header signature, length 92 // Length of FvBlock cannot be 2**64-1 93 // HeaderLength cannot be an odd number 94 // 95 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PcdGet32(PcdFlashFvMainBase); 96 if ((FwVolHeader->Revision != EFI_FVH_REVISION)|| 97 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) || 98 (FwVolHeader->FvLength == ((UINT64) -1)) || 99 ((FwVolHeader->HeaderLength & 0x01) != 0) 100 ) { 101 return EFI_NOT_FOUND; 102 } 103 // 104 // Verify the header checksum 105 // 106 HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2); 107 Ptr = (UINT16 *) FwVolHeader; 108 Checksum = 0; 109 while (HeaderLength > 0) { 110 Checksum = Checksum +*Ptr; 111 Ptr++; 112 HeaderLength--; 113 } 114 115 if (Checksum != 0) { 116 return EFI_NOT_FOUND; 117 } 118 119 return EFI_SUCCESS; 120 } 121 122 /** 123 Peform the boot mode determination logic 124 If the box is closed, then 125 1. If it's first time to boot, it's boot with full config . 126 2. If the ChassisIntrution is selected, force to be a boot with full config 127 3. Otherwise it's boot with no change. 128 129 @param PeiServices General purpose services available to every PEIM. 130 131 @param BootMode The detected boot mode. 132 133 @retval EFI_SUCCESS if the boot mode could be set 134 **/ 135 EFI_STATUS 136 UpdateBootMode ( 137 IN EFI_PEI_SERVICES **PeiServices, 138 OUT EFI_BOOT_MODE *BootMode 139 ) 140 { 141 EFI_STATUS Status; 142 EFI_BOOT_MODE NewBootMode; 143 PEI_CAPSULE_PPI *Capsule; 144 UINT32 RegValue; 145 146 NewBootMode = *BootMode; 147 148 // 149 // Read Sticky R/W Bits 150 // 151 RegValue = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_CFG_STICKY_RW); 152 DEBUG ((EFI_D_ERROR, "RegValue = %08x\n", RegValue)); 153 154 // 155 // Check if we need to boot in recovery mode 156 // 157 if ((RegValue & B_CFG_STICKY_RW_FORCE_RECOVERY) != 0) { 158 NewBootMode = BOOT_IN_RECOVERY_MODE; 159 DEBUG ((EFI_D_ERROR, "RECOVERY from sticky bit\n"));; 160 161 // 162 // Clear force recovery sticky bit 163 // 164 QNCAltPortWrite ( 165 QUARK_SCSS_SOC_UNIT_SB_PORT_ID, 166 QUARK_SCSS_SOC_UNIT_CFG_STICKY_RW, 167 RegValue &(~B_CFG_STICKY_RW_FORCE_RECOVERY) 168 ); 169 170 } else if (ValidateFvHeader (BootMode) != EFI_SUCCESS) { 171 NewBootMode = BOOT_IN_RECOVERY_MODE; 172 DEBUG ((EFI_D_ERROR, "RECOVERY from corrupt FV\n"));; 173 } else if (QNCCheckS3AndClearState ()) { 174 // 175 // Determine if we're in capsule update mode 176 // 177 Status = PeiServicesLocatePpi ( 178 &gPeiCapsulePpiGuid, 179 0, 180 NULL, 181 (VOID **)&Capsule 182 ); 183 if (Status == EFI_SUCCESS) { 184 Status = Capsule->CheckCapsuleUpdate (PeiServices); 185 if (Status == EFI_SUCCESS) { 186 DEBUG ((EFI_D_INFO, "Boot mode Flash Update\n")); 187 NewBootMode = BOOT_ON_FLASH_UPDATE; 188 } else { 189 DEBUG ((EFI_D_INFO, "Boot mode S3 resume\n")); 190 NewBootMode = BOOT_ON_S3_RESUME; 191 } 192 } else { 193 DEBUG ((EFI_D_INFO, "Boot mode S3 resume\n")); 194 NewBootMode = BOOT_ON_S3_RESUME; 195 } 196 } else { 197 // 198 // Check if this is a power on reset 199 // 200 if (QNCCheckPowerOnResetAndClearState ()) { 201 DEBUG ((EFI_D_INFO, "Power On Reset\n")); 202 } 203 if (IsBootWithNoChange (PeiServices)) { 204 DEBUG ((EFI_D_INFO, "Boot with Minimum cfg\n")); 205 NewBootMode = BOOT_ASSUMING_NO_CONFIGURATION_CHANGES; 206 } else { 207 DEBUG ((EFI_D_INFO, "Boot with Full cfg\n")); 208 NewBootMode = BOOT_WITH_FULL_CONFIGURATION; 209 } 210 } 211 212 if (NewBootMode == BOOT_IN_RECOVERY_MODE) { 213 DEBUG ((EFI_D_INFO, "Boot mode recovery\n")); 214 Status = PeiServicesInstallPpi (&mPpiListRecoveryBootMode); 215 ASSERT_EFI_ERROR (Status); 216 } 217 218 Status = PeiServicesSetBootMode (NewBootMode); 219 ASSERT_EFI_ERROR (Status); 220 221 *BootMode = NewBootMode; 222 223 return EFI_SUCCESS; 224 } 225