| 1 | /*++\r |
| 2 | \r |
| 3 | Copyright (c) 2006, Intel Corporation \r |
| 4 | All rights reserved. This program and the accompanying materials \r |
| 5 | are licensed and made available under the terms and conditions of the BSD License \r |
| 6 | which accompanies this distribution. The full text of the license may be found at \r |
| 7 | http://opensource.org/licenses/bsd-license.php \r |
| 8 | \r |
| 9 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r |
| 10 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r |
| 11 | \r |
| 12 | Module Name:\r |
| 13 | \r |
| 14 | FwVol.c\r |
| 15 | \r |
| 16 | Abstract:\r |
| 17 | \r |
| 18 | Pei Core Firmware File System service routines.\r |
| 19 | \r |
| 20 | --*/\r |
| 21 | \r |
| 22 | #include <PeiMain.h>\r |
| 23 | \r |
| 24 | #define GETOCCUPIEDSIZE(ActualSize, Alignment) \\r |
| 25 | (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1))\r |
| 26 | \r |
| 27 | STATIC\r |
| 28 | EFI_FFS_FILE_STATE\r |
| 29 | GetFileState(\r |
| 30 | IN UINT8 ErasePolarity,\r |
| 31 | IN EFI_FFS_FILE_HEADER *FfsHeader\r |
| 32 | )\r |
| 33 | /*++\r |
| 34 | \r |
| 35 | Routine Description:\r |
| 36 | \r |
| 37 | Returns the highest bit set of the State field\r |
| 38 | \r |
| 39 | Arguments:\r |
| 40 | \r |
| 41 | ErasePolarity - Erase Polarity as defined by EFI_FVB_ERASE_POLARITY\r |
| 42 | in the Attributes field.\r |
| 43 | FfsHeader - Pointer to FFS File Header.\r |
| 44 | \r |
| 45 | Returns:\r |
| 46 | Returns the highest bit in the State field\r |
| 47 | \r |
| 48 | --*/\r |
| 49 | {\r |
| 50 | EFI_FFS_FILE_STATE FileState;\r |
| 51 | EFI_FFS_FILE_STATE HighestBit;\r |
| 52 | \r |
| 53 | FileState = FfsHeader->State;\r |
| 54 | \r |
| 55 | if (ErasePolarity != 0) {\r |
| 56 | FileState = (EFI_FFS_FILE_STATE)~FileState;\r |
| 57 | }\r |
| 58 | \r |
| 59 | HighestBit = 0x80;\r |
| 60 | while (HighestBit != 0 && (HighestBit & FileState) == 0) {\r |
| 61 | HighestBit >>= 1;\r |
| 62 | }\r |
| 63 | \r |
| 64 | return HighestBit;\r |
| 65 | } \r |
| 66 | \r |
| 67 | STATIC\r |
| 68 | UINT8\r |
| 69 | CalculateHeaderChecksum (\r |
| 70 | IN EFI_FFS_FILE_HEADER *FileHeader\r |
| 71 | )\r |
| 72 | /*++\r |
| 73 | \r |
| 74 | Routine Description:\r |
| 75 | \r |
| 76 | Calculates the checksum of the header of a file.\r |
| 77 | \r |
| 78 | Arguments:\r |
| 79 | \r |
| 80 | FileHeader - Pointer to FFS File Header.\r |
| 81 | \r |
| 82 | Returns:\r |
| 83 | Checksum of the header.\r |
| 84 | \r |
| 85 | The header is zero byte checksum.\r |
| 86 | - Zero means the header is good.\r |
| 87 | - Non-zero means the header is bad.\r |
| 88 | \r |
| 89 | \r |
| 90 | Bugbug: For PEI performance reason, we comments this code at this time.\r |
| 91 | --*/\r |
| 92 | {\r |
| 93 | UINT8 *ptr;\r |
| 94 | UINTN Index;\r |
| 95 | UINT8 Sum;\r |
| 96 | \r |
| 97 | Sum = 0;\r |
| 98 | ptr = (UINT8 *)FileHeader;\r |
| 99 | \r |
| 100 | for (Index = 0; Index < sizeof(EFI_FFS_FILE_HEADER) - 3; Index += 4) {\r |
| 101 | Sum = (UINT8)(Sum + ptr[Index]);\r |
| 102 | Sum = (UINT8)(Sum + ptr[Index+1]);\r |
| 103 | Sum = (UINT8)(Sum + ptr[Index+2]);\r |
| 104 | Sum = (UINT8)(Sum + ptr[Index+3]);\r |
| 105 | }\r |
| 106 | \r |
| 107 | for (; Index < sizeof(EFI_FFS_FILE_HEADER); Index++) {\r |
| 108 | Sum = (UINT8)(Sum + ptr[Index]);\r |
| 109 | }\r |
| 110 | \r |
| 111 | //\r |
| 112 | // State field (since this indicates the different state of file). \r |
| 113 | //\r |
| 114 | Sum = (UINT8)(Sum - FileHeader->State);\r |
| 115 | //\r |
| 116 | // Checksum field of the file is not part of the header checksum.\r |
| 117 | //\r |
| 118 | Sum = (UINT8)(Sum - FileHeader->IntegrityCheck.Checksum.File);\r |
| 119 | \r |
| 120 | return Sum;\r |
| 121 | }\r |
| 122 | \r |
| 123 | STATIC\r |
| 124 | EFI_STATUS\r |
| 125 | PeiFfsFindNextFileEx (\r |
| 126 | IN EFI_FV_FILETYPE SearchType,\r |
| 127 | IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader,\r |
| 128 | IN OUT EFI_FFS_FILE_HEADER **FileHeader,\r |
| 129 | IN BOOLEAN Flag\r |
| 130 | )\r |
| 131 | /*++\r |
| 132 | \r |
| 133 | Routine Description:\r |
| 134 | Given the input file pointer, search for the next matching file in the\r |
| 135 | FFS volume as defined by SearchType. The search starts from FileHeader inside\r |
| 136 | the Firmware Volume defined by FwVolHeader.\r |
| 137 | \r |
| 138 | Arguments:\r |
| 139 | PeiServices - Pointer to the PEI Core Services Table.\r |
| 140 | SearchType - Filter to find only files of this type.\r |
| 141 | Type EFI_FV_FILETYPE_ALL causes no filtering to be done.\r |
| 142 | FwVolHeader - Pointer to the FV header of the volume to search.\r |
| 143 | This parameter must point to a valid FFS volume.\r |
| 144 | FileHeader - Pointer to the current file from which to begin searching.\r |
| 145 | This pointer will be updated upon return to reflect the file found.\r |
| 146 | Flag - Indicator for if this is for PEI Dispath search \r |
| 147 | Returns:\r |
| 148 | EFI_NOT_FOUND - No files matching the search criteria were found\r |
| 149 | EFI_SUCCESS\r |
| 150 | \r |
| 151 | --*/\r |
| 152 | {\r |
| 153 | EFI_FFS_FILE_HEADER *FfsFileHeader;\r |
| 154 | UINT32 FileLength;\r |
| 155 | UINT32 FileOccupiedSize;\r |
| 156 | UINT32 FileOffset;\r |
| 157 | UINT64 FvLength;\r |
| 158 | UINT8 ErasePolarity;\r |
| 159 | UINT8 FileState;\r |
| 160 | \r |
| 161 | \r |
| 162 | FvLength = FwVolHeader->FvLength;\r |
| 163 | if (FwVolHeader->Attributes & EFI_FVB_ERASE_POLARITY) {\r |
| 164 | ErasePolarity = 1;\r |
| 165 | } else {\r |
| 166 | ErasePolarity = 0;\r |
| 167 | }\r |
| 168 | \r |
| 169 | //\r |
| 170 | // If FileHeader is not specified (NULL) start with the first file in the\r |
| 171 | // firmware volume. Otherwise, start from the FileHeader.\r |
| 172 | //\r |
| 173 | if (*FileHeader == NULL) {\r |
| 174 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader + FwVolHeader->HeaderLength);\r |
| 175 | } else {\r |
| 176 | //\r |
| 177 | // Length is 24 bits wide so mask upper 8 bits\r |
| 178 | // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned.\r |
| 179 | //\r |
| 180 | FileLength = *(UINT32 *)(*FileHeader)->Size & 0x00FFFFFF;\r |
| 181 | FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8);\r |
| 182 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize);\r |
| 183 | }\r |
| 184 | \r |
| 185 | FileOffset = (UINT32) ((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader);\r |
| 186 | ASSERT (FileOffset <= 0xFFFFFFFF);\r |
| 187 | \r |
| 188 | while (FileOffset < (FvLength - sizeof(EFI_FFS_FILE_HEADER))) {\r |
| 189 | //\r |
| 190 | // Get FileState which is the highest bit of the State \r |
| 191 | //\r |
| 192 | FileState = GetFileState (ErasePolarity, FfsFileHeader);\r |
| 193 | \r |
| 194 | switch (FileState) {\r |
| 195 | \r |
| 196 | case EFI_FILE_HEADER_INVALID:\r |
| 197 | FileOffset += sizeof(EFI_FFS_FILE_HEADER);\r |
| 198 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + sizeof(EFI_FFS_FILE_HEADER));\r |
| 199 | break;\r |
| 200 | \r |
| 201 | case EFI_FILE_DATA_VALID:\r |
| 202 | case EFI_FILE_MARKED_FOR_UPDATE:\r |
| 203 | if (CalculateHeaderChecksum (FfsFileHeader) == 0) {\r |
| 204 | FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;\r |
| 205 | FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8);\r |
| 206 | if (Flag) {\r |
| 207 | if ((FfsFileHeader->Type == EFI_FV_FILETYPE_PEIM) || \r |
| 208 | (FfsFileHeader->Type == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER)) { \r |
| 209 | \r |
| 210 | *FileHeader = FfsFileHeader;\r |
| 211 | \r |
| 212 | \r |
| 213 | return EFI_SUCCESS;\r |
| 214 | }\r |
| 215 | } else { \r |
| 216 | if ((SearchType == FfsFileHeader->Type) || \r |
| 217 | (SearchType == EFI_FV_FILETYPE_ALL)) { \r |
| 218 | \r |
| 219 | *FileHeader = FfsFileHeader;\r |
| 220 | \r |
| 221 | \r |
| 222 | return EFI_SUCCESS;\r |
| 223 | }\r |
| 224 | }\r |
| 225 | \r |
| 226 | FileOffset += FileOccupiedSize; \r |
| 227 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);\r |
| 228 | } else {\r |
| 229 | ASSERT (FALSE);\r |
| 230 | return EFI_NOT_FOUND;\r |
| 231 | }\r |
| 232 | break;\r |
| 233 | \r |
| 234 | case EFI_FILE_DELETED:\r |
| 235 | FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;\r |
| 236 | FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8);\r |
| 237 | FileOffset += FileOccupiedSize;\r |
| 238 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);\r |
| 239 | break;\r |
| 240 | \r |
| 241 | default:\r |
| 242 | return EFI_NOT_FOUND;\r |
| 243 | \r |
| 244 | } \r |
| 245 | }\r |
| 246 | \r |
| 247 | return EFI_NOT_FOUND; \r |
| 248 | }\r |
| 249 | \r |
| 250 | \r |
| 251 | EFI_STATUS\r |
| 252 | EFIAPI\r |
| 253 | PeiFfsFindSectionData (\r |
| 254 | IN EFI_PEI_SERVICES **PeiServices,\r |
| 255 | IN EFI_SECTION_TYPE SectionType,\r |
| 256 | IN EFI_FFS_FILE_HEADER *FfsFileHeader,\r |
| 257 | IN OUT VOID **SectionData\r |
| 258 | )\r |
| 259 | /*++\r |
| 260 | \r |
| 261 | Routine Description:\r |
| 262 | Given the input file pointer, search for the next matching section in the\r |
| 263 | FFS volume.\r |
| 264 | \r |
| 265 | Arguments:\r |
| 266 | PeiServices - Pointer to the PEI Core Services Table.\r |
| 267 | SearchType - Filter to find only sections of this type.\r |
| 268 | FfsFileHeader - Pointer to the current file to search.\r |
| 269 | SectionData - Pointer to the Section matching SectionType in FfsFileHeader.\r |
| 270 | - NULL if section not found\r |
| 271 | \r |
| 272 | Returns:\r |
| 273 | EFI_NOT_FOUND - No files matching the search criteria were found\r |
| 274 | EFI_SUCCESS\r |
| 275 | \r |
| 276 | --*/\r |
| 277 | {\r |
| 278 | UINT32 FileSize;\r |
| 279 | EFI_COMMON_SECTION_HEADER *Section;\r |
| 280 | UINT32 SectionLength;\r |
| 281 | UINT32 ParsedLength;\r |
| 282 | \r |
| 283 | \r |
| 284 | //\r |
| 285 | // Size is 24 bits wide so mask upper 8 bits. \r |
| 286 | // Does not include FfsFileHeader header size\r |
| 287 | // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.\r |
| 288 | //\r |
| 289 | Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1);\r |
| 290 | FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;\r |
| 291 | FileSize -= sizeof(EFI_FFS_FILE_HEADER);\r |
| 292 | \r |
| 293 | *SectionData = NULL;\r |
| 294 | ParsedLength = 0;\r |
| 295 | while (ParsedLength < FileSize) {\r |
| 296 | if (Section->Type == SectionType) {\r |
| 297 | *SectionData = (VOID *)(Section + 1);\r |
| 298 | \r |
| 299 | \r |
| 300 | return EFI_SUCCESS;\r |
| 301 | }\r |
| 302 | //\r |
| 303 | // Size is 24 bits wide so mask upper 8 bits. \r |
| 304 | // SectionLength is adjusted it is 4 byte aligned.\r |
| 305 | // Go to the next section\r |
| 306 | //\r |
| 307 | SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF;\r |
| 308 | SectionLength = GETOCCUPIEDSIZE (SectionLength, 4);\r |
| 309 | ASSERT (SectionLength != 0);\r |
| 310 | ParsedLength += SectionLength;\r |
| 311 | Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);\r |
| 312 | }\r |
| 313 | \r |
| 314 | return EFI_NOT_FOUND;\r |
| 315 | \r |
| 316 | }\r |
| 317 | \r |
| 318 | \r |
| 319 | EFI_STATUS\r |
| 320 | FindNextPeim (\r |
| 321 | IN EFI_PEI_SERVICES **PeiServices,\r |
| 322 | IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader,\r |
| 323 | IN OUT EFI_FFS_FILE_HEADER **PeimFileHeader\r |
| 324 | )\r |
| 325 | /*++\r |
| 326 | \r |
| 327 | Routine Description:\r |
| 328 | Given the input file pointer, search for the next matching file in the\r |
| 329 | FFS volume. The search starts from FileHeader inside\r |
| 330 | the Firmware Volume defined by FwVolHeader.\r |
| 331 | \r |
| 332 | Arguments:\r |
| 333 | PeiServices - Pointer to the PEI Core Services Table.\r |
| 334 | \r |
| 335 | FwVolHeader - Pointer to the FV header of the volume to search.\r |
| 336 | This parameter must point to a valid FFS volume.\r |
| 337 | \r |
| 338 | PeimFileHeader - Pointer to the current file from which to begin searching.\r |
| 339 | This pointer will be updated upon return to reflect the file found.\r |
| 340 | \r |
| 341 | Returns:\r |
| 342 | EFI_NOT_FOUND - No files matching the search criteria were found\r |
| 343 | EFI_SUCCESS\r |
| 344 | \r |
| 345 | --*/\r |
| 346 | {\r |
| 347 | return PeiFfsFindNextFileEx ( \r |
| 348 | 0,\r |
| 349 | FwVolHeader,\r |
| 350 | PeimFileHeader,\r |
| 351 | TRUE\r |
| 352 | );\r |
| 353 | }\r |
| 354 | \r |
| 355 | EFI_STATUS\r |
| 356 | EFIAPI\r |
| 357 | PeiFfsFindNextFile (\r |
| 358 | IN EFI_PEI_SERVICES **PeiServices,\r |
| 359 | IN EFI_FV_FILETYPE SearchType,\r |
| 360 | IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader,\r |
| 361 | IN OUT EFI_FFS_FILE_HEADER **FileHeader\r |
| 362 | )\r |
| 363 | /*++\r |
| 364 | \r |
| 365 | Routine Description:\r |
| 366 | Given the input file pointer, search for the next matching file in the\r |
| 367 | FFS volume as defined by SearchType. The search starts from FileHeader inside\r |
| 368 | the Firmware Volume defined by FwVolHeader.\r |
| 369 | \r |
| 370 | Arguments:\r |
| 371 | PeiServices - Pointer to the PEI Core Services Table.\r |
| 372 | \r |
| 373 | SearchType - Filter to find only files of this type.\r |
| 374 | Type EFI_FV_FILETYPE_ALL causes no filtering to be done.\r |
| 375 | \r |
| 376 | FwVolHeader - Pointer to the FV header of the volume to search.\r |
| 377 | This parameter must point to a valid FFS volume.\r |
| 378 | \r |
| 379 | FileHeader - Pointer to the current file from which to begin searching.\r |
| 380 | This pointer will be updated upon return to reflect the file found.\r |
| 381 | \r |
| 382 | Returns:\r |
| 383 | EFI_NOT_FOUND - No files matching the search criteria were found\r |
| 384 | EFI_SUCCESS\r |
| 385 | \r |
| 386 | --*/\r |
| 387 | {\r |
| 388 | return PeiFfsFindNextFileEx ( \r |
| 389 | SearchType,\r |
| 390 | FwVolHeader,\r |
| 391 | FileHeader,\r |
| 392 | FALSE\r |
| 393 | );\r |
| 394 | }\r |
| 395 | \r |
| 396 | EFI_STATUS \r |
| 397 | EFIAPI\r |
| 398 | PeiFvFindNextVolume (\r |
| 399 | IN EFI_PEI_SERVICES **PeiServices,\r |
| 400 | IN UINTN Instance,\r |
| 401 | IN OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader\r |
| 402 | )\r |
| 403 | /*++\r |
| 404 | \r |
| 405 | Routine Description:\r |
| 406 | \r |
| 407 | Return the BFV location\r |
| 408 | \r |
| 409 | BugBug -- Move this to the location of this code to where the\r |
| 410 | other FV and FFS support code lives.\r |
| 411 | Also, update to use FindFV for instances #'s >= 1.\r |
| 412 | \r |
| 413 | Arguments:\r |
| 414 | \r |
| 415 | PeiServices - The PEI core services table.\r |
| 416 | Instance - Instance of FV to find\r |
| 417 | FwVolHeader - Pointer to contain the data to return\r |
| 418 | \r |
| 419 | Returns:\r |
| 420 | Pointer to the Firmware Volume instance requested\r |
| 421 | \r |
| 422 | EFI_INVALID_PARAMETER - FwVolHeader is NULL\r |
| 423 | \r |
| 424 | EFI_SUCCESS - Firmware volume instance successfully found.\r |
| 425 | \r |
| 426 | --*/\r |
| 427 | {\r |
| 428 | PEI_CORE_INSTANCE *PrivateData;\r |
| 429 | EFI_STATUS Status;\r |
| 430 | EFI_PEI_FIND_FV_PPI *FindFvPpi;\r |
| 431 | UINT8 LocalInstance;\r |
| 432 | \r |
| 433 | \r |
| 434 | LocalInstance = (UINT8) Instance;\r |
| 435 | \r |
| 436 | Status = EFI_SUCCESS;\r |
| 437 | PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);\r |
| 438 | \r |
| 439 | if (FwVolHeader == NULL) {\r |
| 440 | \r |
| 441 | return EFI_INVALID_PARAMETER;\r |
| 442 | }\r |
| 443 | \r |
| 444 | if (Instance == 0) {\r |
| 445 | *FwVolHeader = PrivateData->DispatchData.BootFvAddress;\r |
| 446 | \r |
| 447 | \r |
| 448 | return Status;\r |
| 449 | } else {\r |
| 450 | //\r |
| 451 | // Locate all instances of FindFV\r |
| 452 | // Alternately, could use FV HOBs, but the PPI is cleaner\r |
| 453 | //\r |
| 454 | Status = PeiServicesLocatePpi (\r |
| 455 | &gEfiFindFvPpiGuid,\r |
| 456 | 0,\r |
| 457 | NULL,\r |
| 458 | (VOID **)&FindFvPpi\r |
| 459 | );\r |
| 460 | \r |
| 461 | if (Status != EFI_SUCCESS) {\r |
| 462 | Status = EFI_NOT_FOUND;\r |
| 463 | } else {\r |
| 464 | Status = FindFvPpi->FindFv (\r |
| 465 | FindFvPpi,\r |
| 466 | PeiServices,\r |
| 467 | &LocalInstance,\r |
| 468 | FwVolHeader\r |
| 469 | ); \r |
| 470 | \r |
| 471 | }\r |
| 472 | }\r |
| 473 | return Status;\r |
| 474 | }\r |