TianoCore EDK2 master
Loading...
Searching...
No Matches
FaultTolerantWritePei.c
Go to the documentation of this file.
1
10#include <PiPei.h>
11
15#include <Library/PcdLib.h>
16#include <Library/DebugLib.h>
18#include <Library/HobLib.h>
19#include <Library/SafeIntLib.h>
21
22EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = {
23 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
24 &gEdkiiFaultTolerantWriteGuid,
25 NULL
26};
27
45 IN UINTN FtwWorkSpaceSize,
47 )
48{
49 UINTN Offset;
51
52 *FtwWriteHeader = NULL;
53 FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *)(FtwWorkSpaceHeader + 1);
55
56 while (FtwHeader->Complete == FTW_VALID_STATE) {
57 Offset += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);
58 //
59 // If Offset exceed the FTW work space boudary, return error.
60 //
61 if (Offset >= FtwWorkSpaceSize) {
62 *FtwWriteHeader = FtwHeader;
63 return EFI_ABORTED;
64 }
65
66 FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *)((UINT8 *)FtwWorkSpaceHeader + Offset);
67 }
68
69 //
70 // Last write header is found
71 //
72 *FtwWriteHeader = FtwHeader;
73
74 return EFI_SUCCESS;
75}
76
92 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwWriteHeader,
94 )
95{
96 UINTN Index;
98
100 FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *)(FtwWriteHeader + 1);
101
102 //
103 // Try to find the last write record "that has not completed"
104 //
105 for (Index = 0; Index < FtwWriteHeader->NumberOfWrites; Index += 1) {
106 if (FtwRecord->DestinationComplete != FTW_VALID_STATE) {
107 //
108 // The last write record is found
109 //
110 *FtwWriteRecord = FtwRecord;
111 return EFI_SUCCESS;
112 }
113
114 FtwRecord++;
115
116 if (FtwWriteHeader->PrivateDataSize != 0) {
117 FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *)((UINTN)FtwRecord + (UINTN)FtwWriteHeader->PrivateDataSize);
118 }
119 }
120
121 //
122 // if Index == NumberOfWrites, then
123 // the last record has been written successfully,
124 // but the Header->Complete Flag has not been set.
125 // also return the last record.
126 //
127 if (Index == FtwWriteHeader->NumberOfWrites) {
128 *FtwWriteRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *)((UINTN)FtwRecord - FTW_RECORD_SIZE (FtwWriteHeader->PrivateDataSize));
129 return EFI_SUCCESS;
130 }
131
132 return EFI_ABORTED;
133}
134
146BOOLEAN
149 IN UINTN WorkingLength
150 )
151{
152 UINT8 Data;
153
154 if (WorkingHeader == NULL) {
155 return FALSE;
156 }
157
158 if ((WorkingHeader->WorkingBlockValid != FTW_VALID_STATE) || (WorkingHeader->WorkingBlockInvalid == FTW_VALID_STATE)) {
159 DEBUG ((DEBUG_ERROR, "FtwPei: Work block header valid bit check error\n"));
160 return FALSE;
161 }
162
163 if (WorkingHeader->WriteQueueSize != (WorkingLength - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER))) {
164 DEBUG ((DEBUG_ERROR, "FtwPei: Work block header WriteQueueSize check error\n"));
165 return FALSE;
166 }
167
168 //
169 // Check signature with gEdkiiWorkingBlockSignatureGuid
170 //
171 if (!CompareGuid (&gEdkiiWorkingBlockSignatureGuid, &WorkingHeader->Signature)) {
172 DEBUG ((DEBUG_ERROR, "FtwPei: Work block header signature check error, it should be gEdkiiWorkingBlockSignatureGuid\n"));
173 //
174 // To be compatible with old signature gEfiSystemNvDataFvGuid.
175 //
176 if (!CompareGuid (&gEfiSystemNvDataFvGuid, &WorkingHeader->Signature)) {
177 return FALSE;
178 } else {
179 Data = *(UINT8 *)(WorkingHeader + 1);
180 if (Data != 0xff) {
181 DEBUG ((DEBUG_ERROR, "FtwPei: Old format FTW structure can't be handled\n"));
182 ASSERT (FALSE);
183 return FALSE;
184 }
185 }
186 }
187
188 return TRUE;
189}
190
202EFIAPI
204 IN EFI_PEI_FILE_HANDLE FileHandle,
205 IN CONST EFI_PEI_SERVICES **PeiServices
206 )
207{
208 EFI_STATUS Status;
209 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkingBlockHeader;
210 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwLastWriteHeader;
211 EFI_FAULT_TOLERANT_WRITE_RECORD *FtwLastWriteRecord;
212 EFI_PHYSICAL_ADDRESS WorkSpaceAddress;
213 UINTN WorkSpaceLength;
214 EFI_PHYSICAL_ADDRESS SpareAreaAddress;
215 UINTN SpareAreaLength;
216 EFI_PHYSICAL_ADDRESS WorkSpaceInSpareArea;
217 UINT64 Size;
219
220 FtwWorkingBlockHeader = NULL;
221 FtwLastWriteHeader = NULL;
222 FtwLastWriteRecord = NULL;
223
224 SpareAreaAddress = 0;
225 SpareAreaLength = 0;
226 WorkSpaceAddress = 0;
227 WorkSpaceLength = 0;
228
229 Status = GetVariableFlashFtwWorkingInfo (&WorkSpaceAddress, &Size);
230 ASSERT_EFI_ERROR (Status);
231
232 Status = SafeUint64ToUintn (Size, &WorkSpaceLength);
233 // This driver currently assumes the size will be UINTN so assert the value is safe for now.
234 ASSERT_EFI_ERROR (Status);
235
236 Status = GetVariableFlashFtwSpareInfo (&SpareAreaAddress, &Size);
237 ASSERT_EFI_ERROR (Status);
238
239 Status = SafeUint64ToUintn (Size, &SpareAreaLength);
240 // This driver currently assumes the size will be UINTN so assert the value is safe for now.
241 ASSERT_EFI_ERROR (Status);
242
243 //
244 // The address of FTW working base and spare base must not be 0.
245 //
246 ASSERT ((WorkSpaceAddress != 0) && (SpareAreaAddress != 0));
247
248 FtwWorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *)(UINTN)WorkSpaceAddress;
249 if (IsValidWorkSpace (FtwWorkingBlockHeader, WorkSpaceLength)) {
250 Status = FtwGetLastWriteHeader (
251 FtwWorkingBlockHeader,
252 WorkSpaceLength,
253 &FtwLastWriteHeader
254 );
255 if (!EFI_ERROR (Status)) {
256 Status = FtwGetLastWriteRecord (
257 FtwLastWriteHeader,
258 &FtwLastWriteRecord
259 );
260 }
261
262 if (!EFI_ERROR (Status)) {
263 ASSERT (FtwLastWriteRecord != NULL);
264 if ((FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE) && (FtwLastWriteRecord->DestinationComplete != FTW_VALID_STATE)) {
265 //
266 // If FTW last write was still in progress with SpareComplete set and DestinationComplete not set.
267 // It means the target buffer has been backed up in spare block, then target block has been erased,
268 // but the target buffer has not been writen in target block from spare block, we need to build
269 // FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob to hold the FTW last write data.
270 //
271 FtwLastWrite.TargetAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((INT64)SpareAreaAddress + FtwLastWriteRecord->RelativeOffset);
272 FtwLastWrite.SpareAddress = SpareAreaAddress;
273 FtwLastWrite.Length = SpareAreaLength;
274 DEBUG ((
275 DEBUG_INFO,
276 "FtwPei last write data: TargetAddress - 0x%x SpareAddress - 0x%x Length - 0x%x\n",
277 (UINTN)FtwLastWrite.TargetAddress,
278 (UINTN)FtwLastWrite.SpareAddress,
279 (UINTN)FtwLastWrite.Length
280 ));
281 BuildGuidDataHob (&gEdkiiFaultTolerantWriteGuid, (VOID *)&FtwLastWrite, sizeof (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA));
282 }
283 }
284 } else {
285 FtwWorkingBlockHeader = NULL;
286 //
287 // If the working block workspace is not valid, try to find workspace in the spare block.
288 //
289 WorkSpaceInSpareArea = SpareAreaAddress + SpareAreaLength - WorkSpaceLength;
290 while (WorkSpaceInSpareArea >= SpareAreaAddress) {
291 if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid, (EFI_GUID *)(UINTN)WorkSpaceInSpareArea)) {
292 //
293 // Found the workspace.
294 //
295 DEBUG ((DEBUG_INFO, "FtwPei: workspace in spare block is at 0x%x.\n", (UINTN)WorkSpaceInSpareArea));
296 FtwWorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *)(UINTN)WorkSpaceInSpareArea;
297 break;
298 }
299
300 WorkSpaceInSpareArea = WorkSpaceInSpareArea - sizeof (EFI_GUID);
301 }
302
303 if ((FtwWorkingBlockHeader != NULL) && IsValidWorkSpace (FtwWorkingBlockHeader, WorkSpaceLength)) {
304 //
305 // It was workspace self reclaim, build FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob for it.
306 //
307 FtwLastWrite.TargetAddress = WorkSpaceAddress - (WorkSpaceInSpareArea - SpareAreaAddress);
308 FtwLastWrite.SpareAddress = SpareAreaAddress;
309 FtwLastWrite.Length = SpareAreaLength;
310 DEBUG ((
311 DEBUG_INFO,
312 "FtwPei last write data: TargetAddress - 0x%x SpareAddress - 0x%x Length - 0x%x\n",
313 (UINTN)FtwLastWrite.TargetAddress,
314 (UINTN)FtwLastWrite.SpareAddress,
315 (UINTN)FtwLastWrite.Length
316 ));
317 BuildGuidDataHob (&gEdkiiFaultTolerantWriteGuid, (VOID *)&FtwLastWrite, sizeof (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA));
318 } else {
319 //
320 // Both are invalid.
321 //
322 DEBUG ((DEBUG_ERROR, "FtwPei: Both working and spare block are invalid.\n"));
323 }
324 }
325
326 //
327 // Install gEdkiiFaultTolerantWriteGuid PPI to inform the check for FTW last write data has been done.
328 //
329 return PeiServicesInstallPpi (&mPpiListVariable);
330}
UINT64 UINTN
VOID *EFIAPI BuildGuidDataHob(IN CONST EFI_GUID *Guid, IN VOID *Data, IN UINTN DataLength)
Definition: HobLib.c:375
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
Definition: MemLibGuid.c:73
EFI_STATUS EFIAPI PeiServicesInstallPpi(IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList)
EFI_STATUS FtwWriteRecord(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This, IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb, IN UINTN BlockSize)
EFI_STATUS FtwGetLastWriteRecord(IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwWriteHeader, OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwWriteRecord)
BOOLEAN IsValidWorkSpace(IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader, IN UINTN WorkingLength)
EFI_STATUS EFIAPI PeimFaultTolerantWriteInitialize(IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices)
EFI_STATUS FtwGetLastWriteHeader(IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkSpaceHeader, IN UINTN FtwWorkSpaceSize, OUT EFI_FAULT_TOLERANT_WRITE_HEADER **FtwWriteHeader)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
VOID * EFI_PEI_FILE_HANDLE
Definition: PiPeiCis.h:26
RETURN_STATUS EFIAPI SafeUint64ToUintn(IN UINT64 Operand, OUT UINTN *Result)
Definition: SafeIntLib32.c:307
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
GUID EFI_GUID
Definition: UefiBaseType.h:25
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_STATUS EFIAPI GetVariableFlashFtwWorkingInfo(OUT EFI_PHYSICAL_ADDRESS *BaseAddress, OUT UINT64 *Length)
EFI_STATUS EFIAPI GetVariableFlashFtwSpareInfo(OUT EFI_PHYSICAL_ADDRESS *BaseAddress, OUT UINT64 *Length)
Definition: Base.h:213