1 /** @file 2 * Main file supporting the SEC Phase for Versatile Express 3 * 4 * Copyright (c) 2011-2014, ARM Limited. All rights reserved. 5 * 6 * SPDX-License-Identifier: BSD-2-Clause-Patent 7 * 8 **/ 9 10 #include <Uefi.h> 11 #include <Library/BaseLib.h> 12 #include <Library/BaseMemoryLib.h> 13 #include <Library/DebugLib.h> 14 #include <Library/DebugAgentLib.h> 15 #include <Library/PcdLib.h> 16 #include <Library/PeCoffExtraActionLib.h> 17 #include <Library/PeCoffLib.h> 18 19 #include <Pi/PiFirmwareFile.h> 20 #include <Pi/PiFirmwareVolume.h> 21 22 #define GET_OCCUPIED_SIZE(ActualSize, Alignment) \ 23 (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)) 24 25 26 // Vector Table for Sec Phase 27 VOID 28 DebugAgentVectorTable ( 29 VOID 30 ); 31 32 /** 33 Returns the highest bit set of the State field 34 35 @param ErasePolarity Erase Polarity as defined by EFI_FVB2_ERASE_POLARITY 36 in the Attributes field. 37 @param FfsHeader Pointer to FFS File Header 38 39 40 @retval the highest bit in the State field 41 42 **/ 43 STATIC 44 EFI_FFS_FILE_STATE 45 GetFileState ( 46 IN UINT8 ErasePolarity, 47 IN EFI_FFS_FILE_HEADER *FfsHeader 48 ) 49 { 50 EFI_FFS_FILE_STATE FileState; 51 EFI_FFS_FILE_STATE HighestBit; 52 53 FileState = FfsHeader->State; 54 55 if (ErasePolarity != 0) { 56 FileState = (EFI_FFS_FILE_STATE)~FileState; 57 } 58 59 HighestBit = 0x80; 60 while (HighestBit != 0 && (HighestBit & FileState) == 0) { 61 HighestBit >>= 1; 62 } 63 64 return HighestBit; 65 } 66 67 /** 68 Calculates the checksum of the header of a file. 69 The header is a zero byte checksum, so zero means header is good 70 71 @param FfsHeader Pointer to FFS File Header 72 73 @retval Checksum of the header 74 75 **/ 76 STATIC 77 UINT8 78 CalculateHeaderChecksum ( 79 IN EFI_FFS_FILE_HEADER *FileHeader 80 ) 81 { 82 UINT8 Sum; 83 84 // Calculate the sum of the header 85 Sum = CalculateSum8 ((CONST VOID*)FileHeader,sizeof(EFI_FFS_FILE_HEADER)); 86 87 // State field (since this indicates the different state of file). 88 Sum = (UINT8)(Sum - FileHeader->State); 89 90 // Checksum field of the file is not part of the header checksum. 91 Sum = (UINT8)(Sum - FileHeader->IntegrityCheck.Checksum.File); 92 93 return Sum; 94 } 95 96 EFI_STATUS 97 GetFfsFile ( 98 IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader, 99 IN EFI_FV_FILETYPE FileType, 100 OUT EFI_FFS_FILE_HEADER **FileHeader 101 ) 102 { 103 UINT64 FvLength; 104 UINTN FileOffset; 105 EFI_FFS_FILE_HEADER *FfsFileHeader; 106 UINT8 ErasePolarity; 107 UINT8 FileState; 108 UINT32 FileLength; 109 UINT32 FileOccupiedSize; 110 111 ASSERT (FwVolHeader->Signature == EFI_FVH_SIGNATURE); 112 113 FvLength = FwVolHeader->FvLength; 114 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader + FwVolHeader->HeaderLength); 115 FileOffset = FwVolHeader->HeaderLength; 116 117 if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) { 118 ErasePolarity = 1; 119 } else { 120 ErasePolarity = 0; 121 } 122 123 while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) { 124 // Get FileState which is the highest bit of the State 125 FileState = GetFileState (ErasePolarity, FfsFileHeader); 126 127 switch (FileState) { 128 129 case EFI_FILE_HEADER_INVALID: 130 FileOffset += sizeof(EFI_FFS_FILE_HEADER); 131 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + sizeof(EFI_FFS_FILE_HEADER)); 132 break; 133 134 case EFI_FILE_DATA_VALID: 135 case EFI_FILE_MARKED_FOR_UPDATE: 136 if (CalculateHeaderChecksum (FfsFileHeader) != 0) { 137 ASSERT (FALSE); 138 return EFI_NOT_FOUND; 139 } 140 141 if (FfsFileHeader->Type == FileType) { 142 *FileHeader = FfsFileHeader; 143 return EFI_SUCCESS; 144 } 145 146 FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; 147 FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8); 148 149 FileOffset += FileOccupiedSize; 150 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize); 151 break; 152 153 case EFI_FILE_DELETED: 154 FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; 155 FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8); 156 FileOffset += FileOccupiedSize; 157 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize); 158 break; 159 160 default: 161 return EFI_NOT_FOUND; 162 } 163 } 164 return EFI_NOT_FOUND; 165 } 166 167 EFI_STATUS 168 GetImageContext ( 169 IN EFI_FFS_FILE_HEADER *FfsHeader, 170 OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext 171 ) 172 { 173 EFI_STATUS Status; 174 UINTN ParsedLength; 175 UINTN SectionSize; 176 UINTN SectionLength; 177 EFI_COMMON_SECTION_HEADER *Section; 178 VOID *EfiImage; 179 UINTN ImageAddress; 180 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry; 181 VOID *CodeViewEntryPointer; 182 183 Section = (EFI_COMMON_SECTION_HEADER *)(FfsHeader + 1); 184 SectionSize = *(UINT32 *)(FfsHeader->Size) & 0x00FFFFFF; 185 SectionSize -= sizeof (EFI_FFS_FILE_HEADER); 186 ParsedLength = 0; 187 EfiImage = NULL; 188 189 while (ParsedLength < SectionSize) { 190 if ((Section->Type == EFI_SECTION_PE32) || (Section->Type == EFI_SECTION_TE)) { 191 EfiImage = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(Section + 1); 192 break; 193 } 194 195 // 196 // Size is 24 bits wide so mask upper 8 bits. 197 // SectionLength is adjusted it is 4 byte aligned. 198 // Go to the next section 199 // 200 SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF; 201 SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4); 202 ASSERT (SectionLength != 0); 203 ParsedLength += SectionLength; 204 Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength); 205 } 206 207 if (EfiImage == NULL) { 208 return EFI_NOT_FOUND; 209 } 210 211 // Initialize the Image Context 212 ZeroMem (ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT)); 213 ImageContext->Handle = EfiImage; 214 ImageContext->ImageRead = PeCoffLoaderImageReadFromMemory; 215 216 Status = PeCoffLoaderGetImageInfo (ImageContext); 217 if (!EFI_ERROR(Status) && ((VOID*)(UINTN)ImageContext->DebugDirectoryEntryRva != NULL)) { 218 ImageAddress = ImageContext->ImageAddress; 219 if (ImageContext->IsTeImage) { 220 ImageAddress += sizeof (EFI_TE_IMAGE_HEADER) - ((EFI_TE_IMAGE_HEADER*)EfiImage)->StrippedSize; 221 } 222 223 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(ImageAddress + ImageContext->DebugDirectoryEntryRva); 224 if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { 225 CodeViewEntryPointer = (VOID *) (ImageAddress + (UINTN) DebugEntry->RVA); 226 switch (* (UINT32 *) CodeViewEntryPointer) { 227 case CODEVIEW_SIGNATURE_NB10: 228 ImageContext->PdbPointer = (CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY); 229 break; 230 case CODEVIEW_SIGNATURE_RSDS: 231 ImageContext->PdbPointer = (CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY); 232 break; 233 case CODEVIEW_SIGNATURE_MTOC: 234 ImageContext->PdbPointer = (CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY); 235 break; 236 default: 237 break; 238 } 239 } 240 } 241 242 return Status; 243 } 244 245 /** 246 Initialize debug agent. 247 248 This function is used to set up debug environment to support source level debugging. 249 If certain Debug Agent Library instance has to save some private data in the stack, 250 this function must work on the mode that doesn't return to the caller, then 251 the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one 252 function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is 253 responsible to invoke the passing-in function at the end of InitializeDebugAgent(). 254 255 If the parameter Function is not NULL, Debug Agent Library instance will invoke it by 256 passing in the Context to be its parameter. 257 258 If Function() is NULL, Debug Agent Library instance will return after setup debug 259 environment. 260 261 @param[in] InitFlag Init flag is used to decide the initialize process. 262 @param[in] Context Context needed according to InitFlag; it was optional. 263 @param[in] Function Continue function called by debug agent library; it was 264 optional. 265 266 **/ 267 VOID 268 EFIAPI 269 InitializeDebugAgent ( 270 IN UINT32 InitFlag, 271 IN VOID *Context, OPTIONAL 272 IN DEBUG_AGENT_CONTINUE Function OPTIONAL 273 ) 274 { 275 EFI_STATUS Status; 276 EFI_FFS_FILE_HEADER *FfsHeader; 277 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; 278 279 // We use InitFlag to know if DebugAgent has been initialized from 280 // Sec (DEBUG_AGENT_INIT_PREMEM_SEC) or PrePi (DEBUG_AGENT_INIT_POSTMEM_SEC) 281 // modules 282 if (InitFlag == DEBUG_AGENT_INIT_PREMEM_SEC) { 283 // 284 // Get the Sec or PrePeiCore module (defined as SEC type module) 285 // 286 Status = GetFfsFile ((EFI_FIRMWARE_VOLUME_HEADER*)(UINTN)PcdGet64 (PcdSecureFvBaseAddress), EFI_FV_FILETYPE_SECURITY_CORE, &FfsHeader); 287 if (!EFI_ERROR(Status)) { 288 Status = GetImageContext (FfsHeader,&ImageContext); 289 if (!EFI_ERROR(Status)) { 290 PeCoffLoaderRelocateImageExtraAction (&ImageContext); 291 } 292 } 293 } else if (InitFlag == DEBUG_AGENT_INIT_POSTMEM_SEC) { 294 // 295 // Get the PrePi or PrePeiCore module (defined as SEC type module) 296 // 297 Status = GetFfsFile ((EFI_FIRMWARE_VOLUME_HEADER*)(UINTN)PcdGet64 (PcdFvBaseAddress), EFI_FV_FILETYPE_SECURITY_CORE, &FfsHeader); 298 if (!EFI_ERROR(Status)) { 299 Status = GetImageContext (FfsHeader,&ImageContext); 300 if (!EFI_ERROR(Status)) { 301 PeCoffLoaderRelocateImageExtraAction (&ImageContext); 302 } 303 } 304 305 // 306 // Get the PeiCore module (defined as PEI_CORE type module) 307 // 308 Status = GetFfsFile ((EFI_FIRMWARE_VOLUME_HEADER*)(UINTN)PcdGet64 (PcdFvBaseAddress), EFI_FV_FILETYPE_PEI_CORE, &FfsHeader); 309 if (!EFI_ERROR(Status)) { 310 Status = GetImageContext (FfsHeader,&ImageContext); 311 if (!EFI_ERROR(Status)) { 312 PeCoffLoaderRelocateImageExtraAction (&ImageContext); 313 } 314 } 315 } 316 } 317 318 /** 319 Enable/Disable the interrupt of debug timer and return the interrupt state 320 prior to the operation. 321 322 If EnableStatus is TRUE, enable the interrupt of debug timer. 323 If EnableStatus is FALSE, disable the interrupt of debug timer. 324 325 @param[in] EnableStatus Enable/Disable. 326 327 @return FALSE always. 328 329 **/ 330 BOOLEAN 331 EFIAPI 332 SaveAndSetDebugTimerInterrupt ( 333 IN BOOLEAN EnableStatus 334 ) 335 { 336 return FALSE; 337 } 338 339