]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.c
MdeModulePkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Universal / FaultTolerantWritePei / FaultTolerantWritePei.c
1 /** @file
2 This driver installs gEdkiiFaultTolerantWriteGuid PPI to inform
3 the check for FTW last write data has been done.
4
5 Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include <PiPei.h>
11
12 #include <Guid/SystemNvDataGuid.h>
13 #include <Guid/FaultTolerantWrite.h>
14 #include <Library/PeiServicesLib.h>
15 #include <Library/PcdLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/BaseMemoryLib.h>
18 #include <Library/HobLib.h>
19
20 EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = {
21 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
22 &gEdkiiFaultTolerantWriteGuid,
23 NULL
24 };
25
26 /**
27 Get the last Write Header pointer.
28 The last write header is the header whose 'complete' state hasn't been set.
29 After all, this header may be a EMPTY header entry for next Allocate.
30
31
32 @param FtwWorkSpaceHeader Pointer of the working block header
33 @param FtwWorkSpaceSize Size of the work space
34 @param FtwWriteHeader Pointer to retrieve the last write header
35
36 @retval EFI_SUCCESS Get the last write record successfully
37 @retval EFI_ABORTED The FTW work space is damaged
38
39 **/
40 EFI_STATUS
41 FtwGetLastWriteHeader (
42 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkSpaceHeader,
43 IN UINTN FtwWorkSpaceSize,
44 OUT EFI_FAULT_TOLERANT_WRITE_HEADER **FtwWriteHeader
45 )
46 {
47 UINTN Offset;
48 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
49
50 *FtwWriteHeader = NULL;
51 FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *)(FtwWorkSpaceHeader + 1);
52 Offset = sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);
53
54 while (FtwHeader->Complete == FTW_VALID_STATE) {
55 Offset += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);
56 //
57 // If Offset exceed the FTW work space boudary, return error.
58 //
59 if (Offset >= FtwWorkSpaceSize) {
60 *FtwWriteHeader = FtwHeader;
61 return EFI_ABORTED;
62 }
63
64 FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *)((UINT8 *)FtwWorkSpaceHeader + Offset);
65 }
66
67 //
68 // Last write header is found
69 //
70 *FtwWriteHeader = FtwHeader;
71
72 return EFI_SUCCESS;
73 }
74
75 /**
76 Get the last Write Record pointer. The last write Record is the Record
77 whose DestinationCompleted state hasn't been set. After all, this Record
78 may be a EMPTY record entry for next write.
79
80
81 @param FtwWriteHeader Pointer to the write record header
82 @param FtwWriteRecord Pointer to retrieve the last write record
83
84 @retval EFI_SUCCESS Get the last write record successfully
85 @retval EFI_ABORTED The FTW work space is damaged
86
87 **/
88 EFI_STATUS
89 FtwGetLastWriteRecord (
90 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwWriteHeader,
91 OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwWriteRecord
92 )
93 {
94 UINTN Index;
95 EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord;
96
97 *FtwWriteRecord = NULL;
98 FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *)(FtwWriteHeader + 1);
99
100 //
101 // Try to find the last write record "that has not completed"
102 //
103 for (Index = 0; Index < FtwWriteHeader->NumberOfWrites; Index += 1) {
104 if (FtwRecord->DestinationComplete != FTW_VALID_STATE) {
105 //
106 // The last write record is found
107 //
108 *FtwWriteRecord = FtwRecord;
109 return EFI_SUCCESS;
110 }
111
112 FtwRecord++;
113
114 if (FtwWriteHeader->PrivateDataSize != 0) {
115 FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *)((UINTN)FtwRecord + (UINTN)FtwWriteHeader->PrivateDataSize);
116 }
117 }
118
119 //
120 // if Index == NumberOfWrites, then
121 // the last record has been written successfully,
122 // but the Header->Complete Flag has not been set.
123 // also return the last record.
124 //
125 if (Index == FtwWriteHeader->NumberOfWrites) {
126 *FtwWriteRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *)((UINTN)FtwRecord - FTW_RECORD_SIZE (FtwWriteHeader->PrivateDataSize));
127 return EFI_SUCCESS;
128 }
129
130 return EFI_ABORTED;
131 }
132
133 /**
134 Check to see if it is a valid work space.
135
136
137 @param WorkingHeader Pointer of working block header
138 @param WorkingLength Working block length
139
140 @retval TRUE The work space is valid.
141 @retval FALSE The work space is invalid.
142
143 **/
144 BOOLEAN
145 IsValidWorkSpace (
146 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader,
147 IN UINTN WorkingLength
148 )
149 {
150 UINT8 Data;
151
152 if (WorkingHeader == NULL) {
153 return FALSE;
154 }
155
156 if ((WorkingHeader->WorkingBlockValid != FTW_VALID_STATE) || (WorkingHeader->WorkingBlockInvalid == FTW_VALID_STATE)) {
157 DEBUG ((DEBUG_ERROR, "FtwPei: Work block header valid bit check error\n"));
158 return FALSE;
159 }
160
161 if (WorkingHeader->WriteQueueSize != (WorkingLength - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER))) {
162 DEBUG ((DEBUG_ERROR, "FtwPei: Work block header WriteQueueSize check error\n"));
163 return FALSE;
164 }
165
166 //
167 // Check signature with gEdkiiWorkingBlockSignatureGuid
168 //
169 if (!CompareGuid (&gEdkiiWorkingBlockSignatureGuid, &WorkingHeader->Signature)) {
170 DEBUG ((DEBUG_ERROR, "FtwPei: Work block header signature check error, it should be gEdkiiWorkingBlockSignatureGuid\n"));
171 //
172 // To be compatible with old signature gEfiSystemNvDataFvGuid.
173 //
174 if (!CompareGuid (&gEfiSystemNvDataFvGuid, &WorkingHeader->Signature)) {
175 return FALSE;
176 } else {
177 Data = *(UINT8 *)(WorkingHeader + 1);
178 if (Data != 0xff) {
179 DEBUG ((DEBUG_ERROR, "FtwPei: Old format FTW structure can't be handled\n"));
180 ASSERT (FALSE);
181 return FALSE;
182 }
183 }
184 }
185
186 return TRUE;
187 }
188
189 /**
190 Main entry for Fault Tolerant Write PEIM.
191
192 @param[in] FileHandle Handle of the file being invoked.
193 @param[in] PeiServices Pointer to PEI Services table.
194
195 @retval EFI_SUCCESS If the interface could be successfully installed
196 @retval Others Returned from PeiServicesInstallPpi()
197
198 **/
199 EFI_STATUS
200 EFIAPI
201 PeimFaultTolerantWriteInitialize (
202 IN EFI_PEI_FILE_HANDLE FileHandle,
203 IN CONST EFI_PEI_SERVICES **PeiServices
204 )
205 {
206 EFI_STATUS Status;
207 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkingBlockHeader;
208 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwLastWriteHeader;
209 EFI_FAULT_TOLERANT_WRITE_RECORD *FtwLastWriteRecord;
210 EFI_PHYSICAL_ADDRESS WorkSpaceAddress;
211 UINTN WorkSpaceLength;
212 EFI_PHYSICAL_ADDRESS SpareAreaAddress;
213 UINTN SpareAreaLength;
214 EFI_PHYSICAL_ADDRESS WorkSpaceInSpareArea;
215 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA FtwLastWrite;
216
217 FtwWorkingBlockHeader = NULL;
218 FtwLastWriteHeader = NULL;
219 FtwLastWriteRecord = NULL;
220
221 WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS)PcdGet64 (PcdFlashNvStorageFtwWorkingBase64);
222 if (WorkSpaceAddress == 0) {
223 WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS)PcdGet32 (PcdFlashNvStorageFtwWorkingBase);
224 }
225
226 WorkSpaceLength = (UINTN)PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
227
228 SpareAreaAddress = (EFI_PHYSICAL_ADDRESS)PcdGet64 (PcdFlashNvStorageFtwSpareBase64);
229 if (SpareAreaAddress == 0) {
230 SpareAreaAddress = (EFI_PHYSICAL_ADDRESS)PcdGet32 (PcdFlashNvStorageFtwSpareBase);
231 }
232
233 SpareAreaLength = (UINTN)PcdGet32 (PcdFlashNvStorageFtwSpareSize);
234
235 //
236 // The address of FTW working base and spare base must not be 0.
237 //
238 ASSERT ((WorkSpaceAddress != 0) && (SpareAreaAddress != 0));
239
240 FtwWorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *)(UINTN)WorkSpaceAddress;
241 if (IsValidWorkSpace (FtwWorkingBlockHeader, WorkSpaceLength)) {
242 Status = FtwGetLastWriteHeader (
243 FtwWorkingBlockHeader,
244 WorkSpaceLength,
245 &FtwLastWriteHeader
246 );
247 if (!EFI_ERROR (Status)) {
248 Status = FtwGetLastWriteRecord (
249 FtwLastWriteHeader,
250 &FtwLastWriteRecord
251 );
252 }
253
254 if (!EFI_ERROR (Status)) {
255 ASSERT (FtwLastWriteRecord != NULL);
256 if ((FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE) && (FtwLastWriteRecord->DestinationComplete != FTW_VALID_STATE)) {
257 //
258 // If FTW last write was still in progress with SpareComplete set and DestinationComplete not set.
259 // It means the target buffer has been backed up in spare block, then target block has been erased,
260 // but the target buffer has not been writen in target block from spare block, we need to build
261 // FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob to hold the FTW last write data.
262 //
263 FtwLastWrite.TargetAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((INT64)SpareAreaAddress + FtwLastWriteRecord->RelativeOffset);
264 FtwLastWrite.SpareAddress = SpareAreaAddress;
265 FtwLastWrite.Length = SpareAreaLength;
266 DEBUG ((
267 DEBUG_INFO,
268 "FtwPei last write data: TargetAddress - 0x%x SpareAddress - 0x%x Length - 0x%x\n",
269 (UINTN)FtwLastWrite.TargetAddress,
270 (UINTN)FtwLastWrite.SpareAddress,
271 (UINTN)FtwLastWrite.Length
272 ));
273 BuildGuidDataHob (&gEdkiiFaultTolerantWriteGuid, (VOID *)&FtwLastWrite, sizeof (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA));
274 }
275 }
276 } else {
277 FtwWorkingBlockHeader = NULL;
278 //
279 // If the working block workspace is not valid, try to find workspace in the spare block.
280 //
281 WorkSpaceInSpareArea = SpareAreaAddress + SpareAreaLength - WorkSpaceLength;
282 while (WorkSpaceInSpareArea >= SpareAreaAddress) {
283 if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid, (EFI_GUID *)(UINTN)WorkSpaceInSpareArea)) {
284 //
285 // Found the workspace.
286 //
287 DEBUG ((DEBUG_INFO, "FtwPei: workspace in spare block is at 0x%x.\n", (UINTN)WorkSpaceInSpareArea));
288 FtwWorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *)(UINTN)WorkSpaceInSpareArea;
289 break;
290 }
291
292 WorkSpaceInSpareArea = WorkSpaceInSpareArea - sizeof (EFI_GUID);
293 }
294
295 if ((FtwWorkingBlockHeader != NULL) && IsValidWorkSpace (FtwWorkingBlockHeader, WorkSpaceLength)) {
296 //
297 // It was workspace self reclaim, build FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob for it.
298 //
299 FtwLastWrite.TargetAddress = WorkSpaceAddress - (WorkSpaceInSpareArea - SpareAreaAddress);
300 FtwLastWrite.SpareAddress = SpareAreaAddress;
301 FtwLastWrite.Length = SpareAreaLength;
302 DEBUG ((
303 DEBUG_INFO,
304 "FtwPei last write data: TargetAddress - 0x%x SpareAddress - 0x%x Length - 0x%x\n",
305 (UINTN)FtwLastWrite.TargetAddress,
306 (UINTN)FtwLastWrite.SpareAddress,
307 (UINTN)FtwLastWrite.Length
308 ));
309 BuildGuidDataHob (&gEdkiiFaultTolerantWriteGuid, (VOID *)&FtwLastWrite, sizeof (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA));
310 } else {
311 //
312 // Both are invalid.
313 //
314 DEBUG ((DEBUG_ERROR, "FtwPei: Both working and spare block are invalid.\n"));
315 }
316 }
317
318 //
319 // Install gEdkiiFaultTolerantWriteGuid PPI to inform the check for FTW last write data has been done.
320 //
321 return PeiServicesInstallPpi (&mPpiListVariable);
322 }