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