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 
35 #include "PlatformEarlyInit.h"
36 
37 
38 #define NORMALMODE        0
39 #define RECOVERYMODE      1
40 #define SAFEMODE          2
41 #define MANUFACTURINGMODE 3
42 
43 #define GPIO_SSUS_OFFSET    0x2000
44 #define PMU_PWRBTN_B_OFFSET 0x88
45 
46 EFI_PEI_PPI_DESCRIPTOR  mPpiListRecoveryBootMode = {
47   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
48   &gEfiPeiBootInRecoveryModePpiGuid,
49   NULL
50 };
51 
52 /**
53   Return the setting of the Bios configuration jumper
GetConfigJumper(IN CONST EFI_PEI_SERVICES ** PeiServices,IN OUT EFI_PLATFORM_INFO_HOB * PlatformInfoHob)54 
55   @param  VOID
56 
57   @retval RECOVERYMODE       jumper set to recovery mode
58   @retval SAFEMODE           jumper set to config mode
59   @retval NORMALMODE         jumper in normal mode
60 
61 **/
62 UINTN
63 GetConfigJumper(
64     IN CONST EFI_PEI_SERVICES           **PeiServices,
65     IN OUT EFI_PLATFORM_INFO_HOB *PlatformInfoHob
66  )
67 {
68   //
69   // Do the Forced recovery detection based on logic chart above
70   //
71   if (IsRecoveryJumper(PeiServices, PlatformInfoHob)) {
72     return RECOVERYMODE;
73   } else {
74     return NORMALMODE;
75   }
76 }
77 
78 BOOLEAN
79 CheckIfRecoveryMode(
80   IN CONST EFI_PEI_SERVICES           **PeiServices,
81   IN OUT EFI_PLATFORM_INFO_HOB *PlatformInfoHob
CheckIfSafeMode(IN CONST EFI_PEI_SERVICES ** PeiServices,IN OUT EFI_PLATFORM_INFO_HOB * PlatformInfoHob)82  )
83 {
84   if (GetConfigJumper(PeiServices, PlatformInfoHob) == RECOVERYMODE) {
85     return TRUE;
86   }
87   return FALSE;
88 }
89 
90 BOOLEAN
91 CheckIfSafeMode(
92   IN CONST EFI_PEI_SERVICES           **PeiServices,
93   IN OUT EFI_PLATFORM_INFO_HOB *PlatformInfoHob
CheckIfManufacturingMode(IN CONST EFI_PEI_SERVICES ** PeiServices)94  )
95 {
96   if (GetConfigJumper(PeiServices, PlatformInfoHob) == SAFEMODE) {
97     return TRUE;
98   }
99   return FALSE;
100 }
101 
102 BOOLEAN
103 CheckIfManufacturingMode (
104   IN CONST EFI_PEI_SERVICES  **PeiServices
105  )
106 {
107   EFI_STATUS                  Status;
108   EFI_PEI_READ_ONLY_VARIABLE2_PPI  *Variable;
109   UINT32                      Attributes;
110   UINTN                       DataSize;
111   CHAR16                      VarName[] = MFGMODE_VARIABLE_NAME;
112   UINT8                       MfgMode;
113 
114   Status = (*PeiServices)->LocatePpi (
115                              PeiServices,
116                              &gEfiPeiReadOnlyVariable2PpiGuid,
117                              0,
118                              NULL,
119                              (void **)&Variable
120                              );
121   ASSERT_EFI_ERROR (Status);
122 
123   //
124   // Check if SW MMJ mode
125   //
126   Attributes = (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS);
127   DataSize = sizeof (MFG_MODE_VAR);
128 
129   Status = Variable->GetVariable (
130                        Variable,
131                        VarName,
132                        &gMfgModeVariableGuid,
133                        &Attributes,
134                        &DataSize,
UpdateBootMode(IN CONST EFI_PEI_SERVICES ** PeiServices,IN OUT EFI_PLATFORM_INFO_HOB * PlatformInfoHob)135                        &MfgMode
136                        );
137   if (!(EFI_ERROR (Status))) {
138     return TRUE;
139   }
140   return FALSE;
141 }
142 
143 EFI_STATUS
144 UpdateBootMode (
145   IN CONST EFI_PEI_SERVICES                       **PeiServices,
146   IN OUT EFI_PLATFORM_INFO_HOB                    *PlatformInfoHob
147   )
148 {
149   EFI_STATUS                        Status;
150   EFI_BOOT_MODE                     BootMode;
151   UINT16                            SleepType;
152   CHAR16                            *strBootMode;
153   PEI_CAPSULE_PPI                   *Capsule;
154   EFI_PEI_READ_ONLY_VARIABLE2_PPI   *Variable;
155   SYSTEM_CONFIGURATION              SystemConfiguration;
156   UINTN                             VarSize;
157   volatile UINT32                   GpioValue;
158   BOOLEAN                           IsFirstBoot;
159   UINT32                            Data32;
160 
161   Status = (*PeiServices)->GetBootMode(
162                              PeiServices,
163                              &BootMode
164                              );
165   ASSERT_EFI_ERROR (Status);
166   if (BootMode  == BOOT_IN_RECOVERY_MODE){
167     return Status;
168   }
169   GetWakeupEventAndSaveToHob (PeiServices);
170 
171   //
172   // Let's assume things are OK if not told otherwise
173   //
174   BootMode = BOOT_WITH_FULL_CONFIGURATION;
175 
176   //
177   // When this boot is WDT reset, the system needs booting with CrashDump function eanbled.
178   //
179   Data32 = IoRead32 (ACPI_BASE_ADDRESS + R_PCH_TCO_STS);
180 
181   //
182   // Check Power Button, click the power button, the system will boot in fast boot mode,
183   // if it is pressed and hold for a second, it will boot in FullConfiguration/setup mode.
184   //
185   GpioValue = MmioRead32 (IO_BASE_ADDRESS + GPIO_SSUS_OFFSET + PMU_PWRBTN_B_OFFSET);    // The value of GPIOS_16 (PMU_PWRBTN_B)
186   if (((GpioValue & BIT0) != 0)&&((Data32 & B_PCH_TCO_STS_SECOND_TO) != B_PCH_TCO_STS_SECOND_TO)){
187     IsFirstBoot = PcdGetBool(PcdBootState);
188     if (!IsFirstBoot){
189       VarSize = sizeof (SYSTEM_CONFIGURATION);
190       ZeroMem (&SystemConfiguration, sizeof (SYSTEM_CONFIGURATION));
191 
192       Status = (*PeiServices)->LocatePpi (
193                                  PeiServices,
194                                  &gEfiPeiReadOnlyVariable2PpiGuid,
195                                  0,
196                                  NULL,
197                                           (void **)&Variable
198                                  );
199       ASSERT_EFI_ERROR (Status);
200 
201       //
202       // Use normal setup default from NVRAM variable,
203       // the Platform Mode (manufacturing/safe/normal) is handle in PeiGetVariable.
204       //
205       VarSize = sizeof(SYSTEM_CONFIGURATION);
206       Status = Variable->GetVariable (
207                            Variable,
208                            L"Setup",
209                            &gEfiSetupVariableGuid,
210                            NULL,
211                            &VarSize,
212                            &SystemConfiguration
213                            );
214       if (EFI_ERROR (Status) || VarSize != sizeof(SYSTEM_CONFIGURATION)) {
215         //The setup variable is corrupted
216         VarSize = sizeof(SYSTEM_CONFIGURATION);
217         Status = Variable->GetVariable(
218                   Variable,
219                   L"SetupRecovery",
220                   &gEfiSetupVariableGuid,
221                   NULL,
222                   &VarSize,
223                   &SystemConfiguration
224                   );
225         ASSERT_EFI_ERROR (Status);
226       }
227 
228       if (SystemConfiguration.FastBoot == 1) {
229             BootMode = BOOT_WITH_MINIMAL_CONFIGURATION;
230       }
231     }
232   }
233 
234   //
235   // Check if we need to boot in forced recovery mode
236   //
237   if (CheckIfRecoveryMode(PeiServices, PlatformInfoHob)) {
238     BootMode  = BOOT_IN_RECOVERY_MODE;
239   }
240 
241   if (BootMode  == BOOT_IN_RECOVERY_MODE) {
242     Status = (*PeiServices)->InstallPpi (
243                                PeiServices,
244                                &mPpiListRecoveryBootMode
245                                );
246     ASSERT_EFI_ERROR (Status);
247   } else {
248     if (GetSleepTypeAfterWakeup (PeiServices, &SleepType)) {
249       switch (SleepType) {
250         case V_PCH_ACPI_PM1_CNT_S3:
251           BootMode = BOOT_ON_S3_RESUME;
252 
253           //
254           // Determine if we're in capsule update mode
255           //
256           Status = (*PeiServices)->LocatePpi (
257                                      PeiServices,
258                                      &gPeiCapsulePpiGuid,
259                                      0,
260                                      NULL,
261                                      (void **)&Capsule
262                                      );
263 
264           if (Status == EFI_SUCCESS) {
265             if (Capsule->CheckCapsuleUpdate ((EFI_PEI_SERVICES**)PeiServices) == EFI_SUCCESS) {
266               BootMode = BOOT_ON_FLASH_UPDATE;
267             }
268           }
269 
270           break;
271 
272         case V_PCH_ACPI_PM1_CNT_S4:
273           BootMode = BOOT_ON_S4_RESUME;
274           break;
275 
276         case V_PCH_ACPI_PM1_CNT_S5:
277           BootMode = BOOT_ON_S5_RESUME;
278           break;
279       } // switch (SleepType)
280     }
281 
282     //
283     // Check for Safe Mode
284     //
285   }
286 
287   switch (BootMode) {
288     case BOOT_WITH_FULL_CONFIGURATION:
289       strBootMode = L"BOOT_WITH_FULL_CONFIGURATION";
290       break;
291     case BOOT_WITH_MINIMAL_CONFIGURATION:
292       strBootMode = L"BOOT_WITH_MINIMAL_CONFIGURATION";
293       break;
294     case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES:
295       strBootMode = L"BOOT_ASSUMING_NO_CONFIGURATION_CHANGES";
296       break;
297     case BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS:
298       strBootMode = L"BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS";
299       break;
300     case BOOT_WITH_DEFAULT_SETTINGS:
301       strBootMode = L"BOOT_WITH_DEFAULT_SETTINGS";
302       break;
303     case BOOT_ON_S4_RESUME:
304       strBootMode = L"BOOT_ON_S4_RESUME";
305       break;
306     case BOOT_ON_S5_RESUME:
307       strBootMode = L"BOOT_ON_S5_RESUME";
308       break;
309     case BOOT_ON_S2_RESUME:
310       strBootMode = L"BOOT_ON_S2_RESUME";
311       break;
312     case BOOT_ON_S3_RESUME:
313       strBootMode = L"BOOT_ON_S3_RESUME";
314       break;
315     case BOOT_ON_FLASH_UPDATE:
316       strBootMode = L"BOOT_ON_FLASH_UPDATE";
317       break;
318     case BOOT_IN_RECOVERY_MODE:
319       strBootMode = L"BOOT_IN_RECOVERY_MODE";
320       break;
321     default:
322       strBootMode = L"Unknown boot mode";
323   } // switch (BootMode)
324 
325   DEBUG ((EFI_D_ERROR, "Setting BootMode to %s\n", strBootMode));
326   Status = (*PeiServices)->SetBootMode(
327                              PeiServices,
328                              BootMode
329                              );
330   ASSERT_EFI_ERROR (Status);
331 
332   return Status;
333 }
334 
335 /**
336   Get sleep type after wakeup
GetSleepTypeAfterWakeup(IN CONST EFI_PEI_SERVICES ** PeiServices,OUT UINT16 * SleepType)337 
338   @param PeiServices        Pointer to the PEI Service Table.
339   @param SleepType          Sleep type to be returned.
340 
341   @retval TRUE              A wake event occured without power failure.
342   @retval FALSE             Power failure occured or not a wakeup.
343 
344 **/
345 BOOLEAN
346 GetSleepTypeAfterWakeup (
347   IN  CONST EFI_PEI_SERVICES          **PeiServices,
348   OUT UINT16                    *SleepType
349   )
350 {
351   UINT16  Pm1Sts;
352   UINT16  Pm1Cnt;
353   UINT16  GenPmCon1;
354   GenPmCon1 = MmioRead16 (PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1);
355 
356   //
357   // Read the ACPI registers
358   //
359   Pm1Sts  = IoRead16 (ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_STS);
360   Pm1Cnt  = IoRead16 (ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_CNT);
361 
362   if ((GenPmCon1 & (B_PCH_PMC_GEN_PMCON_SUS_PWR_FLR | B_PCH_PMC_GEN_PMCON_GEN_RST_STS)) ||
363      (Pm1Sts & B_PCH_ACPI_PM1_STS_PRBTNOR)) {
364     //
365     // If power failure indicator, then don't attempt s3 resume.
366     // Clear PM1_CNT of S3 and set it to S5 as we just had a power failure, and memory has
367     // lost already.  This is to make sure no one will use PM1_CNT to check for S3 after
368     // power failure.
369     //
370     if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S3) {
371       Pm1Cnt = ((Pm1Cnt & ~B_PCH_ACPI_PM1_CNT_SLP_TYP) | V_PCH_ACPI_PM1_CNT_S5);
372       IoWrite16 (ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_CNT, Pm1Cnt);
373     }
374     //
375     // Clear Wake Status (WAK_STS)
376     //
377     IoWrite16 ((ACPI_BASE_ADDRESS + R_PCH_ACPI_PM1_STS), B_PCH_ACPI_PM1_STS_WAK);
378    }
379   //
380   // Get sleep type if a wake event occurred and there is no power failure
381   //
382   if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S3) {
383     *SleepType = Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP;
384     return TRUE;
385   } else if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S4){
386     *SleepType = Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP;
387     return TRUE;
388   }
389   return FALSE;
390 }
391 
392 VOID
393 SetPlatformBootMode (
394   IN CONST EFI_PEI_SERVICES             **PeiServices,
395   IN OUT EFI_PLATFORM_INFO_HOB *PlatformInfoHob
396   )
397 {
398   EFI_PLATFORM_SETUP_ID       PlatformSetupId;
399 
400   ZeroMem(&PlatformSetupId, sizeof (EFI_PLATFORM_SETUP_ID));
401 
402   CopyMem (&PlatformSetupId.SetupGuid,
403            &gEfiNormalSetupGuid,
404            sizeof (EFI_GUID));
405 
406   if (CheckIfRecoveryMode(PeiServices, PlatformInfoHob)) {
407     //
408     // Recovery mode
409     //
410     CopyMem (&PlatformSetupId.SetupName,
411              &NORMAL_SETUP_NAME,
412              StrSize (NORMAL_SETUP_NAME));
413     PlatformSetupId.PlatformBootMode = PLATFORM_RECOVERY_MODE;
414   } else if (CheckIfSafeMode(PeiServices, PlatformInfoHob)) {
415     //
416     // Safe mode also called config mode or maintenace mode.
417     //
418     CopyMem (&PlatformSetupId.SetupName,
419              &NORMAL_SETUP_NAME,
420              StrSize (NORMAL_SETUP_NAME));
421     PlatformSetupId.PlatformBootMode = PLATFORM_SAFE_MODE;
422 
423   } else if(0) { // else if (CheckIfManufacturingMode(PeiServices)) {
424     //
425     // Manufacturing mode
426     //
427     CopyMem (&PlatformSetupId.SetupName,
428              MANUFACTURE_SETUP_NAME,
429              StrSize (MANUFACTURE_SETUP_NAME));
430     PlatformSetupId.PlatformBootMode = PLATFORM_MANUFACTURING_MODE;
431 
432   } else {
433     //
434     // Default to normal mode.
435     //
436     CopyMem (&PlatformSetupId.SetupName,
437              &NORMAL_SETUP_NAME,
438              StrSize (NORMAL_SETUP_NAME));
439     PlatformSetupId.PlatformBootMode = PLATFORM_NORMAL_MODE;
440   }
441 
442   BuildGuidDataHob (
443     &gEfiPlatformBootModeGuid,
444     &PlatformSetupId,
445     sizeof (EFI_PLATFORM_SETUP_ID)
446     );
447   return;
448 }
449