]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
MdeModulePkg: Add the alignment check for FTW spare area address and length, and...
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / VariableSmmRuntimeDxe.c
... / ...
CommitLineData
1/** @file\r
2\r
3 Implement all four UEFI Runtime Variable services for the nonvolatile\r
4 and volatile storage space and install variable architecture protocol\r
5 based on SMM variable module.\r
6\r
7Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>\r
8This program and the accompanying materials \r
9are licensed and made available under the terms and conditions of the BSD License \r
10which accompanies this distribution. The full text of the license may be found at \r
11http://opensource.org/licenses/bsd-license.php \r
12\r
13THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
14WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
15\r
16**/\r
17#include <PiDxe.h>\r
18#include <Protocol/VariableWrite.h>\r
19#include <Protocol/Variable.h>\r
20#include <Protocol/SmmCommunication.h>\r
21#include <Protocol/SmmVariable.h>\r
22#include <Protocol/VariableLock.h>\r
23\r
24#include <Library/UefiBootServicesTableLib.h>\r
25#include <Library/UefiRuntimeServicesTableLib.h>\r
26#include <Library/MemoryAllocationLib.h>\r
27#include <Library/UefiDriverEntryPoint.h>\r
28#include <Library/UefiRuntimeLib.h>\r
29#include <Library/BaseMemoryLib.h>\r
30#include <Library/DebugLib.h>\r
31#include <Library/PcdLib.h>\r
32#include <Library/UefiLib.h>\r
33#include <Library/BaseLib.h>\r
34\r
35#include <Guid/EventGroup.h>\r
36#include <Guid/VariableFormat.h>\r
37#include <Guid/SmmVariableCommon.h>\r
38\r
39EFI_HANDLE mHandle = NULL; \r
40EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL;\r
41EFI_EVENT mVirtualAddressChangeEvent = NULL;\r
42EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;\r
43UINT8 *mVariableBuffer = NULL;\r
44UINT8 *mVariableBufferPhysical = NULL;\r
45UINTN mVariableBufferSize;\r
46UINTN mVariableBufferPayloadSize;\r
47EFI_LOCK mVariableServicesLock;\r
48EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock;\r
49\r
50/**\r
51 Acquires lock only at boot time. Simply returns at runtime.\r
52\r
53 This is a temperary function that will be removed when\r
54 EfiAcquireLock() in UefiLib can handle the call in UEFI\r
55 Runtimer driver in RT phase.\r
56 It calls EfiAcquireLock() at boot time, and simply returns\r
57 at runtime.\r
58\r
59 @param Lock A pointer to the lock to acquire.\r
60\r
61**/\r
62VOID\r
63AcquireLockOnlyAtBootTime (\r
64 IN EFI_LOCK *Lock\r
65 )\r
66{\r
67 if (!EfiAtRuntime ()) {\r
68 EfiAcquireLock (Lock);\r
69 }\r
70}\r
71\r
72/**\r
73 Releases lock only at boot time. Simply returns at runtime.\r
74\r
75 This is a temperary function which will be removed when\r
76 EfiReleaseLock() in UefiLib can handle the call in UEFI\r
77 Runtimer driver in RT phase.\r
78 It calls EfiReleaseLock() at boot time and simply returns\r
79 at runtime.\r
80\r
81 @param Lock A pointer to the lock to release.\r
82\r
83**/\r
84VOID\r
85ReleaseLockOnlyAtBootTime (\r
86 IN EFI_LOCK *Lock\r
87 )\r
88{\r
89 if (!EfiAtRuntime ()) {\r
90 EfiReleaseLock (Lock);\r
91 }\r
92}\r
93\r
94/**\r
95 Initialize the communicate buffer using DataSize and Function.\r
96\r
97 The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +\r
98 DataSize.\r
99\r
100 @param[out] DataPtr Points to the data in the communicate buffer.\r
101 @param[in] DataSize The data size to send to SMM.\r
102 @param[in] Function The function number to initialize the communicate header.\r
103 \r
104 @retval EFI_INVALID_PARAMETER The data size is too big.\r
105 @retval EFI_SUCCESS Find the specified variable.\r
106\r
107**/\r
108EFI_STATUS\r
109InitCommunicateBuffer (\r
110 OUT VOID **DataPtr OPTIONAL,\r
111 IN UINTN DataSize,\r
112 IN UINTN Function\r
113 )\r
114{\r
115 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; \r
116 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; \r
117\r
118 \r
119 if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {\r
120 return EFI_INVALID_PARAMETER;\r
121 }\r
122\r
123 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;\r
124 CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
125 SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
126 \r
127 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
128 SmmVariableFunctionHeader->Function = Function;\r
129 if (DataPtr != NULL) {\r
130 *DataPtr = SmmVariableFunctionHeader->Data;\r
131 }\r
132\r
133 return EFI_SUCCESS;\r
134}\r
135\r
136\r
137/**\r
138 Send the data in communicate buffer to SMM.\r
139\r
140 @param[in] DataSize This size of the function header and the data.\r
141\r
142 @retval EFI_SUCCESS Success is returned from the functin in SMM.\r
143 @retval Others Failure is returned from the function in SMM. \r
144 \r
145**/\r
146EFI_STATUS\r
147SendCommunicateBuffer (\r
148 IN UINTN DataSize\r
149 )\r
150{\r
151 EFI_STATUS Status;\r
152 UINTN CommSize;\r
153 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; \r
154 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;\r
155 \r
156 CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
157 Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize);\r
158 ASSERT_EFI_ERROR (Status);\r
159\r
160 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;\r
161 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;\r
162 return SmmVariableFunctionHeader->ReturnStatus;\r
163}\r
164\r
165/**\r
166 Mark a variable that will become read-only after leaving the DXE phase of execution.\r
167\r
168 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.\r
169 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.\r
170 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.\r
171\r
172 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked\r
173 as pending to be read-only.\r
174 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.\r
175 Or VariableName is an empty string.\r
176 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has\r
177 already been signaled.\r
178 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.\r
179**/\r
180EFI_STATUS\r
181EFIAPI\r
182VariableLockRequestToLock (\r
183 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,\r
184 IN CHAR16 *VariableName,\r
185 IN EFI_GUID *VendorGuid\r
186 )\r
187{\r
188 EFI_STATUS Status;\r
189 UINTN VariableNameSize;\r
190 UINTN PayloadSize;\r
191 SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock;\r
192\r
193 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
194 return EFI_INVALID_PARAMETER;\r
195 }\r
196\r
197 VariableNameSize = StrSize (VariableName);\r
198\r
199 //\r
200 // If VariableName exceeds SMM payload limit. Return failure\r
201 //\r
202 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {\r
203 return EFI_INVALID_PARAMETER;\r
204 }\r
205\r
206 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
207\r
208 //\r
209 // Init the communicate buffer. The buffer data size is:\r
210 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
211 //\r
212 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;\r
213 Status = InitCommunicateBuffer ((VOID **) &VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);\r
214 if (EFI_ERROR (Status)) {\r
215 goto Done;\r
216 }\r
217 ASSERT (VariableToLock != NULL);\r
218\r
219 CopyGuid (&VariableToLock->Guid, VendorGuid);\r
220 VariableToLock->NameSize = VariableNameSize;\r
221 CopyMem (VariableToLock->Name, VariableName, VariableToLock->NameSize);\r
222\r
223 //\r
224 // Send data to SMM.\r
225 //\r
226 Status = SendCommunicateBuffer (PayloadSize);\r
227\r
228Done:\r
229 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
230 return Status;\r
231}\r
232\r
233/**\r
234 This code finds variable in storage blocks (Volatile or Non-Volatile).\r
235\r
236 @param[in] VariableName Name of Variable to be found.\r
237 @param[in] VendorGuid Variable vendor GUID.\r
238 @param[out] Attributes Attribute value of the variable found.\r
239 @param[in, out] DataSize Size of Data found. If size is less than the\r
240 data, this value contains the required size.\r
241 @param[out] Data Data pointer.\r
242 \r
243 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
244 @retval EFI_SUCCESS Find the specified variable.\r
245 @retval EFI_NOT_FOUND Not found.\r
246 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
247\r
248**/\r
249EFI_STATUS\r
250EFIAPI\r
251RuntimeServiceGetVariable (\r
252 IN CHAR16 *VariableName,\r
253 IN EFI_GUID *VendorGuid,\r
254 OUT UINT32 *Attributes OPTIONAL,\r
255 IN OUT UINTN *DataSize,\r
256 OUT VOID *Data\r
257 )\r
258{\r
259 EFI_STATUS Status;\r
260 UINTN PayloadSize;\r
261 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;\r
262 UINTN TempDataSize;\r
263 UINTN VariableNameSize;\r
264\r
265 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
266 return EFI_INVALID_PARAMETER;\r
267 }\r
268\r
269 if ((*DataSize != 0) && (Data == NULL)) {\r
270 return EFI_INVALID_PARAMETER;\r
271 }\r
272\r
273 TempDataSize = *DataSize;\r
274 VariableNameSize = StrSize (VariableName);\r
275\r
276 //\r
277 // If VariableName exceeds SMM payload limit. Return failure\r
278 //\r
279 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {\r
280 return EFI_INVALID_PARAMETER;\r
281 }\r
282\r
283 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
284\r
285 //\r
286 // Init the communicate buffer. The buffer data size is:\r
287 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
288 //\r
289 if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {\r
290 //\r
291 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
292 //\r
293 TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;\r
294 }\r
295 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;\r
296\r
297 Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);\r
298 if (EFI_ERROR (Status)) {\r
299 goto Done;\r
300 }\r
301 ASSERT (SmmVariableHeader != NULL);\r
302\r
303 CopyGuid (&SmmVariableHeader->Guid, VendorGuid);\r
304 SmmVariableHeader->DataSize = TempDataSize;\r
305 SmmVariableHeader->NameSize = VariableNameSize;\r
306 if (Attributes == NULL) {\r
307 SmmVariableHeader->Attributes = 0;\r
308 } else {\r
309 SmmVariableHeader->Attributes = *Attributes;\r
310 }\r
311 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
312\r
313 //\r
314 // Send data to SMM.\r
315 //\r
316 Status = SendCommunicateBuffer (PayloadSize);\r
317\r
318 //\r
319 // Get data from SMM.\r
320 //\r
321 if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
322 //\r
323 // SMM CommBuffer DataSize can be a trimed value\r
324 // Only update DataSize when needed\r
325 //\r
326 *DataSize = SmmVariableHeader->DataSize;\r
327 }\r
328 if (Attributes != NULL) {\r
329 *Attributes = SmmVariableHeader->Attributes;\r
330 }\r
331\r
332 if (EFI_ERROR (Status)) {\r
333 goto Done;\r
334 }\r
335\r
336 CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);\r
337\r
338Done:\r
339 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
340 return Status;\r
341}\r
342\r
343\r
344/**\r
345 This code Finds the Next available variable.\r
346\r
347 @param[in, out] VariableNameSize Size of the variable name.\r
348 @param[in, out] VariableName Pointer to variable name.\r
349 @param[in, out] VendorGuid Variable Vendor Guid.\r
350\r
351 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
352 @retval EFI_SUCCESS Find the specified variable.\r
353 @retval EFI_NOT_FOUND Not found.\r
354 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
355\r
356**/\r
357EFI_STATUS\r
358EFIAPI\r
359RuntimeServiceGetNextVariableName (\r
360 IN OUT UINTN *VariableNameSize,\r
361 IN OUT CHAR16 *VariableName,\r
362 IN OUT EFI_GUID *VendorGuid\r
363 )\r
364{\r
365 EFI_STATUS Status;\r
366 UINTN PayloadSize;\r
367 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;\r
368 UINTN OutVariableNameSize;\r
369 UINTN InVariableNameSize;\r
370\r
371 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
372 return EFI_INVALID_PARAMETER;\r
373 }\r
374\r
375 OutVariableNameSize = *VariableNameSize;\r
376 InVariableNameSize = StrSize (VariableName);\r
377\r
378 //\r
379 // If input string exceeds SMM payload limit. Return failure\r
380 //\r
381 if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
382 return EFI_INVALID_PARAMETER;\r
383 }\r
384\r
385 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
386\r
387 //\r
388 // Init the communicate buffer. The buffer data size is:\r
389 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
390 //\r
391 if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
392 //\r
393 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
394 //\r
395 OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);\r
396 }\r
397 //\r
398 // Payload should be Guid + NameSize + MAX of Input & Output buffer\r
399 //\r
400 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);\r
401\r
402\r
403 Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);\r
404 if (EFI_ERROR (Status)) {\r
405 goto Done;\r
406 }\r
407 ASSERT (SmmGetNextVariableName != NULL);\r
408\r
409 //\r
410 // SMM comm buffer->NameSize is buffer size for return string\r
411 //\r
412 SmmGetNextVariableName->NameSize = OutVariableNameSize;\r
413\r
414 CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);\r
415 //\r
416 // Copy whole string\r
417 //\r
418 CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);\r
419 if (OutVariableNameSize > InVariableNameSize) {\r
420 ZeroMem ((UINT8 *) SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);\r
421 }\r
422\r
423 //\r
424 // Send data to SMM\r
425 //\r
426 Status = SendCommunicateBuffer (PayloadSize);\r
427\r
428 //\r
429 // Get data from SMM.\r
430 //\r
431 if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
432 //\r
433 // SMM CommBuffer NameSize can be a trimed value\r
434 // Only update VariableNameSize when needed\r
435 //\r
436 *VariableNameSize = SmmGetNextVariableName->NameSize;\r
437 }\r
438 if (EFI_ERROR (Status)) {\r
439 goto Done;\r
440 }\r
441 \r
442 CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);\r
443 CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize); \r
444\r
445Done:\r
446 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
447 return Status;\r
448}\r
449\r
450/**\r
451 This code sets variable in storage blocks (Volatile or Non-Volatile).\r
452\r
453 @param[in] VariableName Name of Variable to be found.\r
454 @param[in] VendorGuid Variable vendor GUID.\r
455 @param[in] Attributes Attribute value of the variable found\r
456 @param[in] DataSize Size of Data found. If size is less than the\r
457 data, this value contains the required size.\r
458 @param[in] Data Data pointer.\r
459\r
460 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
461 @retval EFI_SUCCESS Set successfully.\r
462 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.\r
463 @retval EFI_NOT_FOUND Not found.\r
464 @retval EFI_WRITE_PROTECTED Variable is read-only.\r
465\r
466**/\r
467EFI_STATUS\r
468EFIAPI\r
469RuntimeServiceSetVariable (\r
470 IN CHAR16 *VariableName,\r
471 IN EFI_GUID *VendorGuid,\r
472 IN UINT32 Attributes,\r
473 IN UINTN DataSize,\r
474 IN VOID *Data\r
475 )\r
476{\r
477 EFI_STATUS Status;\r
478 UINTN PayloadSize; \r
479 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;\r
480 UINTN VariableNameSize;\r
481 \r
482 //\r
483 // Check input parameters.\r
484 //\r
485 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
486 return EFI_INVALID_PARAMETER;\r
487 } \r
488\r
489 if (DataSize != 0 && Data == NULL) {\r
490 return EFI_INVALID_PARAMETER;\r
491 }\r
492\r
493 VariableNameSize = StrSize (VariableName);\r
494\r
495 //\r
496 // If VariableName or DataSize exceeds SMM payload limit. Return failure\r
497 //\r
498 if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||\r
499 (DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){\r
500 return EFI_INVALID_PARAMETER;\r
501 }\r
502\r
503 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
504 \r
505 //\r
506 // Init the communicate buffer. The buffer data size is:\r
507 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
508 //\r
509 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;\r
510 Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);\r
511 if (EFI_ERROR (Status)) {\r
512 goto Done;\r
513 }\r
514 ASSERT (SmmVariableHeader != NULL);\r
515\r
516 CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);\r
517 SmmVariableHeader->DataSize = DataSize;\r
518 SmmVariableHeader->NameSize = VariableNameSize;\r
519 SmmVariableHeader->Attributes = Attributes;\r
520 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
521 CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);\r
522\r
523 //\r
524 // Send data to SMM.\r
525 //\r
526 Status = SendCommunicateBuffer (PayloadSize);\r
527\r
528Done:\r
529 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
530 return Status;\r
531}\r
532\r
533\r
534/**\r
535 This code returns information about the EFI variables.\r
536\r
537 @param[in] Attributes Attributes bitmask to specify the type of variables\r
538 on which to return information.\r
539 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
540 for the EFI variables associated with the attributes specified.\r
541 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
542 for EFI variables associated with the attributes specified.\r
543 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
544 associated with the attributes specified.\r
545\r
546 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.\r
547 @retval EFI_SUCCESS Query successfully.\r
548 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.\r
549\r
550**/\r
551EFI_STATUS\r
552EFIAPI\r
553RuntimeServiceQueryVariableInfo (\r
554 IN UINT32 Attributes,\r
555 OUT UINT64 *MaximumVariableStorageSize,\r
556 OUT UINT64 *RemainingVariableStorageSize,\r
557 OUT UINT64 *MaximumVariableSize\r
558 )\r
559{\r
560 EFI_STATUS Status;\r
561 UINTN PayloadSize;\r
562 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;\r
563\r
564 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
565 return EFI_INVALID_PARAMETER;\r
566 }\r
567\r
568 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
569\r
570 //\r
571 // Init the communicate buffer. The buffer data size is:\r
572 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;\r
573 //\r
574 PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);\r
575 Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);\r
576 if (EFI_ERROR (Status)) {\r
577 goto Done;\r
578 }\r
579 ASSERT (SmmQueryVariableInfo != NULL);\r
580\r
581 SmmQueryVariableInfo->Attributes = Attributes;\r
582\r
583 //\r
584 // Send data to SMM.\r
585 //\r
586 Status = SendCommunicateBuffer (PayloadSize);\r
587 if (EFI_ERROR (Status)) {\r
588 goto Done;\r
589 }\r
590\r
591 //\r
592 // Get data from SMM.\r
593 //\r
594 *MaximumVariableSize = SmmQueryVariableInfo->MaximumVariableSize;\r
595 *MaximumVariableStorageSize = SmmQueryVariableInfo->MaximumVariableStorageSize;\r
596 *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize; \r
597\r
598Done:\r
599 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
600 return Status;\r
601}\r
602\r
603\r
604/**\r
605 Exit Boot Services Event notification handler.\r
606\r
607 Notify SMM variable driver about the event.\r
608\r
609 @param[in] Event Event whose notification function is being invoked.\r
610 @param[in] Context Pointer to the notification function's context.\r
611\r
612**/\r
613VOID\r
614EFIAPI\r
615OnExitBootServices (\r
616 IN EFI_EVENT Event,\r
617 IN VOID *Context\r
618 )\r
619{\r
620 //\r
621 // Init the communicate buffer. The buffer data size is:\r
622 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
623 //\r
624 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE); \r
625\r
626 //\r
627 // Send data to SMM.\r
628 //\r
629 SendCommunicateBuffer (0);\r
630}\r
631\r
632\r
633/**\r
634 On Ready To Boot Services Event notification handler.\r
635\r
636 Notify SMM variable driver about the event.\r
637\r
638 @param[in] Event Event whose notification function is being invoked\r
639 @param[in] Context Pointer to the notification function's context\r
640\r
641**/\r
642VOID\r
643EFIAPI\r
644OnReadyToBoot (\r
645 IN EFI_EVENT Event,\r
646 IN VOID *Context\r
647 )\r
648{\r
649 //\r
650 // Init the communicate buffer. The buffer data size is:\r
651 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
652 //\r
653 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);\r
654 \r
655 //\r
656 // Send data to SMM.\r
657 //\r
658 SendCommunicateBuffer (0);\r
659}\r
660\r
661\r
662/**\r
663 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
664\r
665 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
666 It convers pointer to new virtual address.\r
667\r
668 @param[in] Event Event whose notification function is being invoked.\r
669 @param[in] Context Pointer to the notification function's context.\r
670\r
671**/\r
672VOID\r
673EFIAPI\r
674VariableAddressChangeEvent (\r
675 IN EFI_EVENT Event,\r
676 IN VOID *Context\r
677 )\r
678{\r
679 EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);\r
680 EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);\r
681}\r
682\r
683\r
684/**\r
685 Initialize variable service and install Variable Architectural protocol.\r
686\r
687 @param[in] Event Event whose notification function is being invoked.\r
688 @param[in] Context Pointer to the notification function's context.\r
689 \r
690**/\r
691VOID\r
692EFIAPI\r
693SmmVariableReady (\r
694 IN EFI_EVENT Event,\r
695 IN VOID *Context\r
696 )\r
697{\r
698 EFI_STATUS Status;\r
699\r
700 Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);\r
701 if (EFI_ERROR (Status)) {\r
702 return;\r
703 }\r
704 \r
705 Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);\r
706 ASSERT_EFI_ERROR (Status);\r
707 \r
708 //\r
709 // Allocate memory for variable communicate buffer.\r
710 //\r
711 mVariableBufferPayloadSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) +\r
712 OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - sizeof (VARIABLE_HEADER);\r
713 mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;\r
714 mVariableBuffer = AllocateRuntimePool (mVariableBufferSize);\r
715 ASSERT (mVariableBuffer != NULL);\r
716\r
717 //\r
718 // Save the buffer physical address used for SMM conmunication.\r
719 //\r
720 mVariableBufferPhysical = mVariableBuffer;\r
721\r
722 gRT->GetVariable = RuntimeServiceGetVariable;\r
723 gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
724 gRT->SetVariable = RuntimeServiceSetVariable;\r
725 gRT->QueryVariableInfo = RuntimeServiceQueryVariableInfo;\r
726 \r
727 //\r
728 // Install the Variable Architectural Protocol on a new handle.\r
729 //\r
730 Status = gBS->InstallProtocolInterface (\r
731 &mHandle,\r
732 &gEfiVariableArchProtocolGuid, \r
733 EFI_NATIVE_INTERFACE,\r
734 NULL\r
735 );\r
736 ASSERT_EFI_ERROR (Status);\r
737}\r
738\r
739\r
740/**\r
741 SMM Non-Volatile variable write service is ready notify event handler.\r
742\r
743 @param[in] Event Event whose notification function is being invoked.\r
744 @param[in] Context Pointer to the notification function's context.\r
745 \r
746**/\r
747VOID\r
748EFIAPI\r
749SmmVariableWriteReady (\r
750 IN EFI_EVENT Event,\r
751 IN VOID *Context\r
752 )\r
753{\r
754 EFI_STATUS Status;\r
755 VOID *ProtocolOps;\r
756\r
757 //\r
758 // Check whether the protocol is installed or not.\r
759 //\r
760 Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);\r
761 if (EFI_ERROR (Status)) {\r
762 return;\r
763 }\r
764 \r
765 Status = gBS->InstallProtocolInterface (\r
766 &mHandle,\r
767 &gEfiVariableWriteArchProtocolGuid, \r
768 EFI_NATIVE_INTERFACE,\r
769 NULL\r
770 );\r
771 ASSERT_EFI_ERROR (Status); \r
772}\r
773\r
774\r
775/**\r
776 Variable Driver main entry point. The Variable driver places the 4 EFI\r
777 runtime services in the EFI System Table and installs arch protocols \r
778 for variable read and write services being available. It also registers\r
779 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
780\r
781 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
782 @param[in] SystemTable A pointer to the EFI System Table.\r
783 \r
784 @retval EFI_SUCCESS Variable service successfully initialized.\r
785\r
786**/\r
787EFI_STATUS\r
788EFIAPI\r
789VariableSmmRuntimeInitialize (\r
790 IN EFI_HANDLE ImageHandle,\r
791 IN EFI_SYSTEM_TABLE *SystemTable\r
792 )\r
793{\r
794 EFI_STATUS Status;\r
795 VOID *SmmVariableRegistration;\r
796 VOID *SmmVariableWriteRegistration;\r
797 EFI_EVENT OnReadyToBootEvent;\r
798 EFI_EVENT ExitBootServiceEvent;\r
799\r
800 EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);\r
801\r
802 mVariableLock.RequestToLock = VariableLockRequestToLock;\r
803 Status = gBS->InstallMultipleProtocolInterfaces (\r
804 &mHandle,\r
805 &gEdkiiVariableLockProtocolGuid,\r
806 &mVariableLock,\r
807 NULL\r
808 );\r
809 ASSERT_EFI_ERROR (Status);\r
810\r
811 //\r
812 // Smm variable service is ready\r
813 //\r
814 EfiCreateProtocolNotifyEvent (\r
815 &gEfiSmmVariableProtocolGuid, \r
816 TPL_CALLBACK, \r
817 SmmVariableReady, \r
818 NULL, \r
819 &SmmVariableRegistration\r
820 );\r
821\r
822 //\r
823 // Smm Non-Volatile variable write service is ready\r
824 //\r
825 EfiCreateProtocolNotifyEvent (\r
826 &gSmmVariableWriteGuid, \r
827 TPL_CALLBACK, \r
828 SmmVariableWriteReady, \r
829 NULL, \r
830 &SmmVariableWriteRegistration\r
831 );\r
832\r
833 //\r
834 // Register the event to reclaim variable for OS usage.\r
835 //\r
836 EfiCreateEventReadyToBootEx (\r
837 TPL_NOTIFY, \r
838 OnReadyToBoot, \r
839 NULL, \r
840 &OnReadyToBootEvent\r
841 ); \r
842\r
843 //\r
844 // Register the event to inform SMM variable that it is at runtime.\r
845 //\r
846 gBS->CreateEventEx (\r
847 EVT_NOTIFY_SIGNAL,\r
848 TPL_NOTIFY,\r
849 OnExitBootServices,\r
850 NULL,\r
851 &gEfiEventExitBootServicesGuid,\r
852 &ExitBootServiceEvent\r
853 ); \r
854\r
855 //\r
856 // Register the event to convert the pointer for runtime.\r
857 //\r
858 gBS->CreateEventEx (\r
859 EVT_NOTIFY_SIGNAL,\r
860 TPL_NOTIFY,\r
861 VariableAddressChangeEvent,\r
862 NULL,\r
863 &gEfiEventVirtualAddressChangeGuid,\r
864 &mVirtualAddressChangeEvent\r
865 );\r
866 \r
867 return EFI_SUCCESS;\r
868}\r
869\r