1 /** @file 2 * 3 * Copyright (c) 2011-2014, ARM Limited. All rights reserved. 4 * 5 * This program and the accompanying materials 6 * are licensed and made available under the terms and conditions of the BSD License 7 * which accompanies this distribution. The full text of the license may be found at 8 * http://opensource.org/licenses/bsd-license.php 9 * 10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 * 13 **/ 14 15 #include <PiPei.h> 16 17 #include <Library/ArmLib.h> 18 #include <Library/ArmGicLib.h> 19 #include <Library/ArmPlatformLib.h> 20 #include <Library/ArmPlatformSecLib.h> 21 #include <Library/DebugLib.h> 22 #include <Library/PcdLib.h> 23 #include <Library/PrintLib.h> 24 #include <Library/SerialPortLib.h> 25 26 // When the firmware is built as not Standalone, the secondary cores need to wait the firmware 27 // entirely written into DRAM. It is the firmware from DRAM which will wake up the secondary cores. 28 VOID 29 NonSecureWaitForFirmware ( 30 VOID 31 ) 32 { 33 VOID (*SecondaryStart)(VOID); 34 UINTN AcknowledgeInterrupt; 35 UINTN InterruptId; 36 37 // The secondary cores will execute the firmware once wake from WFI. 38 SecondaryStart = (VOID (*)())(UINTN)PcdGet64 (PcdFvBaseAddress); 39 40 ArmCallWFI (); 41 42 // Acknowledge the interrupt and send End of Interrupt signal. 43 AcknowledgeInterrupt = ArmGicAcknowledgeInterrupt (PcdGet32 (PcdGicInterruptInterfaceBase), &InterruptId); 44 // Check if it is a valid interrupt ID 45 if (InterruptId < ArmGicGetMaxNumInterrupts (PcdGet32 (PcdGicDistributorBase))) { 46 // Got a valid SGI number hence signal End of Interrupt 47 ArmGicEndOfInterrupt (PcdGet32 (PcdGicInterruptInterfaceBase), AcknowledgeInterrupt); 48 } 49 50 // Jump to secondary core entry point. 51 SecondaryStart (); 52 53 // PEI Core should always load and never return 54 ASSERT (FALSE); 55 } 56 57 /** 58 Call before jumping to Normal World 59 60 This function allows the firmware platform to do extra actions before 61 jumping to the Normal World 62 63 **/ 64 VOID 65 ArmPlatformSecExtraAction ( 66 IN UINTN MpId, 67 OUT UINTN* JumpAddress 68 ) 69 { 70 CHAR8 Buffer[100]; 71 UINTN CharCount; 72 UINTN* StartAddress; 73 74 if (FeaturePcdGet (PcdStandalone) == FALSE) { 75 76 // 77 // Warning: This code assumes the DRAM has already been initialized by ArmPlatformSecLib 78 // 79 80 if (ArmPlatformIsPrimaryCore (MpId)) { 81 StartAddress = (UINTN*)(UINTN)PcdGet64 (PcdFvBaseAddress); 82 83 // Patch the DRAM to make an infinite loop at the start address 84 *StartAddress = 0xEAFFFFFE; // opcode for while(1) 85 86 CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Waiting for firmware at 0x%08X ...\n\r",StartAddress); 87 SerialPortWrite ((UINT8 *) Buffer, CharCount); 88 89 *JumpAddress = PcdGet64 (PcdFvBaseAddress); 90 } else { 91 // When the primary core is stopped by the hardware debugger to copy the firmware 92 // into DRAM. The secondary cores are still running. As soon as the first bytes of 93 // the firmware are written into DRAM, the secondary cores will start to execute the 94 // code even if the firmware is not entirely written into the memory. 95 // That's why the secondary cores need to be parked in WFI and wake up once the 96 // firmware is ready. 97 98 *JumpAddress = (UINTN)NonSecureWaitForFirmware; 99 } 100 } else if (FeaturePcdGet (PcdSystemMemoryInitializeInSec)) { 101 102 // 103 // Warning: This code assumes the DRAM has already been initialized by ArmPlatformSecLib 104 // 105 106 if (ArmPlatformIsPrimaryCore (MpId)) { 107 // Signal the secondary cores they can jump to PEI phase 108 ArmGicSendSgiTo (PcdGet32 (PcdGicDistributorBase), ARM_GIC_ICDSGIR_FILTER_EVERYONEELSE, 0x0E, PcdGet32 (PcdGicSgiIntId)); 109 110 // To enter into Non Secure state, we need to make a return from exception 111 *JumpAddress = PcdGet64 (PcdFvBaseAddress); 112 } else { 113 // We wait for the primary core to finish to initialize the System Memory. Otherwise the secondary 114 // cores would make crash the system by setting their stacks in DRAM before the primary core has not 115 // finished to initialize the system memory. 116 *JumpAddress = (UINTN)NonSecureWaitForFirmware; 117 } 118 } else { 119 *JumpAddress = PcdGet64 (PcdFvBaseAddress); 120 } 121 } 122