QuarkPlatformPkg/PlatformInit: Fix recovery detection issues
[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
b303605e
MK
122/**\r
123 Peform the boot mode determination logic\r
124 If the box is closed, then\r
125 1. If it's first time to boot, it's boot with full config .\r
126 2. If the ChassisIntrution is selected, force to be a boot with full config\r
127 3. Otherwise it's boot with no change.\r
128\r
129 @param PeiServices General purpose services available to every PEIM.\r
130\r
131 @param BootMode The detected boot mode.\r
132\r
133 @retval EFI_SUCCESS if the boot mode could be set\r
134**/\r
135EFI_STATUS\r
136UpdateBootMode (\r
137 IN EFI_PEI_SERVICES **PeiServices,\r
138 OUT EFI_BOOT_MODE *BootMode\r
139 )\r
140{\r
141 EFI_STATUS Status;\r
142 EFI_BOOT_MODE NewBootMode;\r
143 PEI_CAPSULE_PPI *Capsule;\r
69a0854b
MK
144 UINT32 RegValue;\r
145\r
146 NewBootMode = *BootMode;\r
b303605e
MK
147\r
148 //\r
69a0854b 149 // Read Sticky R/W Bits\r
b303605e 150 //\r
69a0854b
MK
151 RegValue = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_CFG_STICKY_RW);\r
152 DEBUG ((EFI_D_ERROR, "RegValue = %08x\n", RegValue));\r
b303605e
MK
153\r
154 //\r
155 // Check if we need to boot in recovery mode\r
156 //\r
69a0854b 157 if ((RegValue & B_CFG_STICKY_RW_FORCE_RECOVERY) != 0) {\r
b303605e 158 NewBootMode = BOOT_IN_RECOVERY_MODE;\r
69a0854b
MK
159 DEBUG ((EFI_D_ERROR, "RECOVERY from sticky bit\n"));;\r
160\r
161 //\r
162 // Clear force recovery sticky bit\r
163 //\r
164 QNCAltPortWrite (\r
165 QUARK_SCSS_SOC_UNIT_SB_PORT_ID,\r
166 QUARK_SCSS_SOC_UNIT_CFG_STICKY_RW,\r
167 RegValue &(~B_CFG_STICKY_RW_FORCE_RECOVERY)\r
168 );\r
169\r
170 } else if (ValidateFvHeader (BootMode) != EFI_SUCCESS) {\r
b303605e 171 NewBootMode = BOOT_IN_RECOVERY_MODE;\r
69a0854b 172 DEBUG ((EFI_D_ERROR, "RECOVERY from corrupt FV\n"));;\r
b303605e
MK
173 } else if (QNCCheckS3AndClearState ()) {\r
174 //\r
175 // Determine if we're in capsule update mode\r
176 //\r
177 Status = PeiServicesLocatePpi (\r
178 &gPeiCapsulePpiGuid,\r
179 0,\r
180 NULL,\r
181 (VOID **)&Capsule\r
182 );\r
183 if (Status == EFI_SUCCESS) {\r
184 Status = Capsule->CheckCapsuleUpdate (PeiServices);\r
185 if (Status == EFI_SUCCESS) {\r
186 DEBUG ((EFI_D_INFO, "Boot mode Flash Update\n"));\r
187 NewBootMode = BOOT_ON_FLASH_UPDATE;\r
188 } else {\r
189 DEBUG ((EFI_D_INFO, "Boot mode S3 resume\n"));\r
190 NewBootMode = BOOT_ON_S3_RESUME;\r
191 }\r
192 } else {\r
193 DEBUG ((EFI_D_INFO, "Boot mode S3 resume\n"));\r
194 NewBootMode = BOOT_ON_S3_RESUME;\r
195 }\r
196 } else {\r
197 //\r
198 // Check if this is a power on reset\r
199 //\r
200 if (QNCCheckPowerOnResetAndClearState ()) {\r
201 DEBUG ((EFI_D_INFO, "Power On Reset\n"));\r
202 }\r
203 if (IsBootWithNoChange (PeiServices)) {\r
204 DEBUG ((EFI_D_INFO, "Boot with Minimum cfg\n"));\r
205 NewBootMode = BOOT_ASSUMING_NO_CONFIGURATION_CHANGES;\r
206 } else {\r
207 DEBUG ((EFI_D_INFO, "Boot with Full cfg\n"));\r
208 NewBootMode = BOOT_WITH_FULL_CONFIGURATION;\r
209 }\r
210 }\r
b303605e 211\r
b303605e 212 if (NewBootMode == BOOT_IN_RECOVERY_MODE) {\r
69a0854b
MK
213 DEBUG ((EFI_D_INFO, "Boot mode recovery\n"));\r
214 Status = PeiServicesInstallPpi (&mPpiListRecoveryBootMode);\r
215 ASSERT_EFI_ERROR (Status);\r
b303605e
MK
216 }\r
217\r
69a0854b
MK
218 Status = PeiServicesSetBootMode (NewBootMode);\r
219 ASSERT_EFI_ERROR (Status);\r
220\r
221 *BootMode = NewBootMode;\r
222\r
b303605e
MK
223 return EFI_SUCCESS;\r
224}\r