Home | History | Annotate | Download | only in PrePeiCore
      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 <Library/ArmGicLib.h>
     16 
     17 #include <Ppi/ArmMpCoreInfo.h>
     18 
     19 #include "PrePeiCore.h"
     20 
     21 /*
     22  * This is the main function for secondary cores. They loop around until a non Null value is written to
     23  * SYS_FLAGS register.The SYS_FLAGS register is platform specific.
     24  * Note:The secondary cores, while executing secondary_main, assumes that:
     25  *      : SGI 0 is configured as Non-secure interrupt
     26  *      : Priority Mask is configured to allow SGI 0
     27  *      : Interrupt Distributor and CPU interfaces are enabled
     28  *
     29  */
     30 VOID
     31 EFIAPI
     32 SecondaryMain (
     33   IN UINTN MpId
     34   )
     35 {
     36   EFI_STATUS              Status;
     37   UINTN                   PpiListSize;
     38   UINTN                   PpiListCount;
     39   EFI_PEI_PPI_DESCRIPTOR  *PpiList;
     40   ARM_MP_CORE_INFO_PPI    *ArmMpCoreInfoPpi;
     41   UINTN                   Index;
     42   UINTN                   ArmCoreCount;
     43   ARM_CORE_INFO           *ArmCoreInfoTable;
     44   UINT32                  ClusterId;
     45   UINT32                  CoreId;
     46   VOID                    (*SecondaryStart)(VOID);
     47   UINTN                   SecondaryEntryAddr;
     48   UINTN                   AcknowledgeInterrupt;
     49   UINTN                   InterruptId;
     50 
     51   ClusterId = GET_CLUSTER_ID(MpId);
     52   CoreId    = GET_CORE_ID(MpId);
     53 
     54   // Get the gArmMpCoreInfoPpiGuid
     55   PpiListSize = 0;
     56   ArmPlatformGetPlatformPpiList (&PpiListSize, &PpiList);
     57   PpiListCount = PpiListSize / sizeof(EFI_PEI_PPI_DESCRIPTOR);
     58   for (Index = 0; Index < PpiListCount; Index++, PpiList++) {
     59     if (CompareGuid (PpiList->Guid, &gArmMpCoreInfoPpiGuid) == TRUE) {
     60       break;
     61     }
     62   }
     63 
     64   // On MP Core Platform we must implement the ARM MP Core Info PPI
     65   ASSERT (Index != PpiListCount);
     66 
     67   ArmMpCoreInfoPpi = PpiList->Ppi;
     68   ArmCoreCount = 0;
     69   Status = ArmMpCoreInfoPpi->GetMpCoreInfo (&ArmCoreCount, &ArmCoreInfoTable);
     70   ASSERT_EFI_ERROR (Status);
     71 
     72   // Find the core in the ArmCoreTable
     73   for (Index = 0; Index < ArmCoreCount; Index++) {
     74     if ((ArmCoreInfoTable[Index].ClusterId == ClusterId) && (ArmCoreInfoTable[Index].CoreId == CoreId)) {
     75       break;
     76     }
     77   }
     78 
     79   // The ARM Core Info Table must define every core
     80   ASSERT (Index != ArmCoreCount);
     81 
     82   // Clear Secondary cores MailBox
     83   MmioWrite32 (ArmCoreInfoTable[Index].MailboxClearAddress, ArmCoreInfoTable[Index].MailboxClearValue);
     84 
     85   do {
     86     ArmCallWFI ();
     87 
     88     // Read the Mailbox
     89     SecondaryEntryAddr = MmioRead32 (ArmCoreInfoTable[Index].MailboxGetAddress);
     90 
     91     // Acknowledge the interrupt and send End of Interrupt signal.
     92     AcknowledgeInterrupt = ArmGicAcknowledgeInterrupt (PcdGet64 (PcdGicInterruptInterfaceBase), &InterruptId);
     93     // Check if it is a valid interrupt ID
     94     if (InterruptId < ArmGicGetMaxNumInterrupts (PcdGet64 (PcdGicDistributorBase))) {
     95       // Got a valid SGI number hence signal End of Interrupt
     96       ArmGicEndOfInterrupt (PcdGet64 (PcdGicInterruptInterfaceBase), AcknowledgeInterrupt);
     97     }
     98   } while (SecondaryEntryAddr == 0);
     99 
    100   // Jump to secondary core entry point.
    101   SecondaryStart = (VOID (*)())SecondaryEntryAddr;
    102   SecondaryStart();
    103 
    104   // The secondaries shouldn't reach here
    105   ASSERT(FALSE);
    106 }
    107 
    108 VOID
    109 EFIAPI
    110 PrimaryMain (
    111   IN  EFI_PEI_CORE_ENTRY_POINT  PeiCoreEntryPoint
    112   )
    113 {
    114   EFI_SEC_PEI_HAND_OFF        SecCoreData;
    115   UINTN                       PpiListSize;
    116   EFI_PEI_PPI_DESCRIPTOR      *PpiList;
    117   UINTN                       TemporaryRamBase;
    118   UINTN                       TemporaryRamSize;
    119 
    120   CreatePpiList (&PpiListSize, &PpiList);
    121 
    122   // Enable the GIC Distributor
    123   ArmGicEnableDistributor (PcdGet64(PcdGicDistributorBase));
    124 
    125   // If ArmVe has not been built as Standalone then we need to wake up the secondary cores
    126   if (FeaturePcdGet (PcdSendSgiToBringUpSecondaryCores)) {
    127     // Sending SGI to all the Secondary CPU interfaces
    128     ArmGicSendSgiTo (PcdGet64(PcdGicDistributorBase), ARM_GIC_ICDSGIR_FILTER_EVERYONEELSE, 0x0E, PcdGet32 (PcdGicSgiIntId));
    129   }
    130 
    131   // Adjust the Temporary Ram as the new Ppi List (Common + Platform Ppi Lists) is created at
    132   // the base of the primary core stack
    133   PpiListSize = ALIGN_VALUE(PpiListSize, CPU_STACK_ALIGNMENT);
    134   TemporaryRamBase = (UINTN)PcdGet64 (PcdCPUCoresStackBase) + PpiListSize;
    135   TemporaryRamSize = (UINTN)PcdGet32 (PcdCPUCorePrimaryStackSize) - PpiListSize;
    136 
    137   //
    138   // Bind this information into the SEC hand-off state
    139   // Note: this must be in sync with the stuff in the asm file
    140   // Note also:  HOBs (pei temp ram) MUST be above stack
    141   //
    142   SecCoreData.DataSize               = sizeof(EFI_SEC_PEI_HAND_OFF);
    143   SecCoreData.BootFirmwareVolumeBase = (VOID *)(UINTN)PcdGet64 (PcdFvBaseAddress);
    144   SecCoreData.BootFirmwareVolumeSize = PcdGet32 (PcdFvSize);
    145   SecCoreData.TemporaryRamBase       = (VOID *)TemporaryRamBase; // We run on the primary core (and so we use the first stack)
    146   SecCoreData.TemporaryRamSize       = TemporaryRamSize;
    147   SecCoreData.PeiTemporaryRamBase    = SecCoreData.TemporaryRamBase;
    148   SecCoreData.PeiTemporaryRamSize    = ALIGN_VALUE (SecCoreData.TemporaryRamSize / 2, CPU_STACK_ALIGNMENT);
    149   SecCoreData.StackBase              = (VOID *)((UINTN)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize);
    150   SecCoreData.StackSize              = (TemporaryRamBase + TemporaryRamSize) - (UINTN)SecCoreData.StackBase;
    151 
    152   // Jump to PEI core entry point
    153   PeiCoreEntryPoint (&SecCoreData, PpiList);
    154 }
    155