ArmPlatform: Remove dummy padding to make the Reset Vector aligned on 32 bytes boundary
[mirror_edk2.git] / ArmPlatformPkg / Sec / Sec.c
CommitLineData
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 29extern VOID *monitor_vector_table;
30
31VOID ArmSetupGicNonSecure (
32 IN INTN GicDistributorBase,
33 IN INTN GicInterruptInterfaceBase
34);
35
36// Vector Table for Sec Phase
37VOID SecVectorTable (VOID);
38
39VOID NonSecureWaitForFirmware (
40 VOID
41 );
42
43VOID
44enter_monitor_mode(
45 IN VOID* Stack
46 );
47
48VOID
49return_from_exception (
50 IN UINTN NonSecureBase
51 );
52
53VOID
54copy_cpsr_into_spsr (
55 VOID
56 );
57
58VOID
59CEntryPoint (
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.
231VOID 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 249VOID
250SecCommonExceptionEntry (
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}