Home | History | Annotate | Download | only in MpBootDxe
      1 /** @file
      2 
      3   Copyright (c) 2016, AMD Inc. All rights reserved.<BR>
      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/ArmLib.h>
     16 #include <Library/ArmSmcLib.h>
     17 #include <Library/BaseMemoryLib.h>
     18 #include <Library/CacheMaintenanceLib.h>
     19 #include <Library/DebugLib.h>
     20 #include <Library/UefiDriverEntryPoint.h>
     21 #include <Library/UefiBootServicesTableLib.h>
     22 
     23 #include <Guid/ArmMpCoreInfo.h>
     24 #include <Protocol/AmdMpBoot.h>
     25 
     26 
     27 /* These externs are used to relocate our Pen code into pre-allocated memory */
     28 extern VOID  *SecondariesPenStart;
     29 extern VOID  *SecondariesPenEnd;
     30 extern UINTN *AsmParkingBase;
     31 extern UINTN *AsmMailboxBase;
     32 
     33 
     34 STATIC
     35 EFI_PHYSICAL_ADDRESS
     36 ConfigurePen (
     37   IN EFI_PHYSICAL_ADDRESS     MpParkingBase,
     38   IN UINTN                    MpParkingSize,
     39   IN ARM_CORE_INFO            *ArmCoreInfoTable,
     40   IN UINTN                    ArmCoreCount
     41   )
     42 {
     43   EFI_PHYSICAL_ADDRESS     PenBase;
     44   UINTN                    PenSize;
     45   UINTN                    MailboxBase;
     46   UINTN                    CoreNum;
     47   UINTN                    CoreMailbox;
     48   UINTN                    CoreParking;
     49 
     50   //
     51   // Set Pen at the 2K-offset of the Parking area, skipping an 8-byte slot for the Core#.
     52   // For details, refer to the "Multi-processor Startup for ARM Platforms" document:
     53   // https://acpica.org/sites/acpica/files/MP%20Startup%20for%20ARM%20platforms.docx
     54   //
     55   PenBase = (EFI_PHYSICAL_ADDRESS)((UINTN)MpParkingBase + SIZE_2KB + sizeof(UINT64));
     56   PenSize  = (UINTN)&SecondariesPenEnd - (UINTN)&SecondariesPenStart;
     57 
     58   // Relocate the Pen code
     59   CopyMem ((VOID*)(PenBase), (VOID*)&SecondariesPenStart, PenSize);
     60 
     61   // Put spin-table mailboxes below the pen code so we know where they are relative to code.
     62   // Make sure this is 8 byte aligned.
     63   MailboxBase = (UINTN)PenBase + ((UINTN)&SecondariesPenEnd - (UINTN)&SecondariesPenStart);
     64   if (MailboxBase % sizeof(UINT64) != 0) {
     65     MailboxBase += sizeof(UINT64) - MailboxBase % sizeof(UINT64);
     66   }
     67 
     68   // Update variables used in the Pen code
     69   *(UINTN*)(PenBase + ((UINTN)&AsmMailboxBase - (UINTN)&SecondariesPenStart)) = MailboxBase;
     70   *(UINTN*)(PenBase + ((UINTN)&AsmParkingBase - (UINTN)&SecondariesPenStart)) = (UINTN)MpParkingBase;
     71 
     72   for (CoreNum = 0; CoreNum < ArmCoreCount; CoreNum++) {
     73     // Clear the jump address at spin-table slot
     74     CoreMailbox = MailboxBase + CoreNum * sizeof (UINT64);
     75     *((UINTN*)(CoreMailbox)) = 0x0;
     76 
     77     // Clear the jump address and set Core# at mp-parking slot
     78     CoreParking = (UINTN)MpParkingBase + CoreNum * SIZE_4KB;
     79     *((UINTN*)(CoreParking + sizeof (UINT64))) = 0x0;
     80     *((UINTN*)(CoreParking + SIZE_2KB)) = CoreNum;
     81 
     82     // Update table entry to be consumed by FDT parser
     83     ArmCoreInfoTable[CoreNum].MailboxSetAddress = CoreMailbox;
     84   }
     85 
     86   // flush the cache before launching secondary cores
     87   WriteBackDataCacheRange ((VOID *)MpParkingBase, MpParkingSize);
     88 
     89   return PenBase;
     90 }
     91 
     92 
     93 EFI_STATUS
     94 EFIAPI
     95 MpBootDxeEntryPoint (
     96   IN EFI_HANDLE         ImageHandle,
     97   IN EFI_SYSTEM_TABLE   *SystemTable
     98   )
     99 {
    100   EFI_STATUS               Status;
    101   AMD_MP_BOOT_PROTOCOL     *MpBootProtocol;
    102   EFI_PHYSICAL_ADDRESS     MpParkingBase;
    103   UINTN                    MpParkingSize;
    104   ARM_CORE_INFO            *ArmCoreInfoTable;
    105   UINTN                    ArmCoreCount;
    106   UINTN                    CoreNum;
    107   EFI_PHYSICAL_ADDRESS     PenBase;
    108 
    109   DEBUG ((EFI_D_ERROR, "MpBootDxe Loaded\n"));
    110 
    111   MpBootProtocol = NULL;
    112   Status = gBS->LocateProtocol (
    113                &gAmdMpBootProtocolGuid,
    114                NULL,
    115                (VOID **)&MpBootProtocol
    116                );
    117   if (EFI_ERROR (Status) || MpBootProtocol == NULL) {
    118     DEBUG ((EFI_D_ERROR, "Warning: Failed to locate MP-Boot Protocol.\n"));
    119     return EFI_UNSUPPORTED;
    120   }
    121 
    122   if ((VOID *)MpBootProtocol->MpBootInfo == NULL) {
    123     DEBUG ((EFI_D_ERROR, "Warning: MpBootInfo not allocated.\n"));
    124     return EFI_UNSUPPORTED;
    125   }
    126 
    127   MpParkingBase = MpBootProtocol->MpBootInfo->MpParkingBase;
    128   if ((VOID *)MpParkingBase == NULL) {
    129     DEBUG ((EFI_D_ERROR, "Warning: MpParkingBase not allocated.\n"));
    130     return EFI_UNSUPPORTED;
    131   }
    132   if (((UINTN)MpParkingBase & (SIZE_4KB -1)) != 0) {
    133     DEBUG ((EFI_D_ERROR, "Warning: MpParkingBase not 4K aligned.\n"));
    134     return EFI_UNSUPPORTED;
    135   }
    136 
    137   ArmCoreInfoTable = MpBootProtocol->MpBootInfo->ArmCoreInfoTable;
    138   if (ArmCoreInfoTable == NULL) {
    139     DEBUG ((EFI_D_ERROR, "Warning: ArmCoreInfoTable not allocated.\n"));
    140     return EFI_UNSUPPORTED;
    141   }
    142 
    143   ArmCoreCount = MpBootProtocol->MpBootInfo->ArmCoreCount;
    144   if (ArmCoreCount < 2) {
    145     DEBUG ((EFI_D_ERROR, "Warning: Found %d cores.\n", ArmCoreCount));
    146     return EFI_UNSUPPORTED;
    147   }
    148 
    149   MpParkingSize = ArmCoreCount * SIZE_4KB;
    150   if (MpParkingSize > MpBootProtocol->MpBootInfo->MpParkingSize) {
    151     DEBUG ((EFI_D_ERROR, "Warning: MpParkingSize = 0x%lX, not large enough for %d cores.\n",
    152       MpBootProtocol->MpBootInfo->MpParkingSize, ArmCoreCount));
    153     return EFI_UNSUPPORTED;
    154   }
    155 
    156   if ((VOID *)MpBootProtocol->ParkSecondaryCore == NULL) {
    157     DEBUG ((EFI_D_ERROR, "Warning: ParkSecondaryCore() not supported.\n"));
    158     return EFI_UNSUPPORTED;
    159   }
    160 
    161   // Move secondary cores to our new Pen
    162   PenBase = ConfigurePen (MpParkingBase, MpParkingSize, ArmCoreInfoTable, ArmCoreCount);
    163   for (CoreNum = 0; CoreNum < ArmCoreCount; CoreNum++) {
    164     MpBootProtocol->ParkSecondaryCore (&ArmCoreInfoTable[CoreNum], PenBase);
    165   }
    166 
    167   return EFI_SUCCESS;
    168 }
    169 
    170 
    171