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