2 This driver installs gEdkiiFaultTolerantWriteGuid PPI to inform
3 the check for FTW last write data has been done.
5 Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
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 #include <Library/SafeIntLib.h>
20 #include <Library/VariableFlashInfoLib.h>
22 EFI_PEI_PPI_DESCRIPTOR mPpiListVariable
= {
23 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
24 &gEdkiiFaultTolerantWriteGuid
,
29 Get the last Write Header pointer.
30 The last write header is the header whose 'complete' state hasn't been set.
31 After all, this header may be a EMPTY header entry for next Allocate.
34 @param FtwWorkSpaceHeader Pointer of the working block header
35 @param FtwWorkSpaceSize Size of the work space
36 @param FtwWriteHeader Pointer to retrieve the last write header
38 @retval EFI_SUCCESS Get the last write record successfully
39 @retval EFI_ABORTED The FTW work space is damaged
43 FtwGetLastWriteHeader (
44 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*FtwWorkSpaceHeader
,
45 IN UINTN FtwWorkSpaceSize
,
46 OUT EFI_FAULT_TOLERANT_WRITE_HEADER
**FtwWriteHeader
50 EFI_FAULT_TOLERANT_WRITE_HEADER
*FtwHeader
;
52 *FtwWriteHeader
= NULL
;
53 FtwHeader
= (EFI_FAULT_TOLERANT_WRITE_HEADER
*)(FtwWorkSpaceHeader
+ 1);
54 Offset
= sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
);
56 while (FtwHeader
->Complete
== FTW_VALID_STATE
) {
57 Offset
+= FTW_WRITE_TOTAL_SIZE (FtwHeader
->NumberOfWrites
, FtwHeader
->PrivateDataSize
);
59 // If Offset exceed the FTW work space boudary, return error.
61 if (Offset
>= FtwWorkSpaceSize
) {
62 *FtwWriteHeader
= FtwHeader
;
66 FtwHeader
= (EFI_FAULT_TOLERANT_WRITE_HEADER
*)((UINT8
*)FtwWorkSpaceHeader
+ Offset
);
70 // Last write header is found
72 *FtwWriteHeader
= FtwHeader
;
78 Get the last Write Record pointer. The last write Record is the Record
79 whose DestinationCompleted state hasn't been set. After all, this Record
80 may be a EMPTY record entry for next write.
83 @param FtwWriteHeader Pointer to the write record header
84 @param FtwWriteRecord Pointer to retrieve the last write record
86 @retval EFI_SUCCESS Get the last write record successfully
87 @retval EFI_ABORTED The FTW work space is damaged
91 FtwGetLastWriteRecord (
92 IN EFI_FAULT_TOLERANT_WRITE_HEADER
*FtwWriteHeader
,
93 OUT EFI_FAULT_TOLERANT_WRITE_RECORD
**FtwWriteRecord
97 EFI_FAULT_TOLERANT_WRITE_RECORD
*FtwRecord
;
99 *FtwWriteRecord
= NULL
;
100 FtwRecord
= (EFI_FAULT_TOLERANT_WRITE_RECORD
*)(FtwWriteHeader
+ 1);
103 // Try to find the last write record "that has not completed"
105 for (Index
= 0; Index
< FtwWriteHeader
->NumberOfWrites
; Index
+= 1) {
106 if (FtwRecord
->DestinationComplete
!= FTW_VALID_STATE
) {
108 // The last write record is found
110 *FtwWriteRecord
= FtwRecord
;
116 if (FtwWriteHeader
->PrivateDataSize
!= 0) {
117 FtwRecord
= (EFI_FAULT_TOLERANT_WRITE_RECORD
*)((UINTN
)FtwRecord
+ (UINTN
)FtwWriteHeader
->PrivateDataSize
);
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.
127 if (Index
== FtwWriteHeader
->NumberOfWrites
) {
128 *FtwWriteRecord
= (EFI_FAULT_TOLERANT_WRITE_RECORD
*)((UINTN
)FtwRecord
- FTW_RECORD_SIZE (FtwWriteHeader
->PrivateDataSize
));
136 Check to see if it is a valid work space.
139 @param WorkingHeader Pointer of working block header
140 @param WorkingLength Working block length
142 @retval TRUE The work space is valid.
143 @retval FALSE The work space is invalid.
148 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*WorkingHeader
,
149 IN UINTN WorkingLength
154 if (WorkingHeader
== NULL
) {
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"));
163 if (WorkingHeader
->WriteQueueSize
!= (WorkingLength
- sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
))) {
164 DEBUG ((DEBUG_ERROR
, "FtwPei: Work block header WriteQueueSize check error\n"));
169 // Check signature with gEdkiiWorkingBlockSignatureGuid
171 if (!CompareGuid (&gEdkiiWorkingBlockSignatureGuid
, &WorkingHeader
->Signature
)) {
172 DEBUG ((DEBUG_ERROR
, "FtwPei: Work block header signature check error, it should be gEdkiiWorkingBlockSignatureGuid\n"));
174 // To be compatible with old signature gEfiSystemNvDataFvGuid.
176 if (!CompareGuid (&gEfiSystemNvDataFvGuid
, &WorkingHeader
->Signature
)) {
179 Data
= *(UINT8
*)(WorkingHeader
+ 1);
181 DEBUG ((DEBUG_ERROR
, "FtwPei: Old format FTW structure can't be handled\n"));
192 Main entry for Fault Tolerant Write PEIM.
194 @param[in] FileHandle Handle of the file being invoked.
195 @param[in] PeiServices Pointer to PEI Services table.
197 @retval EFI_SUCCESS If the interface could be successfully installed
198 @retval Others Returned from PeiServicesInstallPpi()
203 PeimFaultTolerantWriteInitialize (
204 IN EFI_PEI_FILE_HANDLE FileHandle
,
205 IN CONST EFI_PEI_SERVICES
**PeiServices
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
;
218 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA FtwLastWrite
;
220 FtwWorkingBlockHeader
= NULL
;
221 FtwLastWriteHeader
= NULL
;
222 FtwLastWriteRecord
= NULL
;
224 SpareAreaAddress
= 0;
226 WorkSpaceAddress
= 0;
229 Status
= GetVariableFlashFtwWorkingInfo (&WorkSpaceAddress
, &Size
);
230 ASSERT_EFI_ERROR (Status
);
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
);
236 Status
= GetVariableFlashFtwSpareInfo (&SpareAreaAddress
, &Size
);
237 ASSERT_EFI_ERROR (Status
);
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
);
244 // The address of FTW working base and spare base must not be 0.
246 ASSERT ((WorkSpaceAddress
!= 0) && (SpareAreaAddress
!= 0));
248 FtwWorkingBlockHeader
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*)(UINTN
)WorkSpaceAddress
;
249 if (IsValidWorkSpace (FtwWorkingBlockHeader
, WorkSpaceLength
)) {
250 Status
= FtwGetLastWriteHeader (
251 FtwWorkingBlockHeader
,
255 if (!EFI_ERROR (Status
)) {
256 Status
= FtwGetLastWriteRecord (
262 if (!EFI_ERROR (Status
)) {
263 ASSERT (FtwLastWriteRecord
!= NULL
);
264 if ((FtwLastWriteRecord
->SpareComplete
== FTW_VALID_STATE
) && (FtwLastWriteRecord
->DestinationComplete
!= FTW_VALID_STATE
)) {
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.
271 FtwLastWrite
.TargetAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)((INT64
)SpareAreaAddress
+ FtwLastWriteRecord
->RelativeOffset
);
272 FtwLastWrite
.SpareAddress
= SpareAreaAddress
;
273 FtwLastWrite
.Length
= SpareAreaLength
;
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
281 BuildGuidDataHob (&gEdkiiFaultTolerantWriteGuid
, (VOID
*)&FtwLastWrite
, sizeof (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
));
285 FtwWorkingBlockHeader
= NULL
;
287 // If the working block workspace is not valid, try to find workspace in the spare block.
289 WorkSpaceInSpareArea
= SpareAreaAddress
+ SpareAreaLength
- WorkSpaceLength
;
290 while (WorkSpaceInSpareArea
>= SpareAreaAddress
) {
291 if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid
, (EFI_GUID
*)(UINTN
)WorkSpaceInSpareArea
)) {
293 // Found the workspace.
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
;
300 WorkSpaceInSpareArea
= WorkSpaceInSpareArea
- sizeof (EFI_GUID
);
303 if ((FtwWorkingBlockHeader
!= NULL
) && IsValidWorkSpace (FtwWorkingBlockHeader
, WorkSpaceLength
)) {
305 // It was workspace self reclaim, build FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob for it.
307 FtwLastWrite
.TargetAddress
= WorkSpaceAddress
- (WorkSpaceInSpareArea
- SpareAreaAddress
);
308 FtwLastWrite
.SpareAddress
= SpareAreaAddress
;
309 FtwLastWrite
.Length
= SpareAreaLength
;
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
317 BuildGuidDataHob (&gEdkiiFaultTolerantWriteGuid
, (VOID
*)&FtwLastWrite
, sizeof (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
));
322 DEBUG ((DEBUG_ERROR
, "FtwPei: Both working and spare block are invalid.\n"));
327 // Install gEdkiiFaultTolerantWriteGuid PPI to inform the check for FTW last write data has been done.
329 return PeiServicesInstallPpi (&mPpiListVariable
);