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