]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Sec/Sec.c
ArmPlatformPkg/SP804Timer: Fix IRQ handler when the Timer IRQ is shared
[mirror_edk2.git] / ArmPlatformPkg / Sec / Sec.c
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 }