]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c
The code line where judges if offset exceed the FTW work space boundary, in some...
[mirror_edk2.git] / MdeModulePkg / Universal / FaultTolerantWriteDxe / FtwMisc.c
CommitLineData
85e923a5
LG
1/** @file\r
2\r
3 Internal generic functions to operate flash block.\r
4\r
fe92f438 5Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 6This program and the accompanying materials \r
85e923a5
LG
7are licensed and made available under the terms and conditions of the BSD License \r
8which accompanies this distribution. The full text of the license may be found at \r
9http://opensource.org/licenses/bsd-license.php \r
10 \r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
13\r
14**/\r
15\r
16#include "FaultTolerantWrite.h"\r
17\r
18/**\r
19\r
20 Check whether a flash buffer is erased.\r
21\r
22 @param Buffer Buffer to check\r
23 @param BufferSize Size of the buffer\r
24\r
25 @return A BOOLEAN value indicating erased or not.\r
26\r
27**/\r
28BOOLEAN\r
29IsErasedFlashBuffer (\r
30 IN UINT8 *Buffer,\r
31 IN UINTN BufferSize\r
32 )\r
33{\r
34 BOOLEAN IsEmpty;\r
35 UINT8 *Ptr;\r
36 UINTN Index;\r
37\r
38 Ptr = Buffer;\r
39 IsEmpty = TRUE;\r
40 for (Index = 0; Index < BufferSize; Index += 1) {\r
41 if (*Ptr++ != FTW_ERASED_BYTE) {\r
42 IsEmpty = FALSE;\r
43 break;\r
44 }\r
45 }\r
46\r
47 return IsEmpty;\r
48}\r
49\r
50/**\r
51 To erase the block with the spare block size.\r
52\r
53\r
54 @param FtwDevice The private data of FTW driver\r
55 @param FvBlock FVB Protocol interface\r
56 @param Lba Lba of the firmware block\r
57\r
58 @retval EFI_SUCCESS Block LBA is Erased successfully\r
59 @retval Others Error occurs\r
60\r
61**/\r
62EFI_STATUS\r
63FtwEraseBlock (\r
64 IN EFI_FTW_DEVICE *FtwDevice,\r
65 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
66 EFI_LBA Lba\r
67 )\r
68{\r
69 return FvBlock->EraseBlocks (\r
70 FvBlock,\r
71 Lba,\r
72 FtwDevice->NumberOfSpareBlock,\r
73 EFI_LBA_LIST_TERMINATOR\r
74 );\r
75}\r
76\r
77/**\r
78 Erase spare block.\r
79\r
80 @param FtwDevice The private data of FTW driver\r
81\r
82 @retval EFI_SUCCESS The erase request was successfully completed.\r
83 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.\r
84 @retval EFI_DEVICE_ERROR The block device is not functioning\r
85 correctly and could not be written.\r
86 The firmware device may have been\r
87 partially erased.\r
88 @retval EFI_INVALID_PARAMETER One or more of the LBAs listed\r
89 in the variable argument list do\r
90 not exist in the firmware volume. \r
91\r
92\r
93**/\r
94EFI_STATUS\r
95FtwEraseSpareBlock (\r
96 IN EFI_FTW_DEVICE *FtwDevice\r
97 )\r
98{\r
99 return FtwDevice->FtwBackupFvb->EraseBlocks (\r
100 FtwDevice->FtwBackupFvb,\r
101 FtwDevice->FtwSpareLba,\r
102 FtwDevice->NumberOfSpareBlock,\r
103 EFI_LBA_LIST_TERMINATOR\r
104 );\r
105}\r
106\r
85e923a5
LG
107/**\r
108\r
109 Is it in working block?\r
110\r
111 @param FtwDevice The private data of FTW driver\r
112 @param FvBlock Fvb protocol instance\r
113 @param Lba The block specified\r
114\r
115 @return A BOOLEAN value indicating in working block or not.\r
116\r
117**/\r
118BOOLEAN\r
119IsWorkingBlock (\r
120 EFI_FTW_DEVICE *FtwDevice,\r
121 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
122 EFI_LBA Lba\r
123 )\r
124{\r
125 //\r
126 // If matching the following condition, the target block is in working block.\r
127 // 1. Target block is on the FV of working block (Using the same FVB protocol instance).\r
128 // 2. Lba falls into the range of working block.\r
129 //\r
130 return (BOOLEAN)\r
131 (\r
132 (FvBlock == FtwDevice->FtwFvBlock) &&\r
133 (Lba >= FtwDevice->FtwWorkBlockLba) &&\r
134 (Lba <= FtwDevice->FtwWorkSpaceLba)\r
135 );\r
136}\r
137\r
138/**\r
139\r
140 Get firmware block by address.\r
141\r
142\r
143 @param Address Address specified the block\r
144 @param FvBlock The block caller wanted\r
145\r
146 @retval EFI_SUCCESS The protocol instance if found.\r
147 @retval EFI_NOT_FOUND Block not found\r
148\r
149**/\r
150EFI_HANDLE\r
151GetFvbByAddress (\r
152 IN EFI_PHYSICAL_ADDRESS Address,\r
153 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock\r
154 )\r
155{\r
156 EFI_STATUS Status;\r
157 EFI_HANDLE *HandleBuffer;\r
158 UINTN HandleCount;\r
159 UINTN Index;\r
160 EFI_PHYSICAL_ADDRESS FvbBaseAddress;\r
161 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
162 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
163 EFI_HANDLE FvbHandle;\r
164\r
165 *FvBlock = NULL;\r
166 FvbHandle = NULL;\r
167 //\r
168 // Locate all handles of Fvb protocol\r
169 //\r
8a2d4996 170 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);\r
85e923a5
LG
171 if (EFI_ERROR (Status)) {\r
172 return NULL;\r
173 }\r
174 //\r
175 // Get the FVB to access variable store\r
176 //\r
177 for (Index = 0; Index < HandleCount; Index += 1) {\r
8a2d4996 178 Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb);\r
85e923a5
LG
179 if (EFI_ERROR (Status)) {\r
180 break;\r
181 }\r
182 //\r
183 // Compare the address and select the right one\r
184 //\r
185 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
186 if (EFI_ERROR (Status)) {\r
187 continue;\r
188 }\r
189\r
190 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
191 if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + (FwVolHeader->FvLength - 1)))) {\r
192 *FvBlock = Fvb;\r
193 FvbHandle = HandleBuffer[Index];\r
194 break;\r
195 }\r
196 }\r
197\r
198 FreePool (HandleBuffer);\r
199 return FvbHandle;\r
200}\r
201\r
202/**\r
203\r
204 Is it in boot block?\r
205\r
206 @param FtwDevice The private data of FTW driver\r
207 @param FvBlock Fvb protocol instance\r
208 @param Lba The block specified\r
209\r
210 @return A BOOLEAN value indicating in boot block or not.\r
211\r
212**/\r
213BOOLEAN\r
214IsBootBlock (\r
215 EFI_FTW_DEVICE *FtwDevice,\r
216 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
217 EFI_LBA Lba\r
218 )\r
219{\r
220 EFI_STATUS Status;\r
221 EFI_SWAP_ADDRESS_RANGE_PROTOCOL *SarProtocol;\r
222 EFI_PHYSICAL_ADDRESS BootBlockBase;\r
223 UINTN BootBlockSize;\r
224 EFI_PHYSICAL_ADDRESS BackupBlockBase;\r
225 UINTN BackupBlockSize;\r
226 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb;\r
227 BOOLEAN IsSwapped;\r
228 EFI_HANDLE FvbHandle;\r
229\r
230 if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {\r
231 return FALSE;\r
232 }\r
233\r
8a2d4996 234 Status = FtwGetSarProtocol ((VOID **) &SarProtocol);\r
85e923a5
LG
235 if (EFI_ERROR (Status)) {\r
236 return FALSE;\r
237 }\r
238 //\r
239 // Get the boot block range\r
240 //\r
241 Status = SarProtocol->GetRangeLocation (\r
242 SarProtocol,\r
243 &BootBlockBase,\r
244 &BootBlockSize,\r
245 &BackupBlockBase,\r
246 &BackupBlockSize\r
247 );\r
248 if (EFI_ERROR (Status)) {\r
249 return FALSE;\r
250 }\r
251\r
252 Status = SarProtocol->GetSwapState (SarProtocol, &IsSwapped);\r
253 if (EFI_ERROR (Status)) {\r
254 return FALSE;\r
255 }\r
256 //\r
257 // Get FVB by address\r
258 //\r
259 if (!IsSwapped) {\r
260 FvbHandle = GetFvbByAddress (BootBlockBase, &BootFvb);\r
261 } else {\r
262 FvbHandle = GetFvbByAddress (BackupBlockBase, &BootFvb);\r
263 }\r
264\r
265 if (FvbHandle == NULL) {\r
266 return FALSE;\r
267 }\r
268 //\r
269 // Compare the Fvb\r
270 //\r
271 return (BOOLEAN) (FvBlock == BootFvb);\r
272}\r
273\r
274/**\r
275 Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE.\r
276 Spare block is accessed by FTW working FVB protocol interface. LBA is 1.\r
277 Target block is accessed by FvbBlock protocol interface. LBA is Lba.\r
278\r
279 FTW will do extra work on boot block update.\r
280 FTW should depend on a protocol of EFI_ADDRESS_RANGE_SWAP_PROTOCOL,\r
281 which is produced by a chipset driver.\r
282 FTW updating boot block steps may be:\r
283 1. GetRangeLocation(), if the Range is inside the boot block, FTW know\r
284 that boot block will be update. It shall add a FLAG in the working block.\r
285 2. When spare block is ready,\r
286 3. SetSwapState(EFI_SWAPPED)\r
287 4. erasing boot block,\r
288 5. programming boot block until the boot block is ok.\r
289 6. SetSwapState(UNSWAPPED)\r
290 FTW shall not allow to update boot block when battery state is error.\r
291\r
292 @param FtwDevice The private data of FTW driver\r
293\r
294 @retval EFI_SUCCESS Spare block content is copied to boot block\r
295 @retval EFI_INVALID_PARAMETER Input parameter error\r
296 @retval EFI_OUT_OF_RESOURCES Allocate memory error\r
297 @retval EFI_ABORTED The function could not complete successfully\r
298\r
299**/\r
300EFI_STATUS\r
301FlushSpareBlockToBootBlock (\r
302 EFI_FTW_DEVICE *FtwDevice\r
303 )\r
304{\r
305 EFI_STATUS Status;\r
306 UINTN Length;\r
307 UINT8 *Buffer;\r
308 UINTN Count;\r
309 UINT8 *Ptr;\r
310 UINTN Index;\r
311 BOOLEAN TopSwap;\r
312 EFI_SWAP_ADDRESS_RANGE_PROTOCOL *SarProtocol;\r
313 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb;\r
314 EFI_LBA BootLba;\r
315\r
316 if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {\r
317 return EFI_UNSUPPORTED;\r
318 }\r
319\r
320 //\r
321 // Locate swap address range protocol\r
322 //\r
8a2d4996 323 Status = FtwGetSarProtocol ((VOID **) &SarProtocol);\r
85e923a5
LG
324 if (EFI_ERROR (Status)) {\r
325 return Status;\r
326 }\r
327 //\r
328 // Allocate a memory buffer\r
329 //\r
330 Length = FtwDevice->SpareAreaLength;\r
331 Buffer = AllocatePool (Length);\r
332 if (Buffer == NULL) {\r
333 return EFI_OUT_OF_RESOURCES;\r
334 }\r
335 //\r
336 // Get TopSwap bit state\r
337 //\r
338 Status = SarProtocol->GetSwapState (SarProtocol, &TopSwap);\r
339 if (EFI_ERROR (Status)) {\r
340 DEBUG ((EFI_D_ERROR, "Ftw: Get Top Swapped status - %r\n", Status));\r
341 FreePool (Buffer);\r
342 return EFI_ABORTED;\r
343 }\r
344\r
345 if (TopSwap) {\r
346 //\r
347 // Get FVB of current boot block\r
348 //\r
349 if (GetFvbByAddress (FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength, &BootFvb) == NULL) {\r
350 FreePool (Buffer);\r
351 return EFI_ABORTED;\r
352 }\r
353 //\r
354 // Read data from current boot block\r
355 //\r
356 BootLba = 0;\r
357 Ptr = Buffer;\r
358 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
359 Count = FtwDevice->BlockSize;\r
360 Status = BootFvb->Read (\r
361 BootFvb,\r
362 BootLba + Index,\r
363 0,\r
364 &Count,\r
365 Ptr\r
366 );\r
367 if (EFI_ERROR (Status)) {\r
368 FreePool (Buffer);\r
369 return Status;\r
370 }\r
371\r
372 Ptr += Count;\r
373 }\r
374 } else {\r
375 //\r
376 // Read data from spare block\r
377 //\r
378 Ptr = Buffer;\r
379 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
380 Count = FtwDevice->BlockSize;\r
381 Status = FtwDevice->FtwBackupFvb->Read (\r
382 FtwDevice->FtwBackupFvb,\r
383 FtwDevice->FtwSpareLba + Index,\r
384 0,\r
385 &Count,\r
386 Ptr\r
387 );\r
388 if (EFI_ERROR (Status)) {\r
389 FreePool (Buffer);\r
390 return Status;\r
391 }\r
392\r
393 Ptr += Count;\r
394 }\r
395 //\r
396 // Set TopSwap bit\r
397 //\r
398 Status = SarProtocol->SetSwapState (SarProtocol, TRUE);\r
399 if (EFI_ERROR (Status)) {\r
400 FreePool (Buffer);\r
401 return Status;\r
402 }\r
403 }\r
404 //\r
405 // Erase current spare block\r
406 // Because TopSwap is set, this actually erase the top block (boot block)!\r
407 //\r
408 Status = FtwEraseSpareBlock (FtwDevice);\r
409 if (EFI_ERROR (Status)) {\r
410 FreePool (Buffer);\r
411 return EFI_ABORTED;\r
412 }\r
413 //\r
414 // Write memory buffer currenet spare block. Still top block.\r
415 //\r
416 Ptr = Buffer;\r
417 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
418 Count = FtwDevice->BlockSize;\r
419 Status = FtwDevice->FtwBackupFvb->Write (\r
420 FtwDevice->FtwBackupFvb,\r
421 FtwDevice->FtwSpareLba + Index,\r
422 0,\r
423 &Count,\r
424 Ptr\r
425 );\r
426 if (EFI_ERROR (Status)) {\r
427 DEBUG ((EFI_D_ERROR, "Ftw: FVB Write boot block - %r\n", Status));\r
428 FreePool (Buffer);\r
429 return Status;\r
430 }\r
431\r
432 Ptr += Count;\r
433 }\r
434\r
435 FreePool (Buffer);\r
436\r
437 //\r
438 // Clear TopSwap bit\r
439 //\r
440 Status = SarProtocol->SetSwapState (SarProtocol, FALSE);\r
441\r
442 return Status;\r
443}\r
444\r
445/**\r
446 Copy the content of spare block to a target block. Size is FTW_BLOCK_SIZE.\r
447 Spare block is accessed by FTW backup FVB protocol interface. LBA is 1.\r
448 Target block is accessed by FvbBlock protocol interface. LBA is Lba.\r
449\r
450\r
451 @param FtwDevice The private data of FTW driver\r
452 @param FvBlock FVB Protocol interface to access target block\r
453 @param Lba Lba of the target block\r
454\r
455 @retval EFI_SUCCESS Spare block content is copied to target block\r
456 @retval EFI_INVALID_PARAMETER Input parameter error\r
457 @retval EFI_OUT_OF_RESOURCES Allocate memory error\r
458 @retval EFI_ABORTED The function could not complete successfully\r
459\r
460**/\r
461EFI_STATUS\r
462FlushSpareBlockToTargetBlock (\r
463 EFI_FTW_DEVICE *FtwDevice,\r
464 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
465 EFI_LBA Lba\r
466 )\r
467{\r
468 EFI_STATUS Status;\r
469 UINTN Length;\r
470 UINT8 *Buffer;\r
471 UINTN Count;\r
472 UINT8 *Ptr;\r
473 UINTN Index;\r
474\r
475 if ((FtwDevice == NULL) || (FvBlock == NULL)) {\r
476 return EFI_INVALID_PARAMETER;\r
477 }\r
478 //\r
479 // Allocate a memory buffer\r
480 //\r
481 Length = FtwDevice->SpareAreaLength;\r
482 Buffer = AllocatePool (Length);\r
483 if (Buffer == NULL) {\r
484 return EFI_OUT_OF_RESOURCES;\r
485 }\r
486 //\r
487 // Read all content of spare block to memory buffer\r
488 //\r
489 Ptr = Buffer;\r
490 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
491 Count = FtwDevice->BlockSize;\r
492 Status = FtwDevice->FtwBackupFvb->Read (\r
493 FtwDevice->FtwBackupFvb,\r
494 FtwDevice->FtwSpareLba + Index,\r
495 0,\r
496 &Count,\r
497 Ptr\r
498 );\r
499 if (EFI_ERROR (Status)) {\r
500 FreePool (Buffer);\r
501 return Status;\r
502 }\r
503\r
504 Ptr += Count;\r
505 }\r
506 //\r
507 // Erase the target block\r
508 //\r
509 Status = FtwEraseBlock (FtwDevice, FvBlock, Lba);\r
510 if (EFI_ERROR (Status)) {\r
511 FreePool (Buffer);\r
512 return EFI_ABORTED;\r
513 }\r
514 //\r
515 // Write memory buffer to block, using the FvbBlock protocol interface\r
516 //\r
517 Ptr = Buffer;\r
518 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
519 Count = FtwDevice->BlockSize;\r
520 Status = FvBlock->Write (FvBlock, Lba + Index, 0, &Count, Ptr);\r
521 if (EFI_ERROR (Status)) {\r
522 DEBUG ((EFI_D_ERROR, "Ftw: FVB Write block - %r\n", Status));\r
523 FreePool (Buffer);\r
524 return Status;\r
525 }\r
526\r
527 Ptr += Count;\r
528 }\r
529\r
530 FreePool (Buffer);\r
531\r
532 return Status;\r
533}\r
534\r
535/**\r
536 Copy the content of spare block to working block. Size is FTW_BLOCK_SIZE.\r
537 Spare block is accessed by FTW backup FVB protocol interface. LBA is\r
538 FtwDevice->FtwSpareLba.\r
539 Working block is accessed by FTW working FVB protocol interface. LBA is\r
540 FtwDevice->FtwWorkBlockLba.\r
541\r
542 Since the working block header is important when FTW initializes, the\r
543 state of the operation should be handled carefully. The Crc value is\r
544 calculated without STATE element.\r
545\r
546 @param FtwDevice The private data of FTW driver\r
547\r
548 @retval EFI_SUCCESS Spare block content is copied to target block\r
549 @retval EFI_OUT_OF_RESOURCES Allocate memory error\r
550 @retval EFI_ABORTED The function could not complete successfully\r
551\r
552**/\r
553EFI_STATUS\r
554FlushSpareBlockToWorkingBlock (\r
555 EFI_FTW_DEVICE *FtwDevice\r
556 )\r
557{\r
558 EFI_STATUS Status;\r
559 UINTN Length;\r
560 UINT8 *Buffer;\r
561 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;\r
562 UINTN Count;\r
563 UINT8 *Ptr;\r
564 UINTN Index;\r
565 EFI_LBA WorkSpaceLbaOffset;\r
566\r
567 //\r
568 // Allocate a memory buffer\r
569 //\r
570 Length = FtwDevice->SpareAreaLength;\r
571 Buffer = AllocatePool (Length);\r
572 if (Buffer == NULL) {\r
573 return EFI_OUT_OF_RESOURCES;\r
574 }\r
575 //\r
576 // To guarantee that the WorkingBlockValid is set on spare block\r
577 //\r
578 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,\r
579 // WorkingBlockValid);\r
580 // To skip Signature and Crc: sizeof(EFI_GUID)+sizeof(UINT32).\r
581 //\r
582 FtwUpdateFvState (\r
583 FtwDevice->FtwBackupFvb,\r
584 FtwDevice->FtwWorkSpaceLba,\r
585 FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
586 WORKING_BLOCK_VALID\r
587 );\r
588 //\r
589 // Read from spare block to memory buffer\r
590 //\r
591 Ptr = Buffer;\r
592 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
593 Count = FtwDevice->BlockSize;\r
594 Status = FtwDevice->FtwBackupFvb->Read (\r
595 FtwDevice->FtwBackupFvb,\r
596 FtwDevice->FtwSpareLba + Index,\r
597 0,\r
598 &Count,\r
599 Ptr\r
600 );\r
601 if (EFI_ERROR (Status)) {\r
602 FreePool (Buffer);\r
603 return Status;\r
604 }\r
605\r
606 Ptr += Count;\r
607 }\r
608 //\r
609 // Clear the CRC and STATE, copy data from spare to working block.\r
610 //\r
611 WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba;\r
612 WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (Buffer + (UINTN) WorkSpaceLbaOffset * FtwDevice->BlockSize + FtwDevice->FtwWorkSpaceBase);\r
613 InitWorkSpaceHeader (WorkingBlockHeader);\r
614 WorkingBlockHeader->WorkingBlockValid = FTW_ERASE_POLARITY;\r
615 WorkingBlockHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;\r
616\r
617 //\r
618 // target block is working block, then\r
619 // Set WorkingBlockInvalid in EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER\r
620 // before erase the working block.\r
621 //\r
622 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,\r
623 // WorkingBlockInvalid);\r
624 // So hardcode offset as sizeof(EFI_GUID)+sizeof(UINT32) to\r
625 // skip Signature and Crc.\r
626 //\r
627 Status = FtwUpdateFvState (\r
628 FtwDevice->FtwFvBlock,\r
629 FtwDevice->FtwWorkSpaceLba,\r
630 FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
631 WORKING_BLOCK_INVALID\r
632 );\r
633 if (EFI_ERROR (Status)) {\r
634 FreePool (Buffer);\r
635 return EFI_ABORTED;\r
636 }\r
637\r
638 FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE;\r
639\r
640 //\r
641 // Erase the working block\r
642 //\r
643 Status = FtwEraseBlock (FtwDevice, FtwDevice->FtwFvBlock, FtwDevice->FtwWorkBlockLba);\r
644 if (EFI_ERROR (Status)) {\r
645 FreePool (Buffer);\r
646 return EFI_ABORTED;\r
647 }\r
648 //\r
649 // Write memory buffer to working block, using the FvbBlock protocol interface\r
650 //\r
651 Ptr = Buffer;\r
652 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
653 Count = FtwDevice->BlockSize;\r
654 Status = FtwDevice->FtwFvBlock->Write (\r
655 FtwDevice->FtwFvBlock,\r
656 FtwDevice->FtwWorkBlockLba + Index,\r
657 0,\r
658 &Count,\r
659 Ptr\r
660 );\r
661 if (EFI_ERROR (Status)) {\r
662 DEBUG ((EFI_D_ERROR, "Ftw: FVB Write block - %r\n", Status));\r
663 FreePool (Buffer);\r
664 return Status;\r
665 }\r
666\r
667 Ptr += Count;\r
668 }\r
669 //\r
670 // Since the memory buffer will not be used, free memory Buffer.\r
671 //\r
672 FreePool (Buffer);\r
673\r
674 //\r
675 // Update the VALID of the working block\r
676 //\r
677 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER, WorkingBlockValid);\r
678 // So hardcode offset as sizeof(EFI_GUID)+sizeof(UINT32) to skip Signature and Crc.\r
679 //\r
680 Status = FtwUpdateFvState (\r
681 FtwDevice->FtwFvBlock,\r
682 FtwDevice->FtwWorkSpaceLba,\r
683 FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
684 WORKING_BLOCK_VALID\r
685 );\r
686 if (EFI_ERROR (Status)) {\r
687 return EFI_ABORTED;\r
688 }\r
689\r
690 FtwDevice->FtwWorkSpaceHeader->WorkingBlockValid = FTW_VALID_STATE;\r
691\r
692 return EFI_SUCCESS;\r
693}\r
694\r
695/**\r
696 Update a bit of state on a block device. The location of the bit is\r
697 calculated by the (Lba, Offset, bit). Here bit is determined by the\r
698 the name of a certain bit.\r
699\r
700\r
701 @param FvBlock FVB Protocol interface to access SrcBlock and DestBlock\r
702 @param Lba Lba of a block\r
703 @param Offset Offset on the Lba\r
704 @param NewBit New value that will override the old value if it can be change\r
705\r
706 @retval EFI_SUCCESS A state bit has been updated successfully\r
707 @retval Others Access block device error.\r
708 Notes:\r
709 Assume all bits of State are inside the same BYTE.\r
710 @retval EFI_ABORTED Read block fail\r
711\r
712**/\r
713EFI_STATUS\r
714FtwUpdateFvState (\r
715 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
716 IN EFI_LBA Lba,\r
717 IN UINTN Offset,\r
718 IN UINT8 NewBit\r
719 )\r
720{\r
721 EFI_STATUS Status;\r
722 UINT8 State;\r
723 UINTN Length;\r
724\r
725 //\r
726 // Read state from device, assume State is only one byte.\r
727 //\r
728 Length = sizeof (UINT8);\r
729 Status = FvBlock->Read (FvBlock, Lba, Offset, &Length, &State);\r
730 if (EFI_ERROR (Status)) {\r
731 return EFI_ABORTED;\r
732 }\r
733\r
734 State ^= FTW_POLARITY_REVERT;\r
735 State = (UINT8) (State | NewBit);\r
736 State ^= FTW_POLARITY_REVERT;\r
737\r
738 //\r
739 // Write state back to device\r
740 //\r
741 Length = sizeof (UINT8);\r
742 Status = FvBlock->Write (FvBlock, Lba, Offset, &Length, &State);\r
743\r
744 return Status;\r
745}\r
746\r
747/**\r
748 Get the last Write Header pointer.\r
749 The last write header is the header whose 'complete' state hasn't been set.\r
750 After all, this header may be a EMPTY header entry for next Allocate.\r
751\r
752\r
753 @param FtwWorkSpaceHeader Pointer of the working block header\r
754 @param FtwWorkSpaceSize Size of the work space\r
755 @param FtwWriteHeader Pointer to retrieve the last write header\r
756\r
757 @retval EFI_SUCCESS Get the last write record successfully\r
758 @retval EFI_ABORTED The FTW work space is damaged\r
759\r
760**/\r
761EFI_STATUS\r
762FtwGetLastWriteHeader (\r
763 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkSpaceHeader,\r
764 IN UINTN FtwWorkSpaceSize,\r
765 OUT EFI_FAULT_TOLERANT_WRITE_HEADER **FtwWriteHeader\r
766 )\r
767{\r
768 UINTN Offset;\r
769 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;\r
770\r
771 *FtwWriteHeader = NULL;\r
772 FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *) (FtwWorkSpaceHeader + 1);\r
4601f374 773 Offset = sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);\r
85e923a5
LG
774\r
775 while (FtwHeader->Complete == FTW_VALID_STATE) {\r
776 Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);\r
777 //\r
778 // If Offset exceed the FTW work space boudary, return error.\r
779 //\r
fe92f438 780 if (Offset >= FtwWorkSpaceSize) {\r
85e923a5
LG
781 *FtwWriteHeader = FtwHeader;\r
782 return EFI_ABORTED;\r
783 }\r
784\r
785 FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *) ((UINT8 *) FtwWorkSpaceHeader + Offset);\r
786 }\r
787 //\r
788 // Last write header is found\r
789 //\r
790 *FtwWriteHeader = FtwHeader;\r
791\r
792 return EFI_SUCCESS;\r
793}\r
794\r
795/**\r
796 Get the last Write Record pointer. The last write Record is the Record\r
797 whose DestinationCompleted state hasn't been set. After all, this Record\r
798 may be a EMPTY record entry for next write.\r
799\r
800\r
801 @param FtwWriteHeader Pointer to the write record header\r
802 @param FtwWriteRecord Pointer to retrieve the last write record\r
803\r
804 @retval EFI_SUCCESS Get the last write record successfully\r
805 @retval EFI_ABORTED The FTW work space is damaged\r
806\r
807**/\r
808EFI_STATUS\r
809FtwGetLastWriteRecord (\r
810 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwWriteHeader,\r
811 OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwWriteRecord\r
812 )\r
813{\r
814 UINTN Index;\r
815 EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord;\r
816\r
817 *FtwWriteRecord = NULL;\r
818 FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) (FtwWriteHeader + 1);\r
819\r
820 //\r
821 // Try to find the last write record "that has not completed"\r
822 //\r
823 for (Index = 0; Index < FtwWriteHeader->NumberOfWrites; Index += 1) {\r
824 if (FtwRecord->DestinationComplete != FTW_VALID_STATE) {\r
825 //\r
826 // The last write record is found\r
827 //\r
828 *FtwWriteRecord = FtwRecord;\r
829 return EFI_SUCCESS;\r
830 }\r
831\r
832 FtwRecord++;\r
833\r
834 if (FtwWriteHeader->PrivateDataSize != 0) {\r
835 FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord + FtwWriteHeader->PrivateDataSize);\r
836 }\r
837 }\r
838 //\r
839 // if Index == NumberOfWrites, then\r
840 // the last record has been written successfully,\r
841 // but the Header->Complete Flag has not been set.\r
842 // also return the last record.\r
843 //\r
844 if (Index == FtwWriteHeader->NumberOfWrites) {\r
845 *FtwWriteRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord - RECORD_SIZE (FtwWriteHeader->PrivateDataSize));\r
846 return EFI_SUCCESS;\r
847 }\r
848\r
849 return EFI_ABORTED;\r
850}\r
851\r
852/**\r
853 To check if FtwRecord is the first record of FtwHeader.\r
854\r
855 @param FtwHeader Pointer to the write record header\r
856 @param FtwRecord Pointer to the write record\r
857\r
858 @retval TRUE FtwRecord is the first Record of the FtwHeader\r
859 @retval FALSE FtwRecord is not the first Record of the FtwHeader\r
860\r
861**/\r
862BOOLEAN\r
863IsFirstRecordOfWrites (\r
864 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,\r
865 IN EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord\r
866 )\r
867{\r
868 UINT8 *Head;\r
869 UINT8 *Ptr;\r
870\r
871 Head = (UINT8 *) FtwHeader;\r
872 Ptr = (UINT8 *) FtwRecord;\r
873\r
874 Head += sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER);\r
875 return (BOOLEAN) (Head == Ptr);\r
876}\r
877\r
878/**\r
879 To check if FtwRecord is the last record of FtwHeader. Because the\r
880 FtwHeader has NumberOfWrites & PrivateDataSize, the FtwRecord can be\r
881 determined if it is the last record of FtwHeader.\r
882\r
883 @param FtwHeader Pointer to the write record header\r
884 @param FtwRecord Pointer to the write record\r
885\r
886 @retval TRUE FtwRecord is the last Record of the FtwHeader\r
887 @retval FALSE FtwRecord is not the last Record of the FtwHeader\r
888\r
889**/\r
890BOOLEAN\r
891IsLastRecordOfWrites (\r
892 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,\r
893 IN EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord\r
894 )\r
895{\r
896 UINT8 *Head;\r
897 UINT8 *Ptr;\r
898\r
899 Head = (UINT8 *) FtwHeader;\r
900 Ptr = (UINT8 *) FtwRecord;\r
901\r
902 Head += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites - 1, FtwHeader->PrivateDataSize);\r
903 return (BOOLEAN) (Head == Ptr);\r
904}\r
905\r
906/**\r
907 To check if FtwRecord is the first record of FtwHeader.\r
908\r
909 @param FtwHeader Pointer to the write record header\r
910 @param FtwRecord Pointer to retrieve the previous write record\r
911\r
912 @retval EFI_ACCESS_DENIED Input record is the first record, no previous record is return.\r
913 @retval EFI_SUCCESS The previous write record is found.\r
914\r
915**/\r
916EFI_STATUS\r
917GetPreviousRecordOfWrites (\r
918 IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader,\r
919 IN OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwRecord\r
920 )\r
921{\r
922 UINT8 *Ptr;\r
923\r
924 if (IsFirstRecordOfWrites (FtwHeader, *FtwRecord)) {\r
925 *FtwRecord = NULL;\r
926 return EFI_ACCESS_DENIED;\r
927 }\r
928\r
929 Ptr = (UINT8 *) (*FtwRecord);\r
930 Ptr -= RECORD_SIZE (FtwHeader->PrivateDataSize);\r
931 *FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) Ptr;\r
932 return EFI_SUCCESS;\r
933}\r
8a2d4996 934\r
935/**\r
936 Allocate private data for FTW driver and initialize it.\r
937\r
938 @param[out] FtwData Pointer to the FTW device structure\r
939\r
940 @retval EFI_SUCCESS Initialize the FTW device successfully.\r
941 @retval EFI_OUT_OF_RESOURCES Allocate memory error\r
942 @retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist\r
943\r
944**/\r
945EFI_STATUS\r
946InitFtwDevice (\r
947 OUT EFI_FTW_DEVICE **FtwData \r
948 )\r
949{\r
950 EFI_FTW_DEVICE *FtwDevice;\r
951 \r
952 //\r
953 // Allocate private data of this driver,\r
954 // Including the FtwWorkSpace[FTW_WORK_SPACE_SIZE].\r
955 //\r
956 FtwDevice = AllocateZeroPool (sizeof (EFI_FTW_DEVICE) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize));\r
957 if (FtwDevice == NULL) {\r
958 return EFI_OUT_OF_RESOURCES;\r
959 }\r
960\r
961 //\r
962 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.\r
963 //\r
964 FtwDevice->WorkSpaceLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize);\r
965 FtwDevice->SpareAreaLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize);\r
966 if ((FtwDevice->WorkSpaceLength == 0) || (FtwDevice->SpareAreaLength == 0)) {\r
967 DEBUG ((EFI_D_ERROR, "Ftw: Workspace or Spare block does not exist!\n"));\r
968 FreePool (FtwDevice);\r
969 return EFI_INVALID_PARAMETER;\r
970 }\r
971\r
972 FtwDevice->Signature = FTW_DEVICE_SIGNATURE;\r
973 FtwDevice->FtwFvBlock = NULL;\r
974 FtwDevice->FtwBackupFvb = NULL;\r
975 FtwDevice->FtwWorkSpaceLba = (EFI_LBA) (-1);\r
976 FtwDevice->FtwSpareLba = (EFI_LBA) (-1);\r
977\r
978 FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwWorkingBase64);\r
979 if (FtwDevice->WorkSpaceAddress == 0) {\r
980 FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase);\r
981 }\r
982 \r
983 FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwSpareBase64);\r
984 if (FtwDevice->SpareAreaAddress == 0) {\r
985 FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase);\r
986 } \r
987\r
988 *FtwData = FtwDevice;\r
989 return EFI_SUCCESS;\r
990}\r
991\r
992\r
993/**\r
32732a33 994 Find the proper Firmware Volume Block protocol for FTW operation.\r
8a2d4996 995\r
32732a33 996 @param[in, out] FtwDevice Pointer to the FTW device structure\r
8a2d4996 997\r
32732a33 998 @retval EFI_SUCCESS Find the FVB protocol successfully.\r
8a2d4996 999 @retval EFI_NOT_FOUND No proper FVB protocol was found.\r
1000 @retval EFI_ABORTED Some data can not be got or be invalid.\r
1001 \r
1002**/\r
1003EFI_STATUS\r
1004FindFvbForFtw (\r
1005 IN OUT EFI_FTW_DEVICE *FtwDevice\r
1006 )\r
1007{\r
1008 EFI_STATUS Status;\r
1009 EFI_HANDLE *HandleBuffer;\r
1010 UINTN HandleCount;\r
1011 UINTN Index;\r
1012 EFI_PHYSICAL_ADDRESS FvbBaseAddress;\r
1013 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
1014 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
1015 EFI_FVB_ATTRIBUTES_2 Attributes;\r
1016 EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;\r
1017 UINT32 LbaIndex;\r
1018\r
1019 //\r
1020 // Get all FVB handle.\r
1021 //\r
1022 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);\r
1023 if (EFI_ERROR (Status)) {\r
1024 return EFI_NOT_FOUND;\r
1025 }\r
1026\r
1027 //\r
1028 // Get the FVB to access variable store\r
1029 //\r
1030 Fvb = NULL;\r
1031 for (Index = 0; Index < HandleCount; Index += 1) {\r
1032 Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb);\r
1033 if (EFI_ERROR (Status)) {\r
1034 Status = EFI_NOT_FOUND;\r
1035 break;\r
1036 }\r
1037\r
1038 //\r
1039 // Ensure this FVB protocol support Write operation.\r
1040 //\r
1041 Status = Fvb->GetAttributes (Fvb, &Attributes);\r
1042 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
1043 continue; \r
1044 }\r
1045 //\r
1046 // Compare the address and select the right one\r
1047 //\r
1048 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
1049 if (EFI_ERROR (Status)) {\r
1050 continue;\r
1051 }\r
1052\r
1053 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
1054 if ((FtwDevice->FtwFvBlock == NULL) && (FtwDevice->WorkSpaceAddress >= FvbBaseAddress) &&\r
1055 ((FtwDevice->WorkSpaceAddress + FtwDevice->WorkSpaceLength) <= (FvbBaseAddress + FwVolHeader->FvLength))\r
1056 ) {\r
1057 FtwDevice->FtwFvBlock = Fvb;\r
1058 //\r
1059 // To get the LBA of work space\r
1060 //\r
1061 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {\r
1062 //\r
1063 // Now, one FV has one type of BlockLength\r
1064 //\r
1065 FvbMapEntry = &FwVolHeader->BlockMap[0];\r
1066 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {\r
1067 if ((FtwDevice->WorkSpaceAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))\r
1068 && (FtwDevice->WorkSpaceAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {\r
1069 FtwDevice->FtwWorkSpaceLba = LbaIndex - 1;\r
1070 //\r
1071 // Get the Work space size and Base(Offset)\r
1072 //\r
1073 FtwDevice->FtwWorkSpaceSize = FtwDevice->WorkSpaceLength;\r
1074 FtwDevice->FtwWorkSpaceBase = (UINTN) (FtwDevice->WorkSpaceAddress - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));\r
1075 break;\r
1076 }\r
1077 }\r
1078 }\r
1079 }\r
1080 \r
1081 if ((FtwDevice->FtwBackupFvb == NULL) && (FtwDevice->SpareAreaAddress >= FvbBaseAddress) &&\r
1082 ((FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength) <= (FvbBaseAddress + FwVolHeader->FvLength))\r
1083 ) {\r
1084 FtwDevice->FtwBackupFvb = Fvb;\r
1085 //\r
1086 // To get the LBA of spare\r
1087 //\r
1088 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {\r
1089 //\r
1090 // Now, one FV has one type of BlockLength\r
1091 //\r
1092 FvbMapEntry = &FwVolHeader->BlockMap[0];\r
1093 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {\r
1094 if ((FtwDevice->SpareAreaAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))\r
1095 && (FtwDevice->SpareAreaAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {\r
1096 //\r
1097 // Get the NumberOfSpareBlock and BlockSize\r
1098 //\r
1099 FtwDevice->FtwSpareLba = LbaIndex - 1;\r
1100 FtwDevice->BlockSize = FvbMapEntry->Length;\r
1101 FtwDevice->NumberOfSpareBlock = FtwDevice->SpareAreaLength / FtwDevice->BlockSize;\r
1102 //\r
1103 // Check the range of spare area to make sure that it's in FV range\r
1104 //\r
1105 if ((FtwDevice->FtwSpareLba + FtwDevice->NumberOfSpareBlock) > FvbMapEntry->NumBlocks) {\r
1106 DEBUG ((EFI_D_ERROR, "Ftw: Spare area is out of FV range\n"));\r
1107 FreePool (HandleBuffer);\r
1108 ASSERT (FALSE);\r
1109 return EFI_ABORTED;\r
1110 }\r
1111 break;\r
1112 }\r
1113 }\r
1114 }\r
1115 }\r
1116 }\r
1117 FreePool (HandleBuffer);\r
1118 \r
1119 if ((FtwDevice->FtwBackupFvb == NULL) || (FtwDevice->FtwFvBlock == NULL) ||\r
1120 (FtwDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) || (FtwDevice->FtwSpareLba == (EFI_LBA) (-1))) {\r
1121 return EFI_ABORTED;\r
1122 }\r
1123 \r
1124 return EFI_SUCCESS;\r
1125}\r
1126\r
1127\r
1128/**\r
1129 Initialization for Fault Tolerant Write protocol.\r
1130\r
32732a33 1131 @param[in, out] FtwDevice Pointer to the FTW device structure\r
8a2d4996 1132\r
1133 @retval EFI_SUCCESS Initialize the FTW protocol successfully.\r
1134 @retval EFI_NOT_FOUND No proper FVB protocol was found.\r
1135 \r
1136**/\r
1137EFI_STATUS\r
1138InitFtwProtocol (\r
1139 IN OUT EFI_FTW_DEVICE *FtwDevice\r
1140 )\r
1141{\r
1142 EFI_STATUS Status;\r
1143 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
1144 UINTN Length;\r
1145 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;\r
1146 UINTN Offset;\r
1147 EFI_HANDLE FvbHandle;\r
1148\r
1149 //\r
1150 // Find the right SMM Fvb protocol instance for FTW.\r
1151 //\r
1152 Status = FindFvbForFtw (FtwDevice);\r
1153 if (EFI_ERROR (Status)) {\r
1154 return EFI_NOT_FOUND;\r
1155 } \r
1156 \r
1157 //\r
1158 // Calculate the start LBA of working block. Working block is an area which\r
1159 // contains working space in its last block and has the same size as spare\r
1160 // block, unless there are not enough blocks before the block that contains\r
1161 // working space.\r
1162 //\r
1163 FtwDevice->FtwWorkBlockLba = FtwDevice->FtwWorkSpaceLba - FtwDevice->NumberOfSpareBlock + 1;\r
1164 ASSERT ((INT64) (FtwDevice->FtwWorkBlockLba) >= 0); \r
1165\r
1166 //\r
1167 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.\r
1168 //\r
1169 FtwDevice->FtwWorkSpace = (UINT8 *) (FtwDevice + 1);\r
1170 FtwDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwDevice->FtwWorkSpace;\r
1171\r
1172 FtwDevice->FtwLastWriteHeader = NULL;\r
1173 FtwDevice->FtwLastWriteRecord = NULL;\r
1174\r
1175 //\r
1176 // Refresh the working space data from working block\r
1177 //\r
1178 Status = WorkSpaceRefresh (FtwDevice);\r
1179 ASSERT_EFI_ERROR (Status);\r
1180 //\r
1181 // If the working block workspace is not valid, try the spare block\r
1182 //\r
1183 if (!IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {\r
1184 //\r
1185 // Read from spare block\r
1186 //\r
1187 Length = FtwDevice->FtwWorkSpaceSize;\r
1188 Status = FtwDevice->FtwBackupFvb->Read (\r
1189 FtwDevice->FtwBackupFvb,\r
1190 FtwDevice->FtwSpareLba,\r
1191 FtwDevice->FtwWorkSpaceBase,\r
1192 &Length,\r
1193 FtwDevice->FtwWorkSpace\r
1194 );\r
1195 ASSERT_EFI_ERROR (Status);\r
1196\r
1197 //\r
1198 // If spare block is valid, then replace working block content.\r
1199 //\r
1200 if (IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {\r
1201 Status = FlushSpareBlockToWorkingBlock (FtwDevice);\r
1202 DEBUG ((EFI_D_ERROR, "Ftw: Restart working block update in InitFtwProtocol() - %r\n", Status));\r
1203 FtwAbort (&FtwDevice->FtwInstance);\r
1204 //\r
1205 // Refresh work space.\r
1206 //\r
1207 Status = WorkSpaceRefresh (FtwDevice);\r
1208 ASSERT_EFI_ERROR (Status);\r
1209 } else {\r
1210 DEBUG ((EFI_D_ERROR, "Ftw: Both are invalid, init workspace\n"));\r
1211 //\r
1212 // If both are invalid, then initialize work space.\r
1213 //\r
1214 SetMem (\r
1215 FtwDevice->FtwWorkSpace,\r
1216 FtwDevice->FtwWorkSpaceSize,\r
1217 FTW_ERASED_BYTE\r
1218 );\r
1219 InitWorkSpaceHeader (FtwDevice->FtwWorkSpaceHeader);\r
1220 //\r
1221 // Initialize the work space\r
1222 //\r
1223 Status = FtwReclaimWorkSpace (FtwDevice, FALSE);\r
1224 ASSERT_EFI_ERROR (Status);\r
1225 }\r
1226 }\r
1227 //\r
1228 // If the FtwDevice->FtwLastWriteRecord is 1st record of write header &&\r
1229 // (! SpareComplete) THEN call Abort().\r
1230 //\r
1231 if ((FtwDevice->FtwLastWriteHeader->HeaderAllocated == FTW_VALID_STATE) &&\r
1232 (FtwDevice->FtwLastWriteRecord->SpareComplete != FTW_VALID_STATE) &&\r
1233 IsFirstRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)\r
1234 ) {\r
1235 DEBUG ((EFI_D_ERROR, "Ftw: Init.. find first record not SpareCompleted, abort()\n"));\r
1236 FtwAbort (&FtwDevice->FtwInstance);\r
1237 }\r
1238 //\r
1239 // If Header is incompleted and the last record has completed, then\r
1240 // call Abort() to set the Header->Complete FLAG.\r
1241 //\r
1242 if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&\r
1243 (FtwDevice->FtwLastWriteRecord->DestinationComplete == FTW_VALID_STATE) &&\r
1244 IsLastRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)\r
1245 ) {\r
1246 DEBUG ((EFI_D_ERROR, "Ftw: Init.. find last record completed but header not, abort()\n"));\r
1247 FtwAbort (&FtwDevice->FtwInstance);\r
1248 }\r
1249 //\r
1250 // To check the workspace buffer following last Write header/records is EMPTY or not.\r
1251 // If it's not EMPTY, FTW also need to call reclaim().\r
1252 //\r
1253 FtwHeader = FtwDevice->FtwLastWriteHeader;\r
1254 Offset = (UINT8 *) FtwHeader - FtwDevice->FtwWorkSpace;\r
1255 if (FtwDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {\r
1256 Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);\r
1257 }\r
1258 \r
1259 if (!IsErasedFlashBuffer (FtwDevice->FtwWorkSpace + Offset, FtwDevice->FtwWorkSpaceSize - Offset)) {\r
1260 Status = FtwReclaimWorkSpace (FtwDevice, TRUE);\r
1261 ASSERT_EFI_ERROR (Status);\r
1262 }\r
1263\r
1264 //\r
1265 // Restart if it's boot block\r
1266 //\r
1267 if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&\r
1268 (FtwDevice->FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE)\r
1269 ) {\r
1270 if (FtwDevice->FtwLastWriteRecord->BootBlockUpdate == FTW_VALID_STATE) {\r
1271 Status = FlushSpareBlockToBootBlock (FtwDevice);\r
1272 DEBUG ((EFI_D_ERROR, "Ftw: Restart boot block update - %r\n", Status));\r
1273 ASSERT_EFI_ERROR (Status);\r
1274 FtwAbort (&FtwDevice->FtwInstance);\r
1275 } else {\r
1276 //\r
1277 // if (SpareCompleted) THEN Restart to fault tolerant write.\r
1278 //\r
1279 FvbHandle = NULL;\r
1280 FvbHandle = GetFvbByAddress (FtwDevice->FtwLastWriteRecord->FvBaseAddress, &Fvb);\r
1281 if (FvbHandle != NULL) {\r
1282 Status = FtwRestart (&FtwDevice->FtwInstance, FvbHandle);\r
1283 DEBUG ((EFI_D_ERROR, "FtwLite: Restart last write - %r\n", Status));\r
1284 ASSERT_EFI_ERROR (Status);\r
1285 }\r
1286 FtwAbort (&FtwDevice->FtwInstance);\r
1287 }\r
1288 }\r
1289 //\r
1290 // Hook the protocol API\r
1291 //\r
1292 FtwDevice->FtwInstance.GetMaxBlockSize = FtwGetMaxBlockSize;\r
1293 FtwDevice->FtwInstance.Allocate = FtwAllocate;\r
1294 FtwDevice->FtwInstance.Write = FtwWrite;\r
1295 FtwDevice->FtwInstance.Restart = FtwRestart;\r
1296 FtwDevice->FtwInstance.Abort = FtwAbort;\r
1297 FtwDevice->FtwInstance.GetLastWrite = FtwGetLastWrite;\r
1298 \r
1299 return EFI_SUCCESS;\r
1300}\r
1301\r