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