2 * Main file supporting the SEC Phase for Versatile Express
4 * Copyright (c) 2011, ARM Limited. All rights reserved.
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
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.
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>
27 #define SerialPrint(txt) SerialPortWrite (txt, AsciiStrLen(txt)+1);
29 extern VOID
*monitor_vector_table
;
31 VOID
ArmSetupGicNonSecure (
32 IN INTN GicDistributorBase
,
33 IN INTN GicInterruptInterfaceBase
36 // Vector Table for Sec Phase
37 VOID
SecVectorTable (VOID
);
39 VOID
NonSecureWaitForFirmware (
49 return_from_exception (
50 IN UINTN NonSecureBase
66 // Primary CPU clears out the SCU tag RAMs, secondaries wait
68 if (FixedPcdGet32(PcdMPCoreSupport
)) {
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 ();
77 CharCount
= AsciiSPrint (Buffer
,sizeof (Buffer
),"UEFI firmware built at %a on %a\n\r",__TIME__
, __DATE__
);
78 SerialPortWrite ((UINT8
*) Buffer
, CharCount
);
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);
85 // Invalidate the data cache. Doesn't have to do the Data cache clean.
86 ArmInvalidateDataCache();
88 //Invalidate Instruction Cache
89 ArmInvalidateInstructionCache();
91 //Invalidate I & D TLBs
92 ArmInvalidateInstructionAndDataTlb();
94 // Enable Full Access to CoProcessors
95 ArmWriteCPACR (CPACR_CP_FULL_ACCESS
);
97 // Enable SWP instructions
98 ArmEnableSWPInstruction();
100 // Enable program flow prediction, if supported.
101 ArmEnableBranchPrediction();
103 if (FixedPcdGet32(PcdVFPEnabled
)) {
108 // Initialize peripherals that must be done at the early stage
109 // Example: Some L2x0 controllers must be initialized in Secure World
110 ArmPlatformInitialize ();
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();
119 // Turn Off NOR flash remapping to 0. We can will now see DRAM in low memory
120 ArmPlatformBootRemapping();
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
);
130 // Enter Monitor Mode
131 enter_monitor_mode((VOID
*)(PcdGet32(PcdCPUCoresSecMonStackBase
) + (PcdGet32(PcdCPUCoreSecMonStackSize
) * CoreId
)));
133 //Write the monitor mode vector table address
134 ArmWriteVMBar((UINT32
) &monitor_vector_table
);
136 //-------------------- Monitor Mode ---------------------
137 // setup the Trustzone Chipsets
139 ArmPlatformTrustzoneInit();
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
149 PL390GicEnableDistributor (PcdGet32(PcdGicDistributorBase
));
150 PL390GicEnableInterruptInterface(PcdGet32(PcdGicInterruptInterfaceBase
));
152 // Send SGI to all Secondary core to wake them up from WFI state.
153 PL390GicSendSgiTo (PcdGet32(PcdGicDistributorBase
), GIC_ICDSGIR_FILTER_EVERYONEELSE
, 0x0E);
155 // The secondary cores need to wait until the Trustzone chipsets configuration is done
156 // before swtching to Non Secure World
158 // Enabled GIC CPU Interface
159 PL390GicEnableInterruptInterface (PcdGet32(PcdGicInterruptInterfaceBase
));
161 // Waiting for the SGI from the primary core
164 //Acknowledge the interrupt and send End of Interrupt signal.
165 PL390GicAcknowledgeSgiFrom(PcdGet32(PcdGicInterruptInterfaceBase
),0/*CoreId*/);
168 // Transfer the interrupt to Non-secure World
169 PL390GicSetupNonSecure(PcdGet32(PcdGicDistributorBase
),PcdGet32(PcdGicInterruptInterfaceBase
));
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));
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
);
183 SerialPrint ("Trust Zone Configuration is disabled\n\r");
186 //Trustzone is not enabled, just enable the Distributor and CPU interface
187 PL390GicEnableInterruptInterface(PcdGet32(PcdGicInterruptInterfaceBase
));
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();
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
) {
198 UINTN
* StartAddress
= (UINTN
*)PcdGet32(PcdNormalFdBaseAddress
);
200 // Patch the DRAM to make an infinite loop at the start address
201 *StartAddress
= 0xEAFFFFFE; // opcode for while(1)
203 CharCount
= AsciiSPrint (Buffer
,sizeof (Buffer
),"Waiting for firmware at 0x%08X ...\n\r",StartAddress
);
204 SerialPortWrite ((UINT8
*) Buffer
, CharCount
);
206 // To enter into Non Secure state, we need to make a return from exception
207 return_from_exception(PcdGet32(PcdNormalFdBaseAddress
));
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.
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
);
220 // To enter into Non Secure state, we need to make a return from exception
221 return_from_exception(PcdGet32(PcdNormalFdBaseAddress
));
223 //-------------------- Non Secure Mode ---------------------
225 // PEI Core should always load and never return
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
);
234 // The secondary cores will execute the fimrware once wake from WFI.
235 secondary_start
= (VOID (*)())PcdGet32(PcdNormalFdBaseAddress
);
239 //Acknowledge the interrupt and send End of Interrupt signal.
240 PL390GicAcknowledgeSgiFrom(PcdGet32(PcdGicInterruptInterfaceBase
),0/*CoreId*/);
242 //Jump to secondary core entry point.
245 // PEI Core should always load and never return
250 SecCommonExceptionEntry (
260 CharCount
= AsciiSPrint (Buffer
,sizeof (Buffer
),"Reset Exception at 0x%X\n\r",LR
);
263 CharCount
= AsciiSPrint (Buffer
,sizeof (Buffer
),"Undefined Exception at 0x%X\n\r",LR
);
266 CharCount
= AsciiSPrint (Buffer
,sizeof (Buffer
),"SWI Exception at 0x%X\n\r",LR
);
269 CharCount
= AsciiSPrint (Buffer
,sizeof (Buffer
),"PrefetchAbort Exception at 0x%X\n\r",LR
);
272 CharCount
= AsciiSPrint (Buffer
,sizeof (Buffer
),"DataAbort Exception at 0x%X\n\r",LR
);
275 CharCount
= AsciiSPrint (Buffer
,sizeof (Buffer
),"Reserved Exception at 0x%X\n\r",LR
);
278 CharCount
= AsciiSPrint (Buffer
,sizeof (Buffer
),"IRQ Exception at 0x%X\n\r",LR
);
281 CharCount
= AsciiSPrint (Buffer
,sizeof (Buffer
),"FIQ Exception at 0x%X\n\r",LR
);
284 CharCount
= AsciiSPrint (Buffer
,sizeof (Buffer
),"Unknown Exception at 0x%X\n\r",LR
);
287 SerialPortWrite ((UINT8
*) Buffer
, CharCount
);