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