]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwWorkSpace.c
Partially make EdkModulePkg pass intel IPF compiler with /W4 /WX switched on.
[mirror_edk2.git] / EdkModulePkg / Universal / FirmwareVolume / FaultTolerantWriteLite / Dxe / FtwWorkSpace.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 FtwWorkSpace.c\r
15 \r
16Abstract:\r
17\r
18Revision History\r
19\r
20--*/\r
21\r
22\r
23#include <FtwLite.h>\r
24\r
25BOOLEAN\r
26IsValidWorkSpace (\r
27 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader\r
28 )\r
29/*++\r
30\r
31Routine Description:\r
32 Check to see if it is a valid work space.\r
33\r
34Arguments:\r
35 WorkingHeader - Pointer of working block header \r
36\r
37Returns:\r
38 EFI_SUCCESS - The function completed successfully\r
39 EFI_ABORTED - The function could not complete successfully.\r
40\r
41--*/\r
42{\r
43 EFI_STATUS Status;\r
44 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER WorkingBlockHeader;\r
45\r
46 ASSERT (WorkingHeader != NULL);\r
47 if (WorkingHeader->WorkingBlockValid != FTW_VALID_STATE) {\r
48 return FALSE;\r
49 }\r
50 //\r
51 // Check signature with gEfiSystemNvDataFvGuid\r
52 //\r
53 if (!CompareGuid (&gEfiSystemNvDataFvGuid, &WorkingHeader->Signature)) {\r
54 return FALSE;\r
55 }\r
56 //\r
57 // Check the CRC of header\r
58 //\r
59 CopyMem (\r
60 &WorkingBlockHeader,\r
61 WorkingHeader,\r
62 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)\r
63 );\r
64\r
65 //\r
66 // Filter out the Crc and State fields\r
67 //\r
68 SetMem (\r
69 &WorkingBlockHeader.Crc,\r
70 sizeof (UINT32),\r
71 FTW_ERASED_BYTE\r
72 );\r
73 WorkingBlockHeader.WorkingBlockValid = FTW_ERASE_POLARITY;\r
74 WorkingBlockHeader.WorkingBlockInvalid = FTW_ERASE_POLARITY;\r
75\r
76 //\r
77 // Calculate the Crc of woking block header\r
78 //\r
79 Status = gBS->CalculateCrc32 (\r
80 (UINT8 *) &WorkingBlockHeader,\r
81 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
82 &WorkingBlockHeader.Crc\r
83 );\r
84 ASSERT_EFI_ERROR (Status);\r
85\r
86 if (WorkingBlockHeader.Crc != WorkingHeader->Crc) {\r
87 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Work block header CRC check error\n"));\r
88 return FALSE;\r
89 }\r
90\r
91 return TRUE;\r
92}\r
93\r
94EFI_STATUS\r
95InitWorkSpaceHeader (\r
96 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader\r
97 )\r
98/*++\r
99\r
100Routine Description:\r
101 Initialize a work space when there is no work space.\r
102\r
103Arguments:\r
104 WorkingHeader - Pointer of working block header \r
105\r
106Returns:\r
107 EFI_SUCCESS - The function completed successfully\r
108 EFI_ABORTED - The function could not complete successfully.\r
109\r
110--*/\r
111{\r
112 EFI_STATUS Status;\r
113\r
114 ASSERT (WorkingHeader != NULL);\r
115\r
116 //\r
117 // Here using gEfiSystemNvDataFvGuid as the signature.\r
118 //\r
119 CopyMem (\r
120 &WorkingHeader->Signature,\r
121 &gEfiSystemNvDataFvGuid,\r
122 sizeof (EFI_GUID)\r
123 );\r
124 WorkingHeader->WriteQueueSize = FTW_WORKING_QUEUE_SIZE;\r
125\r
126 //\r
127 // Crc is calculated with all the fields except Crc and STATE\r
128 //\r
129 WorkingHeader->WorkingBlockValid = FTW_ERASE_POLARITY;\r
130 WorkingHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;\r
131 SetMem (&WorkingHeader->Crc, sizeof (UINT32), FTW_ERASED_BYTE);\r
132\r
133 //\r
134 // Calculate the CRC value\r
135 //\r
136 Status = gBS->CalculateCrc32 (\r
137 (UINT8 *) WorkingHeader,\r
138 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
139 &WorkingHeader->Crc\r
140 );\r
141 ASSERT_EFI_ERROR (Status);\r
142\r
143 //\r
144 // Restore the WorkingBlockValid flag to VALID state\r
145 //\r
146 WorkingHeader->WorkingBlockValid = FTW_VALID_STATE;\r
147 WorkingHeader->WorkingBlockInvalid = FTW_INVALID_STATE;\r
148\r
149 return EFI_SUCCESS;\r
150}\r
151\r
152EFI_STATUS\r
153FtwUpdateFvState (\r
154 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
155 IN EFI_LBA Lba,\r
156 IN UINTN Offset,\r
157 IN UINT8 NewBit\r
158 )\r
159/*++\r
160\r
161Routine Description:\r
162 Update a bit of state on a block device. The location of the bit is \r
163 calculated by the (Lba, Offset, bit). Here bit is determined by the \r
164 the name of a certain bit.\r
165\r
166Arguments:\r
167 FvBlock - FVB Protocol interface to access SrcBlock and DestBlock\r
168 Lba - Lba of a block\r
169 Offset - Offset on the Lba\r
170 NewBit - New value that will override the old value if it can be change\r
171\r
172Returns:\r
173 EFI_SUCCESS - A state bit has been updated successfully\r
174 Others - Access block device error.\r
175\r
176Notes:\r
177 Assume all bits of State are inside the same BYTE. \r
178\r
179 EFI_ABORTED - Read block fail\r
180--*/\r
181{\r
182 EFI_STATUS Status;\r
183 UINT8 State;\r
184 UINTN Length;\r
185\r
186 //\r
187 // Read state from device, assume State is only one byte.\r
188 //\r
189 Length = sizeof (UINT8);\r
190 Status = FvBlock->Read (FvBlock, Lba, Offset, &Length, &State);\r
191 if (EFI_ERROR (Status)) {\r
192 return EFI_ABORTED;\r
193 }\r
194\r
195 State ^= FTW_POLARITY_REVERT;\r
1cc8ee78 196 State = (UINT8) (State | NewBit);\r
878ddf1f 197 State ^= FTW_POLARITY_REVERT;\r
198\r
199 //\r
200 // Write state back to device\r
201 //\r
202 Length = sizeof (UINT8);\r
203 Status = FvBlock->Write (FvBlock, Lba, Offset, &Length, &State);\r
204\r
205 return Status;\r
206}\r
207\r
208EFI_STATUS\r
209FtwGetLastRecord (\r
210 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
211 OUT EFI_FTW_LITE_RECORD **FtwLastRecord\r
212 )\r
213/*++\r
214\r
215Routine Description:\r
216 Get the last Write record pointer. \r
217 The last record is the record whose 'complete' state hasn't been set.\r
218 After all, this header may be a EMPTY header entry for next Allocate. \r
219\r
220Arguments:\r
221 FtwLiteDevice - Private data of this driver\r
222 FtwLastRecord - Pointer to retrieve the last write record\r
223\r
224Returns:\r
225 EFI_SUCCESS - Get the last write record successfully\r
226 EFI_ABORTED - The FTW work space is damaged\r
227\r
228--*/\r
229{\r
230 EFI_FTW_LITE_RECORD *Record;\r
231\r
232 Record = (EFI_FTW_LITE_RECORD *) (FtwLiteDevice->FtwWorkSpaceHeader + 1);\r
233 while (Record->WriteCompleted == FTW_VALID_STATE) {\r
234 //\r
235 // If Offset exceed the FTW work space boudary, return error.\r
236 //\r
237 if ((UINTN) ((UINT8 *) Record - FtwLiteDevice->FtwWorkSpace) > FtwLiteDevice->FtwWorkSpaceSize) {\r
238 return EFI_ABORTED;\r
239 }\r
240\r
241 Record++;\r
242 }\r
243 //\r
244 // Last write record is found\r
245 //\r
246 *FtwLastRecord = Record;\r
247 return EFI_SUCCESS;\r
248}\r
249\r
250EFI_STATUS\r
251WorkSpaceRefresh (\r
252 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice\r
253 )\r
254/*++\r
255\r
256Routine Description:\r
257 Read from working block to refresh the work space in memory.\r
258\r
259Arguments:\r
260 FtwLiteDevice - Point to private data of FTW driver\r
261\r
262Returns:\r
263 EFI_SUCCESS - The function completed successfully\r
264 EFI_ABORTED - The function could not complete successfully.\r
265\r
266--*/\r
267{\r
268 EFI_STATUS Status;\r
269 UINTN Length;\r
270 UINTN Offset;\r
271 EFI_FTW_LITE_RECORD *Record;\r
272\r
273 //\r
274 // Initialize WorkSpace as FTW_ERASED_BYTE\r
275 //\r
276 SetMem (\r
277 FtwLiteDevice->FtwWorkSpace,\r
278 FtwLiteDevice->FtwWorkSpaceSize,\r
279 FTW_ERASED_BYTE\r
280 );\r
281\r
282 //\r
283 // Read from working block\r
284 //\r
285 Length = FtwLiteDevice->FtwWorkSpaceSize;\r
286 Status = FtwLiteDevice->FtwFvBlock->Read (\r
287 FtwLiteDevice->FtwFvBlock,\r
288 FtwLiteDevice->FtwWorkSpaceLba,\r
289 FtwLiteDevice->FtwWorkSpaceBase,\r
290 &Length,\r
291 FtwLiteDevice->FtwWorkSpace\r
292 );\r
293 if (EFI_ERROR (Status)) {\r
294 return EFI_ABORTED;\r
295 }\r
296 //\r
297 // Refresh the FtwLastRecord\r
298 //\r
299 Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);\r
300\r
301 Record = FtwLiteDevice->FtwLastRecord;\r
302 Offset = (UINTN) (UINT8 *) Record - (UINTN) FtwLiteDevice->FtwWorkSpace;\r
303\r
304 //\r
305 // IF work space has error or Record is out of the workspace limit, THEN\r
306 // call reclaim.\r
307 //\r
308 if (EFI_ERROR (Status) || (Offset + WRITE_TOTAL_SIZE >= FtwLiteDevice->FtwWorkSpaceSize)) {\r
309 //\r
310 // reclaim work space in working block.\r
311 //\r
312 Status = FtwReclaimWorkSpace (FtwLiteDevice);\r
313 if (EFI_ERROR (Status)) {\r
314 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Reclaim workspace - %r\n", Status));\r
315 return EFI_ABORTED;\r
316 }\r
317 }\r
318\r
319 return EFI_SUCCESS;\r
320}\r
321\r
322EFI_STATUS\r
323CleanupWorkSpace (\r
324 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
325 IN OUT UINT8 *FtwSpaceBuffer,\r
326 IN UINTN BufferSize\r
327 )\r
328/*++\r
329\r
330Routine Description:\r
331 Reclaim the work space. Get rid of all the completed write records\r
332 and write records in the Fault Tolerant work space.\r
333\r
334Arguments:\r
335 FtwLiteDevice - Point to private data of FTW driver\r
336 FtwSpaceBuffer - Buffer to contain the reclaimed clean data\r
337 BufferSize - Size of the FtwSpaceBuffer\r
338\r
339Returns:\r
340 EFI_SUCCESS - The function completed successfully\r
341 EFI_BUFFER_TOO_SMALL - The FtwSpaceBuffer is too small\r
342 EFI_ABORTED - The function could not complete successfully.\r
343\r
344--*/\r
345{\r
346 UINTN Length;\r
347 EFI_FTW_LITE_RECORD *Record;\r
348\r
349 //\r
350 // To check if the buffer is large enough\r
351 //\r
352 Length = FtwLiteDevice->FtwWorkSpaceSize;\r
353 if (BufferSize < Length) {\r
354 return EFI_BUFFER_TOO_SMALL;\r
355 }\r
356 //\r
357 // Clear the content of buffer that will save the new work space data\r
358 //\r
359 SetMem (FtwSpaceBuffer, Length, FTW_ERASED_BYTE);\r
360\r
361 //\r
362 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer\r
363 //\r
364 CopyMem (\r
365 FtwSpaceBuffer,\r
366 FtwLiteDevice->FtwWorkSpaceHeader,\r
367 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)\r
368 );\r
369\r
370 //\r
371 // Get the last record\r
372 //\r
373 Record = FtwLiteDevice->FtwLastRecord;\r
374 if ((Record != NULL) && (Record->WriteAllocated == FTW_VALID_STATE) && (Record->WriteCompleted != FTW_VALID_STATE)) {\r
375 CopyMem (\r
376 (UINT8 *) FtwSpaceBuffer + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
377 Record,\r
378 WRITE_TOTAL_SIZE\r
379 );\r
380 }\r
381\r
382 return EFI_SUCCESS;\r
383}\r
384\r
385EFI_STATUS\r
386FtwReclaimWorkSpace (\r
387 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice\r
388 )\r
389/*++\r
390\r
391Routine Description:\r
392 Reclaim the work space on the working block.\r
393\r
394Arguments:\r
395 FtwLiteDevice - Point to private data of FTW driver\r
396\r
397Returns:\r
398 EFI_SUCCESS - The function completed successfully\r
399 EFI_OUT_OF_RESOURCES - Allocate memory error\r
400 EFI_ABORTED - The function could not complete successfully\r
401\r
402--*/\r
403{\r
404 EFI_STATUS Status;\r
405 UINT8 *TempBuffer;\r
406 UINTN TempBufferSize;\r
407 UINT8 *Ptr;\r
408 UINTN Length;\r
409 UINTN Index;\r
410 UINTN SpareBufferSize;\r
411 UINT8 *SpareBuffer;\r
412 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;\r
413\r
414 DEBUG ((EFI_D_FTW_LITE, "FtwLite: start to reclaim work space\n"));\r
415\r
416 //\r
417 // Read all original data from working block to a memory buffer\r
418 //\r
419 TempBufferSize = FtwLiteDevice->SpareAreaLength;\r
420 Status = gBS->AllocatePool (\r
421 EfiBootServicesData,\r
422 TempBufferSize,\r
423 (VOID **) &TempBuffer\r
424 );\r
425 if (EFI_ERROR (Status)) {\r
426 return EFI_OUT_OF_RESOURCES;\r
427 }\r
428\r
429 ZeroMem (TempBuffer, TempBufferSize);\r
430\r
431 Ptr = TempBuffer;\r
432 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
433 Length = FtwLiteDevice->SizeOfSpareBlock;\r
434 Status = FtwLiteDevice->FtwFvBlock->Read (\r
435 FtwLiteDevice->FtwFvBlock,\r
436 FtwLiteDevice->FtwWorkBlockLba + Index,\r
437 0,\r
438 &Length,\r
439 Ptr\r
440 );\r
441 if (EFI_ERROR (Status)) {\r
442 gBS->FreePool (TempBuffer);\r
443 return EFI_ABORTED;\r
444 }\r
445\r
446 Ptr += Length;\r
447 }\r
448 //\r
449 // Clean up the workspace, remove all the completed records.\r
450 //\r
451 Ptr = TempBuffer +\r
452 ((UINTN) (FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba)) *\r
453 FtwLiteDevice->SizeOfSpareBlock +\r
454 FtwLiteDevice->FtwWorkSpaceBase;\r
455 Status = CleanupWorkSpace (\r
456 FtwLiteDevice,\r
457 Ptr,\r
458 FtwLiteDevice->FtwWorkSpaceSize\r
459 );\r
460\r
461 CopyMem (\r
462 FtwLiteDevice->FtwWorkSpace,\r
463 Ptr,\r
464 FtwLiteDevice->FtwWorkSpaceSize\r
465 );\r
466\r
467 Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);\r
468\r
469 //\r
470 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID\r
471 //\r
472 WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) Ptr;\r
473 WorkingBlockHeader->WorkingBlockValid = FTW_INVALID_STATE;\r
474 WorkingBlockHeader->WorkingBlockInvalid = FTW_INVALID_STATE;\r
475\r
476 //\r
477 // Try to keep the content of spare block\r
478 // Save spare block into a spare backup memory buffer (Sparebuffer)\r
479 //\r
480 SpareBufferSize = FtwLiteDevice->SpareAreaLength;\r
481 SpareBuffer = AllocatePool (SpareBufferSize);\r
482 if (SpareBuffer == NULL) {\r
483 gBS->FreePool (TempBuffer);\r
484 return EFI_OUT_OF_RESOURCES;\r
485 }\r
486\r
487 Ptr = SpareBuffer;\r
488 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
489 Length = FtwLiteDevice->SizeOfSpareBlock;\r
490 Status = FtwLiteDevice->FtwBackupFvb->Read (\r
491 FtwLiteDevice->FtwBackupFvb,\r
492 FtwLiteDevice->FtwSpareLba + Index,\r
493 0,\r
494 &Length,\r
495 Ptr\r
496 );\r
497 if (EFI_ERROR (Status)) {\r
498 gBS->FreePool (TempBuffer);\r
499 gBS->FreePool (SpareBuffer);\r
500 return EFI_ABORTED;\r
501 }\r
502\r
503 Ptr += Length;\r
504 }\r
505 //\r
506 // Write the memory buffer to spare block\r
507 //\r
508 Status = FtwEraseSpareBlock (FtwLiteDevice);\r
509 Ptr = TempBuffer;\r
510 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
511 Length = FtwLiteDevice->SizeOfSpareBlock;\r
512 Status = FtwLiteDevice->FtwBackupFvb->Write (\r
513 FtwLiteDevice->FtwBackupFvb,\r
514 FtwLiteDevice->FtwSpareLba + Index,\r
515 0,\r
516 &Length,\r
517 Ptr\r
518 );\r
519 if (EFI_ERROR (Status)) {\r
520 gBS->FreePool (TempBuffer);\r
521 gBS->FreePool (SpareBuffer);\r
522 return EFI_ABORTED;\r
523 }\r
524\r
525 Ptr += Length;\r
526 }\r
527 //\r
528 // Free TempBuffer\r
529 //\r
530 gBS->FreePool (TempBuffer);\r
531\r
532 //\r
533 // Write the spare block to working block\r
534 //\r
535 Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice);\r
536 if (EFI_ERROR (Status)) {\r
537 gBS->FreePool (SpareBuffer);\r
538 return Status;\r
539 }\r
540 //\r
541 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.\r
542 //\r
543 Status = FtwEraseSpareBlock (FtwLiteDevice);\r
544 Ptr = SpareBuffer;\r
545 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
546 Length = FtwLiteDevice->SizeOfSpareBlock;\r
547 Status = FtwLiteDevice->FtwBackupFvb->Write (\r
548 FtwLiteDevice->FtwBackupFvb,\r
549 FtwLiteDevice->FtwSpareLba + Index,\r
550 0,\r
551 &Length,\r
552 Ptr\r
553 );\r
554 if (EFI_ERROR (Status)) {\r
555 gBS->FreePool (SpareBuffer);\r
556 return EFI_ABORTED;\r
557 }\r
558\r
559 Ptr += Length;\r
560 }\r
561\r
562 gBS->FreePool (SpareBuffer);\r
563\r
564 DEBUG ((EFI_D_FTW_LITE, "FtwLite: reclaim work space success\n"));\r
565\r
566 return EFI_SUCCESS;\r
567}\r