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