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