1 /** @file
2 FFS file access utilities.
3
4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution. The
9 full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "FwVolDriver.h"
18
19 #define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *) ((UINTN) Address))
20
21 /**
22 Set File State in the FfsHeader.
23
24 @param State File state to be set into FFS header.
25 @param FfsHeader Points to the FFS file header
26
27 **/
28 VOID
SetFileState(IN UINT8 State,IN EFI_FFS_FILE_HEADER * FfsHeader)29 SetFileState (
30 IN UINT8 State,
31 IN EFI_FFS_FILE_HEADER *FfsHeader
32 )
33 {
34 //
35 // Set File State in the FfsHeader
36 //
37 FfsHeader->State = (EFI_FFS_FILE_STATE) (FfsHeader->State ^ State);
38 return ;
39 }
40
41 /**
42 Get the FFS file state by checking the highest bit set in the header's state field.
43
44 @param ErasePolarity Erase polarity attribute of the firmware volume
45 @param FfsHeader Points to the FFS file header
46
47 @return FFS File state
48
49 **/
50 EFI_FFS_FILE_STATE
GetFileState(IN UINT8 ErasePolarity,IN EFI_FFS_FILE_HEADER * FfsHeader)51 GetFileState (
52 IN UINT8 ErasePolarity,
53 IN EFI_FFS_FILE_HEADER *FfsHeader
54 )
55 {
56 EFI_FFS_FILE_STATE FileState;
57 UINT8 HighestBit;
58
59 FileState = FfsHeader->State;
60
61 if (ErasePolarity != 0) {
62 FileState = (EFI_FFS_FILE_STATE)~FileState;
63 }
64
65 HighestBit = 0x80;
66 while (HighestBit != 0 && ((HighestBit & FileState) == 0)) {
67 HighestBit >>= 1;
68 }
69
70 return (EFI_FFS_FILE_STATE) HighestBit;
71 }
72
73 /**
74 Convert the Buffer Address to LBA Entry Address.
75
76 @param FvDevice Cached FvDevice
77 @param BufferAddress Address of Buffer
78 @param LbaListEntry Pointer to the got LBA entry that contains the address.
79
80 @retval EFI_NOT_FOUND Buffer address is out of FvDevice.
81 @retval EFI_SUCCESS LBA entry is found for Buffer address.
82
83 **/
84 EFI_STATUS
Buffer2LbaEntry(IN FV_DEVICE * FvDevice,IN EFI_PHYSICAL_ADDRESS BufferAddress,OUT LBA_ENTRY ** LbaListEntry)85 Buffer2LbaEntry (
86 IN FV_DEVICE *FvDevice,
87 IN EFI_PHYSICAL_ADDRESS BufferAddress,
88 OUT LBA_ENTRY **LbaListEntry
89 )
90 {
91 LBA_ENTRY *LbaEntry;
92 LIST_ENTRY *Link;
93
94 Link = FvDevice->LbaHeader.ForwardLink;
95 LbaEntry = (LBA_ENTRY *) Link;
96
97 //
98 // Locate LBA which contains the address
99 //
100 while (&LbaEntry->Link != &FvDevice->LbaHeader) {
101 if ((EFI_PHYSICAL_ADDRESS) (UINTN) (LbaEntry->StartingAddress) > BufferAddress) {
102 break;
103 }
104
105 Link = LbaEntry->Link.ForwardLink;
106 LbaEntry = (LBA_ENTRY *) Link;
107 }
108
109 if (&LbaEntry->Link == &FvDevice->LbaHeader) {
110 return EFI_NOT_FOUND;
111 }
112
113 Link = LbaEntry->Link.BackLink;
114 LbaEntry = (LBA_ENTRY *) Link;
115
116 if (&LbaEntry->Link == &FvDevice->LbaHeader) {
117 return EFI_NOT_FOUND;
118 }
119
120 *LbaListEntry = LbaEntry;
121
122 return EFI_SUCCESS;
123 }
124
125 /**
126 Convert the Buffer Address to LBA Address & Offset.
127
128 @param FvDevice Cached FvDevice
129 @param BufferAddress Address of Buffer
130 @param Lba Pointer to the gob Lba value
131 @param Offset Pointer to the got Offset
132
133 @retval EFI_NOT_FOUND Buffer address is out of FvDevice.
134 @retval EFI_SUCCESS LBA and Offset is found for Buffer address.
135
136 **/
137 EFI_STATUS
Buffer2Lba(IN FV_DEVICE * FvDevice,IN EFI_PHYSICAL_ADDRESS BufferAddress,OUT EFI_LBA * Lba,OUT UINTN * Offset)138 Buffer2Lba (
139 IN FV_DEVICE *FvDevice,
140 IN EFI_PHYSICAL_ADDRESS BufferAddress,
141 OUT EFI_LBA *Lba,
142 OUT UINTN *Offset
143 )
144 {
145 LBA_ENTRY *LbaEntry;
146 EFI_STATUS Status;
147
148 LbaEntry = NULL;
149
150 Status = Buffer2LbaEntry (
151 FvDevice,
152 BufferAddress,
153 &LbaEntry
154 );
155 if (EFI_ERROR (Status)) {
156 return Status;
157 }
158
159 *Lba = LbaEntry->LbaIndex;
160 *Offset = (UINTN) BufferAddress - (UINTN) LbaEntry->StartingAddress;
161
162 return EFI_SUCCESS;
163 }
164
165 /**
166 Check if a block of buffer is erased.
167
168 @param ErasePolarity Erase polarity attribute of the firmware volume
169 @param Buffer The buffer to be checked
170 @param BufferSize Size of the buffer in bytes
171
172 @retval TRUE The block of buffer is erased
173 @retval FALSE The block of buffer is not erased
174
175 **/
176 BOOLEAN
IsBufferErased(IN UINT8 ErasePolarity,IN UINT8 * Buffer,IN UINTN BufferSize)177 IsBufferErased (
178 IN UINT8 ErasePolarity,
179 IN UINT8 *Buffer,
180 IN UINTN BufferSize
181 )
182 {
183 UINTN Count;
184 UINT8 EraseByte;
185
186 if (ErasePolarity == 1) {
187 EraseByte = 0xFF;
188 } else {
189 EraseByte = 0;
190 }
191
192 for (Count = 0; Count < BufferSize; Count++) {
193 if (Buffer[Count] != EraseByte) {
194 return FALSE;
195 }
196 }
197
198 return TRUE;
199 }
200
201 /**
202 Verify checksum of the firmware volume header.
203
204 @param FvHeader Points to the firmware volume header to be checked
205
206 @retval TRUE Checksum verification passed
207 @retval FALSE Checksum verification failed
208
209 **/
210 BOOLEAN
VerifyFvHeaderChecksum(IN EFI_FIRMWARE_VOLUME_HEADER * FvHeader)211 VerifyFvHeaderChecksum (
212 IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
213 )
214 {
215 UINT16 Checksum;
216
217 Checksum = CalculateSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength);
218
219 if (Checksum == 0) {
220 return TRUE;
221 } else {
222 return FALSE;
223 }
224 }
225
226 /**
227 Verify checksum of the FFS file header.
228
229 @param FfsHeader Points to the FFS file header to be checked
230
231 @retval TRUE Checksum verification passed
232 @retval FALSE Checksum verification failed
233
234 **/
235 BOOLEAN
VerifyHeaderChecksum(IN EFI_FFS_FILE_HEADER * FfsHeader)236 VerifyHeaderChecksum (
237 IN EFI_FFS_FILE_HEADER *FfsHeader
238 )
239 {
240 UINT8 HeaderChecksum;
241
242 if (IS_FFS_FILE2 (FfsHeader)) {
243 HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER2));
244 } else {
245 HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER));
246 }
247 HeaderChecksum = (UINT8) (HeaderChecksum - FfsHeader->State - FfsHeader->IntegrityCheck.Checksum.File);
248
249 if (HeaderChecksum == 0) {
250 return TRUE;
251 } else {
252 return FALSE;
253 }
254 }
255
256 /**
257 Verify checksum of the FFS file data.
258
259 @param FfsHeader Points to the FFS file header to be checked
260
261 @retval TRUE Checksum verification passed
262 @retval FALSE Checksum verification failed
263
264 **/
265 BOOLEAN
VerifyFileChecksum(IN EFI_FFS_FILE_HEADER * FfsHeader)266 VerifyFileChecksum (
267 IN EFI_FFS_FILE_HEADER *FfsHeader
268 )
269 {
270 UINT8 FileChecksum;
271 EFI_FV_FILE_ATTRIBUTES Attributes;
272
273 Attributes = FfsHeader->Attributes;
274
275 if ((Attributes & FFS_ATTRIB_CHECKSUM) != 0) {
276
277 //
278 // Check checksum of FFS data
279 //
280 if (IS_FFS_FILE2 (FfsHeader)) {
281 FileChecksum = CalculateSum8 ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2), FFS_FILE2_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER2));
282 } else {
283 FileChecksum = CalculateSum8 ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER), FFS_FILE_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER));
284 }
285 FileChecksum = (UINT8) (FileChecksum + FfsHeader->IntegrityCheck.Checksum.File);
286
287 if (FileChecksum == 0) {
288 return TRUE;
289 } else {
290 return FALSE;
291 }
292
293 } else {
294
295 if (FfsHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
296 return FALSE;
297 } else {
298 return TRUE;
299 }
300 }
301
302 }
303
304 /**
305 Check if it's a valid FFS file header.
306
307 @param ErasePolarity Erase polarity attribute of the firmware volume
308 @param FfsHeader Points to the FFS file header to be checked
309
310 @retval TRUE Valid FFS file header
311 @retval FALSE Invalid FFS file header
312
313 **/
314 BOOLEAN
IsValidFFSHeader(IN UINT8 ErasePolarity,IN EFI_FFS_FILE_HEADER * FfsHeader)315 IsValidFFSHeader (
316 IN UINT8 ErasePolarity,
317 IN EFI_FFS_FILE_HEADER *FfsHeader
318 )
319 {
320 EFI_FFS_FILE_STATE FileState;
321
322 //
323 // Check if it is a free space
324 //
325 if (IsBufferErased (
326 ErasePolarity,
327 (UINT8 *) FfsHeader,
328 sizeof (EFI_FFS_FILE_HEADER)
329 )) {
330 return FALSE;
331 }
332
333 FileState = GetFileState (ErasePolarity, FfsHeader);
334
335 switch (FileState) {
336 case EFI_FILE_HEADER_CONSTRUCTION:
337 //
338 // fall through
339 //
340 case EFI_FILE_HEADER_INVALID:
341 return FALSE;
342
343 case EFI_FILE_HEADER_VALID:
344 //
345 // fall through
346 //
347 case EFI_FILE_DATA_VALID:
348 //
349 // fall through
350 //
351 case EFI_FILE_MARKED_FOR_UPDATE:
352 //
353 // fall through
354 //
355 case EFI_FILE_DELETED:
356 //
357 // Here we need to verify header checksum
358 //
359 if (!VerifyHeaderChecksum (FfsHeader)) {
360 return FALSE;
361 }
362 break;
363
364 default:
365 //
366 // return
367 //
368 return FALSE;
369 }
370
371 return TRUE;
372 }
373
374 /**
375 Get next possible of Firmware File System Header.
376
377 @param ErasePolarity Erase polarity attribute of the firmware volume
378 @param FfsHeader Points to the FFS file header to be skipped.
379
380 @return Pointer to next FFS header.
381
382 **/
383 EFI_PHYSICAL_ADDRESS
GetNextPossibleFileHeader(IN UINT8 ErasePolarity,IN EFI_FFS_FILE_HEADER * FfsHeader)384 GetNextPossibleFileHeader (
385 IN UINT8 ErasePolarity,
386 IN EFI_FFS_FILE_HEADER *FfsHeader
387 )
388 {
389 UINT32 FileLength;
390 UINT32 SkipLength;
391
392 if (!IsValidFFSHeader (ErasePolarity, FfsHeader)) {
393 //
394 // Skip this header
395 //
396 if (IS_FFS_FILE2 (FfsHeader)) {
397 return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2);
398 } else {
399 return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + sizeof (EFI_FFS_FILE_HEADER);
400 }
401 }
402
403 if (IS_FFS_FILE2 (FfsHeader)) {
404 FileLength = FFS_FILE2_SIZE (FfsHeader);
405 } else {
406 FileLength = FFS_FILE_SIZE (FfsHeader);
407 }
408
409 //
410 // Since FileLength is not multiple of 8, we need skip some bytes
411 // to get next possible header
412 //
413 SkipLength = FileLength;
414 while ((SkipLength & 0x07) != 0) {
415 SkipLength++;
416 }
417
418 return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + SkipLength;
419 }
420
421 /**
422 Search FFS file with the same FFS name in FV Cache.
423
424 @param FvDevice Cached FV image.
425 @param FfsHeader Points to the FFS file header to be skipped.
426 @param StateBit FFS file state bit to be checked.
427
428 @return Pointer to next found FFS header. NULL will return if no found.
429
430 **/
431 EFI_FFS_FILE_HEADER *
DuplicateFileExist(IN FV_DEVICE * FvDevice,IN EFI_FFS_FILE_HEADER * FfsHeader,IN EFI_FFS_FILE_STATE StateBit)432 DuplicateFileExist (
433 IN FV_DEVICE *FvDevice,
434 IN EFI_FFS_FILE_HEADER *FfsHeader,
435 IN EFI_FFS_FILE_STATE StateBit
436 )
437 {
438 UINT8 *Ptr;
439 EFI_FFS_FILE_HEADER *NextFfsFile;
440
441 //
442 // Search duplicate file, not from the beginning of FV,
443 // just search the next ocurrence of this file
444 //
445 NextFfsFile = FfsHeader;
446
447 do {
448 Ptr = (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (
449 GetNextPossibleFileHeader (FvDevice->ErasePolarity,
450 NextFfsFile)
451 );
452 NextFfsFile = (EFI_FFS_FILE_HEADER *) Ptr;
453
454 if ((UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength - Ptr <
455 sizeof (EFI_FFS_FILE_HEADER)
456 ) {
457 break;
458 }
459
460 if (!IsValidFFSHeader (FvDevice->ErasePolarity, NextFfsFile)) {
461 continue;
462 }
463
464 if (!VerifyFileChecksum (NextFfsFile)) {
465 continue;
466 }
467
468 if (CompareGuid (&NextFfsFile->Name, &FfsHeader->Name)) {
469 if (GetFileState (FvDevice->ErasePolarity, NextFfsFile) == StateBit) {
470 return NextFfsFile;
471 }
472 }
473 } while (Ptr < (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength);
474
475 return NULL;
476 }
477
478 /**
479 Change FFS file header state and write to FV.
480
481 @param FvDevice Cached FV image.
482 @param FfsHeader Points to the FFS file header to be updated.
483 @param State FFS file state to be set.
484
485 @retval EFI_SUCCESS File state is writen into FV.
486 @retval others File state can't be writen into FV.
487
488 **/
489 EFI_STATUS
UpdateHeaderBit(IN FV_DEVICE * FvDevice,IN EFI_FFS_FILE_HEADER * FfsHeader,IN EFI_FFS_FILE_STATE State)490 UpdateHeaderBit (
491 IN FV_DEVICE *FvDevice,
492 IN EFI_FFS_FILE_HEADER *FfsHeader,
493 IN EFI_FFS_FILE_STATE State
494 )
495 {
496 EFI_STATUS Status;
497 EFI_LBA Lba;
498 UINTN Offset;
499 UINTN NumBytesWritten;
500
501 Lba = 0;
502 Offset = 0;
503
504 SetFileState (State, FfsHeader);
505
506 Buffer2Lba (
507 FvDevice,
508 (EFI_PHYSICAL_ADDRESS) (UINTN) (&FfsHeader->State),
509 &Lba,
510 &Offset
511 );
512 //
513 // Write the state byte into FV
514 //
515 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
516 Status = FvDevice->Fvb->Write (
517 FvDevice->Fvb,
518 Lba,
519 Offset,
520 &NumBytesWritten,
521 &FfsHeader->State
522 );
523 return Status;
524 }
525
526 /**
527 Check if it's a valid FFS file.
528 Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first.
529
530 @param FvDevice Cached FV image.
531 @param FfsHeader Points to the FFS file to be checked
532
533 @retval TRUE Valid FFS file
534 @retval FALSE Invalid FFS file
535
536 **/
537 BOOLEAN
IsValidFFSFile(IN FV_DEVICE * FvDevice,IN EFI_FFS_FILE_HEADER * FfsHeader)538 IsValidFFSFile (
539 IN FV_DEVICE *FvDevice,
540 IN EFI_FFS_FILE_HEADER *FfsHeader
541 )
542 {
543 EFI_FFS_FILE_STATE FileState;
544 UINT8 ErasePolarity;
545
546 ErasePolarity = FvDevice->ErasePolarity;
547
548 FileState = GetFileState (ErasePolarity, FfsHeader);
549
550 switch (FileState) {
551 case EFI_FILE_DATA_VALID:
552 if (!VerifyFileChecksum (FfsHeader)) {
553 return FALSE;
554 }
555
556 if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
557 break;
558 }
559 //
560 // Check if there is another duplicated file with the EFI_FILE_DATA_VALID
561 //
562 if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) {
563 return FALSE;
564 }
565
566 break;
567
568 case EFI_FILE_MARKED_FOR_UPDATE:
569 if (!VerifyFileChecksum (FfsHeader)) {
570 return FALSE;
571 }
572
573 if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
574 //
575 // since its data area is not unperturbed, it cannot be reclaimed,
576 // marked it as deleted
577 //
578 UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED);
579 return TRUE;
580
581 } else if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) {
582 //
583 // Here the found file is more recent than this file,
584 // mark it as deleted
585 //
586 UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED);
587 return TRUE;
588
589 } else {
590 return TRUE;
591 }
592
593 break;
594
595 case EFI_FILE_DELETED:
596 if (!VerifyFileChecksum (FfsHeader)) {
597 return FALSE;
598 }
599
600 break;
601
602 default:
603 return FALSE;
604 }
605
606 return TRUE;
607 }
608
609