1 /** @file 2 Implementation of SMM CPU Services Protocol. 3 4 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR> 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 "PiSmmCpuDxeSmm.h" 16 17 // 18 // SMM CPU Service Protocol instance 19 // 20 EFI_SMM_CPU_SERVICE_PROTOCOL mSmmCpuService = { 21 SmmGetProcessorInfo, 22 SmmSwitchBsp, 23 SmmAddProcessor, 24 SmmRemoveProcessor, 25 SmmWhoAmI, 26 SmmRegisterExceptionHandler 27 }; 28 29 /** 30 Gets processor information on the requested processor at the instant this call is made. 31 32 @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. 33 @param[in] ProcessorNumber The handle number of processor. 34 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for 35 the requested processor is deposited. 36 37 @retval EFI_SUCCESS Processor information was returned. 38 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL. 39 @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid. 40 @retval EFI_NOT_FOUND The processor with the handle specified by 41 ProcessorNumber does not exist in the platform. 42 43 **/ 44 EFI_STATUS 45 EFIAPI 46 SmmGetProcessorInfo ( 47 IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, 48 IN UINTN ProcessorNumber, 49 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer 50 ) 51 { 52 // 53 // Check parameter 54 // 55 if (ProcessorNumber >= mMaxNumberOfCpus || ProcessorInfoBuffer == NULL) { 56 return EFI_INVALID_PARAMETER; 57 } 58 59 if (gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID) { 60 return EFI_NOT_FOUND; 61 } 62 63 // 64 // Fill in processor information 65 // 66 CopyMem (ProcessorInfoBuffer, &gSmmCpuPrivate->ProcessorInfo[ProcessorNumber], sizeof (EFI_PROCESSOR_INFORMATION)); 67 return EFI_SUCCESS; 68 } 69 70 /** 71 This service switches the requested AP to be the BSP since the next SMI. 72 73 @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. 74 @param[in] ProcessorNumber The handle number of AP that is to become the new BSP. 75 76 @retval EFI_SUCCESS BSP will be switched in next SMI. 77 @retval EFI_UNSUPPORTED Switching the BSP or a processor to be hot-removed is not supported. 78 @retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist. 79 @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid. 80 **/ 81 EFI_STATUS 82 EFIAPI 83 SmmSwitchBsp ( 84 IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, 85 IN UINTN ProcessorNumber 86 ) 87 { 88 // 89 // Check parameter 90 // 91 if (ProcessorNumber >= mMaxNumberOfCpus) { 92 return EFI_INVALID_PARAMETER; 93 } 94 95 if (gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID) { 96 return EFI_NOT_FOUND; 97 } 98 99 if (gSmmCpuPrivate->Operation[ProcessorNumber] != SmmCpuNone || 100 gSmst->CurrentlyExecutingCpu == ProcessorNumber) { 101 return EFI_UNSUPPORTED; 102 } 103 104 // 105 // Setting of the BSP for next SMI is pending until all SMI handlers are finished 106 // 107 gSmmCpuPrivate->Operation[ProcessorNumber] = SmmCpuSwitchBsp; 108 return EFI_SUCCESS; 109 } 110 111 /** 112 Notify that a processor was hot-added. 113 114 @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. 115 @param[in] ProcessorId Local APIC ID of the hot-added processor. 116 @param[out] ProcessorNumber The handle number of the hot-added processor. 117 118 @retval EFI_SUCCESS The hot-addition of the specified processors was successfully notified. 119 @retval EFI_UNSUPPORTED Hot addition of processor is not supported. 120 @retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist. 121 @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid. 122 @retval EFI_ALREADY_STARTED The processor is already online in the system. 123 **/ 124 EFI_STATUS 125 EFIAPI 126 SmmAddProcessor ( 127 IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, 128 IN UINT64 ProcessorId, 129 OUT UINTN *ProcessorNumber 130 ) 131 { 132 UINTN Index; 133 134 if (!FeaturePcdGet (PcdCpuHotPlugSupport)) { 135 return EFI_UNSUPPORTED; 136 } 137 138 // 139 // Check parameter 140 // 141 if (ProcessorNumber == NULL || ProcessorId == INVALID_APIC_ID) { 142 return EFI_INVALID_PARAMETER; 143 } 144 145 // 146 // Check if the processor already exists 147 // 148 149 for (Index = 0; Index < mMaxNumberOfCpus; Index++) { 150 if (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == ProcessorId) { 151 return EFI_ALREADY_STARTED; 152 } 153 } 154 155 // 156 // Check CPU hot plug data. The CPU RAS handler should have created the mapping 157 // of the APIC ID to SMBASE. 158 // 159 for (Index = 0; Index < mMaxNumberOfCpus; Index++) { 160 if (mCpuHotPlugData.ApicId[Index] == ProcessorId && 161 gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == INVALID_APIC_ID) { 162 gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId = ProcessorId; 163 gSmmCpuPrivate->ProcessorInfo[Index].StatusFlag = 0; 164 GetProcessorLocationByApicId ( 165 (UINT32)ProcessorId, 166 &gSmmCpuPrivate->ProcessorInfo[Index].Location.Package, 167 &gSmmCpuPrivate->ProcessorInfo[Index].Location.Core, 168 &gSmmCpuPrivate->ProcessorInfo[Index].Location.Thread 169 ); 170 171 *ProcessorNumber = Index; 172 gSmmCpuPrivate->Operation[Index] = SmmCpuAdd; 173 return EFI_SUCCESS; 174 } 175 } 176 177 return EFI_INVALID_PARAMETER; 178 } 179 180 /** 181 Notify that a processor was hot-removed. 182 183 @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. 184 @param[in] ProcessorNumber The handle number of the hot-added processor. 185 186 @retval EFI_SUCCESS The hot-removal of the specified processors was successfully notified. 187 @retval EFI_UNSUPPORTED Hot removal of processor is not supported. 188 @retval EFI_UNSUPPORTED Hot removal of BSP is not supported. 189 @retval EFI_UNSUPPORTED Hot removal of a processor with pending hot-plug operation is not supported. 190 @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid. 191 **/ 192 EFI_STATUS 193 EFIAPI 194 SmmRemoveProcessor ( 195 IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, 196 IN UINTN ProcessorNumber 197 ) 198 { 199 if (!FeaturePcdGet (PcdCpuHotPlugSupport)) { 200 return EFI_UNSUPPORTED; 201 } 202 203 // 204 // Check parameter 205 // 206 if (ProcessorNumber >= mMaxNumberOfCpus || 207 gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID) { 208 return EFI_INVALID_PARAMETER; 209 } 210 211 // 212 // Can't remove BSP 213 // 214 if (ProcessorNumber == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) { 215 return EFI_UNSUPPORTED; 216 } 217 218 if (gSmmCpuPrivate->Operation[ProcessorNumber] != SmmCpuNone) { 219 return EFI_UNSUPPORTED; 220 } 221 222 gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId = INVALID_APIC_ID; 223 mCpuHotPlugData.ApicId[ProcessorNumber] = INVALID_APIC_ID; 224 225 // 226 // Removal of the processor from the CPU list is pending until all SMI handlers are finished 227 // 228 gSmmCpuPrivate->Operation[ProcessorNumber] = SmmCpuRemove; 229 return EFI_SUCCESS; 230 } 231 232 /** 233 This return the handle number for the calling processor. 234 235 @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance. 236 @param[out] ProcessorNumber The handle number of currently executing processor. 237 238 @retval EFI_SUCCESS The current processor handle number was returned 239 in ProcessorNumber. 240 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. 241 242 **/ 243 EFI_STATUS 244 EFIAPI 245 SmmWhoAmI ( 246 IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This, 247 OUT UINTN *ProcessorNumber 248 ) 249 { 250 UINTN Index; 251 UINT64 ApicId; 252 253 // 254 // Check parameter 255 // 256 if (ProcessorNumber == NULL) { 257 return EFI_INVALID_PARAMETER; 258 } 259 260 ApicId = GetApicId (); 261 262 for (Index = 0; Index < mMaxNumberOfCpus; Index++) { 263 if (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == ApicId) { 264 *ProcessorNumber = Index; 265 return EFI_SUCCESS; 266 } 267 } 268 // 269 // This should not happen 270 // 271 ASSERT (FALSE); 272 return EFI_NOT_FOUND; 273 } 274 275 /** 276 Update the SMM CPU list per the pending operation. 277 278 This function is called after return from SMI handlers. 279 **/ 280 VOID 281 SmmCpuUpdate ( 282 VOID 283 ) 284 { 285 UINTN Index; 286 287 // 288 // Handle pending BSP switch operations 289 // 290 for (Index = 0; Index < mMaxNumberOfCpus; Index++) { 291 if (gSmmCpuPrivate->Operation[Index] == SmmCpuSwitchBsp) { 292 gSmmCpuPrivate->Operation[Index] = SmmCpuNone; 293 mSmmMpSyncData->SwitchBsp = TRUE; 294 mSmmMpSyncData->CandidateBsp[Index] = TRUE; 295 } 296 } 297 298 // 299 // Handle pending hot-add operations 300 // 301 for (Index = 0; Index < mMaxNumberOfCpus; Index++) { 302 if (gSmmCpuPrivate->Operation[Index] == SmmCpuAdd) { 303 gSmmCpuPrivate->Operation[Index] = SmmCpuNone; 304 mNumberOfCpus++; 305 } 306 } 307 308 // 309 // Handle pending hot-remove operations 310 // 311 for (Index = 0; Index < mMaxNumberOfCpus; Index++) { 312 if (gSmmCpuPrivate->Operation[Index] == SmmCpuRemove) { 313 gSmmCpuPrivate->Operation[Index] = SmmCpuNone; 314 mNumberOfCpus--; 315 } 316 } 317 } 318 319 /** 320 Register exception handler. 321 322 @param This A pointer to the SMM_CPU_SERVICE_PROTOCOL instance. 323 @param ExceptionType Defines which interrupt or exception to hook. Type EFI_EXCEPTION_TYPE and 324 the valid values for this parameter are defined in EFI_DEBUG_SUPPORT_PROTOCOL 325 of the UEFI 2.0 specification. 326 @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER 327 that is called when a processor interrupt occurs. 328 If this parameter is NULL, then the handler will be uninstalled. 329 330 @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. 331 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was previously installed. 332 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not previously installed. 333 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. 334 335 **/ 336 EFI_STATUS 337 EFIAPI 338 SmmRegisterExceptionHandler ( 339 IN EFI_SMM_CPU_SERVICE_PROTOCOL *This, 340 IN EFI_EXCEPTION_TYPE ExceptionType, 341 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler 342 ) 343 { 344 return RegisterCpuInterruptHandler (ExceptionType, InterruptHandler); 345 } 346 347 /** 348 Initialize SMM CPU Services. 349 350 It installs EFI SMM CPU Services Protocol. 351 352 @param ImageHandle The firmware allocated handle for the EFI image. 353 354 @retval EFI_SUCCESS EFI SMM CPU Services Protocol was installed successfully. 355 **/ 356 EFI_STATUS 357 InitializeSmmCpuServices ( 358 IN EFI_HANDLE Handle 359 ) 360 { 361 EFI_STATUS Status; 362 363 Status = gSmst->SmmInstallProtocolInterface ( 364 &Handle, 365 &gEfiSmmCpuServiceProtocolGuid, 366 EFI_NATIVE_INTERFACE, 367 &mSmmCpuService 368 ); 369 ASSERT_EFI_ERROR (Status); 370 return Status; 371 } 372 373