1d5d0ae9 |
1 | /** @file |
2 | * Main file supporting the SEC Phase for Versatile Express |
3 | * |
4 | * Copyright (c) 2011, 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 <Library/DebugLib.h> |
17 | #include <Library/PcdLib.h> |
18 | #include <Library/BaseLib.h> |
19 | #include <Library/BaseMemoryLib.h> |
20 | #include <Library/ArmLib.h> |
21 | #include <Chipset/ArmV7.h> |
22 | #include <Drivers/PL390Gic.h> |
23 | #include <Library/L2X0CacheLib.h> |
24 | #include <Library/SerialPortLib.h> |
25 | #include <Library/ArmPlatformLib.h> |
26 | |
27 | extern VOID *monitor_vector_table; |
28 | |
29 | VOID ArmSetupGicNonSecure ( |
30 | IN INTN GicDistributorBase, |
31 | IN INTN GicInterruptInterfaceBase |
32 | ); |
33 | |
34 | // Vector Table for Sec Phase |
35 | VOID SecVectorTable (VOID); |
36 | |
37 | VOID NonSecureWaitForFirmware ( |
38 | VOID |
39 | ); |
40 | |
41 | VOID |
42 | enter_monitor_mode( |
43 | IN VOID* Stack |
44 | ); |
45 | |
46 | VOID |
47 | return_from_exception ( |
48 | IN UINTN NonSecureBase |
49 | ); |
50 | |
51 | VOID |
52 | copy_cpsr_into_spsr ( |
53 | VOID |
54 | ); |
55 | |
56 | VOID |
57 | CEntryPoint ( |
58 | IN UINTN CoreId |
59 | ) |
60 | { |
61 | // Primary CPU clears out the SCU tag RAMs, secondaries wait |
62 | if (CoreId == 0) { |
63 | if (FixedPcdGet32(PcdMPCoreSupport)) { |
64 | ArmInvalidScu(); |
65 | } |
66 | |
67 | // SEC phase needs to run library constructors by hand. This assumes we are linked against the SerialLib |
68 | // In non SEC modules the init call is in autogenerated code. |
69 | SerialPortInitialize (); |
70 | // Start talking |
71 | DEBUG ((EFI_D_ERROR, "UART Enabled\n")); |
72 | |
73 | // Now we've got UART, make the check: |
74 | // - The Vector table must be 32-byte aligned |
75 | ASSERT(((UINT32)SecVectorTable & ((1 << 5)-1)) == 0); |
76 | } |
77 | |
78 | // Invalidate the data cache. Doesn't have to do the Data cache clean. |
79 | ArmInvalidateDataCache(); |
80 | |
81 | //Invalidate Instruction Cache |
82 | ArmInvalidateInstructionCache(); |
83 | |
84 | //Invalidate I & D TLBs |
85 | ArmInvalidateInstructionAndDataTlb(); |
86 | |
87 | // Enable Full Access to CoProcessors |
88 | ArmWriteCPACR (CPACR_CP_FULL_ACCESS); |
89 | |
90 | // Enable SWP instructions |
91 | ArmEnableSWPInstruction(); |
92 | |
93 | // Enable program flow prediction, if supported. |
94 | ArmEnableBranchPrediction(); |
95 | |
96 | if (FixedPcdGet32(PcdVFPEnabled)) { |
97 | ArmEnableVFP(); |
98 | } |
99 | |
100 | if (CoreId == 0) { |
101 | // Initialize L2X0 but not enabled |
102 | L2x0CacheInit(PcdGet32(PcdL2x0ControllerBase), FALSE); |
103 | |
104 | // If we skip the PEI Core we could want to initialize the DRAM in the SEC phase. |
105 | // If we are in standalone, we need the initialization to copy the UEFI firmware into DRAM |
106 | if (FeaturePcdGet(PcdSkipPeiCore) || !FeaturePcdGet(PcdStandalone)) { |
107 | // Initialize system memory (DRAM) |
108 | ArmPlatformInitializeSystemMemory(); |
109 | } |
110 | |
111 | // Turn Off NOR flash remapping to 0. We can will now see DRAM in low memory |
112 | ArmPlatformBootRemapping(); |
113 | } |
114 | |
115 | // Test if Trustzone is supported on this platform |
116 | if (ArmPlatformTrustzoneSupported()) { |
117 | if (FixedPcdGet32(PcdMPCoreSupport)) { |
118 | // Setup SMP in Non Secure world |
119 | ArmSetupSmpNonSecure(CoreId); |
120 | } |
121 | |
122 | // Enter Monitor Mode |
123 | enter_monitor_mode((VOID*)(PcdGet32(PcdCPUCoresSecMonStackBase) + (PcdGet32(PcdCPUCoreSecMonStackSize) * CoreId))); |
124 | |
125 | //Write the monitor mode vector table address |
126 | ArmWriteVMBar((UINT32) &monitor_vector_table); |
127 | |
128 | //-------------------- Monitor Mode --------------------- |
129 | // setup the Trustzone Chipsets |
130 | if (CoreId == 0) { |
131 | ArmPlatformTrustzoneInit(); |
132 | |
133 | // Wake up the secondary cores by sending a interrupt to everyone else |
134 | // NOTE 1: The Software Generated Interrupts are always enabled on Cortex-A9 |
135 | // MPcore test chip on Versatile Express board, So the Software doesn't have to |
136 | // enable SGI's explicitly. |
137 | // 2: As no other Interrupts are enabled, doesn't have to worry about the priority. |
138 | // 3: As all the cores are in secure state, use secure SGI's |
139 | // |
140 | |
141 | PL390GicEnableDistributor (PcdGet32(PcdGicDistributorBase)); |
142 | PL390GicEnableInterruptInterface(PcdGet32(PcdGicInterruptInterfaceBase)); |
143 | |
144 | // Send SGI to all Secondary core to wake them up from WFI state. |
145 | PL390GicSendSgiTo (PcdGet32(PcdGicDistributorBase), GIC_ICDSGIR_FILTER_EVERYONEELSE, 0x0E); |
146 | } else { |
147 | // The secondary cores need to wait until the Trustzone chipsets configuration is done |
148 | // before swtching to Non Secure World |
149 | |
150 | // Enabled GIC CPU Interface |
151 | PL390GicEnableInterruptInterface (PcdGet32(PcdGicInterruptInterfaceBase)); |
152 | |
153 | // Waiting for the SGI from the primary core |
154 | ArmCallWFI(); |
155 | |
156 | //Acknowledge the interrupt and send End of Interrupt signal. |
157 | PL390GicAcknowledgeSgiFrom(PcdGet32(PcdGicInterruptInterfaceBase),0/*CoreId*/); |
158 | } |
159 | |
160 | // Transfer the interrupt to Non-secure World |
161 | PL390GicSetupNonSecure(PcdGet32(PcdGicDistributorBase),PcdGet32(PcdGicInterruptInterfaceBase)); |
162 | |
163 | // Write to CP15 Non-secure Access Control Register : |
164 | // - Enable CP10 and CP11 accesses in NS World |
165 | // - Enable Access to Preload Engine in NS World |
166 | // - Enable lockable TLB entries allocation in NS world |
167 | // - Enable R/W access to SMP bit of Auxiliary Control Register in NS world |
168 | ArmWriteNsacr(NSACR_NS_SMP | NSACR_TL | NSACR_PLE | NSACR_CP(10) | NSACR_CP(11)); |
169 | |
170 | // CP15 Secure Configuration Register with Non Secure bit (SCR_NS), CPSR.A modified in any |
171 | // security state (SCR_AW), CPSR.F modified in any security state (SCR_FW) |
172 | ArmWriteScr(SCR_NS | SCR_FW | SCR_AW); |
173 | } else { |
174 | if(0 == CoreId){ |
175 | DEBUG ((EFI_D_ERROR, "Trust Zone Configuration is disabled\n")); |
176 | } |
177 | |
178 | //Trustzone is not enabled, just enable the Distributor and CPU interface |
179 | PL390GicEnableInterruptInterface(PcdGet32(PcdGicInterruptInterfaceBase)); |
180 | |
181 | // With Trustzone support the transition from Sec to Normal world is done by return_from_exception(). |
182 | // If we want to keep this function call we need to ensure the SVC's SPSR point to the same Program |
183 | // Status Register as the the current one (CPSR). |
184 | copy_cpsr_into_spsr(); |
185 | } |
186 | |
187 | // If ArmVe has not been built as Standalone then we need to patch the DRAM to add an infinite loop at the start address |
188 | if (FeaturePcdGet(PcdStandalone) == FALSE) { |
189 | if (CoreId == 0) { |
190 | UINTN* StartAddress = (UINTN*)PcdGet32(PcdEmbeddedFdBaseAddress); |
191 | |
192 | DEBUG ((EFI_D_ERROR, "Waiting for firmware at 0x%08X ...\n",StartAddress)); |
193 | |
194 | // Patch the DRAM to make an infinite loop at the start address |
195 | *StartAddress = 0xEAFFFFFE; // opcode for while(1) |
196 | |
197 | // To enter into Non Secure state, we need to make a return from exception |
198 | return_from_exception(PcdGet32(PcdEmbeddedFdBaseAddress)); |
199 | } else { |
200 | // When the primary core is stopped by the hardware debugger to copy the firmware |
201 | // into DRAM. The secondary cores are still running. As soon as the first bytes of |
202 | // the firmware are written into DRAM, the secondary cores will start to execute the |
203 | // code even if the firmware is not entirely written into the memory. |
204 | // That's why the secondary cores need to be parked in WFI and wake up once the |
205 | // firmware is ready. |
206 | |
207 | // Enter Secondary Cores into non Secure State. To enter into Non Secure state, we need to make a return from exception |
208 | return_from_exception((UINTN)NonSecureWaitForFirmware); |
209 | } |
210 | } else { |
211 | if (CoreId == 0) { |
212 | DEBUG ((EFI_D_ERROR, "Standalone Firmware\n")); |
213 | } |
214 | |
215 | // To enter into Non Secure state, we need to make a return from exception |
216 | return_from_exception(PcdGet32(PcdEmbeddedFdBaseAddress)); |
217 | } |
218 | //-------------------- Non Secure Mode --------------------- |
219 | |
220 | // PEI Core should always load and never return |
221 | ASSERT (FALSE); |
222 | } |
223 | |
224 | // When the firmware is built as not Standalone, the secondary cores need to wait the firmware |
225 | // entirely written into DRAM. It is the firmware from DRAM which will wake up the secondary cores. |
226 | VOID NonSecureWaitForFirmware() { |
227 | VOID (*secondary_start)(VOID); |
228 | |
229 | // The secondary cores will execute the fimrware once wake from WFI. |
230 | secondary_start = (VOID (*)())PcdGet32(PcdEmbeddedFdBaseAddress); |
231 | |
232 | ArmCallWFI(); |
233 | |
234 | //Acknowledge the interrupt and send End of Interrupt signal. |
235 | PL390GicAcknowledgeSgiFrom(PcdGet32(PcdGicInterruptInterfaceBase),0/*CoreId*/); |
236 | |
237 | //Jump to secondary core entry point. |
238 | secondary_start(); |
239 | |
240 | // PEI Core should always load and never return |
241 | ASSERT (FALSE); |
242 | } |
243 | |
244 | VOID SecCommonExceptionEntry(UINT32 Entry, UINT32 LR) { |
245 | switch (Entry) { |
246 | case 0: |
247 | DEBUG((EFI_D_ERROR,"Reset Exception at 0x%X\n",LR)); |
248 | break; |
249 | case 1: |
250 | DEBUG((EFI_D_ERROR,"Undefined Exception at 0x%X\n",LR)); |
251 | break; |
252 | case 2: |
253 | DEBUG((EFI_D_ERROR,"SWI Exception at 0x%X\n",LR)); |
254 | break; |
255 | case 3: |
256 | DEBUG((EFI_D_ERROR,"PrefetchAbort Exception at 0x%X\n",LR)); |
257 | break; |
258 | case 4: |
259 | DEBUG((EFI_D_ERROR,"DataAbort Exception at 0x%X\n",LR)); |
260 | break; |
261 | case 5: |
262 | DEBUG((EFI_D_ERROR,"Reserved Exception at 0x%X\n",LR)); |
263 | break; |
264 | case 6: |
265 | DEBUG((EFI_D_ERROR,"IRQ Exception at 0x%X\n",LR)); |
266 | break; |
267 | case 7: |
268 | DEBUG((EFI_D_ERROR,"FIQ Exception at 0x%X\n",LR)); |
269 | break; |
270 | default: |
271 | DEBUG((EFI_D_ERROR,"Unknown Exception at 0x%X\n",LR)); |
272 | break; |
273 | } |
274 | while(1); |
275 | } |