3 Copyright (c) 2008-2009, Apple Inc. All rights reserved.
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 EFI_DEBUG_IMAGE_INFO_TABLE_HEADER
*gDebugImageTableHeader
= NULL
;
20 ExceptionHandlersStart (
25 ExceptionHandlersEnd (
30 CommonExceptionEntry (
35 AsmCommonExceptionEntry (
40 EFI_EXCEPTION_CALLBACK gExceptionHandlers
[MAX_ARM_EXCEPTION
+ 1];
41 EFI_EXCEPTION_CALLBACK gDebuggerExceptionHandlers
[MAX_ARM_EXCEPTION
+ 1];
46 This function registers and enables the handler specified by InterruptHandler for a processor
47 interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
48 handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
49 The installed handler is called once for each processor interrupt or exception.
51 @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
52 are enabled and FALSE if interrupts are disabled.
53 @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
54 when a processor interrupt occurs. If this parameter is NULL, then the handler
57 @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
58 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
60 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
62 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
66 RegisterInterruptHandler (
67 IN EFI_EXCEPTION_TYPE InterruptType
,
68 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
71 if (InterruptType
> MAX_ARM_EXCEPTION
) {
72 return EFI_UNSUPPORTED
;
75 if ((InterruptHandler
!= NULL
) && (gExceptionHandlers
[InterruptType
] != NULL
)) {
76 return EFI_ALREADY_STARTED
;
79 gExceptionHandlers
[InterruptType
] = InterruptHandler
;
86 This function registers and enables the handler specified by InterruptHandler for a processor
87 interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
88 handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
89 The installed handler is called once for each processor interrupt or exception.
91 @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
92 are enabled and FALSE if interrupts are disabled.
93 @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
94 when a processor interrupt occurs. If this parameter is NULL, then the handler
97 @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
98 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
100 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
101 previously installed.
102 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
106 RegisterDebuggerInterruptHandler (
107 IN EFI_EXCEPTION_TYPE InterruptType
,
108 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
111 if (InterruptType
> MAX_ARM_EXCEPTION
) {
112 return EFI_UNSUPPORTED
;
115 if ((InterruptHandler
!= NULL
) && (gDebuggerExceptionHandlers
[InterruptType
] != NULL
)) {
116 return EFI_ALREADY_STARTED
;
119 gDebuggerExceptionHandlers
[InterruptType
] = InterruptHandler
;
129 IN UINT32 FaultAddress
,
130 OUT UINT32
*ImageBase
,
131 OUT UINT32
*PeCoffSizeOfHeaders
134 EFI_DEBUG_IMAGE_INFO
*DebugTable
;
139 DebugTable
= gDebugImageTableHeader
->EfiDebugImageInfoTable
;
140 if (DebugTable
== NULL
) {
144 Address
= (CHAR8
*)(UINTN
)FaultAddress
;
145 for (Entry
= 0; Entry
< gDebugImageTableHeader
->TableSize
; Entry
++, DebugTable
++) {
146 if (DebugTable
->NormalImage
!= NULL
) {
147 if ((DebugTable
->NormalImage
->ImageInfoType
== EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL
) &&
148 (DebugTable
->NormalImage
->LoadedImageProtocolInstance
!= NULL
)) {
149 if ((Address
>= (CHAR8
*)DebugTable
->NormalImage
->LoadedImageProtocolInstance
->ImageBase
) &&
150 (Address
<= ((CHAR8
*)DebugTable
->NormalImage
->LoadedImageProtocolInstance
->ImageBase
+ DebugTable
->NormalImage
->LoadedImageProtocolInstance
->ImageSize
))) {
151 *ImageBase
= (UINT32
)DebugTable
->NormalImage
->LoadedImageProtocolInstance
->ImageBase
;
152 *PeCoffSizeOfHeaders
= PeCoffGetSizeOfHeaders ((VOID
*)(UINTN
)*ImageBase
);
153 return PeCoffLoaderGetPdbPointer (DebugTable
->NormalImage
->LoadedImageProtocolInstance
->ImageBase
);
163 CHAR8
*gExceptionTypeString
[] = {
165 "Undefined Instruction",
176 CommonCExceptionHandler (
177 IN EFI_EXCEPTION_TYPE ExceptionType
,
178 IN OUT EFI_SYSTEM_CONTEXT SystemContext
181 BOOLEAN Dispatched
= FALSE
;
184 if (ExceptionType
<= MAX_ARM_EXCEPTION
) {
185 if (gDebuggerExceptionHandlers
[ExceptionType
]) {
187 // If DebugSupport hooked the interrupt call the handler. This does not disable
188 // the normal handler.
190 gDebuggerExceptionHandlers
[ExceptionType
] (ExceptionType
, SystemContext
);
193 if (gExceptionHandlers
[ExceptionType
]) {
194 gExceptionHandlers
[ExceptionType
] (ExceptionType
, SystemContext
);
198 DEBUG ((EFI_D_ERROR
, "Unknown exception type %d from %08x\n", ExceptionType
, SystemContext
.SystemContextArm
->PC
));
204 // We did work so this was an expected ExceptionType
209 if (ExceptionType
== EXCEPT_ARM_SOFTWARE_INTERRUPT
) {
211 // ARM JTAG debuggers some times use this vector, so it is not an error to get one
217 // Code after here is the default exception handler... Dump the context
219 DEBUG ((EFI_D_ERROR
, "\n%a Exception from instruction at 0x%08x CPSR 0x%08x\n", gExceptionTypeString
[ExceptionType
], SystemContext
.SystemContextArm
->PC
, SystemContext
.SystemContextArm
->CPSR
));
223 UINT32 PeCoffSizeOfHeader
;
226 Pdb
= GetImageName (SystemContext
.SystemContextArm
->PC
, &ImageBase
, &PeCoffSizeOfHeader
);
227 Offset
= SystemContext
.SystemContextArm
->PC
- ImageBase
;
229 DEBUG ((EFI_D_ERROR
, "%a\n", Pdb
));
232 // A PE/COFF image loads its headers into memory so the headers are
233 // included in the linked addressess. ELF and Mach-O images do not
234 // include the headers so the first byte of the image is usually
235 // text (code). If you look at link maps from ELF or Mach-O images
236 // you need to subtact out the size of the PE/COFF header to get
237 // get the offset that matches the link map.
239 DEBUG ((EFI_D_ERROR
, "loadded at 0x%08x (PE/COFF offset) 0x%08x (ELF or Mach-O offset) 0x%08x\n", ImageBase
, Offset
, Offset
- PeCoffSizeOfHeader
));
242 DEBUG ((EFI_D_ERROR
, " R0 0x%08x R1 0x%08x R2 0x%08x R3 0x%08x\n", SystemContext
.SystemContextArm
->R0
, SystemContext
.SystemContextArm
->R1
, SystemContext
.SystemContextArm
->R2
, SystemContext
.SystemContextArm
->R3
));
243 DEBUG ((EFI_D_ERROR
, " R4 0x%08x R5 0x%08x R6 0x%08x R7 0x%08x\n", SystemContext
.SystemContextArm
->R4
, SystemContext
.SystemContextArm
->R5
, SystemContext
.SystemContextArm
->R6
, SystemContext
.SystemContextArm
->R7
));
244 DEBUG ((EFI_D_ERROR
, " R8 0x%08x R9 0x%08x R10 0x%08x R11 0x%08x\n", SystemContext
.SystemContextArm
->R8
, SystemContext
.SystemContextArm
->R9
, SystemContext
.SystemContextArm
->R10
, SystemContext
.SystemContextArm
->R11
));
245 DEBUG ((EFI_D_ERROR
, "R12 0x%08x SP 0x%08x LR 0x%08x PC 0x%08x\n", SystemContext
.SystemContextArm
->R12
, SystemContext
.SystemContextArm
->SP
, SystemContext
.SystemContextArm
->LR
, SystemContext
.SystemContextArm
->PC
));
246 DEBUG ((EFI_D_ERROR
, "DFSR 0x%08x DFAR 0x%08x IFSR 0x%08x IFAR 0x%08x\n\n", SystemContext
.SystemContextArm
->DFSR
, SystemContext
.SystemContextArm
->DFAR
, SystemContext
.SystemContextArm
->IFSR
, SystemContext
.SystemContextArm
->IFAR
));
257 InitializeExceptions (
258 IN EFI_CPU_ARCH_PROTOCOL
*Cpu
266 EFI_PHYSICAL_ADDRESS Base
;
268 Status
= EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid
, (VOID
**)&gDebugImageTableHeader
);
269 if (EFI_ERROR (Status
)) {
270 gDebugImageTableHeader
= NULL
;
274 // Disable interrupts
276 Cpu
->GetInterruptState (Cpu
, &Enabled
);
277 Cpu
->DisableInterrupt (Cpu
);
280 // Initialize the C entry points for interrupts
282 for (Index
= 0; Index
<= MAX_ARM_EXCEPTION
; Index
++) {
283 Status
= RegisterInterruptHandler (Index
, NULL
);
284 ASSERT_EFI_ERROR (Status
);
286 Status
= RegisterDebuggerInterruptHandler (Index
, NULL
);
287 ASSERT_EFI_ERROR (Status
);
291 // Copy an implementation of the ARM exception vectors to PcdCpuVectorBaseAddress.
293 Length
= (UINTN
)ExceptionHandlersEnd
- (UINTN
)ExceptionHandlersStart
;
296 // Reserve space for the exception handlers
298 Base
= (EFI_PHYSICAL_ADDRESS
)PcdGet32 (PcdCpuVectorBaseAddress
);
299 Status
= gBS
->AllocatePages (AllocateAddress
, EfiBootServicesCode
, EFI_SIZE_TO_PAGES (Length
), &Base
);
300 // If the request was for memory that's not in the memory map (which is often the case for 0x00000000
301 // on embedded systems, for example, we don't want to hang up. So we'll check here for a status of
302 // EFI_NOT_FOUND, and continue in that case.
303 if (EFI_ERROR(Status
) && (Status
!= EFI_NOT_FOUND
)) {
304 ASSERT_EFI_ERROR (Status
);
307 CopyMem ((VOID
*)(UINTN
)PcdGet32 (PcdCpuVectorBaseAddress
), (VOID
*)ExceptionHandlersStart
, Length
);
310 // Patch in the common Assembly exception handler
312 Offset
= (UINTN
)CommonExceptionEntry
- (UINTN
)ExceptionHandlersStart
;
313 *(UINTN
*) ((UINT8
*)(UINTN
)PcdGet32 (PcdCpuVectorBaseAddress
) + Offset
) = (UINTN
)AsmCommonExceptionEntry
;
315 // Flush Caches since we updated executable stuff
316 InvalidateInstructionCacheRange ((VOID
*)PcdGet32(PcdCpuVectorBaseAddress
), Length
);
320 // Restore interrupt state
322 Status
= Cpu
->EnableInterrupt (Cpu
);