]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Drivers/CpuDxe/ArmV6/Exception.c
ARM Packages: Removed trailing spaces
[mirror_edk2.git] / ArmPkg / Drivers / CpuDxe / ArmV6 / Exception.c
CommitLineData
2ef2b01e
A
1/** @file\r
2\r
d6ebcab7 3 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
6defc4db 4 Copyright (c) 2014, ARM Limited. All rights reserved.<BR>\r
3402aac7 5\r
d6ebcab7 6 This program and the accompanying materials\r
2ef2b01e
A
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
3402aac7 16#include "CpuDxe.h"\r
f659880b 17\r
1bfda055 18//FIXME: Will not compile on non-ARMv7 builds\r
19#include <Chipset/ArmV7.h>\r
2ef2b01e
A
20\r
21VOID\r
22ExceptionHandlersStart (\r
23 VOID\r
24 );\r
25\r
26VOID\r
27ExceptionHandlersEnd (\r
28 VOID\r
29 );\r
30\r
31VOID\r
32CommonExceptionEntry (\r
33 VOID\r
34 );\r
35\r
36VOID\r
37AsmCommonExceptionEntry (\r
38 VOID\r
39 );\r
40\r
41\r
42EFI_EXCEPTION_CALLBACK gExceptionHandlers[MAX_ARM_EXCEPTION + 1];\r
43EFI_EXCEPTION_CALLBACK gDebuggerExceptionHandlers[MAX_ARM_EXCEPTION + 1];\r
44\r
45\r
46\r
47/**\r
3402aac7
RC
48 This function registers and enables the handler specified by InterruptHandler for a processor\r
49 interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the\r
50 handler for the processor interrupt or exception type specified by InterruptType is uninstalled.\r
2ef2b01e
A
51 The installed handler is called once for each processor interrupt or exception.\r
52\r
53 @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts\r
54 are enabled and FALSE if interrupts are disabled.\r
55 @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called\r
56 when a processor interrupt occurs. If this parameter is NULL, then the handler\r
57 will be uninstalled.\r
58\r
59 @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.\r
60 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was\r
61 previously installed.\r
62 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not\r
63 previously installed.\r
64 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.\r
65\r
66**/\r
67EFI_STATUS\r
68RegisterInterruptHandler (\r
69 IN EFI_EXCEPTION_TYPE InterruptType,\r
70 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler\r
71 )\r
72{\r
73 if (InterruptType > MAX_ARM_EXCEPTION) {\r
74 return EFI_UNSUPPORTED;\r
75 }\r
76\r
77 if ((InterruptHandler != NULL) && (gExceptionHandlers[InterruptType] != NULL)) {\r
78 return EFI_ALREADY_STARTED;\r
79 }\r
80\r
81 gExceptionHandlers[InterruptType] = InterruptHandler;\r
82\r
83 return EFI_SUCCESS;\r
84}\r
85\r
86\r
f659880b 87\r
f659880b 88\r
2ef2b01e
A
89VOID\r
90EFIAPI\r
91CommonCExceptionHandler (\r
92 IN EFI_EXCEPTION_TYPE ExceptionType,\r
93 IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
94 )\r
95{\r
2ef2b01e 96 if (ExceptionType <= MAX_ARM_EXCEPTION) {\r
2ef2b01e
A
97 if (gExceptionHandlers[ExceptionType]) {\r
98 gExceptionHandlers[ExceptionType] (ExceptionType, SystemContext);\r
9f50cb97 99 return;\r
2ef2b01e 100 }\r
8a4d81e6
A
101 } else {\r
102 DEBUG ((EFI_D_ERROR, "Unknown exception type %d from %08x\n", ExceptionType, SystemContext.SystemContextArm->PC));\r
103 ASSERT (FALSE);\r
2ef2b01e 104 }\r
3402aac7 105\r
2ef2b01e
A
106 if (ExceptionType == EXCEPT_ARM_SOFTWARE_INTERRUPT) {\r
107 //\r
108 // ARM JTAG debuggers some times use this vector, so it is not an error to get one\r
109 //\r
110 return;\r
111 }\r
112\r
6f72e28d 113 DefaultExceptionHandler (ExceptionType, SystemContext);\r
2ef2b01e
A
114}\r
115\r
116\r
117\r
118EFI_STATUS\r
119InitializeExceptions (\r
120 IN EFI_CPU_ARCH_PROTOCOL *Cpu\r
121 )\r
122{\r
123 EFI_STATUS Status;\r
124 UINTN Offset;\r
125 UINTN Length;\r
126 UINTN Index;\r
0416278c 127 BOOLEAN IrqEnabled;\r
128 BOOLEAN FiqEnabled;\r
2ef2b01e 129 EFI_PHYSICAL_ADDRESS Base;\r
41d47802 130 UINT32 *VectorBase;\r
2ef2b01e 131\r
1bfda055 132 Status = EFI_SUCCESS;\r
6e882393 133 ZeroMem (gExceptionHandlers,sizeof(*gExceptionHandlers));\r
134\r
2ef2b01e
A
135 //\r
136 // Disable interrupts\r
137 //\r
0416278c 138 Cpu->GetInterruptState (Cpu, &IrqEnabled);\r
2ef2b01e
A
139 Cpu->DisableInterrupt (Cpu);\r
140\r
0416278c 141 //\r
3402aac7
RC
142 // EFI does not use the FIQ, but a debugger might so we must disable\r
143 // as we take over the exception vectors.\r
0416278c 144 //\r
145 FiqEnabled = ArmGetFiqState ();\r
146 ArmDisableFiq ();\r
147\r
1bfda055 148 if (FeaturePcdGet(PcdRelocateVectorTable) == TRUE) {\r
63adfb11 149 //\r
150 // Copy an implementation of the ARM exception vectors to PcdCpuVectorBaseAddress.\r
151 //\r
152 Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;\r
153\r
f0fef790 154 // Check if the exception vector is in the low address\r
155 if (PcdGet32 (PcdCpuVectorBaseAddress) == 0x0) {\r
156 // Set SCTLR.V to 0 to enable VBAR to be used\r
157 ArmSetLowVectors ();\r
158 } else {\r
159 ArmSetHighVectors ();\r
160 }\r
161\r
63adfb11 162 //\r
163 // Reserve space for the exception handlers\r
164 //\r
165 Base = (EFI_PHYSICAL_ADDRESS)PcdGet32 (PcdCpuVectorBaseAddress);\r
166 VectorBase = (UINT32 *)(UINTN)Base;\r
167 Status = gBS->AllocatePages (AllocateAddress, EfiBootServicesCode, EFI_SIZE_TO_PAGES (Length), &Base);\r
168 // If the request was for memory that's not in the memory map (which is often the case for 0x00000000\r
169 // on embedded systems, for example, we don't want to hang up. So we'll check here for a status of\r
170 // EFI_NOT_FOUND, and continue in that case.\r
171 if (EFI_ERROR(Status) && (Status != EFI_NOT_FOUND)) {\r
172 ASSERT_EFI_ERROR (Status);\r
173 }\r
174\r
eeec69c5 175 if (FeaturePcdGet(PcdDebuggerExceptionSupport) == TRUE) {\r
1bfda055 176 // Save existing vector table, in case debugger is already hooked in\r
177 CopyMem ((VOID *)gDebuggerExceptionHandlers, (VOID *)VectorBase, sizeof (gDebuggerExceptionHandlers));\r
eeec69c5 178 }\r
63adfb11 179\r
180 // Copy our assembly code into the page that contains the exception vectors.\r
181 CopyMem ((VOID *)VectorBase, (VOID *)ExceptionHandlersStart, Length);\r
182\r
183 //\r
184 // Patch in the common Assembly exception handler\r
185 //\r
186 Offset = (UINTN)CommonExceptionEntry - (UINTN)ExceptionHandlersStart;\r
187 *(UINTN *) ((UINT8 *)(UINTN)PcdGet32 (PcdCpuVectorBaseAddress) + Offset) = (UINTN)AsmCommonExceptionEntry;\r
188\r
189 //\r
190 // Initialize the C entry points for interrupts\r
191 //\r
192 for (Index = 0; Index <= MAX_ARM_EXCEPTION; Index++) {\r
eeec69c5 193 if (!FeaturePcdGet(PcdDebuggerExceptionSupport) ||\r
194 (gDebuggerExceptionHandlers[Index] == 0) || (gDebuggerExceptionHandlers[Index] == (VOID *)(UINTN)0xEAFFFFFE)) {\r
63adfb11 195 // Exception handler contains branch to vector location (jmp $) so no handler\r
196 // NOTE: This code assumes vectors are ARM and not Thumb code\r
197 Status = RegisterInterruptHandler (Index, NULL);\r
198 ASSERT_EFI_ERROR (Status);\r
199 } else {\r
200 // If the debugger has already hooked put its vector back\r
201 VectorBase[Index] = (UINT32)(UINTN)gDebuggerExceptionHandlers[Index];\r
1bfda055 202 }\r
63adfb11 203 }\r
204\r
205 // Flush Caches since we updated executable stuff\r
206 InvalidateInstructionCacheRange ((VOID *)PcdGet32(PcdCpuVectorBaseAddress), Length);\r
1bfda055 207\r
63adfb11 208 //Note: On ARM processor with the Security Extension, the Vector Table can be located anywhere in the memory.\r
209 // The Vector Base Address Register defines the location\r
1c1e70fa 210 ArmWriteVBar (PcdGet32(PcdCpuVectorBaseAddress));\r
62d441fb 211 } else {\r
1c1e70fa 212 // The Vector table must be 32-byte aligned\r
6defc4db
OM
213 if (((UINT32)ExceptionHandlersStart & ARM_VECTOR_TABLE_ALIGNMENT) != 0) {\r
214 ASSERT (0);\r
215 return EFI_INVALID_PARAMETER;\r
216 }\r
1c1e70fa 217\r
1bfda055 218 // We do not copy the Exception Table at PcdGet32(PcdCpuVectorBaseAddress). We just set Vector Base Address to point into CpuDxe code.\r
1c1e70fa 219 ArmWriteVBar ((UINT32)ExceptionHandlersStart);\r
9f50cb97 220 }\r
221\r
0416278c 222 if (FiqEnabled) {\r
223 ArmEnableFiq ();\r
224 }\r
225\r
226 if (IrqEnabled) {\r
3402aac7 227 //\r
2ef2b01e
A
228 // Restore interrupt state\r
229 //\r
230 Status = Cpu->EnableInterrupt (Cpu);\r
231 }\r
232\r
233 return Status;\r
234}\r