1 /** @file 2 3 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR> 4 5 6 This program and the accompanying materials are licensed and made available under 7 8 the terms and conditions of the BSD License that accompanies this distribution. 9 10 The full text of the license may be found at 11 12 http://opensource.org/licenses/bsd-license.php. 13 14 15 16 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 17 18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 19 20 21 22 23 Module Name: 24 25 26 BootMode.c 27 28 Abstract: 29 30 EFI PEIM to provide the platform support functionality on the Thurley. 31 32 33 --*/ 34 #include "CommonHeader.h" 35 #include "Platform.h" 36 #include "PlatformBaseAddresses.h" 37 #include "PchAccess.h" 38 #include "PlatformBootMode.h" 39 #include <Guid/SetupVariable.h> 40 41 #include <Guid/BootState.h> 42 43 // 44 // Priority of our boot modes, highest priority first 45 // 46 EFI_BOOT_MODE mBootModePriority[] = { 47 BOOT_IN_RECOVERY_MODE, 48 BOOT_WITH_DEFAULT_SETTINGS, 49 BOOT_ON_FLASH_UPDATE, 50 BOOT_ON_S2_RESUME, 51 BOOT_ON_S3_RESUME, 52 BOOT_ON_S4_RESUME, 53 BOOT_WITH_MINIMAL_CONFIGURATION, 54 BOOT_ASSUMING_NO_CONFIGURATION_CHANGES, 55 BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS, 56 BOOT_WITH_FULL_CONFIGURATION, 57 BOOT_ON_S5_RESUME 58 }; 59 60 EFI_PEI_NOTIFY_DESCRIPTOR mCapsuleNotifyList[1] = { 61 { 62 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), 63 &gPeiCapsulePpiGuid, 64 CapsulePpiNotifyCallback 65 } 66 }; CapsulePpiNotifyCallback(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_NOTIFY_DESCRIPTOR * NotifyDescriptor,IN VOID * Ppi)67 68 BOOLEAN 69 GetSleepTypeAfterWakeup ( 70 IN CONST EFI_PEI_SERVICES **PeiServices, 71 OUT UINT16 *SleepType 72 ); 73 74 EFI_STATUS 75 EFIAPI 76 CapsulePpiNotifyCallback ( 77 IN EFI_PEI_SERVICES **PeiServices, 78 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, 79 IN VOID *Ppi 80 ) 81 { 82 EFI_STATUS Status; 83 EFI_BOOT_MODE BootMode; 84 PEI_CAPSULE_PPI *Capsule; 85 86 Status = (*PeiServices)->GetBootMode((const EFI_PEI_SERVICES **)PeiServices, &BootMode); 87 ASSERT_EFI_ERROR (Status); 88 89 if (BootMode == BOOT_ON_S3_RESUME) { 90 // 91 // Determine if we're in capsule update mode 92 // 93 Status = (*PeiServices)->LocatePpi ((const EFI_PEI_SERVICES **)PeiServices, 94 &gPeiCapsulePpiGuid, 95 0, 96 NULL, 97 (VOID **)&Capsule 98 ); 99 100 if (Status == EFI_SUCCESS) { 101 if (Capsule->CheckCapsuleUpdate ((EFI_PEI_SERVICES**)PeiServices) == EFI_SUCCESS) { 102 BootMode = BOOT_ON_FLASH_UPDATE; 103 Status = (*PeiServices)->SetBootMode((const EFI_PEI_SERVICES **)PeiServices, BootMode); 104 ASSERT_EFI_ERROR (Status); 105 } 106 } 107 } 108 109 return Status; 110 } 111 112 /** IsPreviousBootSuccessful(IN CONST EFI_PEI_SERVICES ** PeiServices)113 Check CMOS register bit to determine if previous boot was successful 114 115 @param PeiServices pointer to the PEI Service Table 116 117 @retval TRUE - Previous Boot was success 118 @retval FALSE - Previous Boot wasn't success 119 120 **/ 121 BOOLEAN 122 IsPreviousBootSuccessful( 123 IN CONST EFI_PEI_SERVICES **PeiServices 124 125 ) 126 { 127 EFI_STATUS Status; 128 BOOLEAN BootState; 129 UINTN DataSize; 130 CHAR16 VarName[] = BOOT_STATE_VARIABLE_NAME; 131 EFI_PEI_READ_ONLY_VARIABLE2_PPI *PeiVar; 132 133 Status = (**PeiServices).LocatePpi ( 134 PeiServices, 135 &gEfiPeiReadOnlyVariable2PpiGuid, 136 0, 137 NULL, 138 (void **)&PeiVar 139 ); 140 ASSERT_EFI_ERROR (Status); 141 142 // 143 // Get last Boot State Variable to confirm that it is not a first boot . 144 // 145 146 DataSize = sizeof (BOOLEAN); 147 Status = PeiVar->GetVariable ( 148 PeiVar, 149 VarName, 150 &gEfiBootStateGuid, 151 NULL, 152 &DataSize, 153 &BootState 154 ); 155 if (EFI_ERROR (Status) || (BootState == TRUE)) { 156 return FALSE; 157 } 158 159 DEBUG ((EFI_D_INFO, "Previous boot cycle successfully completed handover to OS\n")); 160 return TRUE; 161 } 162 #ifdef NOCS_S3_SUPPORT 163 EFI_STATUS 164 UpdateBootMode ( 165 IN CONST EFI_PEI_SERVICES **PeiServices 166 ) 167 { 168 EFI_STATUS Status; 169 EFI_BOOT_MODE BootMode; 170 UINT16 SleepType; 171 CHAR16 *strBootMode; 172 173 Status = (*PeiServices)->GetBootMode(PeiServices, &BootMode); 174 ASSERT_EFI_ERROR (Status); 175 if (BootMode == BOOT_IN_RECOVERY_MODE){ 176 return Status; 177 } 178 179 // 180 // Let's assume things are OK if not told otherwise 181 // 182 BootMode = BOOT_WITH_FULL_CONFIGURATION; 183 184 if (GetSleepTypeAfterWakeup (PeiServices, &SleepType)) { 185 switch (SleepType) { 186 case V_PCH_ACPI_PM1_CNT_S3: 187 BootMode = BOOT_ON_S3_RESUME; 188 Status = (*PeiServices)->NotifyPpi (PeiServices, &mCapsuleNotifyList[0]); 189 ASSERT_EFI_ERROR (Status); 190 break; 191 192 case V_PCH_ACPI_PM1_CNT_S4: 193 BootMode = BOOT_ON_S4_RESUME; 194 break; 195 196 case V_PCH_ACPI_PM1_CNT_S5: 197 BootMode = BOOT_ON_S5_RESUME; 198 break; 199 } // switch (SleepType) 200 } 201 202 if (IsFastBootEnabled (PeiServices) && IsPreviousBootSuccessful (PeiServices)) { 203 DEBUG ((EFI_D_INFO, "Prioritizing Boot mode to BOOT_WITH_MINIMAL_CONFIGURATION\n")); 204 PrioritizeBootMode (&BootMode, BOOT_WITH_MINIMAL_CONFIGURATION); 205 } 206 207 switch (BootMode) { 208 case BOOT_WITH_FULL_CONFIGURATION: 209 strBootMode = L"BOOT_WITH_FULL_CONFIGURATION"; 210 break; 211 case BOOT_WITH_MINIMAL_CONFIGURATION: 212 strBootMode = L"BOOT_WITH_MINIMAL_CONFIGURATION"; 213 break; 214 case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES: 215 strBootMode = L"BOOT_ASSUMING_NO_CONFIGURATION_CHANGES"; 216 break; 217 case BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS: 218 strBootMode = L"BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS"; 219 break; 220 case BOOT_WITH_DEFAULT_SETTINGS: 221 strBootMode = L"BOOT_WITH_DEFAULT_SETTINGS"; 222 break; 223 case BOOT_ON_S4_RESUME: 224 strBootMode = L"BOOT_ON_S4_RESUME"; 225 break; 226 case BOOT_ON_S5_RESUME: 227 strBootMode = L"BOOT_ON_S5_RESUME"; 228 break; 229 case BOOT_ON_S2_RESUME: 230 strBootMode = L"BOOT_ON_S2_RESUME"; 231 break; 232 case BOOT_ON_S3_RESUME: 233 strBootMode = L"BOOT_ON_S3_RESUME"; 234 235 break; 236 case BOOT_ON_FLASH_UPDATE: 237 strBootMode = L"BOOT_ON_FLASH_UPDATE"; 238 break; 239 case BOOT_IN_RECOVERY_MODE: 240 strBootMode = L"BOOT_IN_RECOVERY_MODE"; 241 break; 242 default: 243 strBootMode = L"Unknown boot mode"; 244 } // switch (BootMode) 245 246 DEBUG ((EFI_D_ERROR, "Setting BootMode to %s\n", strBootMode)); 247 Status = (*PeiServices)->SetBootMode(PeiServices, BootMode); 248 ASSERT_EFI_ERROR (Status); 249 250 return Status; 251 } 252 #endif 253 254 /** 255 Get sleep type after wakeup GetSleepTypeAfterWakeup(IN CONST EFI_PEI_SERVICES ** PeiServices,OUT UINT16 * SleepType)256 257 @param PeiServices Pointer to the PEI Service Table. 258 @param SleepType Sleep type to be returned. 259 260 @retval TRUE A wake event occured without power failure. 261 @retval FALSE Power failure occured or not a wakeup. 262 263 **/ 264 BOOLEAN 265 GetSleepTypeAfterWakeup ( 266 IN CONST EFI_PEI_SERVICES **PeiServices, 267 OUT UINT16 *SleepType 268 ) 269 { 270 UINT16 Pm1Sts; 271 UINT16 Pm1Cnt; 272 UINT16 GenPmCon1; 273 // 274 // VLV BIOS Specification 0.6.2 - Section 18.4, "Power Failure Consideration" 275 // 276 // When the SUS_PWR_FLR bit is set, it indicates the SUS well power is lost. 277 // This bit is in the SUS Well and defaults to 1�b1 based on RSMRST# assertion (not cleared by any type of reset). 278 // System BIOS should follow cold boot path if SUS_PWR_FLR (PBASE + 0x20[14]), 279 // GEN_RST_STS (PBASE + 0x20[9]) or PWRBTNOR_STS (ABASE + 0x00[11]) is set to 1�b1 280 // regardless of the value in the SLP_TYP (ABASE + 0x04[12:10]) field. 281 // 282 GenPmCon1 = MmioRead16 (PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1); 283 284 // 285 // Read the ACPI registers 286 // 287 Pm1Sts = IoRead16 (ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_STS); 288 Pm1Cnt = IoRead16 (ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_CNT); 289 290 if ((GenPmCon1 & (B_PCH_PMC_GEN_PMCON_SUS_PWR_FLR | B_PCH_PMC_GEN_PMCON_GEN_RST_STS)) || 291 (Pm1Sts & B_PCH_ACPI_PM1_STS_PRBTNOR)) { 292 // 293 // If power failure indicator, then don't attempt s3 resume. 294 // Clear PM1_CNT of S3 and set it to S5 as we just had a power failure, and memory has 295 // lost already. This is to make sure no one will use PM1_CNT to check for S3 after 296 // power failure. 297 // 298 if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S3) { 299 Pm1Cnt = ((Pm1Cnt & ~B_PCH_ACPI_PM1_CNT_SLP_TYP) | V_PCH_ACPI_PM1_CNT_S5); 300 IoWrite16 (ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_CNT, Pm1Cnt); 301 } 302 // 303 // Clear Wake Status (WAK_STS) 304 // 305 } 306 // 307 // Get sleep type if a wake event occurred and there is no power failure 308 // 309 if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S3) { 310 *SleepType = Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP; 311 return TRUE; 312 } else if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S4) { 313 *SleepType = Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP; 314 return TRUE; 315 } 316 return FALSE; 317 } 318 319 BOOLEAN 320 EFIAPI 321 IsFastBootEnabled ( 322 IN CONST EFI_PEI_SERVICES **PeiServices 323 ) 324 { 325 EFI_STATUS Status; 326 EFI_PEI_READ_ONLY_VARIABLE2_PPI *PeiReadOnlyVarPpi; 327 UINTN VarSize; 328 SYSTEM_CONFIGURATION SystemConfiguration; 329 BOOLEAN FastBootEnabledStatus; 330 331 FastBootEnabledStatus = FALSE; 332 Status = (**PeiServices).LocatePpi ( 333 PeiServices, 334 &gEfiPeiReadOnlyVariable2PpiGuid, 335 0, 336 NULL, 337 (void **)&PeiReadOnlyVarPpi 338 ); 339 if (Status == EFI_SUCCESS) { 340 VarSize = sizeof (SYSTEM_CONFIGURATION); 341 Status = PeiReadOnlyVarPpi->GetVariable ( 342 PeiReadOnlyVarPpi, 343 PLATFORM_SETUP_VARIABLE_NAME, 344 &gEfiSetupVariableGuid, 345 NULL, 346 &VarSize, 347 &SystemConfiguration 348 ); 349 if (Status == EFI_SUCCESS) { 350 if (SystemConfiguration.FastBoot != 0) { 351 FastBootEnabledStatus = TRUE; 352 } 353 } 354 } 355 356 return FastBootEnabledStatus; 357 } 358 359 /** 360 Given the current boot mode, and a proposed new boot mode, determine 361 which has priority. If the new boot mode has higher priority, then 362 make it the current boot mode. PrioritizeBootMode(IN OUT EFI_BOOT_MODE * CurrentBootMode,IN EFI_BOOT_MODE NewBootMode)363 364 @param CurrentBootMode pointer to current planned boot mode 365 @param NewBootMode proposed boot mode 366 367 @retval EFI_NOT_FOUND if either boot mode is not recognized 368 @retval EFI_SUCCESS if both boot mode values were recognized and 369 were processed. 370 **/ 371 EFI_STATUS 372 PrioritizeBootMode ( 373 IN OUT EFI_BOOT_MODE *CurrentBootMode, 374 IN EFI_BOOT_MODE NewBootMode 375 ) 376 { 377 UINT32 CurrentIndex; 378 UINT32 NewIndex; 379 380 // 381 // Find the position of the current boot mode in our priority array 382 // 383 for ( CurrentIndex = 0; 384 CurrentIndex < sizeof (mBootModePriority) / sizeof (mBootModePriority[0]); 385 CurrentIndex++) { 386 if (mBootModePriority[CurrentIndex] == *CurrentBootMode) { 387 break; 388 } 389 } 390 if (CurrentIndex >= sizeof (mBootModePriority) / sizeof (mBootModePriority[0])) { 391 return EFI_NOT_FOUND; 392 } 393 394 // 395 // Find the position of the new boot mode in our priority array 396 // 397 for ( NewIndex = 0; 398 NewIndex < sizeof (mBootModePriority) / sizeof (mBootModePriority[0]); 399 NewIndex++) { 400 if (mBootModePriority[NewIndex] == NewBootMode) { 401 // 402 // If this new boot mode occurs before the current boot mode in the 403 // priority array, then take it. 404 // 405 if (NewIndex < CurrentIndex) { 406 *CurrentBootMode = NewBootMode; 407 } 408 return EFI_SUCCESS; 409 } 410 } 411 return EFI_NOT_FOUND; 412 } 413