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