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