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