1 /** @file
2 * Main file supporting the SEC Phase on ARM Platforms
3 *
4 * Copyright (c) 2011-2014, 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/ArmTrustedMonitorLib.h>
17 #include <Library/DebugAgentLib.h>
18 #include <Library/PrintLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/SerialPortLib.h>
21 #include <Library/ArmGicLib.h>
22 #include <Library/ArmPlatformLib.h>
23
24 #include "SecInternal.h"
25
26 #define SerialPrint(txt) SerialPortWrite ((UINT8*)txt, AsciiStrLen(txt)+1);
27
28 VOID
CEntryPoint(IN UINTN MpId,IN UINTN SecBootMode)29 CEntryPoint (
30 IN UINTN MpId,
31 IN UINTN SecBootMode
32 )
33 {
34 CHAR8 Buffer[100];
35 UINTN CharCount;
36 UINTN JumpAddress;
37
38 // Invalidate the data cache. Doesn't have to do the Data cache clean.
39 ArmInvalidateDataCache ();
40
41 // Invalidate Instruction Cache
42 ArmInvalidateInstructionCache ();
43
44 // Invalidate I & D TLBs
45 ArmInvalidateTlb ();
46
47 // CPU specific settings
48 ArmCpuSetup (MpId);
49
50 // Enable Floating Point Coprocessor if supported by the platform
51 if (FixedPcdGet32 (PcdVFPEnabled)) {
52 ArmEnableVFP ();
53 }
54
55 // Initialize peripherals that must be done at the early stage
56 // Example: Some L2 controller, interconnect, clock, DMC, etc
57 ArmPlatformSecInitialize (MpId);
58
59 // Primary CPU clears out the SCU tag RAMs, secondaries wait
60 if (ArmPlatformIsPrimaryCore (MpId) && (SecBootMode == ARM_SEC_COLD_BOOT)) {
61 if (ArmIsMpCore()) {
62 // Signal for the initial memory is configured (event: BOOT_MEM_INIT)
63 ArmCallSEV ();
64 }
65
66 // SEC phase needs to run library constructors by hand. This assumes we are linked against the SerialLib
67 // In non SEC modules the init call is in autogenerated code.
68 SerialPortInitialize ();
69
70 // Start talking
71 if (FixedPcdGetBool (PcdTrustzoneSupport)) {
72 CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Secure firmware (version %s built at %a on %a)\n\r",
73 (CHAR16*)PcdGetPtr(PcdFirmwareVersionString), __TIME__, __DATE__);
74 } else {
75 CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Boot firmware (version %s built at %a on %a)\n\r",
76 (CHAR16*)PcdGetPtr(PcdFirmwareVersionString), __TIME__, __DATE__);
77 }
78 SerialPortWrite ((UINT8 *) Buffer, CharCount);
79
80 // Initialize the Debug Agent for Source Level Debugging
81 InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, NULL, NULL);
82 SaveAndSetDebugTimerInterrupt (TRUE);
83
84 // Enable the GIC distributor and CPU Interface
85 // - no other Interrupts are enabled, doesn't have to worry about the priority.
86 // - all the cores are in secure state, use secure SGI's
87 ArmGicEnableDistributor (PcdGet32(PcdGicDistributorBase));
88 ArmGicEnableInterruptInterface (PcdGet32(PcdGicInterruptInterfaceBase));
89 } else {
90 // Enable the GIC CPU Interface
91 ArmGicEnableInterruptInterface (PcdGet32(PcdGicInterruptInterfaceBase));
92 }
93
94 // Enable Full Access to CoProcessors
95 ArmWriteCpacr (CPACR_CP_FULL_ACCESS);
96
97 // Test if Trustzone is supported on this platform
98 if (FixedPcdGetBool (PcdTrustzoneSupport)) {
99 if (ArmIsMpCore ()) {
100 // Setup SMP in Non Secure world
101 ArmCpuSetupSmpNonSecure (GET_CORE_ID(MpId));
102 }
103
104 // Either we use the Secure Stacks for Secure Monitor (in this case (Base == 0) && (Size == 0))
105 // Or we use separate Secure Monitor stacks (but (Base != 0) && (Size != 0))
106 ASSERT (((PcdGet32(PcdCPUCoresSecMonStackBase) == 0) && (PcdGet32(PcdCPUCoreSecMonStackSize) == 0)) ||
107 ((PcdGet32(PcdCPUCoresSecMonStackBase) != 0) && (PcdGet32(PcdCPUCoreSecMonStackSize) != 0)));
108
109 // Enter Monitor Mode
110 enter_monitor_mode (
111 (UINTN)TrustedWorldInitialization, MpId, SecBootMode,
112 (VOID*) (PcdGet32 (PcdCPUCoresSecMonStackBase) +
113 (PcdGet32 (PcdCPUCoreSecMonStackSize) * (ArmPlatformGetCorePosition (MpId) + 1)))
114 );
115 } else {
116 if (ArmPlatformIsPrimaryCore (MpId)) {
117 SerialPrint ("Trust Zone Configuration is disabled\n\r");
118 }
119
120 // With Trustzone support the transition from Sec to Normal world is done by return_from_exception().
121 // If we want to keep this function call we need to ensure the SVC's SPSR point to the same Program
122 // Status Register as the the current one (CPSR).
123 copy_cpsr_into_spsr ();
124
125 // Call the Platform specific function to execute additional actions if required
126 JumpAddress = PcdGet64 (PcdFvBaseAddress);
127 ArmPlatformSecExtraAction (MpId, &JumpAddress);
128
129 NonTrustedWorldTransition (MpId, JumpAddress);
130 }
131 ASSERT (0); // We must never return from the above function
132 }
133
134 VOID
TrustedWorldInitialization(IN UINTN MpId,IN UINTN SecBootMode)135 TrustedWorldInitialization (
136 IN UINTN MpId,
137 IN UINTN SecBootMode
138 )
139 {
140 UINTN JumpAddress;
141
142 //-------------------- Monitor Mode ---------------------
143
144 // Set up Monitor World (Vector Table, etc)
145 ArmSecureMonitorWorldInitialize ();
146
147 // Transfer the interrupt to Non-secure World
148 ArmGicSetupNonSecure (MpId, PcdGet32(PcdGicDistributorBase), PcdGet32(PcdGicInterruptInterfaceBase));
149
150 // Initialize platform specific security policy
151 ArmPlatformSecTrustzoneInit (MpId);
152
153 // Setup the Trustzone Chipsets
154 if (SecBootMode == ARM_SEC_COLD_BOOT) {
155 if (ArmPlatformIsPrimaryCore (MpId)) {
156 if (ArmIsMpCore()) {
157 // Signal the secondary core the Security settings is done (event: EVENT_SECURE_INIT)
158 ArmCallSEV ();
159 }
160 } else {
161 // The secondary cores need to wait until the Trustzone chipsets configuration is done
162 // before switching to Non Secure World
163
164 // Wait for the Primary Core to finish the initialization of the Secure World (event: EVENT_SECURE_INIT)
165 ArmCallWFE ();
166 }
167 }
168
169 // Call the Platform specific function to execute additional actions if required
170 JumpAddress = PcdGet64 (PcdFvBaseAddress);
171 ArmPlatformSecExtraAction (MpId, &JumpAddress);
172
173 // Initialize architecture specific security policy
174 ArmSecArchTrustzoneInit ();
175
176 // CP15 Secure Configuration Register
177 ArmWriteScr (PcdGet32 (PcdArmScr));
178
179 NonTrustedWorldTransition (MpId, JumpAddress);
180 }
181
182 VOID
NonTrustedWorldTransition(IN UINTN MpId,IN UINTN JumpAddress)183 NonTrustedWorldTransition (
184 IN UINTN MpId,
185 IN UINTN JumpAddress
186 )
187 {
188 // If PcdArmNonSecModeTransition is defined then set this specific mode to CPSR before the transition
189 // By not set, the mode for Non Secure World is SVC
190 if (PcdGet32 (PcdArmNonSecModeTransition) != 0) {
191 set_non_secure_mode ((ARM_PROCESSOR_MODE)PcdGet32 (PcdArmNonSecModeTransition));
192 }
193
194 return_from_exception (JumpAddress);
195 //-------------------- Non Secure Mode ---------------------
196
197 // PEI Core should always load and never return
198 ASSERT (FALSE);
199 }
200
201