]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/FtwWorkSpace.c
Add comments and DoxyGen format for these files.
[mirror_edk2.git] / MdeModulePkg / Universal / FirmwareVolume / FaultTolerantWriteDxe / FtwWorkSpace.c
1 /** @file
2
3 Internal functions to operate Working Block Space.
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
17 #include <FtwLite.h>
18
19 BOOLEAN
20 IsValidWorkSpace (
21 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
22 )
23 /*++
24
25 Routine Description:
26 Check to see if it is a valid work space.
27
28 Arguments:
29 WorkingHeader - Pointer of working block header
30
31 Returns:
32 EFI_SUCCESS - The function completed successfully
33 EFI_ABORTED - The function could not complete successfully.
34
35 --*/
36 {
37 EFI_STATUS Status;
38 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER WorkingBlockHeader;
39
40 ASSERT (WorkingHeader != NULL);
41 if (WorkingHeader->WorkingBlockValid != FTW_VALID_STATE) {
42 return FALSE;
43 }
44 //
45 // Check signature with gEfiSystemNvDataFvGuid
46 //
47 if (!CompareGuid (&gEfiSystemNvDataFvGuid, &WorkingHeader->Signature)) {
48 return FALSE;
49 }
50 //
51 // Check the CRC of header
52 //
53 CopyMem (
54 &WorkingBlockHeader,
55 WorkingHeader,
56 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)
57 );
58
59 //
60 // Filter out the Crc and State fields
61 //
62 SetMem (
63 &WorkingBlockHeader.Crc,
64 sizeof (UINT32),
65 FTW_ERASED_BYTE
66 );
67 WorkingBlockHeader.WorkingBlockValid = FTW_ERASE_POLARITY;
68 WorkingBlockHeader.WorkingBlockInvalid = FTW_ERASE_POLARITY;
69
70 //
71 // Calculate the Crc of woking block header
72 //
73 Status = gBS->CalculateCrc32 (
74 (UINT8 *) &WorkingBlockHeader,
75 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
76 &WorkingBlockHeader.Crc
77 );
78 ASSERT_EFI_ERROR (Status);
79
80 if (WorkingBlockHeader.Crc != WorkingHeader->Crc) {
81 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Work block header CRC check error\n"));
82 return FALSE;
83 }
84
85 return TRUE;
86 }
87
88 EFI_STATUS
89 InitWorkSpaceHeader (
90 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
91 )
92 /*++
93
94 Routine Description:
95 Initialize a work space when there is no work space.
96
97 Arguments:
98 WorkingHeader - Pointer of working block header
99
100 Returns:
101 EFI_SUCCESS - The function completed successfully
102 EFI_ABORTED - The function could not complete successfully.
103
104 --*/
105 {
106 EFI_STATUS Status;
107
108 ASSERT (WorkingHeader != NULL);
109
110 //
111 // Here using gEfiSystemNvDataFvGuid as the signature.
112 //
113 CopyMem (
114 &WorkingHeader->Signature,
115 &gEfiSystemNvDataFvGuid,
116 sizeof (EFI_GUID)
117 );
118 WorkingHeader->WriteQueueSize = FTW_WORKING_QUEUE_SIZE;
119
120 //
121 // Crc is calculated with all the fields except Crc and STATE
122 //
123 WorkingHeader->WorkingBlockValid = FTW_ERASE_POLARITY;
124 WorkingHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;
125 SetMem (&WorkingHeader->Crc, sizeof (UINT32), FTW_ERASED_BYTE);
126
127 //
128 // Calculate the CRC value
129 //
130 Status = gBS->CalculateCrc32 (
131 (UINT8 *) WorkingHeader,
132 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
133 &WorkingHeader->Crc
134 );
135 ASSERT_EFI_ERROR (Status);
136
137 //
138 // Restore the WorkingBlockValid flag to VALID state
139 //
140 WorkingHeader->WorkingBlockValid = FTW_VALID_STATE;
141 WorkingHeader->WorkingBlockInvalid = FTW_INVALID_STATE;
142
143 return EFI_SUCCESS;
144 }
145
146 EFI_STATUS
147 FtwUpdateFvState (
148 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
149 IN EFI_LBA Lba,
150 IN UINTN Offset,
151 IN UINT8 NewBit
152 )
153 /*++
154
155 Routine Description:
156 Update a bit of state on a block device. The location of the bit is
157 calculated by the (Lba, Offset, bit). Here bit is determined by the
158 the name of a certain bit.
159
160 Arguments:
161 FvBlock - FVB Protocol interface to access SrcBlock and DestBlock
162 Lba - Lba of a block
163 Offset - Offset on the Lba
164 NewBit - New value that will override the old value if it can be change
165
166 Returns:
167 EFI_SUCCESS - A state bit has been updated successfully
168 Others - Access block device error.
169
170 Notes:
171 Assume all bits of State are inside the same BYTE.
172
173 EFI_ABORTED - Read block fail
174 --*/
175 {
176 EFI_STATUS Status;
177 UINT8 State;
178 UINTN Length;
179
180 //
181 // Read state from device, assume State is only one byte.
182 //
183 Length = sizeof (UINT8);
184 Status = FvBlock->Read (FvBlock, Lba, Offset, &Length, &State);
185 if (EFI_ERROR (Status)) {
186 return EFI_ABORTED;
187 }
188
189 State ^= FTW_POLARITY_REVERT;
190 State = (UINT8) (State | NewBit);
191 State ^= FTW_POLARITY_REVERT;
192
193 //
194 // Write state back to device
195 //
196 Length = sizeof (UINT8);
197 Status = FvBlock->Write (FvBlock, Lba, Offset, &Length, &State);
198
199 return Status;
200 }
201
202 EFI_STATUS
203 FtwGetLastRecord (
204 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
205 OUT EFI_FTW_LITE_RECORD **FtwLastRecord
206 )
207 /*++
208
209 Routine Description:
210 Get the last Write record pointer.
211 The last record is the record whose 'complete' state hasn't been set.
212 After all, this header may be a EMPTY header entry for next Allocate.
213
214 Arguments:
215 FtwLiteDevice - Private data of this driver
216 FtwLastRecord - Pointer to retrieve the last write record
217
218 Returns:
219 EFI_SUCCESS - Get the last write record successfully
220 EFI_ABORTED - The FTW work space is damaged
221
222 --*/
223 {
224 EFI_FTW_LITE_RECORD *Record;
225
226 Record = (EFI_FTW_LITE_RECORD *) (FtwLiteDevice->FtwWorkSpaceHeader + 1);
227 while (Record->WriteCompleted == FTW_VALID_STATE) {
228 //
229 // If Offset exceed the FTW work space boudary, return error.
230 //
231 if ((UINTN) ((UINT8 *) Record - FtwLiteDevice->FtwWorkSpace) > FtwLiteDevice->FtwWorkSpaceSize) {
232 return EFI_ABORTED;
233 }
234
235 Record++;
236 }
237 //
238 // Last write record is found
239 //
240 *FtwLastRecord = Record;
241 return EFI_SUCCESS;
242 }
243
244 EFI_STATUS
245 WorkSpaceRefresh (
246 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
247 )
248 /*++
249
250 Routine Description:
251 Read from working block to refresh the work space in memory.
252
253 Arguments:
254 FtwLiteDevice - Point to private data of FTW driver
255
256 Returns:
257 EFI_SUCCESS - The function completed successfully
258 EFI_ABORTED - The function could not complete successfully.
259
260 --*/
261 {
262 EFI_STATUS Status;
263 UINTN Length;
264 UINTN Offset;
265 EFI_FTW_LITE_RECORD *Record;
266
267 //
268 // Initialize WorkSpace as FTW_ERASED_BYTE
269 //
270 SetMem (
271 FtwLiteDevice->FtwWorkSpace,
272 FtwLiteDevice->FtwWorkSpaceSize,
273 FTW_ERASED_BYTE
274 );
275
276 //
277 // Read from working block
278 //
279 Length = FtwLiteDevice->FtwWorkSpaceSize;
280 Status = FtwLiteDevice->FtwFvBlock->Read (
281 FtwLiteDevice->FtwFvBlock,
282 FtwLiteDevice->FtwWorkSpaceLba,
283 FtwLiteDevice->FtwWorkSpaceBase,
284 &Length,
285 FtwLiteDevice->FtwWorkSpace
286 );
287 if (EFI_ERROR (Status)) {
288 return EFI_ABORTED;
289 }
290 //
291 // Refresh the FtwLastRecord
292 //
293 Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);
294
295 Record = FtwLiteDevice->FtwLastRecord;
296 Offset = (UINTN) (UINT8 *) Record - (UINTN) FtwLiteDevice->FtwWorkSpace;
297
298 //
299 // IF work space has error or Record is out of the workspace limit, THEN
300 // call reclaim.
301 //
302 if (EFI_ERROR (Status) || (Offset + WRITE_TOTAL_SIZE >= FtwLiteDevice->FtwWorkSpaceSize)) {
303 //
304 // reclaim work space in working block.
305 //
306 Status = FtwReclaimWorkSpace (FtwLiteDevice);
307 if (EFI_ERROR (Status)) {
308 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Reclaim workspace - %r\n", Status));
309 return EFI_ABORTED;
310 }
311 }
312
313 return EFI_SUCCESS;
314 }
315
316 EFI_STATUS
317 CleanupWorkSpace (
318 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
319 IN OUT UINT8 *FtwSpaceBuffer,
320 IN UINTN BufferSize
321 )
322 /*++
323
324 Routine Description:
325 Reclaim the work space. Get rid of all the completed write records
326 and write records in the Fault Tolerant work space.
327
328 Arguments:
329 FtwLiteDevice - Point to private data of FTW driver
330 FtwSpaceBuffer - Buffer to contain the reclaimed clean data
331 BufferSize - Size of the FtwSpaceBuffer
332
333 Returns:
334 EFI_SUCCESS - The function completed successfully
335 EFI_BUFFER_TOO_SMALL - The FtwSpaceBuffer is too small
336 EFI_ABORTED - The function could not complete successfully.
337
338 --*/
339 {
340 UINTN Length;
341 EFI_FTW_LITE_RECORD *Record;
342
343 //
344 // To check if the buffer is large enough
345 //
346 Length = FtwLiteDevice->FtwWorkSpaceSize;
347 if (BufferSize < Length) {
348 return EFI_BUFFER_TOO_SMALL;
349 }
350 //
351 // Clear the content of buffer that will save the new work space data
352 //
353 SetMem (FtwSpaceBuffer, Length, FTW_ERASED_BYTE);
354
355 //
356 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
357 //
358 CopyMem (
359 FtwSpaceBuffer,
360 FtwLiteDevice->FtwWorkSpaceHeader,
361 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)
362 );
363
364 //
365 // Get the last record
366 //
367 Record = FtwLiteDevice->FtwLastRecord;
368 if ((Record != NULL) && (Record->WriteAllocated == FTW_VALID_STATE) && (Record->WriteCompleted != FTW_VALID_STATE)) {
369 CopyMem (
370 (UINT8 *) FtwSpaceBuffer + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
371 Record,
372 WRITE_TOTAL_SIZE
373 );
374 }
375
376 return EFI_SUCCESS;
377 }
378
379 EFI_STATUS
380 FtwReclaimWorkSpace (
381 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
382 )
383 /*++
384
385 Routine Description:
386 Reclaim the work space on the working block.
387
388 Arguments:
389 FtwLiteDevice - Point to private data of FTW driver
390
391 Returns:
392 EFI_SUCCESS - The function completed successfully
393 EFI_OUT_OF_RESOURCES - Allocate memory error
394 EFI_ABORTED - The function could not complete successfully
395
396 --*/
397 {
398 EFI_STATUS Status;
399 UINT8 *TempBuffer;
400 UINTN TempBufferSize;
401 UINT8 *Ptr;
402 UINTN Length;
403 UINTN Index;
404 UINTN SpareBufferSize;
405 UINT8 *SpareBuffer;
406 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;
407
408 DEBUG ((EFI_D_FTW_LITE, "FtwLite: start to reclaim work space\n"));
409
410 //
411 // Read all original data from working block to a memory buffer
412 //
413 TempBufferSize = FtwLiteDevice->SpareAreaLength;
414 TempBuffer = AllocateZeroPool (TempBufferSize);
415 if (TempBuffer != NULL) {
416 return EFI_OUT_OF_RESOURCES;
417 }
418
419 Ptr = TempBuffer;
420 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
421 Length = FtwLiteDevice->SizeOfSpareBlock;
422 Status = FtwLiteDevice->FtwFvBlock->Read (
423 FtwLiteDevice->FtwFvBlock,
424 FtwLiteDevice->FtwWorkBlockLba + Index,
425 0,
426 &Length,
427 Ptr
428 );
429 if (EFI_ERROR (Status)) {
430 FreePool (TempBuffer);
431 return EFI_ABORTED;
432 }
433
434 Ptr += Length;
435 }
436 //
437 // Clean up the workspace, remove all the completed records.
438 //
439 Ptr = TempBuffer +
440 ((UINTN) (FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba)) *
441 FtwLiteDevice->SizeOfSpareBlock + FtwLiteDevice->FtwWorkSpaceBase;
442
443 Status = CleanupWorkSpace (
444 FtwLiteDevice,
445 Ptr,
446 FtwLiteDevice->FtwWorkSpaceSize
447 );
448
449 CopyMem (
450 FtwLiteDevice->FtwWorkSpace,
451 Ptr,
452 FtwLiteDevice->FtwWorkSpaceSize
453 );
454
455 Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);
456
457 //
458 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
459 //
460 WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) Ptr;
461 WorkingBlockHeader->WorkingBlockValid = FTW_INVALID_STATE;
462 WorkingBlockHeader->WorkingBlockInvalid = FTW_INVALID_STATE;
463
464 //
465 // Try to keep the content of spare block
466 // Save spare block into a spare backup memory buffer (Sparebuffer)
467 //
468 SpareBufferSize = FtwLiteDevice->SpareAreaLength;
469 SpareBuffer = AllocatePool (SpareBufferSize);
470 if (SpareBuffer == NULL) {
471 FreePool (TempBuffer);
472 return EFI_OUT_OF_RESOURCES;
473 }
474
475 Ptr = SpareBuffer;
476 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
477 Length = FtwLiteDevice->SizeOfSpareBlock;
478 Status = FtwLiteDevice->FtwBackupFvb->Read (
479 FtwLiteDevice->FtwBackupFvb,
480 FtwLiteDevice->FtwSpareLba + Index,
481 0,
482 &Length,
483 Ptr
484 );
485 if (EFI_ERROR (Status)) {
486 FreePool (TempBuffer);
487 FreePool (SpareBuffer);
488 return EFI_ABORTED;
489 }
490
491 Ptr += Length;
492 }
493 //
494 // Write the memory buffer to spare block
495 //
496 Status = FtwEraseSpareBlock (FtwLiteDevice);
497 Ptr = TempBuffer;
498 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
499 Length = FtwLiteDevice->SizeOfSpareBlock;
500 Status = FtwLiteDevice->FtwBackupFvb->Write (
501 FtwLiteDevice->FtwBackupFvb,
502 FtwLiteDevice->FtwSpareLba + Index,
503 0,
504 &Length,
505 Ptr
506 );
507 if (EFI_ERROR (Status)) {
508 FreePool (TempBuffer);
509 FreePool (SpareBuffer);
510 return EFI_ABORTED;
511 }
512
513 Ptr += Length;
514 }
515 //
516 // Free TempBuffer
517 //
518 FreePool (TempBuffer);
519
520 //
521 // Write the spare block to working block
522 //
523 Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice);
524 if (EFI_ERROR (Status)) {
525 FreePool (SpareBuffer);
526 return Status;
527 }
528 //
529 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
530 //
531 Status = FtwEraseSpareBlock (FtwLiteDevice);
532 Ptr = SpareBuffer;
533 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
534 Length = FtwLiteDevice->SizeOfSpareBlock;
535 Status = FtwLiteDevice->FtwBackupFvb->Write (
536 FtwLiteDevice->FtwBackupFvb,
537 FtwLiteDevice->FtwSpareLba + Index,
538 0,
539 &Length,
540 Ptr
541 );
542 if (EFI_ERROR (Status)) {
543 FreePool (SpareBuffer);
544 return EFI_ABORTED;
545 }
546
547 Ptr += Length;
548 }
549
550 FreePool (SpareBuffer);
551
552 DEBUG ((EFI_D_FTW_LITE, "FtwLite: reclaim work space success\n"));
553
554 return EFI_SUCCESS;
555 }