1 | /** @file
|
---|
2 | SMM MP protocol implementation
|
---|
3 |
|
---|
4 | Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
|
---|
5 |
|
---|
6 | SPDX-License-Identifier: BSD-2-Clause-Patent
|
---|
7 |
|
---|
8 | **/
|
---|
9 |
|
---|
10 | #include "PiSmmCpuDxeSmm.h"
|
---|
11 | #include "SmmMp.h"
|
---|
12 |
|
---|
13 | ///
|
---|
14 | /// SMM MP Protocol instance
|
---|
15 | ///
|
---|
16 | EFI_MM_MP_PROTOCOL mSmmMp = {
|
---|
17 | EFI_MM_MP_PROTOCOL_REVISION,
|
---|
18 | 0,
|
---|
19 | SmmMpGetNumberOfProcessors,
|
---|
20 | SmmMpDispatchProcedure,
|
---|
21 | SmmMpBroadcastProcedure,
|
---|
22 | SmmMpSetStartupProcedure,
|
---|
23 | SmmMpCheckForProcedure,
|
---|
24 | SmmMpWaitForProcedure
|
---|
25 | };
|
---|
26 |
|
---|
27 | /**
|
---|
28 | Service to retrieves the number of logical processor in the platform.
|
---|
29 |
|
---|
30 | @param[in] This The EFI_MM_MP_PROTOCOL instance.
|
---|
31 | @param[out] NumberOfProcessors Pointer to the total number of logical processors in the system,
|
---|
32 | including the BSP and all APs.
|
---|
33 |
|
---|
34 | @retval EFI_SUCCESS The number of processors was retrieved successfully
|
---|
35 | @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL
|
---|
36 | **/
|
---|
37 | EFI_STATUS
|
---|
38 | EFIAPI
|
---|
39 | SmmMpGetNumberOfProcessors (
|
---|
40 | IN CONST EFI_MM_MP_PROTOCOL *This,
|
---|
41 | OUT UINTN *NumberOfProcessors
|
---|
42 | )
|
---|
43 | {
|
---|
44 | if (NumberOfProcessors == NULL) {
|
---|
45 | return EFI_INVALID_PARAMETER;
|
---|
46 | }
|
---|
47 |
|
---|
48 | *NumberOfProcessors = gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
|
---|
49 |
|
---|
50 | return EFI_SUCCESS;
|
---|
51 | }
|
---|
52 |
|
---|
53 | /**
|
---|
54 | This service allows the caller to invoke a procedure one of the application processors (AP). This
|
---|
55 | function uses an optional token parameter to support blocking and non-blocking modes. If the token
|
---|
56 | is passed into the call, the function will operate in a non-blocking fashion and the caller can
|
---|
57 | check for completion with CheckOnProcedure or WaitForProcedure.
|
---|
58 |
|
---|
59 | @param[in] This The EFI_MM_MP_PROTOCOL instance.
|
---|
60 | @param[in] Procedure A pointer to the procedure to be run on the designated target
|
---|
61 | AP of the system. Type EFI_AP_PROCEDURE2 is defined below in
|
---|
62 | related definitions.
|
---|
63 | @param[in] CpuNumber The zero-based index of the processor number of the target
|
---|
64 | AP, on which the code stream is supposed to run. If the number
|
---|
65 | points to the calling processor then it will not run the
|
---|
66 | supplied code.
|
---|
67 | @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for this AP to
|
---|
68 | finish execution of Procedure, either for blocking or
|
---|
69 | non-blocking mode. Zero means infinity. If the timeout
|
---|
70 | expires before this AP returns from Procedure, then Procedure
|
---|
71 | on the AP is terminated. If the timeout expires in blocking
|
---|
72 | mode, the call returns EFI_TIMEOUT. If the timeout expires
|
---|
73 | in non-blocking mode, the timeout determined can be through
|
---|
74 | CheckOnProcedure or WaitForProcedure.
|
---|
75 | Note that timeout support is optional. Whether an
|
---|
76 | implementation supports this feature, can be determined via
|
---|
77 | the Attributes data member.
|
---|
78 | @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code
|
---|
79 | that is run by the AP. It is an optional common mailbox
|
---|
80 | between APs and the caller to share information.
|
---|
81 | @param[in,out] Token This is parameter is broken into two components:
|
---|
82 | 1.Token->Completion is an optional parameter that allows the
|
---|
83 | caller to execute the procedure in a blocking or non-blocking
|
---|
84 | fashion. If it is NULL the call is blocking, and the call will
|
---|
85 | not return until the AP has completed the procedure. If the
|
---|
86 | token is not NULL, the call will return immediately. The caller
|
---|
87 | can check whether the procedure has completed with
|
---|
88 | CheckOnProcedure or WaitForProcedure.
|
---|
89 | 2.Token->Status The implementation updates the address pointed
|
---|
90 | at by this variable with the status code returned by Procedure
|
---|
91 | when it completes execution on the target AP, or with EFI_TIMEOUT
|
---|
92 | if the Procedure fails to complete within the optional timeout.
|
---|
93 | The implementation will update this variable with EFI_NOT_READY
|
---|
94 | prior to starting Procedure on the target AP
|
---|
95 | @param[in,out] CPUStatus This optional pointer may be used to get the status code returned
|
---|
96 | by Procedure when it completes execution on the target AP, or with
|
---|
97 | EFI_TIMEOUT if the Procedure fails to complete within the optional
|
---|
98 | timeout. The implementation will update this variable with
|
---|
99 | EFI_NOT_READY prior to starting Procedure on the target AP.
|
---|
100 |
|
---|
101 | @retval EFI_SUCCESS In the blocking case, this indicates that Procedure has completed
|
---|
102 | execution on the target AP.
|
---|
103 | In the non-blocking case this indicates that the procedure has
|
---|
104 | been successfully scheduled for execution on the target AP.
|
---|
105 | @retval EFI_INVALID_PARAMETER The input arguments are out of range. Either the target AP is the
|
---|
106 | caller of the function, or the Procedure or Token is NULL
|
---|
107 | @retval EFI_NOT_READY If the target AP is busy executing another procedure
|
---|
108 | @retval EFI_ALREADY_STARTED Token is already in use for another procedure
|
---|
109 | @retval EFI_TIMEOUT In blocking mode, the timeout expired before the specified AP
|
---|
110 | has finished
|
---|
111 | @retval EFI_OUT_OF_RESOURCES Could not allocate a required resource.
|
---|
112 |
|
---|
113 | **/
|
---|
114 | EFI_STATUS
|
---|
115 | EFIAPI
|
---|
116 | SmmMpDispatchProcedure (
|
---|
117 | IN CONST EFI_MM_MP_PROTOCOL *This,
|
---|
118 | IN EFI_AP_PROCEDURE2 Procedure,
|
---|
119 | IN UINTN CpuNumber,
|
---|
120 | IN UINTN TimeoutInMicroseconds,
|
---|
121 | IN OUT VOID *ProcedureArguments OPTIONAL,
|
---|
122 | IN OUT MM_COMPLETION *Token,
|
---|
123 | IN OUT EFI_STATUS *CPUStatus
|
---|
124 | )
|
---|
125 | {
|
---|
126 | return InternalSmmStartupThisAp (
|
---|
127 | Procedure,
|
---|
128 | CpuNumber,
|
---|
129 | ProcedureArguments,
|
---|
130 | Token,
|
---|
131 | TimeoutInMicroseconds,
|
---|
132 | CPUStatus
|
---|
133 | );
|
---|
134 | }
|
---|
135 |
|
---|
136 | /**
|
---|
137 | This service allows the caller to invoke a procedure on all running application processors (AP)
|
---|
138 | except the caller. This function uses an optional token parameter to support blocking and
|
---|
139 | nonblocking modes. If the token is passed into the call, the function will operate in a non-blocking
|
---|
140 | fashion and the caller can check for completion with CheckOnProcedure or WaitForProcedure.
|
---|
141 |
|
---|
142 | It is not necessary for the implementation to run the procedure on every processor on the platform.
|
---|
143 | Processors that are powered down in such a way that they cannot respond to interrupts, may be
|
---|
144 | excluded from the broadcast.
|
---|
145 |
|
---|
146 |
|
---|
147 | @param[in] This The EFI_MM_MP_PROTOCOL instance.
|
---|
148 | @param[in] Procedure A pointer to the code stream to be run on the APs that have
|
---|
149 | entered MM. Type EFI_AP_PROCEDURE is defined below in related
|
---|
150 | definitions.
|
---|
151 | @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for the APs to finish
|
---|
152 | execution of Procedure, either for blocking or non-blocking mode.
|
---|
153 | Zero means infinity. If the timeout expires before all APs return
|
---|
154 | from Procedure, then Procedure on the failed APs is terminated. If
|
---|
155 | the timeout expires in blocking mode, the call returns EFI_TIMEOUT.
|
---|
156 | If the timeout expires in non-blocking mode, the timeout determined
|
---|
157 | can be through CheckOnProcedure or WaitForProcedure.
|
---|
158 | Note that timeout support is optional. Whether an implementation
|
---|
159 | supports this feature can be determined via the Attributes data
|
---|
160 | member.
|
---|
161 | @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code
|
---|
162 | that is run by the AP. It is an optional common mailbox
|
---|
163 | between APs and the caller to share information.
|
---|
164 | @param[in,out] Token This is parameter is broken into two components:
|
---|
165 | 1.Token->Completion is an optional parameter that allows the
|
---|
166 | caller to execute the procedure in a blocking or non-blocking
|
---|
167 | fashion. If it is NULL the call is blocking, and the call will
|
---|
168 | not return until the AP has completed the procedure. If the
|
---|
169 | token is not NULL, the call will return immediately. The caller
|
---|
170 | can check whether the procedure has completed with
|
---|
171 | CheckOnProcedure or WaitForProcedure.
|
---|
172 | 2.Token->Status The implementation updates the address pointed
|
---|
173 | at by this variable with the status code returned by Procedure
|
---|
174 | when it completes execution on the target AP, or with EFI_TIMEOUT
|
---|
175 | if the Procedure fails to complete within the optional timeout.
|
---|
176 | The implementation will update this variable with EFI_NOT_READY
|
---|
177 | prior to starting Procedure on the target AP
|
---|
178 | @param[in,out] CPUStatus This optional pointer may be used to get the individual status
|
---|
179 | returned by every AP that participated in the broadcast. This
|
---|
180 | parameter if used provides the base address of an array to hold
|
---|
181 | the EFI_STATUS value of each AP in the system. The size of the
|
---|
182 | array can be ascertained by the GetNumberOfProcessors function.
|
---|
183 | As mentioned above, the broadcast may not include every processor
|
---|
184 | in the system. Some implementations may exclude processors that
|
---|
185 | have been powered down in such a way that they are not responsive
|
---|
186 | to interrupts. Additionally the broadcast excludes the processor
|
---|
187 | which is making the BroadcastProcedure call. For every excluded
|
---|
188 | processor, the array entry must contain a value of EFI_NOT_STARTED
|
---|
189 |
|
---|
190 | @retval EFI_SUCCESS In the blocking case, this indicates that Procedure has completed
|
---|
191 | execution on the APs.
|
---|
192 | In the non-blocking case this indicates that the procedure has
|
---|
193 | been successfully scheduled for execution on the APs.
|
---|
194 | @retval EFI_INVALID_PARAMETER The Procedure or Token is NULL
|
---|
195 | @retval EFI_NOT_READY If the target AP is busy executing another procedure
|
---|
196 | @retval EFI_ALREADY_STARTED Token is already in use for another procedure
|
---|
197 | @retval EFI_TIMEOUT In blocking mode, the timeout expired before the specified AP
|
---|
198 | has finished.
|
---|
199 | @retval EFI_OUT_OF_RESOURCES Could not allocate a required resource.
|
---|
200 |
|
---|
201 | **/
|
---|
202 | EFI_STATUS
|
---|
203 | EFIAPI
|
---|
204 | SmmMpBroadcastProcedure (
|
---|
205 | IN CONST EFI_MM_MP_PROTOCOL *This,
|
---|
206 | IN EFI_AP_PROCEDURE2 Procedure,
|
---|
207 | IN UINTN TimeoutInMicroseconds,
|
---|
208 | IN OUT VOID *ProcedureArguments OPTIONAL,
|
---|
209 | IN OUT MM_COMPLETION *Token,
|
---|
210 | IN OUT EFI_STATUS *CPUStatus
|
---|
211 | )
|
---|
212 | {
|
---|
213 | return InternalSmmStartupAllAPs(
|
---|
214 | Procedure,
|
---|
215 | TimeoutInMicroseconds,
|
---|
216 | ProcedureArguments,
|
---|
217 | Token,
|
---|
218 | CPUStatus
|
---|
219 | );
|
---|
220 | }
|
---|
221 |
|
---|
222 | /**
|
---|
223 | This service allows the caller to set a startup procedure that will be executed when an AP powers
|
---|
224 | up from a state where core configuration and context is lost. The procedure is execution has the
|
---|
225 | following properties:
|
---|
226 | 1. The procedure executes before the processor is handed over to the operating system.
|
---|
227 | 2. All processors execute the same startup procedure.
|
---|
228 | 3. The procedure may run in parallel with other procedures invoked through the functions in this
|
---|
229 | protocol, or with processors that are executing an MM handler or running in the operating system.
|
---|
230 |
|
---|
231 |
|
---|
232 | @param[in] This The EFI_MM_MP_PROTOCOL instance.
|
---|
233 | @param[in] Procedure A pointer to the code stream to be run on the designated target AP
|
---|
234 | of the system. Type EFI_AP_PROCEDURE is defined below in Volume 2
|
---|
235 | with the related definitions of
|
---|
236 | EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.
|
---|
237 | If caller may pass a value of NULL to deregister any existing
|
---|
238 | startup procedure.
|
---|
239 | @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code that is
|
---|
240 | run by the AP. It is an optional common mailbox between APs and
|
---|
241 | the caller to share information
|
---|
242 |
|
---|
243 | @retval EFI_SUCCESS The Procedure has been set successfully.
|
---|
244 | @retval EFI_INVALID_PARAMETER The Procedure is NULL but ProcedureArguments not NULL.
|
---|
245 |
|
---|
246 | **/
|
---|
247 | EFI_STATUS
|
---|
248 | EFIAPI
|
---|
249 | SmmMpSetStartupProcedure (
|
---|
250 | IN CONST EFI_MM_MP_PROTOCOL *This,
|
---|
251 | IN EFI_AP_PROCEDURE Procedure,
|
---|
252 | IN OUT VOID *ProcedureArguments OPTIONAL
|
---|
253 | )
|
---|
254 | {
|
---|
255 | return RegisterStartupProcedure (Procedure, ProcedureArguments);
|
---|
256 | }
|
---|
257 |
|
---|
258 | /**
|
---|
259 | When non-blocking execution of a procedure on an AP is invoked with DispatchProcedure,
|
---|
260 | via the use of a token, this function can be used to check for completion of the procedure on the AP.
|
---|
261 | The function takes the token that was passed into the DispatchProcedure call. If the procedure
|
---|
262 | is complete, and therefore it is now possible to run another procedure on the same AP, this function
|
---|
263 | returns EFI_SUCESS. In this case the status returned by the procedure that executed on the AP is
|
---|
264 | returned in the token's Status field. If the procedure has not yet completed, then this function
|
---|
265 | returns EFI_NOT_READY.
|
---|
266 |
|
---|
267 | When a non-blocking execution of a procedure is invoked with BroadcastProcedure, via the
|
---|
268 | use of a token, this function can be used to check for completion of the procedure on all the
|
---|
269 | broadcast APs. The function takes the token that was passed into the BroadcastProcedure
|
---|
270 | call. If the procedure is complete on all broadcast APs this function returns EFI_SUCESS. In this
|
---|
271 | case the Status field in the token passed into the function reflects the overall result of the
|
---|
272 | invocation, which may be EFI_SUCCESS, if all executions succeeded, or the first observed failure.
|
---|
273 | If the procedure has not yet completed on the broadcast APs, the function returns
|
---|
274 | EFI_NOT_READY.
|
---|
275 |
|
---|
276 | @param[in] This The EFI_MM_MP_PROTOCOL instance.
|
---|
277 | @param[in] Token This parameter describes the token that was passed into
|
---|
278 | DispatchProcedure or BroadcastProcedure.
|
---|
279 |
|
---|
280 | @retval EFI_SUCCESS Procedure has completed.
|
---|
281 | @retval EFI_NOT_READY The Procedure has not completed.
|
---|
282 | @retval EFI_INVALID_PARAMETER Token or Token->Completion is NULL
|
---|
283 | @retval EFI_NOT_FOUND Token is not currently in use for a non-blocking call
|
---|
284 |
|
---|
285 | **/
|
---|
286 | EFI_STATUS
|
---|
287 | EFIAPI
|
---|
288 | SmmMpCheckForProcedure (
|
---|
289 | IN CONST EFI_MM_MP_PROTOCOL *This,
|
---|
290 | IN MM_COMPLETION Token
|
---|
291 | )
|
---|
292 | {
|
---|
293 | if (Token == NULL) {
|
---|
294 | return EFI_INVALID_PARAMETER;
|
---|
295 | }
|
---|
296 |
|
---|
297 | if (!IsTokenInUse ((SPIN_LOCK *)Token)) {
|
---|
298 | return EFI_NOT_FOUND;
|
---|
299 | }
|
---|
300 |
|
---|
301 | return IsApReady ((SPIN_LOCK *)Token);
|
---|
302 | }
|
---|
303 |
|
---|
304 | /**
|
---|
305 | When a non-blocking execution of a procedure on an AP is invoked via DispatchProcedure,
|
---|
306 | this function will block the caller until the remote procedure has completed on the designated AP.
|
---|
307 | The non-blocking procedure invocation is identified by the Token parameter, which must match the
|
---|
308 | token that used when DispatchProcedure was called. Upon completion the status returned by
|
---|
309 | the procedure that executed on the AP is used to update the token's Status field.
|
---|
310 |
|
---|
311 | When a non-blocking execution of a procedure on an AP is invoked via BroadcastProcedure
|
---|
312 | this function will block the caller until the remote procedure has completed on all of the APs that
|
---|
313 | entered MM. The non-blocking procedure invocation is identified by the Token parameter, which
|
---|
314 | must match the token that used when BroadcastProcedure was called. Upon completion the
|
---|
315 | overall status returned by the procedures that executed on the broadcast AP is used to update the
|
---|
316 | token's Status field. The overall status may be EFI_SUCCESS, if all executions succeeded, or the
|
---|
317 | first observed failure.
|
---|
318 |
|
---|
319 |
|
---|
320 | @param[in] This The EFI_MM_MP_PROTOCOL instance.
|
---|
321 | @param[in] Token This parameter describes the token that was passed into
|
---|
322 | DispatchProcedure or BroadcastProcedure.
|
---|
323 |
|
---|
324 | @retval EFI_SUCCESS Procedure has completed.
|
---|
325 | @retval EFI_INVALID_PARAMETER Token or Token->Completion is NULL
|
---|
326 | @retval EFI_NOT_FOUND Token is not currently in use for a non-blocking call
|
---|
327 |
|
---|
328 | **/
|
---|
329 | EFI_STATUS
|
---|
330 | EFIAPI
|
---|
331 | SmmMpWaitForProcedure (
|
---|
332 | IN CONST EFI_MM_MP_PROTOCOL *This,
|
---|
333 | IN MM_COMPLETION Token
|
---|
334 | )
|
---|
335 | {
|
---|
336 | EFI_STATUS Status;
|
---|
337 |
|
---|
338 | do {
|
---|
339 | Status = SmmMpCheckForProcedure (This, Token);
|
---|
340 | } while (Status == EFI_NOT_READY);
|
---|
341 |
|
---|
342 | return Status;
|
---|
343 | }
|
---|
344 |
|
---|