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