1 /** @file 2 3 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR> 4 5 This program and the accompanying materials are licensed and made available under 7 the terms and conditions of the BSD License that accompanies this distribution. 9 The full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php. 13 15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 17 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 19 21 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 }; 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 /** 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 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 1b1 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 1b1 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. 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 < ARRAY_SIZE (mBootModePriority); 385 CurrentIndex++) { 386 if (mBootModePriority[CurrentIndex] == *CurrentBootMode) { 387 break; 388 } 389 } 390 if (CurrentIndex >= ARRAY_SIZE (mBootModePriority)) { 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 < ARRAY_SIZE (mBootModePriority); 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