TianoCore EDK2 master
Loading...
Searching...
No Matches
UpdateWorkingBlock.c
Go to the documentation of this file.
1
10#include "FaultTolerantWrite.h"
11
12EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER mWorkingBlockHeader = { ZERO_GUID, 0, 0, 0, 0, { 0, 0, 0 }, 0 };
13
23VOID
25 IN UINTN WorkSpaceLength
26 )
27{
28 //
29 // Check signature with gEdkiiWorkingBlockSignatureGuid.
30 //
31 if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid, &mWorkingBlockHeader.Signature)) {
32 //
33 // The local work space header has been initialized.
34 //
35 return;
36 }
37
38 SetMem (
39 &mWorkingBlockHeader,
41 FTW_ERASED_BYTE
42 );
43
44 //
45 // Here using gEdkiiWorkingBlockSignatureGuid as the signature.
46 //
47 CopyMem (
48 &mWorkingBlockHeader.Signature,
49 &gEdkiiWorkingBlockSignatureGuid,
50 sizeof (EFI_GUID)
51 );
52 mWorkingBlockHeader.WriteQueueSize = WorkSpaceLength - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);
53
54 //
55 // Crc is calculated with all the fields except Crc and STATE, so leave them as FTW_ERASED_BYTE.
56 //
57
58 //
59 // Calculate the Crc of woking block header
60 //
61 mWorkingBlockHeader.Crc = FtwCalculateCrc32 (
62 &mWorkingBlockHeader,
64 );
65
66 mWorkingBlockHeader.WorkingBlockValid = FTW_VALID_STATE;
67 mWorkingBlockHeader.WorkingBlockInvalid = FTW_INVALID_STATE;
68}
69
80BOOLEAN
83 )
84{
85 if (WorkingHeader == NULL) {
86 return FALSE;
87 }
88
89 if (CompareMem (WorkingHeader, &mWorkingBlockHeader, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)) == 0) {
90 return TRUE;
91 }
92
93 DEBUG ((DEBUG_INFO, "Ftw: Work block header check mismatch\n"));
94 return FALSE;
95}
96
109 )
110{
111 if (WorkingHeader == NULL) {
112 return EFI_INVALID_PARAMETER;
113 }
114
115 CopyMem (WorkingHeader, &mWorkingBlockHeader, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER));
116
117 return EFI_SUCCESS;
118}
119
137 IN UINTN BlockSize,
138 IN EFI_LBA Lba,
139 IN UINTN Offset,
140 IN UINTN Length,
141 OUT UINT8 *Buffer
142 )
143{
144 EFI_STATUS Status;
145 UINT8 *Ptr;
146 UINTN MyLength;
147
148 //
149 // Calculate the real Offset and Lba to write.
150 //
151 while (Offset >= BlockSize) {
152 Offset -= BlockSize;
153 Lba++;
154 }
155
156 Ptr = Buffer;
157 while (Length > 0) {
158 if ((Offset + Length) > BlockSize) {
159 MyLength = BlockSize - Offset;
160 } else {
161 MyLength = Length;
162 }
163
164 Status = FvBlock->Read (
165 FvBlock,
166 Lba,
167 Offset,
168 &MyLength,
169 Ptr
170 );
171 if (EFI_ERROR (Status)) {
172 return EFI_ABORTED;
173 }
174
175 Offset = 0;
176 Length -= MyLength;
177 Ptr += MyLength;
178 Lba++;
179 }
180
181 return EFI_SUCCESS;
182}
183
201 IN UINTN BlockSize,
202 IN EFI_LBA Lba,
203 IN UINTN Offset,
204 IN UINTN Length,
205 IN UINT8 *Buffer
206 )
207{
208 EFI_STATUS Status;
209 UINT8 *Ptr;
210 UINTN MyLength;
211
212 //
213 // Calculate the real Offset and Lba to write.
214 //
215 while (Offset >= BlockSize) {
216 Offset -= BlockSize;
217 Lba++;
218 }
219
220 Ptr = Buffer;
221 while (Length > 0) {
222 if ((Offset + Length) > BlockSize) {
223 MyLength = BlockSize - Offset;
224 } else {
225 MyLength = Length;
226 }
227
228 Status = FvBlock->Write (
229 FvBlock,
230 Lba,
231 Offset,
232 &MyLength,
233 Ptr
234 );
235 if (EFI_ERROR (Status)) {
236 return EFI_ABORTED;
237 }
238
239 Offset = 0;
240 Length -= MyLength;
241 Ptr += MyLength;
242 Lba++;
243 }
244
245 return EFI_SUCCESS;
246}
247
259 IN EFI_FTW_DEVICE *FtwDevice
260 )
261{
262 EFI_STATUS Status;
263 UINTN RemainingSpaceSize;
264
265 //
266 // Initialize WorkSpace as FTW_ERASED_BYTE
267 //
268 SetMem (
269 FtwDevice->FtwWorkSpace,
270 FtwDevice->FtwWorkSpaceSize,
271 FTW_ERASED_BYTE
272 );
273
274 //
275 // Read from working block
276 //
277 Status = ReadWorkSpaceData (
278 FtwDevice->FtwFvBlock,
279 FtwDevice->WorkBlockSize,
280 FtwDevice->FtwWorkSpaceLba,
281 FtwDevice->FtwWorkSpaceBase,
282 FtwDevice->FtwWorkSpaceSize,
283 FtwDevice->FtwWorkSpace
284 );
285 if (EFI_ERROR (Status)) {
286 return EFI_ABORTED;
287 }
288
289 //
290 // Refresh the FtwLastWriteHeader
291 //
292 Status = FtwGetLastWriteHeader (
293 FtwDevice->FtwWorkSpaceHeader,
294 FtwDevice->FtwWorkSpaceSize,
295 &FtwDevice->FtwLastWriteHeader
296 );
297 RemainingSpaceSize = FtwDevice->FtwWorkSpaceSize - ((UINTN)FtwDevice->FtwLastWriteHeader - (UINTN)FtwDevice->FtwWorkSpace);
298 DEBUG ((DEBUG_INFO, "Ftw: Remaining work space size - %x\n", RemainingSpaceSize));
299 //
300 // If FtwGetLastWriteHeader() returns error, or the remaining space size is even not enough to contain
301 // one EFI_FAULT_TOLERANT_WRITE_HEADER + one EFI_FAULT_TOLERANT_WRITE_RECORD(It will cause that the header
302 // pointed by FtwDevice->FtwLastWriteHeader or record pointed by FtwDevice->FtwLastWriteRecord may contain invalid data),
303 // it needs to reclaim work space.
304 //
305 if (EFI_ERROR (Status) || (RemainingSpaceSize < sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER) + sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD))) {
306 //
307 // reclaim work space in working block.
308 //
309 Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
310 if (EFI_ERROR (Status)) {
311 DEBUG ((DEBUG_ERROR, "Ftw: Reclaim workspace - %r\n", Status));
312 return EFI_ABORTED;
313 }
314
315 //
316 // Read from working block again
317 //
318 Status = ReadWorkSpaceData (
319 FtwDevice->FtwFvBlock,
320 FtwDevice->WorkBlockSize,
321 FtwDevice->FtwWorkSpaceLba,
322 FtwDevice->FtwWorkSpaceBase,
323 FtwDevice->FtwWorkSpaceSize,
324 FtwDevice->FtwWorkSpace
325 );
326 if (EFI_ERROR (Status)) {
327 return EFI_ABORTED;
328 }
329
330 Status = FtwGetLastWriteHeader (
331 FtwDevice->FtwWorkSpaceHeader,
332 FtwDevice->FtwWorkSpaceSize,
333 &FtwDevice->FtwLastWriteHeader
334 );
335 if (EFI_ERROR (Status)) {
336 return EFI_ABORTED;
337 }
338 }
339
340 //
341 // Refresh the FtwLastWriteRecord
342 //
343 Status = FtwGetLastWriteRecord (
344 FtwDevice->FtwLastWriteHeader,
345 &FtwDevice->FtwLastWriteRecord
346 );
347 if (EFI_ERROR (Status)) {
348 return EFI_ABORTED;
349 }
350
351 return EFI_SUCCESS;
352}
353
367 IN EFI_FTW_DEVICE *FtwDevice,
368 IN BOOLEAN PreserveRecord
369 )
370{
371 EFI_STATUS Status;
372 UINTN Length;
374 UINT8 *TempBuffer;
375 UINTN TempBufferSize;
376 UINTN SpareBufferSize;
377 UINT8 *SpareBuffer;
378 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;
379 UINTN Index;
380 UINT8 *Ptr;
381 EFI_LBA WorkSpaceLbaOffset;
382
383 DEBUG ((DEBUG_INFO, "Ftw: start to reclaim work space\n"));
384
385 WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba;
386
387 //
388 // Read all original data from working block to a memory buffer
389 //
390 TempBufferSize = FtwDevice->NumberOfWorkBlock * FtwDevice->WorkBlockSize;
391 TempBuffer = AllocateZeroPool (TempBufferSize);
392 if (TempBuffer == NULL) {
393 return EFI_OUT_OF_RESOURCES;
394 }
395
396 Ptr = TempBuffer;
397 for (Index = 0; Index < FtwDevice->NumberOfWorkBlock; Index += 1) {
398 Length = FtwDevice->WorkBlockSize;
399 Status = FtwDevice->FtwFvBlock->Read (
400 FtwDevice->FtwFvBlock,
401 FtwDevice->FtwWorkBlockLba + Index,
402 0,
403 &Length,
404 Ptr
405 );
406 if (EFI_ERROR (Status)) {
407 FreePool (TempBuffer);
408 return EFI_ABORTED;
409 }
410
411 Ptr += Length;
412 }
413
414 //
415 // Clean up the workspace, remove all the completed records.
416 //
417 Ptr = TempBuffer +
418 (UINTN)WorkSpaceLbaOffset * FtwDevice->WorkBlockSize +
419 FtwDevice->FtwWorkSpaceBase;
420
421 //
422 // Clear the content of buffer that will save the new work space data
423 //
424 SetMem (Ptr, FtwDevice->FtwWorkSpaceSize, FTW_ERASED_BYTE);
425
426 //
427 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
428 //
429 CopyMem (
430 Ptr,
431 FtwDevice->FtwWorkSpaceHeader,
433 );
434 if (PreserveRecord) {
435 //
436 // Get the last record following the header,
437 //
438 Status = FtwGetLastWriteHeader (
439 FtwDevice->FtwWorkSpaceHeader,
440 FtwDevice->FtwWorkSpaceSize,
441 &FtwDevice->FtwLastWriteHeader
442 );
443 Header = FtwDevice->FtwLastWriteHeader;
444 if (!EFI_ERROR (Status) && (Header != NULL) && (Header->Complete != FTW_VALID_STATE) && (Header->HeaderAllocated == FTW_VALID_STATE)) {
445 CopyMem (
447 FtwDevice->FtwLastWriteHeader,
448 FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites, Header->PrivateDataSize)
449 );
450 }
451 }
452
453 CopyMem (
454 FtwDevice->FtwWorkSpace,
455 Ptr,
456 FtwDevice->FtwWorkSpaceSize
457 );
458
460 FtwDevice->FtwWorkSpaceHeader,
461 FtwDevice->FtwWorkSpaceSize,
462 &FtwDevice->FtwLastWriteHeader
463 );
464
466 FtwDevice->FtwLastWriteHeader,
467 &FtwDevice->FtwLastWriteRecord
468 );
469
470 //
471 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
472 //
473 WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *)(TempBuffer +
474 (UINTN)WorkSpaceLbaOffset * FtwDevice->WorkBlockSize +
475 FtwDevice->FtwWorkSpaceBase);
476 WorkingBlockHeader->WorkingBlockValid = FTW_INVALID_STATE;
477 WorkingBlockHeader->WorkingBlockInvalid = FTW_INVALID_STATE;
478
479 //
480 // Try to keep the content of spare block
481 // Save spare block into a spare backup memory buffer (Sparebuffer)
482 //
483 SpareBufferSize = FtwDevice->SpareAreaLength;
484 SpareBuffer = AllocatePool (SpareBufferSize);
485 if (SpareBuffer == NULL) {
486 FreePool (TempBuffer);
487 return EFI_OUT_OF_RESOURCES;
488 }
489
490 Ptr = SpareBuffer;
491 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
492 Length = FtwDevice->SpareBlockSize;
493 Status = FtwDevice->FtwBackupFvb->Read (
494 FtwDevice->FtwBackupFvb,
495 FtwDevice->FtwSpareLba + Index,
496 0,
497 &Length,
498 Ptr
499 );
500 if (EFI_ERROR (Status)) {
501 FreePool (TempBuffer);
502 FreePool (SpareBuffer);
503 return EFI_ABORTED;
504 }
505
506 Ptr += Length;
507 }
508
509 //
510 // Write the memory buffer to spare block
511 //
512 Status = FtwEraseSpareBlock (FtwDevice);
513 if (EFI_ERROR (Status)) {
514 FreePool (TempBuffer);
515 FreePool (SpareBuffer);
516 return EFI_ABORTED;
517 }
518
519 Ptr = TempBuffer;
520 for (Index = 0; TempBufferSize > 0; Index += 1) {
521 if (TempBufferSize > FtwDevice->SpareBlockSize) {
522 Length = FtwDevice->SpareBlockSize;
523 } else {
524 Length = TempBufferSize;
525 }
526
527 Status = FtwDevice->FtwBackupFvb->Write (
528 FtwDevice->FtwBackupFvb,
529 FtwDevice->FtwSpareLba + Index,
530 0,
531 &Length,
532 Ptr
533 );
534 if (EFI_ERROR (Status)) {
535 FreePool (TempBuffer);
536 FreePool (SpareBuffer);
537 return EFI_ABORTED;
538 }
539
540 Ptr += Length;
541 TempBufferSize -= Length;
542 }
543
544 //
545 // Free TempBuffer
546 //
547 FreePool (TempBuffer);
548
549 //
550 // Set the WorkingBlockValid in spare block
551 //
552 Status = FtwUpdateFvState (
553 FtwDevice->FtwBackupFvb,
554 FtwDevice->SpareBlockSize,
555 FtwDevice->FtwSpareLba + FtwDevice->FtwWorkSpaceLbaInSpare,
556 FtwDevice->FtwWorkSpaceBaseInSpare + sizeof (EFI_GUID) + sizeof (UINT32),
557 WORKING_BLOCK_VALID
558 );
559 if (EFI_ERROR (Status)) {
560 FreePool (SpareBuffer);
561 return EFI_ABORTED;
562 }
563
564 //
565 // Before erase the working block, set WorkingBlockInvalid in working block.
566 //
567 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
568 // WorkingBlockInvalid);
569 //
570 Status = FtwUpdateFvState (
571 FtwDevice->FtwFvBlock,
572 FtwDevice->WorkBlockSize,
573 FtwDevice->FtwWorkSpaceLba,
574 FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
575 WORKING_BLOCK_INVALID
576 );
577 if (EFI_ERROR (Status)) {
578 FreePool (SpareBuffer);
579 return EFI_ABORTED;
580 }
581
582 FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE;
583
584 //
585 // Write the spare block to working block
586 //
587 Status = FlushSpareBlockToWorkingBlock (FtwDevice);
588 if (EFI_ERROR (Status)) {
589 FreePool (SpareBuffer);
590 return Status;
591 }
592
593 //
594 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
595 //
596 Status = FtwEraseSpareBlock (FtwDevice);
597 if (EFI_ERROR (Status)) {
598 FreePool (SpareBuffer);
599 return EFI_ABORTED;
600 }
601
602 Ptr = SpareBuffer;
603 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {
604 Length = FtwDevice->SpareBlockSize;
605 Status = FtwDevice->FtwBackupFvb->Write (
606 FtwDevice->FtwBackupFvb,
607 FtwDevice->FtwSpareLba + Index,
608 0,
609 &Length,
610 Ptr
611 );
612 if (EFI_ERROR (Status)) {
613 FreePool (SpareBuffer);
614 return EFI_ABORTED;
615 }
616
617 Ptr += Length;
618 }
619
620 FreePool (SpareBuffer);
621
622 DEBUG ((DEBUG_INFO, "Ftw: reclaim work space successfully\n"));
623
624 return EFI_SUCCESS;
625}
UINT64 UINTN
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI SetMem(OUT VOID *Buffer, IN UINTN Length, IN UINT8 Value)
Definition: SetMemWrapper.c:38
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
Definition: MemLibGuid.c:73
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#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 DEBUG(Expression)
Definition: DebugLib.h:434
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
UINT64 EFI_LBA
Definition: UefiBaseType.h:45
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_STATUS FtwEraseSpareBlock(IN EFI_FTW_DEVICE *FtwDevice)
Definition: FtwMisc.c:91
EFI_STATUS FtwGetLastWriteRecord(IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwWriteHeader, OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwWriteRecord)
Definition: FtwMisc.c:854
EFI_STATUS FlushSpareBlockToWorkingBlock(EFI_FTW_DEVICE *FtwDevice)
Definition: FtwMisc.c:576
EFI_STATUS FtwGetLastWriteHeader(IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkSpaceHeader, IN UINTN FtwWorkSpaceSize, OUT EFI_FAULT_TOLERANT_WRITE_HEADER **FtwWriteHeader)
Definition: FtwMisc.c:800
UINT32 FtwCalculateCrc32(IN VOID *Buffer, IN UINTN Length)
EFI_STATUS FtwUpdateFvState(IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, IN UINTN BlockSize, IN EFI_LBA Lba, IN UINTN Offset, IN UINT8 NewBit)
Definition: FtwMisc.c:743
BOOLEAN IsValidWorkSpace(IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader)
EFI_STATUS InitWorkSpaceHeader(IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader)
EFI_STATUS FtwReclaimWorkSpace(IN EFI_FTW_DEVICE *FtwDevice, IN BOOLEAN PreserveRecord)
EFI_STATUS WorkSpaceRefresh(IN EFI_FTW_DEVICE *FtwDevice)
EFI_STATUS WriteWorkSpaceData(IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, IN UINTN BlockSize, IN EFI_LBA Lba, IN UINTN Offset, IN UINTN Length, IN UINT8 *Buffer)
VOID InitializeLocalWorkSpaceHeader(IN UINTN WorkSpaceLength)
EFI_STATUS ReadWorkSpaceData(IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock, IN UINTN BlockSize, IN EFI_LBA Lba, IN UINTN Offset, IN UINTN Length, OUT UINT8 *Buffer)
Definition: Base.h:213