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