]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Compatibility/SmmBaseOnSmmBase2Thunk/SmmBaseOnSmmBase2Thunk.c
Security enhancement to SMM Base thunk drivers: Framework SMM drivers can't be loaded...
[mirror_edk2.git] / EdkCompatibilityPkg / Compatibility / SmmBaseOnSmmBase2Thunk / SmmBaseOnSmmBase2Thunk.c
1 /** @file
2 SMM Base Protocol on SMM Base2 Protocol Thunk driver.
3
4 This driver co-operates with SMM Base Helper SMM driver to provide SMM Base Protocol
5 based on SMM Base2 Protocol.
6
7 This thunk driver is expected to be loaded before PI SMM IPL driver so that
8 SMM BASE Protocol can be published immediately after SMM Base2 Protocol is installed to
9 make SMM Base Protocol.InSmm() as early as possible.
10
11 Copyright (c) 2009 - 2010, Intel Corporation
12 All rights reserved. This program and the accompanying materials
13 are licensed and made available under the terms and conditions of the BSD License
14 which accompanies this distribution. The full text of the license may be found at
15 http://opensource.org/licenses/bsd-license.php
16
17 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19
20 **/
21
22 #include <PiDxe.h>
23 #include <FrameworkSmm.h>
24
25 #include <Protocol/SmmBase2.h>
26 #include <Protocol/SmmCommunication.h>
27 #include <Protocol/SmmBaseHelperReady.h>
28
29 #include <Guid/SmmBaseThunkCommunication.h>
30 #include <Guid/EventGroup.h>
31
32 #include <Library/DebugLib.h>
33 #include <Library/UefiBootServicesTableLib.h>
34 #include <Library/UefiDriverEntryPoint.h>
35 #include <Library/UefiLib.h>
36 #include <Library/UefiRuntimeLib.h>
37
38 SMMBASETHUNK_COMMUNICATION_DATA mCommunicationData = {
39 EFI_SMM_BASE_THUNK_COMMUNICATION_GUID,
40 sizeof (SMMBASE_FUNCTION_DATA)
41 };
42
43 EFI_HANDLE mSmmBaseHandle = NULL;
44 EFI_SMM_BASE2_PROTOCOL *mSmmBase2 = NULL;
45 EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
46 EFI_SMM_BASE_HELPER_READY_PROTOCOL *mSmmBaseHelperReady = NULL;
47 BOOLEAN mAtRuntime = FALSE;
48
49 /**
50 Determine if in SMM mode.
51
52 @retval TRUE In SMM mode.
53 @retval FALSE Not in SMM mode.
54 **/
55 BOOLEAN
56 IsInSmm (
57 VOID
58 )
59 {
60 EFI_STATUS Status;
61 BOOLEAN InSmm;
62
63 Status = mSmmBase2->InSmm (mSmmBase2, &InSmm);
64 ASSERT_EFI_ERROR (Status);
65 return InSmm;
66 }
67
68 /**
69 Invoke services provided by SMM Base Helper SMM driver.
70 **/
71 VOID
72 SmmBaseHelperService (
73 VOID
74 )
75 {
76 UINTN DataSize;
77
78 mCommunicationData.FunctionData.Status = EFI_UNSUPPORTED;
79 mCommunicationData.FunctionData.SmmBaseImageHandle = mSmmBaseHandle;
80
81 if ((mCommunicationData.FunctionData.Function != SmmBaseFunctionCommunicate) && IsInSmm()) {
82 ///
83 /// If in SMM mode, directly call services in SMM Base Helper.
84 ///
85 DataSize = (UINTN)(sizeof (SMMBASE_FUNCTION_DATA));
86 mSmmBaseHelperReady->ServiceEntry (
87 NULL,
88 NULL,
89 &mCommunicationData.FunctionData,
90 &DataSize
91 );
92 } else {
93 ///
94 /// Call services in SMM Base Helper via SMM Communication Protocol.
95 ///
96 DataSize = (UINTN)(sizeof (mCommunicationData));
97 mSmmCommunication->Communicate (
98 mSmmCommunication,
99 &mCommunicationData,
100 &DataSize
101 );
102 }
103 }
104
105 /**
106 Register a given driver into SMRAM. This is the equivalent of performing
107 the LoadImage/StartImage into System Management Mode.
108
109 @param[in] This Protocol instance pointer.
110 @param[in] FilePath Location of the image to be installed as the handler.
111 @param[in] SourceBuffer Optional source buffer in case the image file
112 is in memory.
113 @param[in] SourceSize Size of the source image file, if in memory.
114 @param[out] ImageHandle The handle that the base driver uses to decode
115 the handler. Unique among SMM handlers only,
116 not unique across DXE/EFI.
117 @param[in] LegacyIA32Binary An optional parameter specifying that the associated
118 file is a real-mode IA-32 binary.
119
120 @retval EFI_SUCCESS The operation was successful.
121 @retval EFI_OUT_OF_RESOURCES There were no additional SMRAM resources to load the handler
122 @retval EFI_UNSUPPORTED This platform does not support 16-bit handlers.
123 @retval EFI_UNSUPPORTED Platform is in runtime.
124 @retval EFI_INVALID_PARAMETER The handlers was not the correct image type
125 **/
126 EFI_STATUS
127 EFIAPI
128 SmmBaseRegister (
129 IN EFI_SMM_BASE_PROTOCOL *This,
130 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
131 IN VOID *SourceBuffer,
132 IN UINTN SourceSize,
133 OUT EFI_HANDLE *ImageHandle,
134 IN BOOLEAN LegacyIA32Binary
135 )
136 {
137 if (mAtRuntime || LegacyIA32Binary) {
138 return EFI_UNSUPPORTED;
139 }
140
141 mCommunicationData.FunctionData.Function = SmmBaseFunctionRegister;
142 mCommunicationData.FunctionData.Args.Register.FilePath = FilePath;
143 mCommunicationData.FunctionData.Args.Register.SourceBuffer = SourceBuffer;
144 mCommunicationData.FunctionData.Args.Register.SourceSize = SourceSize;
145 mCommunicationData.FunctionData.Args.Register.ImageHandle = ImageHandle;
146 mCommunicationData.FunctionData.Args.Register.LegacyIA32Binary = LegacyIA32Binary;
147
148 SmmBaseHelperService ();
149 return mCommunicationData.FunctionData.Status;
150 }
151
152 /**
153 Removes a handler from execution within SMRAM. This is the equivalent of performing
154 the UnloadImage in System Management Mode.
155
156 @param[in] This Protocol instance pointer.
157 @param[in] ImageHandle The handler to be removed.
158
159 @retval EFI_SUCCESS The operation was successful
160 @retval EFI_INVALID_PARAMETER The handler did not exist
161 @retval EFI_UNSUPPORTED Platform is in runtime.
162 **/
163 EFI_STATUS
164 EFIAPI
165 SmmBaseUnregister (
166 IN EFI_SMM_BASE_PROTOCOL *This,
167 IN EFI_HANDLE ImageHandle
168 )
169 {
170 if (mAtRuntime) {
171 return EFI_UNSUPPORTED;
172 }
173
174 mCommunicationData.FunctionData.Function = SmmBaseFunctionUnregister;
175 mCommunicationData.FunctionData.Args.UnRegister.ImageHandle = ImageHandle;
176
177 SmmBaseHelperService ();
178 return mCommunicationData.FunctionData.Status;
179 }
180
181 /**
182 The SMM Inter-module Communicate Service Communicate() function
183 provides a service to send/receive messages from a registered
184 EFI service. The BASE protocol driver is responsible for doing
185 any of the copies such that the data lives in boot-service-accessible RAM.
186
187 @param[in] This Protocol instance pointer.
188 @param[in] ImageHandle The handle of the registered driver.
189 @param[in, out] CommunicationBuffer Pointer to the buffer to convey into SMRAM.
190 @param[in, out] BufferSize The size of the data buffer being passed in.
191 On exit, the size of data being returned.
192 Zero if the handler does not wish to reply with any data.
193
194 @retval EFI_SUCCESS The message was successfully posted
195 @retval EFI_INVALID_PARAMETER The buffer was NULL
196 **/
197 EFI_STATUS
198 EFIAPI
199 SmmBaseCommunicate (
200 IN EFI_SMM_BASE_PROTOCOL *This,
201 IN EFI_HANDLE ImageHandle,
202 IN OUT VOID *CommunicationBuffer,
203 IN OUT UINTN *BufferSize
204 )
205 {
206 ///
207 /// Note this is a runtime interface
208 ///
209
210 if (CommunicationBuffer == NULL || BufferSize == NULL) {
211 return EFI_INVALID_PARAMETER;
212 }
213
214 mCommunicationData.FunctionData.Function = SmmBaseFunctionCommunicate;
215 mCommunicationData.FunctionData.Args.Communicate.ImageHandle = ImageHandle;
216 mCommunicationData.FunctionData.Args.Communicate.CommunicationBuffer = CommunicationBuffer;
217 mCommunicationData.FunctionData.Args.Communicate.SourceSize = BufferSize;
218
219 SmmBaseHelperService ();
220 return mCommunicationData.FunctionData.Status;
221 }
222
223 /**
224 Register a callback to execute within SMM.
225 This allows receipt of messages created with EFI_SMM_BASE_PROTOCOL.Communicate().
226
227 @param[in] This Protocol instance pointer.
228 @param[in] SmmImageHandle Handle of the callback service.
229 @param[in] CallbackAddress Address of the callback service.
230 @param[in] MakeLast If present, will stipulate that the handler is posted to
231 be executed last in the dispatch table.
232 @param[in] FloatingPointSave An optional parameter that informs the
233 EFI_SMM_ACCESS_PROTOCOL Driver core if it needs to save
234 the floating point register state. If any handler
235 require this, the state will be saved for all handlers.
236
237 @retval EFI_SUCCESS The operation was successful
238 @retval EFI_OUT_OF_RESOURCES Not enough space in the dispatch queue
239 @retval EFI_UNSUPPORTED Platform is in runtime.
240 @retval EFI_UNSUPPORTED The caller is not in SMM.
241 **/
242 EFI_STATUS
243 EFIAPI
244 SmmBaseRegisterCallback (
245 IN EFI_SMM_BASE_PROTOCOL *This,
246 IN EFI_HANDLE SmmImageHandle,
247 IN EFI_SMM_CALLBACK_ENTRY_POINT CallbackAddress,
248 IN BOOLEAN MakeLast,
249 IN BOOLEAN FloatingPointSave
250 )
251 {
252 if (!IsInSmm()) {
253 return EFI_UNSUPPORTED;
254 }
255
256 mCommunicationData.FunctionData.Function = SmmBaseFunctionRegisterCallback;
257 mCommunicationData.FunctionData.Args.RegisterCallback.SmmImageHandle = SmmImageHandle;
258 mCommunicationData.FunctionData.Args.RegisterCallback.CallbackAddress = CallbackAddress;
259 mCommunicationData.FunctionData.Args.RegisterCallback.MakeLast = MakeLast;
260 mCommunicationData.FunctionData.Args.RegisterCallback.FloatingPointSave = FloatingPointSave;
261
262 SmmBaseHelperService();
263 return mCommunicationData.FunctionData.Status;
264 }
265
266 /**
267 This routine tells caller if execution context is SMM or not.
268
269 @param[in] This Protocol instance pointer.
270 @param[out] InSmm Whether the caller is inside SMM for IA-32
271 or servicing a PMI for the Itanium processor
272 family.
273
274 @retval EFI_SUCCESS The operation was successful
275 @retval EFI_INVALID_PARAMETER InSmm was NULL.
276 **/
277 EFI_STATUS
278 EFIAPI
279 SmmBaseInSmm (
280 IN EFI_SMM_BASE_PROTOCOL *This,
281 OUT BOOLEAN *InSmm
282 )
283 {
284 return mSmmBase2->InSmm (mSmmBase2, InSmm);
285 }
286
287 /**
288 The SmmAllocatePool() function allocates a memory region of Size bytes from memory of
289 type PoolType and returns the address of the allocated memory in the location referenced
290 by Buffer. This function allocates pages from EFI SMRAM Memory as needed to grow the
291 requested pool type. All allocations are eight-byte aligned.
292
293 @param[in] This Protocol instance pointer.
294 @param[in] PoolType The type of pool to allocate.
295 The only supported type is EfiRuntimeServicesData;
296 the interface will internally map this runtime request to
297 SMRAM for IA-32 and leave as this type for the Itanium
298 processor family. Other types can be ignored.
299 @param[in] Size The number of bytes to allocate from the pool.
300 @param[out] Buffer A pointer to a pointer to the allocated buffer if the call
301 succeeds; undefined otherwise.
302
303 @retval EFI_SUCCESS The requested number of bytes was allocated.
304 @retval EFI_OUT_OF_RESOURCES The pool requested could not be allocated.
305 @retval EFI_UNSUPPORTED Platform is in runtime.
306 **/
307 EFI_STATUS
308 EFIAPI
309 SmmBaseSmmAllocatePool (
310 IN EFI_SMM_BASE_PROTOCOL *This,
311 IN EFI_MEMORY_TYPE PoolType,
312 IN UINTN Size,
313 OUT VOID **Buffer
314 )
315 {
316 if (mAtRuntime) {
317 return EFI_UNSUPPORTED;
318 }
319
320 mCommunicationData.FunctionData.Function = SmmBaseFunctionAllocatePool;
321 mCommunicationData.FunctionData.Args.AllocatePool.PoolType = PoolType;
322 mCommunicationData.FunctionData.Args.AllocatePool.Size = Size;
323 mCommunicationData.FunctionData.Args.AllocatePool.Buffer = Buffer;
324
325 SmmBaseHelperService ();
326 return mCommunicationData.FunctionData.Status;
327 }
328
329 /**
330 The SmmFreePool() function returns the memory specified by Buffer to the system.
331 On return, the memory's type is EFI SMRAM Memory. The Buffer that is freed must
332 have been allocated by SmmAllocatePool().
333
334 @param[in] This Protocol instance pointer.
335 @param[in] Buffer Pointer to the buffer allocation.
336
337 @retval EFI_SUCCESS The memory was returned to the system.
338 @retval EFI_INVALID_PARAMETER Buffer was invalid.
339 @retval EFI_UNSUPPORTED Platform is in runtime.
340 **/
341 EFI_STATUS
342 EFIAPI
343 SmmBaseSmmFreePool (
344 IN EFI_SMM_BASE_PROTOCOL *This,
345 IN VOID *Buffer
346 )
347 {
348 if (mAtRuntime) {
349 return EFI_UNSUPPORTED;
350 }
351
352 mCommunicationData.FunctionData.Function = SmmBaseFunctionFreePool;
353 mCommunicationData.FunctionData.Args.FreePool.Buffer = Buffer;
354
355 SmmBaseHelperService ();
356 return mCommunicationData.FunctionData.Status;
357 }
358
359 /**
360 The GetSmstLocation() function returns the location of the System Management
361 Service Table. The use of the API is such that a driver can discover the
362 location of the SMST in its entry point and then cache it in some driver
363 global variable so that the SMST can be invoked in subsequent callbacks.
364
365 @param[in] This Protocol instance pointer.
366 @param[out] Smst Pointer to the SMST.
367
368 @retval EFI_SUCCESS The operation was successful
369 @retval EFI_INVALID_PARAMETER Smst was invalid.
370 @retval EFI_UNSUPPORTED Not in SMM.
371 **/
372 EFI_STATUS
373 EFIAPI
374 SmmBaseGetSmstLocation (
375 IN EFI_SMM_BASE_PROTOCOL *This,
376 OUT EFI_SMM_SYSTEM_TABLE **Smst
377 )
378 {
379 if (!IsInSmm ()) {
380 return EFI_UNSUPPORTED;
381 }
382
383 if (Smst == NULL) {
384 return EFI_INVALID_PARAMETER;
385 }
386
387 *Smst = mSmmBaseHelperReady->FrameworkSmst;
388 return EFI_SUCCESS;
389 }
390
391 /**
392 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
393
394 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
395 It convers pointer to new virtual address.
396
397 @param Event Event whose notification function is being invoked
398 @param Context Pointer to the notification function's context
399 **/
400 VOID
401 EFIAPI
402 SmmBaseAddressChangeEvent (
403 IN EFI_EVENT Event,
404 IN VOID *Context
405 )
406 {
407 EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);
408 }
409
410 ///
411 /// SMM Base Protocol instance
412 ///
413 EFI_SMM_BASE_PROTOCOL mSmmBase = {
414 SmmBaseRegister,
415 SmmBaseUnregister,
416 SmmBaseCommunicate,
417 SmmBaseRegisterCallback,
418 SmmBaseInSmm,
419 SmmBaseSmmAllocatePool,
420 SmmBaseSmmFreePool,
421 SmmBaseGetSmstLocation
422 };
423
424 /**
425 Notification function on Exit Boot Services Event.
426
427 This function sets a flag indicating it is in Runtime phase.
428
429 @param Event Event whose notification function is being invoked
430 @param Context Pointer to the notification function's context
431 **/
432 VOID
433 EFIAPI
434 SmmBaseExitBootServicesEventNotify (
435 IN EFI_EVENT Event,
436 IN VOID *Context
437 )
438 {
439 mAtRuntime = TRUE;
440 }
441
442 /**
443 Entry Point for SMM Base Protocol on SMM Base2 Protocol Thunk driver.
444
445 @param[in] ImageHandle Image handle of this driver.
446 @param[in] SystemTable A Pointer to the EFI System Table.
447
448 @retval EFI_SUCCESS The entry point is executed successfully.
449 **/
450 EFI_STATUS
451 EFIAPI
452 SmmBaseThunkMain (
453 IN EFI_HANDLE ImageHandle,
454 IN EFI_SYSTEM_TABLE *SystemTable
455 )
456 {
457 EFI_STATUS Status;
458 EFI_EVENT Event;
459
460 mSmmBaseHandle = ImageHandle;
461
462 //
463 // Assume only one instance of SMM Base2 Protocol in the system
464 // Locate SMM Base2 Protocol
465 //
466 Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID **) &mSmmBase2);
467 ASSERT_EFI_ERROR (Status);
468
469 //
470 // Assume only one instance of SMM Communication Protocol in the system
471 // Locate SMM Communication Protocol
472 //
473 gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);
474 ASSERT_EFI_ERROR (Status);
475
476 //
477 // Assume only one instance of SMM Base Helper Ready Protocol in the system
478 // Locate SMM Base Helper Ready Protocol
479 //
480 Status = gBS->LocateProtocol (&gEfiSmmBaseHelperReadyProtocolGuid, NULL, (VOID **) &mSmmBaseHelperReady);
481 ASSERT_EFI_ERROR (Status);
482
483 //
484 // Create event notification on Exit Boot Services event.
485 //
486 Status = gBS->CreateEventEx (
487 EVT_NOTIFY_SIGNAL,
488 TPL_NOTIFY,
489 SmmBaseExitBootServicesEventNotify,
490 NULL,
491 &gEfiEventExitBootServicesGuid,
492 &Event
493 );
494 ASSERT_EFI_ERROR (Status);
495
496 //
497 // Create event on SetVirtualAddressMap() to convert mSmmCommunication from a physical address to a virtual address
498 //
499 Status = gBS->CreateEventEx (
500 EVT_NOTIFY_SIGNAL,
501 TPL_NOTIFY,
502 SmmBaseAddressChangeEvent,
503 NULL,
504 &gEfiEventVirtualAddressChangeGuid,
505 &Event
506 );
507 ASSERT_EFI_ERROR (Status);
508
509 //
510 // Publish Framework SMM BASE Protocol immediately after SMM Base2 Protocol is installed to
511 // make SMM Base Protocol.InSmm() available as early as possible.
512 //
513 Status = gBS->InstallMultipleProtocolInterfaces (
514 &mSmmBaseHandle,
515 &gEfiSmmBaseProtocolGuid, &mSmmBase,
516 NULL
517 );
518 ASSERT_EFI_ERROR (Status);
519
520 return EFI_SUCCESS;
521 }