]> git.proxmox.com Git - mirror_edk2.git/blame - QuarkPlatformPkg/Platform/Pei/PlatformInit/BootMode.c
QuarkPlatformPkg/ForceRecovery: Add UEFI application to force recovery
[mirror_edk2.git] / QuarkPlatformPkg / Platform / Pei / PlatformInit / BootMode.c
CommitLineData
b303605e
MK
1/** @file\r
2This file provide the function to detect boot mode\r
3\r
4Copyright (c) 2013 Intel Corporation.\r
5\r
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16\r
17#include "CommonHeader.h"\r
18#include <Pi/PiFirmwareVolume.h>\r
19\r
20EFI_PEI_PPI_DESCRIPTOR mPpiListRecoveryBootMode = {\r
21 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
22 &gEfiPeiBootInRecoveryModePpiGuid,\r
23 NULL\r
24};\r
25\r
26/**\r
27 If the box was opened, it's boot with full config.\r
28 If the box is closed, then\r
29 1. If it's first time to boot, it's boot with full config .\r
30 2. If the ChassisIntrution is selected, force to be a boot with full config\r
31 3. Otherwise it's boot with no change.\r
32\r
33 @param PeiServices General purpose services available to every PEIM.\r
34\r
35 @retval TRUE If it's boot with no change.\r
36\r
37 @retval FALSE If boot with no change.\r
38**/\r
39BOOLEAN\r
40IsBootWithNoChange (\r
41 IN EFI_PEI_SERVICES **PeiServices\r
42 )\r
43{\r
44 BOOLEAN IsFirstBoot = FALSE;\r
45\r
46 BOOLEAN EnableFastBoot = FALSE;\r
47 IsFirstBoot = PcdGetBool(PcdBootState);\r
48 EnableFastBoot = PcdGetBool (PcdEnableFastBoot);\r
49\r
50 DEBUG ((EFI_D_INFO, "IsFirstBoot = %x , EnableFastBoot= %x. \n", IsFirstBoot, EnableFastBoot));\r
51\r
52 if ((!IsFirstBoot) && EnableFastBoot) {\r
53 return TRUE;\r
54 } else {\r
55 return FALSE;\r
56 }\r
57}\r
58\r
59\r
60/**\r
61\r
62Routine Description:\r
63\r
64 This function is used to verify if the FV header is validate.\r
65\r
66 @param FwVolHeader - The FV header that to be verified.\r
67\r
68 @retval EFI_SUCCESS - The Fv header is valid.\r
69 @retval EFI_NOT_FOUND - The Fv header is invalid.\r
70\r
71**/\r
72EFI_STATUS\r
73ValidateFvHeader (\r
74 EFI_BOOT_MODE *BootMode\r
75 )\r
76{\r
77 UINT16 *Ptr;\r
78 UINT16 HeaderLength;\r
79 UINT16 Checksum;\r
80\r
81 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
82\r
83 if (BOOT_IN_RECOVERY_MODE == *BootMode) {\r
84 DEBUG ((EFI_D_INFO, "Boot mode recovery\n"));\r
85 return EFI_SUCCESS;\r
86 }\r
87 //\r
88 // Let's check whether FvMain header is valid, if not enter into recovery mode\r
89 //\r
90 //\r
91 // Verify the header revision, header signature, length\r
92 // Length of FvBlock cannot be 2**64-1\r
93 // HeaderLength cannot be an odd number\r
94 //\r
95 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PcdGet32(PcdFlashFvMainBase);\r
96 if ((FwVolHeader->Revision != EFI_FVH_REVISION)||\r
97 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||\r
98 (FwVolHeader->FvLength == ((UINT64) -1)) ||\r
99 ((FwVolHeader->HeaderLength & 0x01) != 0)\r
100 ) {\r
101 return EFI_NOT_FOUND;\r
102 }\r
103 //\r
104 // Verify the header checksum\r
105 //\r
106 HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2);\r
107 Ptr = (UINT16 *) FwVolHeader;\r
108 Checksum = 0;\r
109 while (HeaderLength > 0) {\r
110 Checksum = Checksum +*Ptr;\r
111 Ptr++;\r
112 HeaderLength--;\r
113 }\r
114\r
115 if (Checksum != 0) {\r
116 return EFI_NOT_FOUND;\r
117 }\r
118\r
119 return EFI_SUCCESS;\r
120}\r
121\r
122/**\r
123\r
124 Check whether go to recovery path\r
125 @retval TRUE Go to recovery path\r
126 @retval FALSE Go to normal path\r
127\r
128**/\r
129BOOLEAN\r
130OemRecoveryBootMode ()\r
131{\r
132 return PlatformIsBootWithRecoveryStage1 ();\r
133}\r
134\r
135/**\r
136 Peform the boot mode determination logic\r
137 If the box is closed, then\r
138 1. If it's first time to boot, it's boot with full config .\r
139 2. If the ChassisIntrution is selected, force to be a boot with full config\r
140 3. Otherwise it's boot with no change.\r
141\r
142 @param PeiServices General purpose services available to every PEIM.\r
143\r
144 @param BootMode The detected boot mode.\r
145\r
146 @retval EFI_SUCCESS if the boot mode could be set\r
147**/\r
148EFI_STATUS\r
149UpdateBootMode (\r
150 IN EFI_PEI_SERVICES **PeiServices,\r
151 OUT EFI_BOOT_MODE *BootMode\r
152 )\r
153{\r
154 EFI_STATUS Status;\r
155 EFI_BOOT_MODE NewBootMode;\r
156 PEI_CAPSULE_PPI *Capsule;\r
157 CHAR8 UserSelection;\r
158 UINT32 Straps32;\r
159\r
160 //\r
161 // Read Straps. Used later if recovery boot.\r
162 //\r
163 Straps32 = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_STPDDRCFG);\r
164\r
165 //\r
166 // Check if we need to boot in recovery mode\r
167 //\r
168 if ((ValidateFvHeader (BootMode) != EFI_SUCCESS)) {\r
169 DEBUG ((EFI_D_INFO, "Force Boot mode recovery\n"));\r
170 NewBootMode = BOOT_IN_RECOVERY_MODE;\r
171 Status = PeiServicesInstallPpi (&mPpiListRecoveryBootMode);\r
172 ASSERT_EFI_ERROR (Status);\r
173 if (OemRecoveryBootMode () == FALSE) {\r
174 DEBUG ((EFI_D_INFO, "Recovery stage1 not Active, reboot to activate recovery stage1 image\n"));\r
175 OemInitiateRecoveryAndWait ();\r
176 }\r
177 } else if (OemRecoveryBootMode ()) {\r
178 DEBUG ((EFI_D_INFO, "Boot mode recovery\n"));\r
179 NewBootMode = BOOT_IN_RECOVERY_MODE;\r
180 Status = PeiServicesInstallPpi (&mPpiListRecoveryBootMode);\r
181 ASSERT_EFI_ERROR (Status);\r
182 } else if (QNCCheckS3AndClearState ()) {\r
183 //\r
184 // Determine if we're in capsule update mode\r
185 //\r
186 Status = PeiServicesLocatePpi (\r
187 &gPeiCapsulePpiGuid,\r
188 0,\r
189 NULL,\r
190 (VOID **)&Capsule\r
191 );\r
192 if (Status == EFI_SUCCESS) {\r
193 Status = Capsule->CheckCapsuleUpdate (PeiServices);\r
194 if (Status == EFI_SUCCESS) {\r
195 DEBUG ((EFI_D_INFO, "Boot mode Flash Update\n"));\r
196 NewBootMode = BOOT_ON_FLASH_UPDATE;\r
197 } else {\r
198 DEBUG ((EFI_D_INFO, "Boot mode S3 resume\n"));\r
199 NewBootMode = BOOT_ON_S3_RESUME;\r
200 }\r
201 } else {\r
202 DEBUG ((EFI_D_INFO, "Boot mode S3 resume\n"));\r
203 NewBootMode = BOOT_ON_S3_RESUME;\r
204 }\r
205 } else {\r
206 //\r
207 // Check if this is a power on reset\r
208 //\r
209 if (QNCCheckPowerOnResetAndClearState ()) {\r
210 DEBUG ((EFI_D_INFO, "Power On Reset\n"));\r
211 }\r
212 if (IsBootWithNoChange (PeiServices)) {\r
213 DEBUG ((EFI_D_INFO, "Boot with Minimum cfg\n"));\r
214 NewBootMode = BOOT_ASSUMING_NO_CONFIGURATION_CHANGES;\r
215 } else {\r
216 DEBUG ((EFI_D_INFO, "Boot with Full cfg\n"));\r
217 NewBootMode = BOOT_WITH_FULL_CONFIGURATION;\r
218 }\r
219 }\r
220 *BootMode = NewBootMode;\r
221 Status = PeiServicesSetBootMode (NewBootMode);\r
222 ASSERT_EFI_ERROR (Status);\r
223\r
224 //\r
225 // If Recovery Boot then prompt the user to insert a USB key with recovery nodule and\r
226 // continue with the recovery. Also give the user a chance to retry a normal boot.\r
227 //\r
228 if (NewBootMode == BOOT_IN_RECOVERY_MODE) {\r
229 if ((Straps32 & B_STPDDRCFG_FORCE_RECOVERY) == 0) {\r
230 DEBUG ((EFI_D_ERROR, "*****************************************************************\n"));\r
231 DEBUG ((EFI_D_ERROR, "***** Force Recovery Jumper Detected. *****\n"));\r
232 DEBUG ((EFI_D_ERROR, "***** Attempting auto recovery of system flash. *****\n"));\r
233 DEBUG ((EFI_D_ERROR, "***** Expecting USB key with recovery module connected. *****\n"));\r
234 DEBUG ((EFI_D_ERROR, "***** PLEASE REMOVE FORCE RECOVERY JUMPER. *****\n"));\r
235 DEBUG ((EFI_D_ERROR, "*****************************************************************\n"));\r
236 } else {\r
237 DEBUG ((EFI_D_ERROR, "*****************************************************************\n"));\r
238 DEBUG ((EFI_D_ERROR, "***** ERROR: System boot failure!!!!!!! *****\n"));\r
239 DEBUG ((EFI_D_ERROR, "***** - Press 'R' if you wish to force system recovery *****\n"));\r
240 DEBUG ((EFI_D_ERROR, "***** (connect USB key with recovery module first) *****\n"));\r
241 DEBUG ((EFI_D_ERROR, "***** - Press any other key to attempt another boot *****\n"));\r
242 DEBUG ((EFI_D_ERROR, "*****************************************************************\n"));\r
243\r
244 UserSelection = PlatformDebugPortGetChar8 ();\r
245 if ((UserSelection != 'R') && (UserSelection != 'r')) {\r
246 DEBUG ((EFI_D_ERROR, "New boot attempt selected........\n"));\r
247 //\r
248 // Initialte the cold reset\r
249 //\r
250 ResetCold ();\r
251 }\r
252 DEBUG ((EFI_D_ERROR, "Recovery boot selected..........\n"));\r
253 }\r
254 }\r
255\r
256 return EFI_SUCCESS;\r
257}\r