]>
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> | |
2637d1ef | 18 | #include <Library/PrintLib.h> |
1d5d0ae9 | 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> | |
1d5d0ae9 | 24 | #include <Library/SerialPortLib.h> |
25 | #include <Library/ArmPlatformLib.h> | |
26 | ||
2637d1ef | 27 | #define SerialPrint(txt) SerialPortWrite (txt, AsciiStrLen(txt)+1); |
28 | ||
1d5d0ae9 | 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 | { | |
2637d1ef | 63 | CHAR8 Buffer[100]; |
64 | UINTN CharCount; | |
65 | ||
1d5d0ae9 | 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 (); | |
2637d1ef | 75 | |
1d5d0ae9 | 76 | // Start talking |
2637d1ef | 77 | CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"UEFI firmware built at %a on %a\n\r",__TIME__, __DATE__); |
78 | SerialPortWrite ((UINT8 *) Buffer, CharCount); | |
1d5d0ae9 | 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) { | |
8e06b586 | 108 | // Initialize peripherals that must be done at the early stage |
109 | // Example: Some L2x0 controllers must be initialized in Secure World | |
110 | ArmPlatformInitialize (); | |
1d5d0ae9 | 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){ | |
2637d1ef | 183 | SerialPrint ("Trust Zone Configuration is disabled\n\r"); |
1d5d0ae9 | 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) { | |
262a9b04 | 198 | UINTN* StartAddress = (UINTN*)PcdGet32(PcdNormalFdBaseAddress); |
1d5d0ae9 | 199 | |
1d5d0ae9 | 200 | // Patch the DRAM to make an infinite loop at the start address |
201 | *StartAddress = 0xEAFFFFFE; // opcode for while(1) | |
202 | ||
2637d1ef | 203 | CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Waiting for firmware at 0x%08X ...\n\r",StartAddress); |
204 | SerialPortWrite ((UINT8 *) Buffer, CharCount); | |
205 | ||
1d5d0ae9 | 206 | // To enter into Non Secure state, we need to make a return from exception |
262a9b04 | 207 | return_from_exception(PcdGet32(PcdNormalFdBaseAddress)); |
1d5d0ae9 | 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 { | |
1d5d0ae9 | 220 | // To enter into Non Secure state, we need to make a return from exception |
262a9b04 | 221 | return_from_exception(PcdGet32(PcdNormalFdBaseAddress)); |
1d5d0ae9 | 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. | |
262a9b04 | 235 | secondary_start = (VOID (*)())PcdGet32(PcdNormalFdBaseAddress); |
1d5d0ae9 | 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 | ||
2637d1ef | 249 | VOID |
250 | SecCommonExceptionEntry ( | |
251 | IN UINT32 Entry, | |
252 | IN UINT32 LR | |
253 | ) | |
254 | { | |
255 | CHAR8 Buffer[100]; | |
256 | UINTN CharCount; | |
257 | ||
1d5d0ae9 | 258 | switch (Entry) { |
259 | case 0: | |
2637d1ef | 260 | CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Reset Exception at 0x%X\n\r",LR); |
1d5d0ae9 | 261 | break; |
262 | case 1: | |
2637d1ef | 263 | CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Undefined Exception at 0x%X\n\r",LR); |
1d5d0ae9 | 264 | break; |
265 | case 2: | |
2637d1ef | 266 | CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"SWI Exception at 0x%X\n\r",LR); |
1d5d0ae9 | 267 | break; |
268 | case 3: | |
2637d1ef | 269 | CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"PrefetchAbort Exception at 0x%X\n\r",LR); |
1d5d0ae9 | 270 | break; |
271 | case 4: | |
2637d1ef | 272 | CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"DataAbort Exception at 0x%X\n\r",LR); |
1d5d0ae9 | 273 | break; |
274 | case 5: | |
2637d1ef | 275 | CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Reserved Exception at 0x%X\n\r",LR); |
1d5d0ae9 | 276 | break; |
277 | case 6: | |
2637d1ef | 278 | CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"IRQ Exception at 0x%X\n\r",LR); |
1d5d0ae9 | 279 | break; |
280 | case 7: | |
2637d1ef | 281 | CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"FIQ Exception at 0x%X\n\r",LR); |
1d5d0ae9 | 282 | break; |
283 | default: | |
2637d1ef | 284 | CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Unknown Exception at 0x%X\n\r",LR); |
1d5d0ae9 | 285 | break; |
286 | } | |
2637d1ef | 287 | SerialPortWrite ((UINT8 *) Buffer, CharCount); |
1d5d0ae9 | 288 | while(1); |
289 | } |