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