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