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 "PrePi.h"
16 
17 #include <Library/ArmGicLib.h>
18 
19 #include <Ppi/ArmMpCoreInfo.h>
20 
21 VOID
PrimaryMain(IN UINTN UefiMemoryBase,IN UINTN StacksBase,IN UINT64 StartTimeStamp)22 PrimaryMain (
23   IN  UINTN                     UefiMemoryBase,
24   IN  UINTN                     StacksBase,
25   IN  UINT64                    StartTimeStamp
26   )
27 {
28   // Enable the GIC Distributor
29   ArmGicEnableDistributor(PcdGet32(PcdGicDistributorBase));
30 
31   // In some cases, the secondary cores are waiting for an SGI from the next stage boot loader to resume their initialization
32   if (!FixedPcdGet32(PcdSendSgiToBringUpSecondaryCores)) {
33     // Sending SGI to all the Secondary CPU interfaces
34     ArmGicSendSgiTo (PcdGet32(PcdGicDistributorBase), ARM_GIC_ICDSGIR_FILTER_EVERYONEELSE, 0x0E, PcdGet32 (PcdGicSgiIntId));
35   }
36 
37   PrePiMain (UefiMemoryBase, StacksBase, StartTimeStamp);
38 
39   // We must never return
40   ASSERT(FALSE);
41 }
42 
43 VOID
SecondaryMain(IN UINTN MpId)44 SecondaryMain (
45   IN  UINTN                     MpId
46   )
47 {
48   EFI_STATUS              Status;
49   ARM_MP_CORE_INFO_PPI    *ArmMpCoreInfoPpi;
50   UINTN                   Index;
51   UINTN                   ArmCoreCount;
52   ARM_CORE_INFO           *ArmCoreInfoTable;
53   UINT32                  ClusterId;
54   UINT32                  CoreId;
55   VOID                    (*SecondaryStart)(VOID);
56   UINTN                   SecondaryEntryAddr;
57   UINTN                   AcknowledgeInterrupt;
58   UINTN                   InterruptId;
59 
60   ClusterId = GET_CLUSTER_ID(MpId);
61   CoreId    = GET_CORE_ID(MpId);
62 
63   // On MP Core Platform we must implement the ARM MP Core Info PPI (gArmMpCoreInfoPpiGuid)
64   Status = GetPlatformPpi (&gArmMpCoreInfoPpiGuid, (VOID**)&ArmMpCoreInfoPpi);
65   ASSERT_EFI_ERROR (Status);
66 
67   ArmCoreCount = 0;
68   Status = ArmMpCoreInfoPpi->GetMpCoreInfo (&ArmCoreCount, &ArmCoreInfoTable);
69   ASSERT_EFI_ERROR (Status);
70 
71   // Find the core in the ArmCoreTable
72   for (Index = 0; Index < ArmCoreCount; Index++) {
73     if ((ArmCoreInfoTable[Index].ClusterId == ClusterId) && (ArmCoreInfoTable[Index].CoreId == CoreId)) {
74       break;
75     }
76   }
77 
78   // The ARM Core Info Table must define every core
79   ASSERT (Index != ArmCoreCount);
80 
81   // Clear Secondary cores MailBox
82   MmioWrite32 (ArmCoreInfoTable[Index].MailboxClearAddress, ArmCoreInfoTable[Index].MailboxClearValue);
83 
84   do {
85     ArmCallWFI ();
86 
87     // Read the Mailbox
88     SecondaryEntryAddr = MmioRead32 (ArmCoreInfoTable[Index].MailboxGetAddress);
89 
90     // Acknowledge the interrupt and send End of Interrupt signal.
91     AcknowledgeInterrupt = ArmGicAcknowledgeInterrupt (PcdGet32 (PcdGicInterruptInterfaceBase), &InterruptId);
92     // Check if it is a valid interrupt ID
93     if (InterruptId < ArmGicGetMaxNumInterrupts (PcdGet32 (PcdGicDistributorBase))) {
94       // Got a valid SGI number hence signal End of Interrupt
95       ArmGicEndOfInterrupt (PcdGet32 (PcdGicInterruptInterfaceBase), AcknowledgeInterrupt);
96     }
97   } while (SecondaryEntryAddr == 0);
98 
99   // Jump to secondary core entry point.
100   SecondaryStart = (VOID (*)())SecondaryEntryAddr;
101   SecondaryStart();
102 
103   // The secondaries shouldn't reach here
104   ASSERT(FALSE);
105 }
106