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