summaryrefslogtreecommitdiff
path: root/edk2/ArmPlatformPkg/Sec/Sec.c
diff options
context:
space:
mode:
authorandrewfish <andrewfish@6f19259b-4bc3-4df7-8a09-765794883524>2011-02-01 05:41:42 +0000
committerandrewfish <andrewfish@6f19259b-4bc3-4df7-8a09-765794883524>2011-02-01 05:41:42 +0000
commitb970e2043fa26c36bec6e208c514fc447e799ac8 (patch)
tree8df6901c737422596ee0406ac57bad2fb1c20311 /edk2/ArmPlatformPkg/Sec/Sec.c
parent8847f6b7bcfb10376b4898bac611edbdbe9116e1 (diff)
Add ArmPlatformPkg from ARM Ltd. patch.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk@11291 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'edk2/ArmPlatformPkg/Sec/Sec.c')
-rw-r--r--edk2/ArmPlatformPkg/Sec/Sec.c275
1 files changed, 275 insertions, 0 deletions
diff --git a/edk2/ArmPlatformPkg/Sec/Sec.c b/edk2/ArmPlatformPkg/Sec/Sec.c
new file mode 100644
index 000000000..2ae01d8e5
--- /dev/null
+++ b/edk2/ArmPlatformPkg/Sec/Sec.c
@@ -0,0 +1,275 @@
+/** @file
+* Main file supporting the SEC Phase for Versatile Express
+*
+* Copyright (c) 2011, 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/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ArmLib.h>
+#include <Chipset/ArmV7.h>
+#include <Drivers/PL390Gic.h>
+#include <Library/L2X0CacheLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/ArmPlatformLib.h>
+
+extern VOID *monitor_vector_table;
+
+VOID ArmSetupGicNonSecure (
+ IN INTN GicDistributorBase,
+ IN INTN GicInterruptInterfaceBase
+);
+
+// Vector Table for Sec Phase
+VOID SecVectorTable (VOID);
+
+VOID NonSecureWaitForFirmware (
+ VOID
+ );
+
+VOID
+enter_monitor_mode(
+ IN VOID* Stack
+ );
+
+VOID
+return_from_exception (
+ IN UINTN NonSecureBase
+ );
+
+VOID
+copy_cpsr_into_spsr (
+ VOID
+ );
+
+VOID
+CEntryPoint (
+ IN UINTN CoreId
+ )
+{
+ // Primary CPU clears out the SCU tag RAMs, secondaries wait
+ if (CoreId == 0) {
+ if (FixedPcdGet32(PcdMPCoreSupport)) {
+ ArmInvalidScu();
+ }
+
+ // 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
+ DEBUG ((EFI_D_ERROR, "UART Enabled\n"));
+
+ // Now we've got UART, make the check:
+ // - The Vector table must be 32-byte aligned
+ ASSERT(((UINT32)SecVectorTable & ((1 << 5)-1)) == 0);
+ }
+
+ // Invalidate the data cache. Doesn't have to do the Data cache clean.
+ ArmInvalidateDataCache();
+
+ //Invalidate Instruction Cache
+ ArmInvalidateInstructionCache();
+
+ //Invalidate I & D TLBs
+ ArmInvalidateInstructionAndDataTlb();
+
+ // Enable Full Access to CoProcessors
+ ArmWriteCPACR (CPACR_CP_FULL_ACCESS);
+
+ // Enable SWP instructions
+ ArmEnableSWPInstruction();
+
+ // Enable program flow prediction, if supported.
+ ArmEnableBranchPrediction();
+
+ if (FixedPcdGet32(PcdVFPEnabled)) {
+ ArmEnableVFP();
+ }
+
+ if (CoreId == 0) {
+ // Initialize L2X0 but not enabled
+ L2x0CacheInit(PcdGet32(PcdL2x0ControllerBase), FALSE);
+
+ // If we skip the PEI Core we could want to initialize the DRAM in the SEC phase.
+ // If we are in standalone, we need the initialization to copy the UEFI firmware into DRAM
+ if (FeaturePcdGet(PcdSkipPeiCore) || !FeaturePcdGet(PcdStandalone)) {
+ // Initialize system memory (DRAM)
+ ArmPlatformInitializeSystemMemory();
+ }
+
+ // Turn Off NOR flash remapping to 0. We can will now see DRAM in low memory
+ ArmPlatformBootRemapping();
+ }
+
+ // Test if Trustzone is supported on this platform
+ if (ArmPlatformTrustzoneSupported()) {
+ if (FixedPcdGet32(PcdMPCoreSupport)) {
+ // Setup SMP in Non Secure world
+ ArmSetupSmpNonSecure(CoreId);
+ }
+
+ // Enter Monitor Mode
+ enter_monitor_mode((VOID*)(PcdGet32(PcdCPUCoresSecMonStackBase) + (PcdGet32(PcdCPUCoreSecMonStackSize) * CoreId)));
+
+ //Write the monitor mode vector table address
+ ArmWriteVMBar((UINT32) &monitor_vector_table);
+
+ //-------------------- Monitor Mode ---------------------
+ // setup the Trustzone Chipsets
+ if (CoreId == 0) {
+ ArmPlatformTrustzoneInit();
+
+ // Wake up the secondary cores by sending a interrupt to everyone else
+ // NOTE 1: The Software Generated Interrupts are always enabled on Cortex-A9
+ // MPcore test chip on Versatile Express board, So the Software doesn't have to
+ // enable SGI's explicitly.
+ // 2: As no other Interrupts are enabled, doesn't have to worry about the priority.
+ // 3: As all the cores are in secure state, use secure SGI's
+ //
+
+ PL390GicEnableDistributor (PcdGet32(PcdGicDistributorBase));
+ PL390GicEnableInterruptInterface(PcdGet32(PcdGicInterruptInterfaceBase));
+
+ // Send SGI to all Secondary core to wake them up from WFI state.
+ PL390GicSendSgiTo (PcdGet32(PcdGicDistributorBase), GIC_ICDSGIR_FILTER_EVERYONEELSE, 0x0E);
+ } else {
+ // The secondary cores need to wait until the Trustzone chipsets configuration is done
+ // before swtching to Non Secure World
+
+ // Enabled GIC CPU Interface
+ PL390GicEnableInterruptInterface (PcdGet32(PcdGicInterruptInterfaceBase));
+
+ // Waiting for the SGI from the primary core
+ ArmCallWFI();
+
+ //Acknowledge the interrupt and send End of Interrupt signal.
+ PL390GicAcknowledgeSgiFrom(PcdGet32(PcdGicInterruptInterfaceBase),0/*CoreId*/);
+ }
+
+ // Transfer the interrupt to Non-secure World
+ PL390GicSetupNonSecure(PcdGet32(PcdGicDistributorBase),PcdGet32(PcdGicInterruptInterfaceBase));
+
+ // Write to CP15 Non-secure Access Control Register :
+ // - Enable CP10 and CP11 accesses in NS World
+ // - Enable Access to Preload Engine in NS World
+ // - Enable lockable TLB entries allocation in NS world
+ // - Enable R/W access to SMP bit of Auxiliary Control Register in NS world
+ ArmWriteNsacr(NSACR_NS_SMP | NSACR_TL | NSACR_PLE | NSACR_CP(10) | NSACR_CP(11));
+
+ // CP15 Secure Configuration Register with Non Secure bit (SCR_NS), CPSR.A modified in any
+ // security state (SCR_AW), CPSR.F modified in any security state (SCR_FW)
+ ArmWriteScr(SCR_NS | SCR_FW | SCR_AW);
+ } else {
+ if(0 == CoreId){
+ DEBUG ((EFI_D_ERROR, "Trust Zone Configuration is disabled\n"));
+ }
+
+ //Trustzone is not enabled, just enable the Distributor and CPU interface
+ PL390GicEnableInterruptInterface(PcdGet32(PcdGicInterruptInterfaceBase));
+
+ // 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();
+ }
+
+ // If ArmVe has not been built as Standalone then we need to patch the DRAM to add an infinite loop at the start address
+ if (FeaturePcdGet(PcdStandalone) == FALSE) {
+ if (CoreId == 0) {
+ UINTN* StartAddress = (UINTN*)PcdGet32(PcdEmbeddedFdBaseAddress);
+
+ DEBUG ((EFI_D_ERROR, "Waiting for firmware at 0x%08X ...\n",StartAddress));
+
+ // Patch the DRAM to make an infinite loop at the start address
+ *StartAddress = 0xEAFFFFFE; // opcode for while(1)
+
+ // To enter into Non Secure state, we need to make a return from exception
+ return_from_exception(PcdGet32(PcdEmbeddedFdBaseAddress));
+ } else {
+ // When the primary core is stopped by the hardware debugger to copy the firmware
+ // into DRAM. The secondary cores are still running. As soon as the first bytes of
+ // the firmware are written into DRAM, the secondary cores will start to execute the
+ // code even if the firmware is not entirely written into the memory.
+ // That's why the secondary cores need to be parked in WFI and wake up once the
+ // firmware is ready.
+
+ // Enter Secondary Cores into non Secure State. To enter into Non Secure state, we need to make a return from exception
+ return_from_exception((UINTN)NonSecureWaitForFirmware);
+ }
+ } else {
+ if (CoreId == 0) {
+ DEBUG ((EFI_D_ERROR, "Standalone Firmware\n"));
+ }
+
+ // To enter into Non Secure state, we need to make a return from exception
+ return_from_exception(PcdGet32(PcdEmbeddedFdBaseAddress));
+ }
+ //-------------------- Non Secure Mode ---------------------
+
+ // PEI Core should always load and never return
+ ASSERT (FALSE);
+}
+
+// When the firmware is built as not Standalone, the secondary cores need to wait the firmware
+// entirely written into DRAM. It is the firmware from DRAM which will wake up the secondary cores.
+VOID NonSecureWaitForFirmware() {
+ VOID (*secondary_start)(VOID);
+
+ // The secondary cores will execute the fimrware once wake from WFI.
+ secondary_start = (VOID (*)())PcdGet32(PcdEmbeddedFdBaseAddress);
+
+ ArmCallWFI();
+
+ //Acknowledge the interrupt and send End of Interrupt signal.
+ PL390GicAcknowledgeSgiFrom(PcdGet32(PcdGicInterruptInterfaceBase),0/*CoreId*/);
+
+ //Jump to secondary core entry point.
+ secondary_start();
+
+ // PEI Core should always load and never return
+ ASSERT (FALSE);
+}
+
+VOID SecCommonExceptionEntry(UINT32 Entry, UINT32 LR) {
+ switch (Entry) {
+ case 0:
+ DEBUG((EFI_D_ERROR,"Reset Exception at 0x%X\n",LR));
+ break;
+ case 1:
+ DEBUG((EFI_D_ERROR,"Undefined Exception at 0x%X\n",LR));
+ break;
+ case 2:
+ DEBUG((EFI_D_ERROR,"SWI Exception at 0x%X\n",LR));
+ break;
+ case 3:
+ DEBUG((EFI_D_ERROR,"PrefetchAbort Exception at 0x%X\n",LR));
+ break;
+ case 4:
+ DEBUG((EFI_D_ERROR,"DataAbort Exception at 0x%X\n",LR));
+ break;
+ case 5:
+ DEBUG((EFI_D_ERROR,"Reserved Exception at 0x%X\n",LR));
+ break;
+ case 6:
+ DEBUG((EFI_D_ERROR,"IRQ Exception at 0x%X\n",LR));
+ break;
+ case 7:
+ DEBUG((EFI_D_ERROR,"FIQ Exception at 0x%X\n",LR));
+ break;
+ default:
+ DEBUG((EFI_D_ERROR,"Unknown Exception at 0x%X\n",LR));
+ break;
+ }
+ while(1);
+}