]>
Commit | Line | Data |
---|---|---|
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 | } |