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
GetFileState(IN UINT8 ErasePolarity,IN EFI_FFS_FILE_HEADER * FfsHeader)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
CalculateHeaderChecksum(IN EFI_FFS_FILE_HEADER * FileHeader)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
GetFfsFile(IN EFI_FIRMWARE_VOLUME_HEADER * FwVolHeader,IN EFI_FV_FILETYPE FileType,OUT EFI_FFS_FILE_HEADER ** FileHeader)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
GetImageContext(IN EFI_FFS_FILE_HEADER * FfsHeader,OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)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
InitializeDebugAgent(IN UINT32 InitFlag,IN VOID * Context,OPTIONAL IN DEBUG_AGENT_CONTINUE Function OPTIONAL)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
SaveAndSetDebugTimerInterrupt(IN BOOLEAN EnableStatus)332 SaveAndSetDebugTimerInterrupt (
333   IN BOOLEAN                EnableStatus
334   )
335 {
336   return FALSE;
337 }
338 
339