]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
Add SMM Variable implementation.
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / VariableSmmRuntimeDxe.c
1 /** @file
2
3 Implement all four UEFI Runtime Variable services for the nonvolatile
4 and volatile storage space and install variable architecture protocol
5 based on SMM variable module.
6
7 Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16 **/
17
18 #include <Protocol/VariableWrite.h>
19 #include <Protocol/Variable.h>
20 #include <Protocol/SmmCommunication.h>
21
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/UefiRuntimeServicesTableLib.h>
24 #include <Library/MemoryAllocationLib.h>
25 #include <Library/UefiDriverEntryPoint.h>
26 #include <Library/UefiRuntimeLib.h>
27 #include <Library/BaseMemoryLib.h>
28 #include <Library/DebugLib.h>
29 #include <Library/PcdLib.h>
30 #include <Library/UefiLib.h>
31 #include <Library/BaseLib.h>
32
33 #include <Guid/EventGroup.h>
34 #include "VariableSmmCommon.h"
35
36 EFI_HANDLE mHandle = NULL;
37 EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL;
38 EFI_EVENT mVirtualAddressChangeEvent = NULL;
39 EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
40 UINT8 *mVariableBuffer = NULL;
41 UINT8 *mVariableBufferPhysical = NULL;
42 EFI_GUID mSmmVariableWriteGuid = EFI_SMM_VARIABLE_WRITE_GUID;
43 UINTN mVariableBufferSize;
44
45
46 /**
47 Initialize the communicate buffer using DataSize and Function.
48
49 The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
50 DataSize.
51
52 @param[out] DataPtr Points to the data in the communicate buffer.
53 @param[in] DataSize The data size to send to SMM.
54 @param[in] Function The function number to initialize the communicate header.
55
56 @retval EFI_INVALID_PARAMETER The data size is too big.
57 @retval EFI_SUCCESS Find the specified variable.
58
59 **/
60 EFI_STATUS
61 InitCommunicateBuffer (
62 OUT VOID **DataPtr OPTIONAL,
63 IN UINTN DataSize,
64 IN UINTN Function
65 )
66 {
67 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
68 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
69
70
71 if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {
72 return EFI_INVALID_PARAMETER;
73 }
74
75 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;
76 CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
77 SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
78
79 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
80 SmmVariableFunctionHeader->Function = Function;
81 if (DataPtr != NULL) {
82 *DataPtr = SmmVariableFunctionHeader->Data;
83 }
84
85 return EFI_SUCCESS;
86 }
87
88
89 /**
90 Send the data in communicate buffer to SMM.
91
92 @param[in] DataSize This size of the function header and the data.
93
94 @RetVal EFI_SUCCESS Success is returned from the functin in SMM.
95 @RetVal Others Failure is returned from the function in SMM.
96
97 **/
98 EFI_STATUS
99 SendCommunicateBuffer (
100 IN UINTN DataSize
101 )
102 {
103 EFI_STATUS Status;
104 UINTN CommSize;
105 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
106 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
107
108 CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
109 Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize);
110 ASSERT_EFI_ERROR (Status);
111
112 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;
113 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;
114 return SmmVariableFunctionHeader->ReturnStatus;
115 }
116
117
118 /**
119 This code finds variable in storage blocks (Volatile or Non-Volatile).
120
121 @param[in] VariableName Name of Variable to be found.
122 @param[in] VendorGuid Variable vendor GUID.
123 @param[out] Attributes Attribute value of the variable found.
124 @param[in, out] DataSize Size of Data found. If size is less than the
125 data, this value contains the required size.
126 @param[out] Data Data pointer.
127
128 @retval EFI_INVALID_PARAMETER Invalid parameter.
129 @retval EFI_SUCCESS Find the specified variable.
130 @retval EFI_NOT_FOUND Not found.
131 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
132
133 **/
134 EFI_STATUS
135 EFIAPI
136 RuntimeServiceGetVariable (
137 IN CHAR16 *VariableName,
138 IN EFI_GUID *VendorGuid,
139 OUT UINT32 *Attributes OPTIONAL,
140 IN OUT UINTN *DataSize,
141 OUT VOID *Data
142 )
143 {
144 EFI_STATUS Status;
145 UINTN PayloadSize;
146 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
147
148 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
149 return EFI_INVALID_PARAMETER;
150 }
151
152 if ((*DataSize != 0) && (Data == NULL)) {
153 return EFI_INVALID_PARAMETER;
154 }
155
156 //
157 // Init the communicate buffer. The buffer data size is:
158 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
159 //
160 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + StrSize (VariableName);
161 Status = InitCommunicateBuffer (&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);
162 if (EFI_ERROR (Status)) {
163 return Status;
164 }
165 ASSERT (SmmVariableHeader != NULL);
166
167 CopyGuid (&SmmVariableHeader->Guid, VendorGuid);
168 SmmVariableHeader->DataSize = *DataSize;
169 SmmVariableHeader->NameSize = StrSize (VariableName);
170 if (Attributes == NULL) {
171 SmmVariableHeader->Attributes = 0;
172 } else {
173 SmmVariableHeader->Attributes = *Attributes;
174 }
175 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
176
177 //
178 // Send data to SMM.
179 //
180 Status = SendCommunicateBuffer (PayloadSize);
181
182 //
183 // Get data from SMM.
184 //
185 *DataSize = SmmVariableHeader->DataSize;
186 if (Attributes != NULL) {
187 *Attributes = SmmVariableHeader->Attributes;
188 }
189
190 if (EFI_ERROR (Status)) {
191 return Status;
192 }
193
194 CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);
195
196 return Status;
197 }
198
199
200 /**
201 This code Finds the Next available variable.
202
203 @param[in, out] VariableNameSize Size of the variable name.
204 @param[in, out] VariableName Pointer to variable name.
205 @param[in, out] VendorGuid Variable Vendor Guid.
206
207 @retval EFI_INVALID_PARAMETER Invalid parameter.
208 @retval EFI_SUCCESS Find the specified variable.
209 @retval EFI_NOT_FOUND Not found.
210 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
211
212 **/
213 EFI_STATUS
214 EFIAPI
215 RuntimeServiceGetNextVariableName (
216 IN OUT UINTN *VariableNameSize,
217 IN OUT CHAR16 *VariableName,
218 IN OUT EFI_GUID *VendorGuid
219 )
220 {
221 EFI_STATUS Status;
222 UINTN PayloadSize;
223 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;
224
225 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
226 return EFI_INVALID_PARAMETER;
227 }
228
229 //
230 // Init the communicate buffer. The buffer data size is:
231 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
232 //
233 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + *VariableNameSize;
234 Status = InitCommunicateBuffer (&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);
235 if (EFI_ERROR (Status)) {
236 return Status;
237 }
238 ASSERT (SmmGetNextVariableName != NULL);
239
240 SmmGetNextVariableName->NameSize = *VariableNameSize;
241 CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);
242 CopyMem (SmmGetNextVariableName->Name, VariableName, *VariableNameSize);
243
244 //
245 // Send data to SMM
246 //
247 Status = SendCommunicateBuffer (PayloadSize);
248
249 //
250 // Get data from SMM.
251 //
252 *VariableNameSize = SmmGetNextVariableName->NameSize;
253 if (EFI_ERROR (Status)) {
254 return Status;
255 }
256
257 CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);
258 CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);
259
260 return Status;
261 }
262
263 /**
264 This code sets variable in storage blocks (Volatile or Non-Volatile).
265
266 @param[in] VariableName Name of Variable to be found.
267 @param[in] VendorGuid Variable vendor GUID.
268 @param[in] Attributes Attribute value of the variable found
269 @param[in] DataSize Size of Data found. If size is less than the
270 data, this value contains the required size.
271 @param[in] Data Data pointer.
272
273 @retval EFI_INVALID_PARAMETER Invalid parameter.
274 @retval EFI_SUCCESS Set successfully.
275 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.
276 @retval EFI_NOT_FOUND Not found.
277 @retval EFI_WRITE_PROTECTED Variable is read-only.
278
279 **/
280 EFI_STATUS
281 EFIAPI
282 RuntimeServiceSetVariable (
283 IN CHAR16 *VariableName,
284 IN EFI_GUID *VendorGuid,
285 IN UINT32 Attributes,
286 IN UINTN DataSize,
287 IN VOID *Data
288 )
289 {
290 EFI_STATUS Status;
291 UINTN PayloadSize;
292 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
293
294 //
295 // Check input parameters.
296 //
297 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
298 return EFI_INVALID_PARAMETER;
299 }
300
301 if (DataSize != 0 && Data == NULL) {
302 return EFI_INVALID_PARAMETER;
303 }
304
305 //
306 // Init the communicate buffer. The buffer data size is:
307 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
308 //
309 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + StrSize (VariableName) + DataSize;
310 Status = InitCommunicateBuffer (&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);
311 if (EFI_ERROR (Status)) {
312 return Status;
313 }
314 ASSERT (SmmVariableHeader != NULL);
315
316 CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);
317 SmmVariableHeader->DataSize = DataSize;
318 SmmVariableHeader->NameSize = StrSize (VariableName);
319 SmmVariableHeader->Attributes = Attributes;
320 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
321 CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);
322
323 //
324 // Send data to SMM.
325 //
326 Status = SendCommunicateBuffer (PayloadSize);
327
328 return Status;
329 }
330
331
332 /**
333 This code returns information about the EFI variables.
334
335 @param[in] Attributes Attributes bitmask to specify the type of variables
336 on which to return information.
337 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
338 for the EFI variables associated with the attributes specified.
339 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
340 for EFI variables associated with the attributes specified.
341 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
342 associated with the attributes specified.
343
344 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
345 @retval EFI_SUCCESS Query successfully.
346 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.
347
348 **/
349 EFI_STATUS
350 EFIAPI
351 RuntimeServiceQueryVariableInfo (
352 IN UINT32 Attributes,
353 OUT UINT64 *MaximumVariableStorageSize,
354 OUT UINT64 *RemainingVariableStorageSize,
355 OUT UINT64 *MaximumVariableSize
356 )
357 {
358 EFI_STATUS Status;
359 UINTN PayloadSize;
360 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;
361
362 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
363 return EFI_INVALID_PARAMETER;
364 }
365
366 //
367 // Init the communicate buffer. The buffer data size is:
368 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
369 //
370 PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY);
371 Status = InitCommunicateBuffer (&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);
372 if (EFI_ERROR (Status)) {
373 return Status;
374 }
375 ASSERT (SmmQueryVariableInfo != NULL);
376
377 SmmQueryVariableInfo->Attributes = Attributes;
378
379 //
380 // Send data to SMM.
381 //
382 Status = SendCommunicateBuffer (PayloadSize);
383 if (EFI_ERROR (Status)) {
384 return Status;
385 }
386
387 //
388 // Get data from SMM.
389 //
390 *MaximumVariableSize = SmmQueryVariableInfo->MaximumVariableSize;
391 *MaximumVariableStorageSize = SmmQueryVariableInfo->MaximumVariableStorageSize;
392 *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize;
393
394 return EFI_SUCCESS;
395 }
396
397
398 /**
399 Exit Boot Services Event notification handler.
400
401 Notify SMM variable driver about the event.
402
403 @param[in] Event Event whose notification function is being invoked.
404 @param[in] Context Pointer to the notification function's context.
405
406 **/
407 VOID
408 EFIAPI
409 OnExitBootServices (
410 IN EFI_EVENT Event,
411 IN VOID *Context
412 )
413 {
414 //
415 // Init the communicate buffer. The buffer data size is:
416 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
417 //
418 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE);
419
420 //
421 // Send data to SMM.
422 //
423 SendCommunicateBuffer (0);
424 }
425
426
427 /**
428 On Ready To Boot Services Event notification handler.
429
430 Notify SMM variable driver about the event.
431
432 @param[in] Event Event whose notification function is being invoked
433 @param[in] Context Pointer to the notification function's context
434
435 **/
436 VOID
437 EFIAPI
438 OnReadyToBoot (
439 IN EFI_EVENT Event,
440 IN VOID *Context
441 )
442 {
443 //
444 // Init the communicate buffer. The buffer data size is:
445 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
446 //
447 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);
448
449 //
450 // Send data to SMM.
451 //
452 SendCommunicateBuffer (0);
453 }
454
455
456 /**
457 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
458
459 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
460 It convers pointer to new virtual address.
461
462 @param[in] Event Event whose notification function is being invoked.
463 @param[in] Context Pointer to the notification function's context.
464
465 **/
466 VOID
467 EFIAPI
468 VariableAddressChangeEvent (
469 IN EFI_EVENT Event,
470 IN VOID *Context
471 )
472 {
473 EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);
474 EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);
475 }
476
477
478 /**
479 Initialize variable service and install Variable Architectural protocol.
480
481 @param[in] Event Event whose notification function is being invoked.
482 @param[in] Context Pointer to the notification function's context.
483
484 **/
485 VOID
486 EFIAPI
487 SmmVariableReady (
488 IN EFI_EVENT Event,
489 IN VOID *Context
490 )
491 {
492 EFI_STATUS Status;
493
494 Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);
495 if (EFI_ERROR (Status)) {
496 return;
497 }
498
499 Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);
500 ASSERT_EFI_ERROR (Status);
501
502 //
503 // Allocate memory for variable store.
504 //
505 mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
506 mVariableBufferSize += MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));
507 mVariableBuffer = AllocateRuntimePool (mVariableBufferSize);
508 ASSERT (mVariableBuffer != NULL);
509
510 //
511 // Save the buffer physical address used for SMM conmunication.
512 //
513 mVariableBufferPhysical = mVariableBuffer;
514
515 gRT->GetVariable = RuntimeServiceGetVariable;
516 gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;
517 gRT->SetVariable = RuntimeServiceSetVariable;
518 gRT->QueryVariableInfo = RuntimeServiceQueryVariableInfo;
519
520 //
521 // Install the Variable Architectural Protocol on a new handle.
522 //
523 Status = gBS->InstallProtocolInterface (
524 &mHandle,
525 &gEfiVariableArchProtocolGuid,
526 EFI_NATIVE_INTERFACE,
527 NULL
528 );
529 ASSERT_EFI_ERROR (Status);
530 }
531
532
533 /**
534 SMM Non-Volatile variable write service is ready notify event handler.
535
536 @param[in] Event Event whose notification function is being invoked.
537 @param[in] Context Pointer to the notification function's context.
538
539 **/
540 VOID
541 EFIAPI
542 SmmVariableWriteReady (
543 IN EFI_EVENT Event,
544 IN VOID *Context
545 )
546 {
547 EFI_STATUS Status;
548 VOID *ProtocolOps;
549
550 //
551 // Check whether the protocol is installed or not.
552 //
553 Status = gBS->LocateProtocol (&mSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);
554 if (EFI_ERROR (Status)) {
555 return;
556 }
557
558 Status = gBS->InstallProtocolInterface (
559 &mHandle,
560 &gEfiVariableWriteArchProtocolGuid,
561 EFI_NATIVE_INTERFACE,
562 NULL
563 );
564 ASSERT_EFI_ERROR (Status);
565 }
566
567
568 /**
569 Variable Driver main entry point. The Variable driver places the 4 EFI
570 runtime services in the EFI System Table and installs arch protocols
571 for variable read and write services being availible. It also registers
572 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
573
574 @param[in] ImageHandle The firmware allocated handle for the EFI image.
575 @param[in] SystemTable A pointer to the EFI System Table.
576
577 @retval EFI_SUCCESS Variable service successfully initialized.
578
579 **/
580 EFI_STATUS
581 EFIAPI
582 VariableSmmRuntimeInitialize (
583 IN EFI_HANDLE ImageHandle,
584 IN EFI_SYSTEM_TABLE *SystemTable
585 )
586 {
587 VOID *SmmVariableRegistration;
588 VOID *SmmVariableWriteRegistration;
589 EFI_EVENT OnReadyToBootEvent;
590 EFI_EVENT ExitBootServiceEvent;
591
592 //
593 // Smm variable service is ready
594 //
595 EfiCreateProtocolNotifyEvent (
596 &gEfiSmmVariableProtocolGuid,
597 TPL_CALLBACK,
598 SmmVariableReady,
599 NULL,
600 &SmmVariableRegistration
601 );
602
603 //
604 // Smm Non-Volatile variable write service is ready
605 //
606 EfiCreateProtocolNotifyEvent (
607 &mSmmVariableWriteGuid,
608 TPL_CALLBACK,
609 SmmVariableWriteReady,
610 NULL,
611 &SmmVariableWriteRegistration
612 );
613
614 //
615 // Register the event to reclaim variable for OS usage.
616 //
617 EfiCreateEventReadyToBootEx (
618 TPL_NOTIFY,
619 OnReadyToBoot,
620 NULL,
621 &OnReadyToBootEvent
622 );
623
624 //
625 // Register the event to inform SMM variable that it is at runtime.
626 //
627 gBS->CreateEventEx (
628 EVT_NOTIFY_SIGNAL,
629 TPL_NOTIFY,
630 OnExitBootServices,
631 NULL,
632 &gEfiEventExitBootServicesGuid,
633 &ExitBootServiceEvent
634 );
635
636 //
637 // Register the event to convert the pointer for runtime.
638 //
639 gBS->CreateEventEx (
640 EVT_NOTIFY_SIGNAL,
641 TPL_NOTIFY,
642 VariableAddressChangeEvent,
643 NULL,
644 &gEfiEventVirtualAddressChangeGuid,
645 &mVirtualAddressChangeEvent
646 );
647
648 return EFI_SUCCESS;
649 }
650