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