| /** @file | |
| * Main file supporting the SEC Phase on ARM Platforms | |
| * | |
| * Copyright (c) 2011-2012, ARM Limited. All rights reserved. | |
| * | |
| * This program and the accompanying materials | |
| * are licensed and made available under the terms and conditions of the BSD License | |
| * which accompanies this distribution. The full text of the license may be found at | |
| * http://opensource.org/licenses/bsd-license.php | |
| * | |
| * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| * | |
| **/ | |
| #include <Library/ArmTrustedMonitorLib.h> | |
| #include <Library/DebugAgentLib.h> | |
| #include <Library/PrintLib.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/SerialPortLib.h> | |
| #include <Library/ArmGicLib.h> | |
| #include "SecInternal.h" | |
| #define SerialPrint(txt) SerialPortWrite ((UINT8*)txt, AsciiStrLen(txt)+1); | |
| VOID | |
| CEntryPoint ( | |
| IN UINTN MpId, | |
| IN UINTN SecBootMode | |
| ) | |
| { | |
| CHAR8 Buffer[100]; | |
| UINTN CharCount; | |
| UINTN JumpAddress; | |
| // Invalidate the data cache. Doesn't have to do the Data cache clean. | |
| ArmInvalidateDataCache (); | |
| // Invalidate Instruction Cache | |
| ArmInvalidateInstructionCache (); | |
| // Invalidate I & D TLBs | |
| ArmInvalidateInstructionAndDataTlb (); | |
| // CPU specific settings | |
| ArmCpuSetup (MpId); | |
| // Enable Floating Point Coprocessor if supported by the platform | |
| if (FixedPcdGet32 (PcdVFPEnabled)) { | |
| ArmEnableVFP (); | |
| } | |
| // Initialize peripherals that must be done at the early stage | |
| // Example: Some L2 controller, interconnect, clock, DMC, etc | |
| ArmPlatformSecInitialize (MpId); | |
| // Primary CPU clears out the SCU tag RAMs, secondaries wait | |
| if (ArmPlatformIsPrimaryCore (MpId) && (SecBootMode == ARM_SEC_COLD_BOOT)) { | |
| if (ArmIsMpCore()) { | |
| // Signal for the initial memory is configured (event: BOOT_MEM_INIT) | |
| ArmCallSEV (); | |
| } | |
| // SEC phase needs to run library constructors by hand. This assumes we are linked against the SerialLib | |
| // In non SEC modules the init call is in autogenerated code. | |
| SerialPortInitialize (); | |
| // Start talking | |
| if (FixedPcdGetBool (PcdTrustzoneSupport)) { | |
| CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Secure firmware (version %s built at %a on %a)\n\r", | |
| (CHAR16*)PcdGetPtr(PcdFirmwareVersionString), __TIME__, __DATE__); | |
| } else { | |
| CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Boot firmware (version %s built at %a on %a)\n\r", | |
| (CHAR16*)PcdGetPtr(PcdFirmwareVersionString), __TIME__, __DATE__); | |
| } | |
| SerialPortWrite ((UINT8 *) Buffer, CharCount); | |
| // Initialize the Debug Agent for Source Level Debugging | |
| InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, NULL, NULL); | |
| SaveAndSetDebugTimerInterrupt (TRUE); | |
| // Enable the GIC distributor and CPU Interface | |
| // - no other Interrupts are enabled, doesn't have to worry about the priority. | |
| // - all the cores are in secure state, use secure SGI's | |
| ArmGicEnableDistributor (PcdGet32(PcdGicDistributorBase)); | |
| ArmGicEnableInterruptInterface (PcdGet32(PcdGicInterruptInterfaceBase)); | |
| } else { | |
| // Enable the GIC CPU Interface | |
| ArmGicEnableInterruptInterface (PcdGet32(PcdGicInterruptInterfaceBase)); | |
| } | |
| // Enable Full Access to CoProcessors | |
| ArmWriteCpacr (CPACR_CP_FULL_ACCESS); | |
| // Test if Trustzone is supported on this platform | |
| if (FixedPcdGetBool (PcdTrustzoneSupport)) { | |
| if (ArmIsMpCore ()) { | |
| // Setup SMP in Non Secure world | |
| ArmCpuSetupSmpNonSecure (GET_CORE_ID(MpId)); | |
| } | |
| // Either we use the Secure Stacks for Secure Monitor (in this case (Base == 0) && (Size == 0)) | |
| // Or we use separate Secure Monitor stacks (but (Base != 0) && (Size != 0)) | |
| ASSERT (((PcdGet32(PcdCPUCoresSecMonStackBase) == 0) && (PcdGet32(PcdCPUCoreSecMonStackSize) == 0)) || | |
| ((PcdGet32(PcdCPUCoresSecMonStackBase) != 0) && (PcdGet32(PcdCPUCoreSecMonStackSize) != 0))); | |
| // Enter Monitor Mode | |
| enter_monitor_mode ((UINTN)TrustedWorldInitialization, MpId, SecBootMode, (VOID*)(PcdGet32(PcdCPUCoresSecMonStackBase) + (PcdGet32(PcdCPUCoreSecMonStackSize) * (GET_CORE_POS(MpId) + 1)))); | |
| } else { | |
| if (ArmPlatformIsPrimaryCore (MpId)) { | |
| SerialPrint ("Trust Zone Configuration is disabled\n\r"); | |
| } | |
| // With Trustzone support the transition from Sec to Normal world is done by return_from_exception(). | |
| // If we want to keep this function call we need to ensure the SVC's SPSR point to the same Program | |
| // Status Register as the the current one (CPSR). | |
| copy_cpsr_into_spsr (); | |
| // Call the Platform specific function to execute additional actions if required | |
| JumpAddress = PcdGet32 (PcdFvBaseAddress); | |
| ArmPlatformSecExtraAction (MpId, &JumpAddress); | |
| NonTrustedWorldTransition (MpId, JumpAddress); | |
| } | |
| ASSERT (0); // We must never return from the above function | |
| } | |
| VOID | |
| TrustedWorldInitialization ( | |
| IN UINTN MpId, | |
| IN UINTN SecBootMode | |
| ) | |
| { | |
| UINTN JumpAddress; | |
| //-------------------- Monitor Mode --------------------- | |
| // Set up Monitor World (Vector Table, etc) | |
| ArmSecureMonitorWorldInitialize (); | |
| // Transfer the interrupt to Non-secure World | |
| ArmGicSetupNonSecure (MpId, PcdGet32(PcdGicDistributorBase), PcdGet32(PcdGicInterruptInterfaceBase)); | |
| // Initialize platform specific security policy | |
| ArmPlatformSecTrustzoneInit (MpId); | |
| // Setup the Trustzone Chipsets | |
| if (SecBootMode == ARM_SEC_COLD_BOOT) { | |
| if (ArmPlatformIsPrimaryCore (MpId)) { | |
| if (ArmIsMpCore()) { | |
| // Signal the secondary core the Security settings is done (event: EVENT_SECURE_INIT) | |
| ArmCallSEV (); | |
| } | |
| } else { | |
| // The secondary cores need to wait until the Trustzone chipsets configuration is done | |
| // before switching to Non Secure World | |
| // Wait for the Primary Core to finish the initialization of the Secure World (event: EVENT_SECURE_INIT) | |
| ArmCallWFE (); | |
| } | |
| } | |
| // Call the Platform specific function to execute additional actions if required | |
| JumpAddress = PcdGet32 (PcdFvBaseAddress); | |
| ArmPlatformSecExtraAction (MpId, &JumpAddress); | |
| // Initialize architecture specific security policy | |
| ArmSecArchTrustzoneInit (); | |
| // CP15 Secure Configuration Register | |
| ArmWriteScr (PcdGet32 (PcdArmScr)); | |
| NonTrustedWorldTransition (MpId, JumpAddress); | |
| } | |
| VOID | |
| NonTrustedWorldTransition ( | |
| IN UINTN MpId, | |
| IN UINTN JumpAddress | |
| ) | |
| { | |
| // If PcdArmNonSecModeTransition is defined then set this specific mode to CPSR before the transition | |
| // By not set, the mode for Non Secure World is SVC | |
| if (PcdGet32 (PcdArmNonSecModeTransition) != 0) { | |
| set_non_secure_mode ((ARM_PROCESSOR_MODE)PcdGet32 (PcdArmNonSecModeTransition)); | |
| } | |
| return_from_exception (JumpAddress); | |
| //-------------------- Non Secure Mode --------------------- | |
| // PEI Core should always load and never return | |
| ASSERT (FALSE); | |
| } | |