]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/FtwMisc.c
Add comments and DoxyGen format for these files.
[mirror_edk2.git] / MdeModulePkg / Universal / FirmwareVolume / FaultTolerantWriteDxe / FtwMisc.c
CommitLineData
6cc9ca32
LG
1/** @file\r
2\r
3 Internal generic functions to support fault tolerant write.\r
d7dec593 4\r
6cc9ca32 5Copyright (c) 2006 - 2008, Intel Corporation \r
d7dec593 6All rights reserved. This program and the accompanying materials \r
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
6cc9ca32 14**/\r
d7dec593 15\r
16#include <FtwLite.h>\r
17\r
18BOOLEAN\r
19IsErasedFlashBuffer (\r
20 IN BOOLEAN Polarity,\r
21 IN UINT8 *Buffer,\r
22 IN UINTN BufferSize\r
23 )\r
24/*++\r
25\r
26Routine Description:\r
27\r
28 Check whether a flash buffer is erased.\r
29\r
30Arguments:\r
31\r
32 Polarity - All 1 or all 0\r
33 Buffer - Buffer to check\r
34 BufferSize - Size of the buffer\r
35\r
36Returns:\r
37\r
38 Erased or not.\r
39\r
40--*/\r
41{\r
42 UINT8 ErasedValue;\r
43 UINT8 *Ptr;\r
44\r
45 if (Polarity) {\r
46 ErasedValue = 0xFF;\r
47 } else {\r
48 ErasedValue = 0;\r
49 }\r
50\r
51 Ptr = Buffer;\r
52 while (BufferSize--) {\r
53 if (*Ptr++ != ErasedValue) {\r
54 return FALSE;\r
55 }\r
56 }\r
57\r
58 return TRUE;\r
59}\r
60\r
61EFI_STATUS\r
62FtwEraseBlock (\r
63 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
64 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
65 EFI_LBA Lba\r
66 )\r
67/*++\r
68\r
69Routine Description:\r
70 To Erase one block. The size is FTW_BLOCK_SIZE\r
71\r
72Arguments:\r
73 FtwLiteDevice - Calling context\r
74 FvBlock - FVB Protocol interface\r
75 Lba - Lba of the firmware block\r
76\r
77Returns:\r
78 EFI_SUCCESS - Block LBA is Erased successfully\r
79 Others - Error occurs\r
80\r
81--*/\r
82{\r
83 return FvBlock->EraseBlocks (\r
84 FvBlock,\r
85 Lba,\r
86 FtwLiteDevice->NumberOfSpareBlock,\r
87 EFI_LBA_LIST_TERMINATOR\r
88 );\r
89}\r
90\r
91EFI_STATUS\r
92FtwEraseSpareBlock (\r
93 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice\r
94 )\r
95/*++\r
96\r
97Routine Description:\r
98\r
99 Erase spare block.\r
100\r
101Arguments:\r
102\r
103 FtwLiteDevice - Calling context\r
104\r
105Returns:\r
106\r
107 Status code\r
108\r
109--*/\r
110{\r
111 return FtwLiteDevice->FtwBackupFvb->EraseBlocks (\r
112 FtwLiteDevice->FtwBackupFvb,\r
113 FtwLiteDevice->FtwSpareLba,\r
114 FtwLiteDevice->NumberOfSpareBlock,\r
115 EFI_LBA_LIST_TERMINATOR\r
116 );\r
117}\r
118\r
119EFI_STATUS\r
120FtwGetFvbByHandle (\r
121 IN EFI_HANDLE FvBlockHandle,\r
122 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock\r
123 )\r
124/*++\r
125\r
126Routine Description:\r
127 Retrive the proper FVB protocol interface by HANDLE.\r
128\r
129Arguments:\r
130 FvBlockHandle - The handle of FVB protocol that provides services for \r
131 reading, writing, and erasing the target block.\r
132 FvBlock - The interface of FVB protocol\r
133\r
134Returns:\r
135 EFI_SUCCESS - The function completed successfully\r
136 EFI_ABORTED - The function could not complete successfully\r
137--*/\r
138{\r
139 //\r
140 // To get the FVB protocol interface on the handle\r
141 //\r
142 return gBS->HandleProtocol (\r
143 FvBlockHandle,\r
144 &gEfiFirmwareVolumeBlockProtocolGuid,\r
145 (VOID **) FvBlock\r
146 );\r
147}\r
148\r
149EFI_STATUS\r
150GetFvbByAddress (\r
151 IN EFI_PHYSICAL_ADDRESS Address,\r
152 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock\r
153 )\r
154/*++\r
155\r
156Routine Description:\r
157\r
158 Get firmware block by address.\r
159\r
160Arguments:\r
161\r
162 Address - Address specified the block\r
163 FvBlock - The block caller wanted\r
164\r
165Returns:\r
166\r
167 Status code\r
168\r
169 EFI_NOT_FOUND - Block not found\r
170\r
171--*/\r
172{\r
173 EFI_STATUS Status;\r
174 EFI_HANDLE *HandleBuffer;\r
175 UINTN HandleCount;\r
176 UINTN Index;\r
177 EFI_PHYSICAL_ADDRESS FvbBaseAddress;\r
178 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
179 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
180\r
181 *FvBlock = NULL;\r
182 //\r
183 // Locate all handles of Fvb protocol\r
184 //\r
185 Status = gBS->LocateHandleBuffer (\r
186 ByProtocol,\r
187 &gEfiFirmwareVolumeBlockProtocolGuid,\r
188 NULL,\r
189 &HandleCount,\r
190 &HandleBuffer\r
191 );\r
192 if (EFI_ERROR (Status)) {\r
193 return EFI_NOT_FOUND;\r
194 }\r
195 //\r
196 // Search all FVB until find the right one\r
197 //\r
198 for (Index = 0; Index < HandleCount; Index += 1) {\r
199 Status = gBS->HandleProtocol (\r
200 HandleBuffer[Index],\r
201 &gEfiFirmwareVolumeBlockProtocolGuid,\r
202 (VOID **) &Fvb\r
203 );\r
204 if (EFI_ERROR (Status)) {\r
205 Status = EFI_NOT_FOUND;\r
206 break;\r
207 }\r
208 //\r
209 // Compare the address and select the right one\r
210 //\r
211 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
212 if (EFI_ERROR (Status)) {\r
213 continue;\r
214 }\r
215\r
216 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
217 if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + (FwVolHeader->FvLength - 1)))) {\r
218 *FvBlock = Fvb;\r
219 Status = EFI_SUCCESS;\r
220 break;\r
221 }\r
222 }\r
223\r
224 FreePool (HandleBuffer);\r
225 return Status;\r
226}\r
227\r
228BOOLEAN\r
229IsInWorkingBlock (\r
230 EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
231 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
232 EFI_LBA Lba\r
233 )\r
234/*++\r
235\r
236Routine Description:\r
237\r
238 Is it in working block?\r
239\r
240Arguments:\r
241\r
242 FtwLiteDevice - Calling context\r
243 FvBlock - Fvb protocol instance\r
244 Lba - The block specified\r
245\r
246Returns:\r
247\r
248 In working block or not\r
249\r
250--*/\r
251{\r
252 //\r
253 // If matching the following condition, the target block is in working block.\r
254 // 1. Target block is on the FV of working block (Using the same FVB protocol instance).\r
255 // 2. Lba falls into the range of working block.\r
256 //\r
257 return (BOOLEAN)\r
258 (\r
259 (FvBlock == FtwLiteDevice->FtwFvBlock) &&\r
260 (Lba >= FtwLiteDevice->FtwWorkBlockLba) &&\r
261 (Lba <= FtwLiteDevice->FtwWorkSpaceLba)\r
262 );\r
263}\r
264\r
265EFI_STATUS\r
266FlushSpareBlockToTargetBlock (\r
267 EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
268 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
269 EFI_LBA Lba\r
270 )\r
271/*++\r
272\r
273Routine Description:\r
274 Copy the content of spare block to a target block. Size is FTW_BLOCK_SIZE.\r
275 Spare block is accessed by FTW backup FVB protocol interface. LBA is \r
276 FtwLiteDevice->FtwSpareLba.\r
277 Target block is accessed by FvBlock protocol interface. LBA is Lba.\r
278\r
279Arguments:\r
280 FtwLiteDevice - The private data of FTW_LITE driver\r
281 FvBlock - FVB Protocol interface to access target block\r
282 Lba - Lba of the target block\r
283\r
284Returns:\r
285 EFI_SUCCESS - Spare block content is copied to target block\r
286 EFI_INVALID_PARAMETER - Input parameter error\r
287 EFI_OUT_OF_RESOURCES - Allocate memory error\r
288 EFI_ABORTED - The function could not complete successfully\r
289\r
290--*/\r
291{\r
292 EFI_STATUS Status;\r
293 UINTN Length;\r
294 UINT8 *Buffer;\r
295 UINTN Count;\r
296 UINT8 *Ptr;\r
297 UINTN Index;\r
298\r
299 if ((FtwLiteDevice == NULL) || (FvBlock == NULL)) {\r
300 return EFI_INVALID_PARAMETER;\r
301 }\r
302 //\r
303 // Allocate a memory buffer\r
304 //\r
305 Length = FtwLiteDevice->SpareAreaLength;\r
306 Buffer = AllocatePool (Length);\r
307 if (Buffer == NULL) {\r
308 return EFI_OUT_OF_RESOURCES;\r
309 }\r
310 //\r
311 // Read all content of spare block to memory buffer\r
312 //\r
313 Ptr = Buffer;\r
314 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
315 Count = FtwLiteDevice->SizeOfSpareBlock;\r
316 Status = FtwLiteDevice->FtwBackupFvb->Read (\r
317 FtwLiteDevice->FtwBackupFvb,\r
318 FtwLiteDevice->FtwSpareLba + Index,\r
319 0,\r
320 &Count,\r
321 Ptr\r
322 );\r
323 if (EFI_ERROR (Status)) {\r
324 FreePool (Buffer);\r
325 return Status;\r
326 }\r
327\r
328 Ptr += Count;\r
329 }\r
330 //\r
331 // Erase the target block\r
332 //\r
333 Status = FtwEraseBlock (FtwLiteDevice, FvBlock, Lba);\r
334 if (EFI_ERROR (Status)) {\r
335 FreePool (Buffer);\r
336 return EFI_ABORTED;\r
337 }\r
338 //\r
339 // Write memory buffer to block, using the FvbBlock protocol interface\r
340 //\r
341 Ptr = Buffer;\r
342 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
343 Count = FtwLiteDevice->SizeOfSpareBlock;\r
344 Status = FvBlock->Write (FvBlock, Lba + Index, 0, &Count, Ptr);\r
345 if (EFI_ERROR (Status)) {\r
346 DEBUG ((EFI_D_FTW_LITE, "FtwLite: FVB Write block - %r\n", Status));\r
347 FreePool (Buffer);\r
348 return Status;\r
349 }\r
350\r
351 Ptr += Count;\r
352 }\r
353\r
354 FreePool (Buffer);\r
355\r
356 return Status;\r
357}\r
358\r
359EFI_STATUS\r
360FlushSpareBlockToWorkingBlock (\r
361 EFI_FTW_LITE_DEVICE *FtwLiteDevice\r
362 )\r
363/*++\r
364\r
365Routine Description:\r
366 Copy the content of spare block to working block. Size is FTW_BLOCK_SIZE.\r
367 Spare block is accessed by FTW backup FVB protocol interface. LBA is \r
368 FtwLiteDevice->FtwSpareLba.\r
369 Working block is accessed by FTW working FVB protocol interface. LBA is \r
370 FtwLiteDevice->FtwWorkBlockLba.\r
371\r
372Arguments:\r
373 FtwLiteDevice - The private data of FTW_LITE driver\r
374\r
375Returns:\r
376 EFI_SUCCESS - Spare block content is copied to target block\r
377 EFI_OUT_OF_RESOURCES - Allocate memory error\r
378 EFI_ABORTED - The function could not complete successfully\r
379\r
380Notes:\r
381 Since the working block header is important when FTW initializes, the \r
382 state of the operation should be handled carefully. The Crc value is \r
383 calculated without STATE element. \r
384\r
385--*/\r
386{\r
387 EFI_STATUS Status;\r
388 UINTN Length;\r
389 UINT8 *Buffer;\r
390 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;\r
391 EFI_LBA WorkSpaceLbaOffset;\r
392 UINTN Count;\r
393 UINT8 *Ptr;\r
394 UINTN Index;\r
395\r
396 //\r
397 // Allocate a memory buffer\r
398 //\r
399 Length = FtwLiteDevice->SpareAreaLength;\r
400 Buffer = AllocatePool (Length);\r
401 if (Buffer == NULL) {\r
402 return EFI_OUT_OF_RESOURCES;\r
403 }\r
404 //\r
405 // To guarantee that the WorkingBlockValid is set on spare block\r
406 //\r
407 WorkSpaceLbaOffset = FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba;\r
408 FtwUpdateFvState (\r
409 FtwLiteDevice->FtwBackupFvb,\r
410 FtwLiteDevice->FtwSpareLba + WorkSpaceLbaOffset,\r
411 FtwLiteDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
412 WORKING_BLOCK_VALID\r
413 );\r
414 //\r
415 // Read from spare block to memory buffer\r
416 //\r
417 Ptr = Buffer;\r
418 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
419 Count = FtwLiteDevice->SizeOfSpareBlock;\r
420 Status = FtwLiteDevice->FtwBackupFvb->Read (\r
421 FtwLiteDevice->FtwBackupFvb,\r
422 FtwLiteDevice->FtwSpareLba + Index,\r
423 0,\r
424 &Count,\r
425 Ptr\r
426 );\r
427 if (EFI_ERROR (Status)) {\r
428 FreePool (Buffer);\r
429 return Status;\r
430 }\r
431\r
432 Ptr += Count;\r
433 }\r
434 //\r
435 // Clear the CRC and STATE, copy data from spare to working block.\r
436 //\r
437 WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (Buffer + (UINTN) WorkSpaceLbaOffset * FtwLiteDevice->SizeOfSpareBlock + FtwLiteDevice->FtwWorkSpaceBase);\r
438 InitWorkSpaceHeader (WorkingBlockHeader);\r
439 WorkingBlockHeader->WorkingBlockValid = FTW_ERASE_POLARITY;\r
440 WorkingBlockHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;\r
441\r
442 //\r
443 // target block is working block, then\r
444 // Set WorkingBlockInvalid in EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER\r
445 // before erase the working block.\r
446 //\r
447 // Offset = EFI_FIELD_OFFSET(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,\r
448 // WorkingBlockInvalid);\r
449 // To skip Signature and Crc: sizeof(EFI_GUID)+sizeof(UINT32).\r
450 //\r
451 Status = FtwUpdateFvState (\r
452 FtwLiteDevice->FtwFvBlock,\r
453 FtwLiteDevice->FtwWorkSpaceLba,\r
454 FtwLiteDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
455 WORKING_BLOCK_INVALID\r
456 );\r
457 if (EFI_ERROR (Status)) {\r
458 FreePool (Buffer);\r
459 return EFI_ABORTED;\r
460 }\r
461\r
462 FtwLiteDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE;\r
463\r
464 //\r
465 // Erase the working block\r
466 //\r
467 Status = FtwEraseBlock (\r
468 FtwLiteDevice,\r
469 FtwLiteDevice->FtwFvBlock,\r
470 FtwLiteDevice->FtwWorkBlockLba\r
471 );\r
472 if (EFI_ERROR (Status)) {\r
473 FreePool (Buffer);\r
474 return EFI_ABORTED;\r
475 }\r
476 //\r
477 // Write memory buffer to working block, using the FvbBlock protocol interface\r
478 //\r
479 Ptr = Buffer;\r
480 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
481 Count = FtwLiteDevice->SizeOfSpareBlock;\r
482 Status = FtwLiteDevice->FtwFvBlock->Write (\r
483 FtwLiteDevice->FtwFvBlock,\r
484 FtwLiteDevice->FtwWorkBlockLba + Index,\r
485 0,\r
486 &Count,\r
487 Ptr\r
488 );\r
489 if (EFI_ERROR (Status)) {\r
490 DEBUG ((EFI_D_FTW_LITE, "FtwLite: FVB Write block - %r\n", Status));\r
491 FreePool (Buffer);\r
492 return Status;\r
493 }\r
494\r
495 Ptr += Count;\r
496 }\r
497 //\r
498 // Since the memory buffer will not be used, free memory Buffer.\r
499 //\r
500 FreePool (Buffer);\r
501\r
502 //\r
503 // Update the VALID of the working block\r
504 //\r
505 // Offset = EFI_FIELD_OFFSET(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,\r
506 // WorkingBlockValid);\r
507 // Hardcode offset sizeof(EFI_GUID)+sizeof(UINT32), to skip Signature and Crc\r
508 //\r
509 Status = FtwUpdateFvState (\r
510 FtwLiteDevice->FtwFvBlock,\r
511 FtwLiteDevice->FtwWorkSpaceLba,\r
512 FtwLiteDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
513 WORKING_BLOCK_VALID\r
514 );\r
515 if (EFI_ERROR (Status)) {\r
516 return EFI_ABORTED;\r
517 }\r
518\r
519 FtwLiteDevice->FtwWorkSpaceHeader->WorkingBlockValid = FTW_VALID_STATE;\r
520\r
521 return EFI_SUCCESS;\r
522}\r