]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
MdeModulePkg: INF/DEC file updates to EDK II packages
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / VariableSmmRuntimeDxe.c
CommitLineData
8a2d4996 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
4e1005ec 7Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
8a2d4996 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
d00ed85e 17#include <PiDxe.h>\r
8a2d4996 18#include <Protocol/VariableWrite.h>\r
19#include <Protocol/Variable.h>\r
20#include <Protocol/SmmCommunication.h>\r
d00ed85e 21#include <Protocol/SmmVariable.h>\r
ff843847 22#include <Protocol/VariableLock.h>\r
8a2d4996 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
d00ed85e 36#include <Guid/VariableFormat.h>\r
37#include <Guid/SmmVariableCommon.h>\r
8a2d4996 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
8a2d4996 45UINTN mVariableBufferSize;\r
5e5bb2a9 46UINTN mVariableBufferPayloadSize;\r
6ed1ec59 47EFI_LOCK mVariableServicesLock;\r
ff843847 48EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock;\r
8a2d4996 49\r
6ed1ec59
SZ
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
8a2d4996 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
32732a33 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
8a2d4996 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
ff843847
RN
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
51547bb8 189 UINTN VariableNameSize;\r
ff843847
RN
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
51547bb8 197 VariableNameSize = StrSize (VariableName);\r
4e1005ec 198 VariableToLock = NULL;\r
51547bb8
RN
199\r
200 //\r
201 // If VariableName exceeds SMM payload limit. Return failure\r
202 //\r
203 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {\r
204 return EFI_INVALID_PARAMETER;\r
205 }\r
206\r
ff843847
RN
207 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
208\r
209 //\r
210 // Init the communicate buffer. The buffer data size is:\r
211 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
212 //\r
51547bb8 213 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;\r
ff843847
RN
214 Status = InitCommunicateBuffer ((VOID **) &VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);\r
215 if (EFI_ERROR (Status)) {\r
216 goto Done;\r
217 }\r
218 ASSERT (VariableToLock != NULL);\r
219\r
220 CopyGuid (&VariableToLock->Guid, VendorGuid);\r
51547bb8 221 VariableToLock->NameSize = VariableNameSize;\r
ff843847
RN
222 CopyMem (VariableToLock->Name, VariableName, VariableToLock->NameSize);\r
223\r
224 //\r
225 // Send data to SMM.\r
226 //\r
227 Status = SendCommunicateBuffer (PayloadSize);\r
228\r
229Done:\r
230 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
231 return Status;\r
232}\r
8a2d4996 233\r
234/**\r
235 This code finds variable in storage blocks (Volatile or Non-Volatile).\r
236\r
237 @param[in] VariableName Name of Variable to be found.\r
238 @param[in] VendorGuid Variable vendor GUID.\r
239 @param[out] Attributes Attribute value of the variable found.\r
240 @param[in, out] DataSize Size of Data found. If size is less than the\r
241 data, this value contains the required size.\r
242 @param[out] Data Data pointer.\r
243 \r
244 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
245 @retval EFI_SUCCESS Find the specified variable.\r
246 @retval EFI_NOT_FOUND Not found.\r
247 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
248\r
249**/\r
250EFI_STATUS\r
251EFIAPI\r
252RuntimeServiceGetVariable (\r
253 IN CHAR16 *VariableName,\r
254 IN EFI_GUID *VendorGuid,\r
255 OUT UINT32 *Attributes OPTIONAL,\r
256 IN OUT UINTN *DataSize,\r
257 OUT VOID *Data\r
258 )\r
259{\r
260 EFI_STATUS Status;\r
261 UINTN PayloadSize;\r
262 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;\r
3a146f2a 263 UINTN TempDataSize;\r
9d00d20e 264 UINTN VariableNameSize;\r
8a2d4996 265\r
266 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
267 return EFI_INVALID_PARAMETER;\r
268 }\r
269\r
270 if ((*DataSize != 0) && (Data == NULL)) {\r
271 return EFI_INVALID_PARAMETER;\r
272 }\r
6ed1ec59 273\r
3a146f2a 274 TempDataSize = *DataSize;\r
9d00d20e 275 VariableNameSize = StrSize (VariableName);\r
4e1005ec 276 SmmVariableHeader = NULL;\r
3a146f2a 277\r
278 //\r
279 // If VariableName exceeds SMM payload limit. Return failure\r
280 //\r
5e5bb2a9 281 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {\r
3588bb35
SZ
282 return EFI_INVALID_PARAMETER;\r
283 }\r
284\r
6ed1ec59
SZ
285 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
286\r
8a2d4996 287 //\r
288 // Init the communicate buffer. The buffer data size is:\r
6ed1ec59 289 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
8a2d4996 290 //\r
5e5bb2a9 291 if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {\r
3a146f2a 292 //\r
293 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
294 //\r
5e5bb2a9 295 TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;\r
3a146f2a 296 }\r
9d00d20e 297 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;\r
3a146f2a 298\r
5c7fa429 299 Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);\r
8a2d4996 300 if (EFI_ERROR (Status)) {\r
6ed1ec59 301 goto Done;\r
8a2d4996 302 }\r
303 ASSERT (SmmVariableHeader != NULL);\r
304\r
305 CopyGuid (&SmmVariableHeader->Guid, VendorGuid);\r
3a146f2a 306 SmmVariableHeader->DataSize = TempDataSize;\r
9d00d20e 307 SmmVariableHeader->NameSize = VariableNameSize;\r
8a2d4996 308 if (Attributes == NULL) {\r
309 SmmVariableHeader->Attributes = 0;\r
310 } else {\r
311 SmmVariableHeader->Attributes = *Attributes;\r
312 }\r
313 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
314\r
315 //\r
316 // Send data to SMM.\r
317 //\r
318 Status = SendCommunicateBuffer (PayloadSize);\r
319\r
320 //\r
321 // Get data from SMM.\r
322 //\r
3a146f2a 323 if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
324 //\r
325 // SMM CommBuffer DataSize can be a trimed value\r
326 // Only update DataSize when needed\r
327 //\r
328 *DataSize = SmmVariableHeader->DataSize;\r
329 }\r
8a2d4996 330 if (Attributes != NULL) {\r
331 *Attributes = SmmVariableHeader->Attributes;\r
332 }\r
333\r
334 if (EFI_ERROR (Status)) {\r
6ed1ec59 335 goto Done;\r
8a2d4996 336 }\r
337\r
338 CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);\r
339\r
6ed1ec59
SZ
340Done:\r
341 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
8a2d4996 342 return Status;\r
343}\r
344\r
345\r
346/**\r
347 This code Finds the Next available variable.\r
348\r
349 @param[in, out] VariableNameSize Size of the variable name.\r
350 @param[in, out] VariableName Pointer to variable name.\r
351 @param[in, out] VendorGuid Variable Vendor Guid.\r
352\r
353 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
354 @retval EFI_SUCCESS Find the specified variable.\r
355 @retval EFI_NOT_FOUND Not found.\r
356 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
357\r
358**/\r
359EFI_STATUS\r
360EFIAPI\r
361RuntimeServiceGetNextVariableName (\r
362 IN OUT UINTN *VariableNameSize,\r
363 IN OUT CHAR16 *VariableName,\r
364 IN OUT EFI_GUID *VendorGuid\r
365 )\r
366{\r
367 EFI_STATUS Status;\r
368 UINTN PayloadSize;\r
369 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;\r
9d00d20e
SZ
370 UINTN OutVariableNameSize;\r
371 UINTN InVariableNameSize;\r
8a2d4996 372\r
373 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
374 return EFI_INVALID_PARAMETER;\r
375 }\r
6ed1ec59 376\r
9d00d20e
SZ
377 OutVariableNameSize = *VariableNameSize;\r
378 InVariableNameSize = StrSize (VariableName);\r
4e1005ec 379 SmmGetNextVariableName = NULL;\r
0c55190f 380\r
381 //\r
382 // If input string exceeds SMM payload limit. Return failure\r
383 //\r
5e5bb2a9 384 if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
3588bb35
SZ
385 return EFI_INVALID_PARAMETER;\r
386 }\r
387\r
6ed1ec59
SZ
388 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
389\r
8a2d4996 390 //\r
391 // Init the communicate buffer. The buffer data size is:\r
392 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
393 //\r
5e5bb2a9 394 if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
0c55190f 395 //\r
396 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
397 //\r
5e5bb2a9 398 OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);\r
0c55190f 399 }\r
400 //\r
401 // Payload should be Guid + NameSize + MAX of Input & Output buffer\r
402 //\r
9d00d20e 403 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);\r
0c55190f 404\r
405\r
5c7fa429 406 Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);\r
8a2d4996 407 if (EFI_ERROR (Status)) {\r
6ed1ec59 408 goto Done;\r
8a2d4996 409 }\r
410 ASSERT (SmmGetNextVariableName != NULL);\r
411\r
0c55190f 412 //\r
413 // SMM comm buffer->NameSize is buffer size for return string\r
414 //\r
9d00d20e 415 SmmGetNextVariableName->NameSize = OutVariableNameSize;\r
0c55190f 416\r
8a2d4996 417 CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);\r
0c55190f 418 //\r
419 // Copy whole string\r
420 //\r
9d00d20e
SZ
421 CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);\r
422 if (OutVariableNameSize > InVariableNameSize) {\r
423 ZeroMem ((UINT8 *) SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);\r
424 }\r
8a2d4996 425\r
426 //\r
427 // Send data to SMM\r
428 //\r
429 Status = SendCommunicateBuffer (PayloadSize);\r
430\r
431 //\r
432 // Get data from SMM.\r
433 //\r
9d00d20e
SZ
434 if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
435 //\r
436 // SMM CommBuffer NameSize can be a trimed value\r
437 // Only update VariableNameSize when needed\r
438 //\r
439 *VariableNameSize = SmmGetNextVariableName->NameSize;\r
440 }\r
8a2d4996 441 if (EFI_ERROR (Status)) {\r
6ed1ec59 442 goto Done;\r
8a2d4996 443 }\r
444 \r
445 CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);\r
446 CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize); \r
447\r
6ed1ec59
SZ
448Done:\r
449 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
8a2d4996 450 return Status;\r
451}\r
452\r
453/**\r
454 This code sets variable in storage blocks (Volatile or Non-Volatile).\r
455\r
456 @param[in] VariableName Name of Variable to be found.\r
457 @param[in] VendorGuid Variable vendor GUID.\r
458 @param[in] Attributes Attribute value of the variable found\r
459 @param[in] DataSize Size of Data found. If size is less than the\r
460 data, this value contains the required size.\r
461 @param[in] Data Data pointer.\r
462\r
463 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
464 @retval EFI_SUCCESS Set successfully.\r
465 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.\r
466 @retval EFI_NOT_FOUND Not found.\r
467 @retval EFI_WRITE_PROTECTED Variable is read-only.\r
468\r
469**/\r
470EFI_STATUS\r
471EFIAPI\r
472RuntimeServiceSetVariable (\r
473 IN CHAR16 *VariableName,\r
474 IN EFI_GUID *VendorGuid,\r
475 IN UINT32 Attributes,\r
476 IN UINTN DataSize,\r
477 IN VOID *Data\r
478 )\r
479{\r
480 EFI_STATUS Status;\r
481 UINTN PayloadSize; \r
482 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;\r
9d00d20e 483 UINTN VariableNameSize;\r
8a2d4996 484 \r
485 //\r
486 // Check input parameters.\r
487 //\r
488 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
489 return EFI_INVALID_PARAMETER;\r
490 } \r
491\r
492 if (DataSize != 0 && Data == NULL) {\r
493 return EFI_INVALID_PARAMETER;\r
494 }\r
6ed1ec59 495\r
9d00d20e 496 VariableNameSize = StrSize (VariableName);\r
4e1005ec 497 SmmVariableHeader = NULL;\r
3588bb35 498\r
5e5bb2a9
SZ
499 //\r
500 // If VariableName or DataSize exceeds SMM payload limit. Return failure\r
501 //\r
502 if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||\r
503 (DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){\r
56251c66 504 return EFI_INVALID_PARAMETER;\r
505 }\r
506\r
6ed1ec59
SZ
507 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
508 \r
8a2d4996 509 //\r
510 // Init the communicate buffer. The buffer data size is:\r
511 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
512 //\r
9d00d20e 513 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;\r
5c7fa429 514 Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);\r
8a2d4996 515 if (EFI_ERROR (Status)) {\r
6ed1ec59 516 goto Done;\r
8a2d4996 517 }\r
518 ASSERT (SmmVariableHeader != NULL);\r
519\r
520 CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);\r
521 SmmVariableHeader->DataSize = DataSize;\r
9d00d20e 522 SmmVariableHeader->NameSize = VariableNameSize;\r
8a2d4996 523 SmmVariableHeader->Attributes = Attributes;\r
524 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
525 CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);\r
526\r
527 //\r
528 // Send data to SMM.\r
529 //\r
530 Status = SendCommunicateBuffer (PayloadSize);\r
6ed1ec59
SZ
531\r
532Done:\r
533 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
8a2d4996 534 return Status;\r
535}\r
536\r
537\r
538/**\r
539 This code returns information about the EFI variables.\r
540\r
541 @param[in] Attributes Attributes bitmask to specify the type of variables\r
542 on which to return information.\r
543 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
544 for the EFI variables associated with the attributes specified.\r
545 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
546 for EFI variables associated with the attributes specified.\r
547 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
548 associated with the attributes specified.\r
549\r
550 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.\r
551 @retval EFI_SUCCESS Query successfully.\r
552 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.\r
553\r
554**/\r
555EFI_STATUS\r
556EFIAPI\r
557RuntimeServiceQueryVariableInfo (\r
558 IN UINT32 Attributes,\r
559 OUT UINT64 *MaximumVariableStorageSize,\r
560 OUT UINT64 *RemainingVariableStorageSize,\r
561 OUT UINT64 *MaximumVariableSize\r
562 )\r
563{\r
564 EFI_STATUS Status;\r
565 UINTN PayloadSize;\r
566 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;\r
567\r
4e1005ec
ED
568 SmmQueryVariableInfo = NULL;\r
569\r
8a2d4996 570 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
571 return EFI_INVALID_PARAMETER;\r
572 }\r
6ed1ec59
SZ
573\r
574 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
575\r
8a2d4996 576 //\r
577 // Init the communicate buffer. The buffer data size is:\r
578 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;\r
579 //\r
d00ed85e 580 PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);\r
5c7fa429 581 Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);\r
8a2d4996 582 if (EFI_ERROR (Status)) {\r
6ed1ec59 583 goto Done;\r
8a2d4996 584 }\r
585 ASSERT (SmmQueryVariableInfo != NULL);\r
586\r
587 SmmQueryVariableInfo->Attributes = Attributes;\r
588\r
589 //\r
590 // Send data to SMM.\r
591 //\r
592 Status = SendCommunicateBuffer (PayloadSize);\r
593 if (EFI_ERROR (Status)) {\r
6ed1ec59 594 goto Done;\r
8a2d4996 595 }\r
596\r
597 //\r
598 // Get data from SMM.\r
599 //\r
600 *MaximumVariableSize = SmmQueryVariableInfo->MaximumVariableSize;\r
601 *MaximumVariableStorageSize = SmmQueryVariableInfo->MaximumVariableStorageSize;\r
602 *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize; \r
6ed1ec59
SZ
603\r
604Done:\r
605 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
aab9212f 606 return Status;\r
8a2d4996 607}\r
608\r
609\r
610/**\r
611 Exit Boot Services Event notification handler.\r
612\r
613 Notify SMM variable driver about the event.\r
614\r
615 @param[in] Event Event whose notification function is being invoked.\r
616 @param[in] Context Pointer to the notification function's context.\r
617\r
618**/\r
619VOID\r
620EFIAPI\r
621OnExitBootServices (\r
622 IN EFI_EVENT Event,\r
623 IN VOID *Context\r
624 )\r
625{\r
626 //\r
627 // Init the communicate buffer. The buffer data size is:\r
628 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
629 //\r
630 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE); \r
631\r
632 //\r
633 // Send data to SMM.\r
634 //\r
635 SendCommunicateBuffer (0);\r
636}\r
637\r
638\r
639/**\r
640 On Ready To Boot Services Event notification handler.\r
641\r
642 Notify SMM variable driver about the event.\r
643\r
644 @param[in] Event Event whose notification function is being invoked\r
645 @param[in] Context Pointer to the notification function's context\r
646\r
647**/\r
648VOID\r
649EFIAPI\r
650OnReadyToBoot (\r
651 IN EFI_EVENT Event,\r
652 IN VOID *Context\r
653 )\r
654{\r
655 //\r
656 // Init the communicate buffer. The buffer data size is:\r
657 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
658 //\r
659 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);\r
660 \r
661 //\r
662 // Send data to SMM.\r
663 //\r
664 SendCommunicateBuffer (0);\r
665}\r
666\r
667\r
668/**\r
669 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
670\r
671 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
672 It convers pointer to new virtual address.\r
673\r
674 @param[in] Event Event whose notification function is being invoked.\r
675 @param[in] Context Pointer to the notification function's context.\r
676\r
677**/\r
678VOID\r
679EFIAPI\r
680VariableAddressChangeEvent (\r
681 IN EFI_EVENT Event,\r
682 IN VOID *Context\r
683 )\r
684{\r
685 EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);\r
686 EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);\r
687}\r
688\r
689\r
690/**\r
691 Initialize variable service and install Variable Architectural protocol.\r
692\r
693 @param[in] Event Event whose notification function is being invoked.\r
694 @param[in] Context Pointer to the notification function's context.\r
695 \r
696**/\r
697VOID\r
698EFIAPI\r
699SmmVariableReady (\r
700 IN EFI_EVENT Event,\r
701 IN VOID *Context\r
702 )\r
703{\r
704 EFI_STATUS Status;\r
705\r
706 Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);\r
707 if (EFI_ERROR (Status)) {\r
708 return;\r
709 }\r
710 \r
711 Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);\r
712 ASSERT_EFI_ERROR (Status);\r
713 \r
714 //\r
5e5bb2a9 715 // Allocate memory for variable communicate buffer.\r
8a2d4996 716 //\r
5e5bb2a9
SZ
717 mVariableBufferPayloadSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) +\r
718 OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - sizeof (VARIABLE_HEADER);\r
719 mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;\r
8a2d4996 720 mVariableBuffer = AllocateRuntimePool (mVariableBufferSize);\r
721 ASSERT (mVariableBuffer != NULL);\r
722\r
723 //\r
724 // Save the buffer physical address used for SMM conmunication.\r
725 //\r
726 mVariableBufferPhysical = mVariableBuffer;\r
727\r
728 gRT->GetVariable = RuntimeServiceGetVariable;\r
729 gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
730 gRT->SetVariable = RuntimeServiceSetVariable;\r
731 gRT->QueryVariableInfo = RuntimeServiceQueryVariableInfo;\r
732 \r
733 //\r
734 // Install the Variable Architectural Protocol on a new handle.\r
735 //\r
736 Status = gBS->InstallProtocolInterface (\r
737 &mHandle,\r
738 &gEfiVariableArchProtocolGuid, \r
739 EFI_NATIVE_INTERFACE,\r
740 NULL\r
741 );\r
742 ASSERT_EFI_ERROR (Status);\r
743}\r
744\r
745\r
746/**\r
747 SMM Non-Volatile variable write service is ready notify event handler.\r
748\r
749 @param[in] Event Event whose notification function is being invoked.\r
750 @param[in] Context Pointer to the notification function's context.\r
751 \r
752**/\r
753VOID\r
754EFIAPI\r
755SmmVariableWriteReady (\r
756 IN EFI_EVENT Event,\r
757 IN VOID *Context\r
758 )\r
759{\r
760 EFI_STATUS Status;\r
761 VOID *ProtocolOps;\r
762\r
763 //\r
764 // Check whether the protocol is installed or not.\r
765 //\r
d00ed85e 766 Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);\r
8a2d4996 767 if (EFI_ERROR (Status)) {\r
768 return;\r
769 }\r
770 \r
771 Status = gBS->InstallProtocolInterface (\r
772 &mHandle,\r
773 &gEfiVariableWriteArchProtocolGuid, \r
774 EFI_NATIVE_INTERFACE,\r
775 NULL\r
776 );\r
777 ASSERT_EFI_ERROR (Status); \r
778}\r
779\r
780\r
781/**\r
782 Variable Driver main entry point. The Variable driver places the 4 EFI\r
783 runtime services in the EFI System Table and installs arch protocols \r
d00ed85e 784 for variable read and write services being available. It also registers\r
8a2d4996 785 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
786\r
787 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
788 @param[in] SystemTable A pointer to the EFI System Table.\r
789 \r
790 @retval EFI_SUCCESS Variable service successfully initialized.\r
791\r
792**/\r
793EFI_STATUS\r
794EFIAPI\r
795VariableSmmRuntimeInitialize (\r
796 IN EFI_HANDLE ImageHandle,\r
797 IN EFI_SYSTEM_TABLE *SystemTable\r
798 )\r
799{\r
ff843847 800 EFI_STATUS Status;\r
8a2d4996 801 VOID *SmmVariableRegistration;\r
802 VOID *SmmVariableWriteRegistration;\r
803 EFI_EVENT OnReadyToBootEvent;\r
804 EFI_EVENT ExitBootServiceEvent;\r
6ed1ec59
SZ
805\r
806 EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);\r
807\r
ff843847
RN
808 mVariableLock.RequestToLock = VariableLockRequestToLock;\r
809 Status = gBS->InstallMultipleProtocolInterfaces (\r
810 &mHandle,\r
811 &gEdkiiVariableLockProtocolGuid,\r
812 &mVariableLock,\r
813 NULL\r
814 );\r
815 ASSERT_EFI_ERROR (Status);\r
816\r
8a2d4996 817 //\r
818 // Smm variable service is ready\r
819 //\r
820 EfiCreateProtocolNotifyEvent (\r
821 &gEfiSmmVariableProtocolGuid, \r
822 TPL_CALLBACK, \r
823 SmmVariableReady, \r
824 NULL, \r
825 &SmmVariableRegistration\r
826 );\r
827\r
828 //\r
829 // Smm Non-Volatile variable write service is ready\r
830 //\r
831 EfiCreateProtocolNotifyEvent (\r
d00ed85e 832 &gSmmVariableWriteGuid, \r
8a2d4996 833 TPL_CALLBACK, \r
834 SmmVariableWriteReady, \r
835 NULL, \r
836 &SmmVariableWriteRegistration\r
837 );\r
838\r
839 //\r
840 // Register the event to reclaim variable for OS usage.\r
841 //\r
842 EfiCreateEventReadyToBootEx (\r
843 TPL_NOTIFY, \r
844 OnReadyToBoot, \r
845 NULL, \r
846 &OnReadyToBootEvent\r
847 ); \r
848\r
849 //\r
850 // Register the event to inform SMM variable that it is at runtime.\r
851 //\r
852 gBS->CreateEventEx (\r
853 EVT_NOTIFY_SIGNAL,\r
854 TPL_NOTIFY,\r
855 OnExitBootServices,\r
856 NULL,\r
857 &gEfiEventExitBootServicesGuid,\r
858 &ExitBootServiceEvent\r
859 ); \r
860\r
861 //\r
862 // Register the event to convert the pointer for runtime.\r
863 //\r
864 gBS->CreateEventEx (\r
865 EVT_NOTIFY_SIGNAL,\r
866 TPL_NOTIFY,\r
867 VariableAddressChangeEvent,\r
868 NULL,\r
869 &gEfiEventVirtualAddressChangeGuid,\r
870 &mVirtualAddressChangeEvent\r
871 );\r
872 \r
873 return EFI_SUCCESS;\r
874}\r
875\r