0dd3d24cf37d2274ebbf8d9edbfb7077e9afecd5
[mirror_edk2.git] / QuarkPlatformPkg / Platform / Pei / PlatformInit / BootMode.c
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
124 Check whether go to recovery path
125 @retval TRUE Go to recovery path
126 @retval FALSE Go to normal path
127
128 **/
129 BOOLEAN
130 OemRecoveryBootMode ()
131 {
132 return PlatformIsBootWithRecoveryStage1 ();
133 }
134
135 /**
136 Peform the boot mode determination logic
137 If the box is closed, then
138 1. If it's first time to boot, it's boot with full config .
139 2. If the ChassisIntrution is selected, force to be a boot with full config
140 3. Otherwise it's boot with no change.
141
142 @param PeiServices General purpose services available to every PEIM.
143
144 @param BootMode The detected boot mode.
145
146 @retval EFI_SUCCESS if the boot mode could be set
147 **/
148 EFI_STATUS
149 UpdateBootMode (
150 IN EFI_PEI_SERVICES **PeiServices,
151 OUT EFI_BOOT_MODE *BootMode
152 )
153 {
154 EFI_STATUS Status;
155 EFI_BOOT_MODE NewBootMode;
156 PEI_CAPSULE_PPI *Capsule;
157 CHAR8 UserSelection;
158 UINT32 Straps32;
159
160 //
161 // Read Straps. Used later if recovery boot.
162 //
163 Straps32 = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_STPDDRCFG);
164
165 //
166 // Check if we need to boot in recovery mode
167 //
168 if ((ValidateFvHeader (BootMode) != EFI_SUCCESS)) {
169 DEBUG ((EFI_D_INFO, "Force Boot mode recovery\n"));
170 NewBootMode = BOOT_IN_RECOVERY_MODE;
171 Status = PeiServicesInstallPpi (&mPpiListRecoveryBootMode);
172 ASSERT_EFI_ERROR (Status);
173 if (OemRecoveryBootMode () == FALSE) {
174 DEBUG ((EFI_D_INFO, "Recovery stage1 not Active, reboot to activate recovery stage1 image\n"));
175 OemInitiateRecoveryAndWait ();
176 }
177 } else if (OemRecoveryBootMode ()) {
178 DEBUG ((EFI_D_INFO, "Boot mode recovery\n"));
179 NewBootMode = BOOT_IN_RECOVERY_MODE;
180 Status = PeiServicesInstallPpi (&mPpiListRecoveryBootMode);
181 ASSERT_EFI_ERROR (Status);
182 } else if (QNCCheckS3AndClearState ()) {
183 //
184 // Determine if we're in capsule update mode
185 //
186 Status = PeiServicesLocatePpi (
187 &gPeiCapsulePpiGuid,
188 0,
189 NULL,
190 (VOID **)&Capsule
191 );
192 if (Status == EFI_SUCCESS) {
193 Status = Capsule->CheckCapsuleUpdate (PeiServices);
194 if (Status == EFI_SUCCESS) {
195 DEBUG ((EFI_D_INFO, "Boot mode Flash Update\n"));
196 NewBootMode = BOOT_ON_FLASH_UPDATE;
197 } else {
198 DEBUG ((EFI_D_INFO, "Boot mode S3 resume\n"));
199 NewBootMode = BOOT_ON_S3_RESUME;
200 }
201 } else {
202 DEBUG ((EFI_D_INFO, "Boot mode S3 resume\n"));
203 NewBootMode = BOOT_ON_S3_RESUME;
204 }
205 } else {
206 //
207 // Check if this is a power on reset
208 //
209 if (QNCCheckPowerOnResetAndClearState ()) {
210 DEBUG ((EFI_D_INFO, "Power On Reset\n"));
211 }
212 if (IsBootWithNoChange (PeiServices)) {
213 DEBUG ((EFI_D_INFO, "Boot with Minimum cfg\n"));
214 NewBootMode = BOOT_ASSUMING_NO_CONFIGURATION_CHANGES;
215 } else {
216 DEBUG ((EFI_D_INFO, "Boot with Full cfg\n"));
217 NewBootMode = BOOT_WITH_FULL_CONFIGURATION;
218 }
219 }
220 *BootMode = NewBootMode;
221 Status = PeiServicesSetBootMode (NewBootMode);
222 ASSERT_EFI_ERROR (Status);
223
224 //
225 // If Recovery Boot then prompt the user to insert a USB key with recovery nodule and
226 // continue with the recovery. Also give the user a chance to retry a normal boot.
227 //
228 if (NewBootMode == BOOT_IN_RECOVERY_MODE) {
229 if ((Straps32 & B_STPDDRCFG_FORCE_RECOVERY) == 0) {
230 DEBUG ((EFI_D_ERROR, "*****************************************************************\n"));
231 DEBUG ((EFI_D_ERROR, "***** Force Recovery Jumper Detected. *****\n"));
232 DEBUG ((EFI_D_ERROR, "***** Attempting auto recovery of system flash. *****\n"));
233 DEBUG ((EFI_D_ERROR, "***** Expecting USB key with recovery module connected. *****\n"));
234 DEBUG ((EFI_D_ERROR, "***** PLEASE REMOVE FORCE RECOVERY JUMPER. *****\n"));
235 DEBUG ((EFI_D_ERROR, "*****************************************************************\n"));
236 } else {
237 DEBUG ((EFI_D_ERROR, "*****************************************************************\n"));
238 DEBUG ((EFI_D_ERROR, "***** ERROR: System boot failure!!!!!!! *****\n"));
239 DEBUG ((EFI_D_ERROR, "***** - Press 'R' if you wish to force system recovery *****\n"));
240 DEBUG ((EFI_D_ERROR, "***** (connect USB key with recovery module first) *****\n"));
241 DEBUG ((EFI_D_ERROR, "***** - Press any other key to attempt another boot *****\n"));
242 DEBUG ((EFI_D_ERROR, "*****************************************************************\n"));
243
244 UserSelection = PlatformDebugPortGetChar8 ();
245 if ((UserSelection != 'R') && (UserSelection != 'r')) {
246 DEBUG ((EFI_D_ERROR, "New boot attempt selected........\n"));
247 //
248 // Initialte the cold reset
249 //
250 ResetCold ();
251 }
252 DEBUG ((EFI_D_ERROR, "Recovery boot selected..........\n"));
253 }
254 }
255
256 return EFI_SUCCESS;
257 }