]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/Ffs.c
IntelFrameworkModulePkg: Add FwVolDxe driver
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / FirmwareVolume / FwVolDxe / Ffs.c
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
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
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
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
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
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
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
236 VerifyHeaderChecksum (
237 IN EFI_FFS_FILE_HEADER *FfsHeader
238 )
239 {
240 UINT8 HeaderChecksum;
241
242 HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER));
243 HeaderChecksum = (UINT8) (HeaderChecksum - FfsHeader->State - FfsHeader->IntegrityCheck.Checksum.File);
244
245 if (HeaderChecksum == 0) {
246 return TRUE;
247 } else {
248 return FALSE;
249 }
250 }
251
252 /**
253 Verify checksum of the FFS file data.
254
255 @param FfsHeader Points to the FFS file header to be checked
256
257 @retval TRUE Checksum verification passed
258 @retval FALSE Checksum verification failed
259
260 **/
261 BOOLEAN
262 VerifyFileChecksum (
263 IN EFI_FFS_FILE_HEADER *FfsHeader
264 )
265 {
266 UINT8 FileChecksum;
267 EFI_FV_FILE_ATTRIBUTES Attributes;
268 UINT32 FileSize;
269
270 Attributes = FfsHeader->Attributes;
271
272 if ((Attributes & FFS_ATTRIB_CHECKSUM) != 0) {
273
274 FileSize = *(UINT32 *) FfsHeader->Size & 0x00FFFFFF;
275
276 //
277 // Check checksum of FFS data
278 //
279 FileChecksum = CalculateSum8 ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER), FileSize - sizeof (EFI_FFS_FILE_HEADER));
280 FileChecksum = (UINT8) (FileChecksum + FfsHeader->IntegrityCheck.Checksum.File);
281
282 if (FileChecksum == 0) {
283 return TRUE;
284 } else {
285 return FALSE;
286 }
287
288 } else {
289
290 if (FfsHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
291 return FALSE;
292 } else {
293 return TRUE;
294 }
295 }
296
297 }
298
299 /**
300 Check if it's a valid FFS file header.
301
302 @param ErasePolarity Erase polarity attribute of the firmware volume
303 @param FfsHeader Points to the FFS file header to be checked
304
305 @retval TRUE Valid FFS file header
306 @retval FALSE Invalid FFS file header
307
308 **/
309 BOOLEAN
310 IsValidFFSHeader (
311 IN UINT8 ErasePolarity,
312 IN EFI_FFS_FILE_HEADER *FfsHeader
313 )
314 {
315 EFI_FFS_FILE_STATE FileState;
316
317 //
318 // Check if it is a free space
319 //
320 if (IsBufferErased (
321 ErasePolarity,
322 (UINT8 *) FfsHeader,
323 sizeof (EFI_FFS_FILE_HEADER)
324 )) {
325 return FALSE;
326 }
327
328 FileState = GetFileState (ErasePolarity, FfsHeader);
329
330 switch (FileState) {
331 case EFI_FILE_HEADER_CONSTRUCTION:
332 //
333 // fall through
334 //
335 case EFI_FILE_HEADER_INVALID:
336 return FALSE;
337
338 case EFI_FILE_HEADER_VALID:
339 //
340 // fall through
341 //
342 case EFI_FILE_DATA_VALID:
343 //
344 // fall through
345 //
346 case EFI_FILE_MARKED_FOR_UPDATE:
347 //
348 // fall through
349 //
350 case EFI_FILE_DELETED:
351 //
352 // Here we need to verify header checksum
353 //
354 if (!VerifyHeaderChecksum (FfsHeader)) {
355 return FALSE;
356 }
357 break;
358
359 default:
360 //
361 // return
362 //
363 return FALSE;
364 }
365
366 return TRUE;
367 }
368
369 /**
370 Get next possible of Firmware File System Header.
371
372 @param ErasePolarity Erase polarity attribute of the firmware volume
373 @param FfsHeader Points to the FFS file header to be skipped.
374
375 @return Pointer to next FFS header.
376
377 **/
378 EFI_PHYSICAL_ADDRESS
379 GetNextPossibleFileHeader (
380 IN UINT8 ErasePolarity,
381 IN EFI_FFS_FILE_HEADER *FfsHeader
382 )
383 {
384 UINT32 FileLength;
385 UINT32 SkipLength;
386
387 if (!IsValidFFSHeader (ErasePolarity, FfsHeader)) {
388 //
389 // Skip this header
390 //
391 return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + sizeof (EFI_FFS_FILE_HEADER);
392 }
393
394 FileLength = *(UINT32 *) FfsHeader->Size & 0x00FFFFFF;
395
396 //
397 // Since FileLength is not multiple of 8, we need skip some bytes
398 // to get next possible header
399 //
400 SkipLength = FileLength;
401 while ((SkipLength & 0x07) != 0) {
402 SkipLength++;
403 }
404
405 return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + SkipLength;
406 }
407
408 /**
409 Search FFS file with the same FFS name in FV Cache.
410
411 @param FvDevice Cached FV image.
412 @param FfsHeader Points to the FFS file header to be skipped.
413 @param StateBit FFS file state bit to be checked.
414
415 @return Pointer to next found FFS header. NULL will return if no found.
416
417 **/
418 EFI_FFS_FILE_HEADER *
419 DuplicateFileExist (
420 IN FV_DEVICE *FvDevice,
421 IN EFI_FFS_FILE_HEADER *FfsHeader,
422 IN EFI_FFS_FILE_STATE StateBit
423 )
424 {
425 UINT8 *Ptr;
426 EFI_FFS_FILE_HEADER *NextFfsFile;
427
428 //
429 // Search duplicate file, not from the beginning of FV,
430 // just search the next ocurrence of this file
431 //
432 NextFfsFile = FfsHeader;
433
434 do {
435 Ptr = (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (
436 GetNextPossibleFileHeader (FvDevice->ErasePolarity,
437 NextFfsFile)
438 );
439 NextFfsFile = (EFI_FFS_FILE_HEADER *) Ptr;
440
441 if ((UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength - Ptr <
442 sizeof (EFI_FFS_FILE_HEADER)
443 ) {
444 break;
445 }
446
447 if (!IsValidFFSHeader (FvDevice->ErasePolarity, NextFfsFile)) {
448 continue;
449 }
450
451 if (!VerifyFileChecksum (NextFfsFile)) {
452 continue;
453 }
454
455 if (CompareGuid (&NextFfsFile->Name, &FfsHeader->Name)) {
456 if (GetFileState (FvDevice->ErasePolarity, NextFfsFile) == StateBit) {
457 return NextFfsFile;
458 }
459 }
460 } while (Ptr < (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength);
461
462 return NULL;
463 }
464
465 /**
466 Change FFS file header state and write to FV.
467
468 @param FvDevice Cached FV image.
469 @param FfsHeader Points to the FFS file header to be updated.
470 @param State FFS file state to be set.
471
472 @retval EFI_SUCCESS File state is writen into FV.
473 @retval others File state can't be writen into FV.
474
475 **/
476 EFI_STATUS
477 UpdateHeaderBit (
478 IN FV_DEVICE *FvDevice,
479 IN EFI_FFS_FILE_HEADER *FfsHeader,
480 IN EFI_FFS_FILE_STATE State
481 )
482 {
483 EFI_STATUS Status;
484 EFI_LBA Lba;
485 UINTN Offset;
486 UINTN NumBytesWritten;
487
488 Lba = 0;
489 Offset = 0;
490
491 SetFileState (State, FfsHeader);
492
493 Buffer2Lba (
494 FvDevice,
495 (EFI_PHYSICAL_ADDRESS) (UINTN) (&FfsHeader->State),
496 &Lba,
497 &Offset
498 );
499 //
500 // Write the state byte into FV
501 //
502 NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
503 Status = FvDevice->Fvb->Write (
504 FvDevice->Fvb,
505 Lba,
506 Offset,
507 &NumBytesWritten,
508 &FfsHeader->State
509 );
510 return Status;
511 }
512
513 /**
514 Check if it's a valid FFS file.
515 Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first.
516
517 @param FvDevice Cached FV image.
518 @param FfsHeader Points to the FFS file to be checked
519
520 @retval TRUE Valid FFS file
521 @retval FALSE Invalid FFS file
522
523 **/
524 BOOLEAN
525 IsValidFFSFile (
526 IN FV_DEVICE *FvDevice,
527 IN EFI_FFS_FILE_HEADER *FfsHeader
528 )
529 {
530 EFI_FFS_FILE_STATE FileState;
531 UINT8 ErasePolarity;
532
533 ErasePolarity = FvDevice->ErasePolarity;
534
535 FileState = GetFileState (ErasePolarity, FfsHeader);
536
537 switch (FileState) {
538 case EFI_FILE_DATA_VALID:
539 if (!VerifyFileChecksum (FfsHeader)) {
540 return FALSE;
541 }
542
543 if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
544 break;
545 }
546 //
547 // Check if there is another duplicated file with the EFI_FILE_DATA_VALID
548 //
549 if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) {
550 return FALSE;
551 }
552
553 break;
554
555 case EFI_FILE_MARKED_FOR_UPDATE:
556 if (!VerifyFileChecksum (FfsHeader)) {
557 return FALSE;
558 }
559
560 if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
561 //
562 // since its data area is not unperturbed, it cannot be reclaimed,
563 // marked it as deleted
564 //
565 UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED);
566 return TRUE;
567
568 } else if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) {
569 //
570 // Here the found file is more recent than this file,
571 // mark it as deleted
572 //
573 UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED);
574 return TRUE;
575
576 } else {
577 return TRUE;
578 }
579
580 break;
581
582 case EFI_FILE_DELETED:
583 if (!VerifyFileChecksum (FfsHeader)) {
584 return FALSE;
585 }
586
587 break;
588
589 default:
590 return FALSE;
591 }
592
593 return TRUE;
594 }
595
596 /**
597 Locate the first file in FV.
598
599 @param FvDevice Cached FV image.
600 @param FirstFile Points to the got first FFS file header.
601
602 @retval EFI_NOT_FOUND No FFS file is found in FV.
603 @retval EFI_SUCCESS The first FFS file is got.
604
605 **/
606 EFI_STATUS
607 FvLocateFirstFile (
608 IN FV_DEVICE *FvDevice,
609 OUT EFI_FFS_FILE_HEADER **FirstFile
610 )
611 {
612 FFS_FILE_LIST_ENTRY *TmpFileList;
613 LIST_ENTRY *Link;
614
615 Link = FvDevice->FfsFileListHeader.ForwardLink;
616
617 if (Link == &FvDevice->FfsFileListHeader) {
618 return EFI_NOT_FOUND;
619 }
620
621 TmpFileList = (FFS_FILE_LIST_ENTRY *) Link;
622 *FirstFile = (EFI_FFS_FILE_HEADER *) TmpFileList->FfsHeader;
623
624 return EFI_SUCCESS;
625 }