VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.c@ 71635

Last change on this file since 71635 was 58466, checked in by vboxsync, 9 years ago

EFI/Firmware: Merged in the svn:eol-style, svn:mime-type and trailing whitespace cleanup that was done after the initial UDK2014.SP1 import: svn merge /vendor/edk2/UDK2014.SP1 /vendor/edk2/current .

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette