]> git.proxmox.com Git - mirror_edk2.git/blame - 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
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
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
RN
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
ff843847
RN
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
51547bb8 212 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;\r
ff843847
RN
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
51547bb8 220 VariableToLock->NameSize = VariableNameSize;\r
ff843847
RN
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
8a2d4996 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
3a146f2a 262 UINTN TempDataSize;\r
9d00d20e 263 UINTN VariableNameSize;\r
8a2d4996 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
6ed1ec59 272\r
3a146f2a 273 TempDataSize = *DataSize;\r
9d00d20e 274 VariableNameSize = StrSize (VariableName);\r
3a146f2a 275\r
276 //\r
277 // If VariableName exceeds SMM payload limit. Return failure\r
278 //\r
5e5bb2a9 279 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {\r
3588bb35
SZ
280 return EFI_INVALID_PARAMETER;\r
281 }\r
282\r
6ed1ec59
SZ
283 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
284\r
8a2d4996 285 //\r
286 // Init the communicate buffer. The buffer data size is:\r
6ed1ec59 287 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
8a2d4996 288 //\r
5e5bb2a9 289 if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {\r
3a146f2a 290 //\r
291 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
292 //\r
5e5bb2a9 293 TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;\r
3a146f2a 294 }\r
9d00d20e 295 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;\r
3a146f2a 296\r
5c7fa429 297 Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);\r
8a2d4996 298 if (EFI_ERROR (Status)) {\r
6ed1ec59 299 goto Done;\r
8a2d4996 300 }\r
301 ASSERT (SmmVariableHeader != NULL);\r
302\r
303 CopyGuid (&SmmVariableHeader->Guid, VendorGuid);\r
3a146f2a 304 SmmVariableHeader->DataSize = TempDataSize;\r
9d00d20e 305 SmmVariableHeader->NameSize = VariableNameSize;\r
8a2d4996 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
3a146f2a 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
8a2d4996 328 if (Attributes != NULL) {\r
329 *Attributes = SmmVariableHeader->Attributes;\r
330 }\r
331\r
332 if (EFI_ERROR (Status)) {\r
6ed1ec59 333 goto Done;\r
8a2d4996 334 }\r
335\r
336 CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);\r
337\r
6ed1ec59
SZ
338Done:\r
339 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
8a2d4996 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
9d00d20e
SZ
368 UINTN OutVariableNameSize;\r
369 UINTN InVariableNameSize;\r
8a2d4996 370\r
371 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
372 return EFI_INVALID_PARAMETER;\r
373 }\r
6ed1ec59 374\r
9d00d20e
SZ
375 OutVariableNameSize = *VariableNameSize;\r
376 InVariableNameSize = StrSize (VariableName);\r
0c55190f 377\r
378 //\r
379 // If input string exceeds SMM payload limit. Return failure\r
380 //\r
5e5bb2a9 381 if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
3588bb35
SZ
382 return EFI_INVALID_PARAMETER;\r
383 }\r
384\r
6ed1ec59
SZ
385 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
386\r
8a2d4996 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
5e5bb2a9 391 if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
0c55190f 392 //\r
393 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
394 //\r
5e5bb2a9 395 OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);\r
0c55190f 396 }\r
397 //\r
398 // Payload should be Guid + NameSize + MAX of Input & Output buffer\r
399 //\r
9d00d20e 400 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);\r
0c55190f 401\r
402\r
5c7fa429 403 Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);\r
8a2d4996 404 if (EFI_ERROR (Status)) {\r
6ed1ec59 405 goto Done;\r
8a2d4996 406 }\r
407 ASSERT (SmmGetNextVariableName != NULL);\r
408\r
0c55190f 409 //\r
410 // SMM comm buffer->NameSize is buffer size for return string\r
411 //\r
9d00d20e 412 SmmGetNextVariableName->NameSize = OutVariableNameSize;\r
0c55190f 413\r
8a2d4996 414 CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);\r
0c55190f 415 //\r
416 // Copy whole string\r
417 //\r
9d00d20e
SZ
418 CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);\r
419 if (OutVariableNameSize > InVariableNameSize) {\r
420 ZeroMem ((UINT8 *) SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);\r
421 }\r
8a2d4996 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
9d00d20e
SZ
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
8a2d4996 438 if (EFI_ERROR (Status)) {\r
6ed1ec59 439 goto Done;\r
8a2d4996 440 }\r
441 \r
442 CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);\r
443 CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize); \r
444\r
6ed1ec59
SZ
445Done:\r
446 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
8a2d4996 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
9d00d20e 480 UINTN VariableNameSize;\r
8a2d4996 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
6ed1ec59 492\r
9d00d20e 493 VariableNameSize = StrSize (VariableName);\r
3588bb35 494\r
5e5bb2a9
SZ
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
56251c66 500 return EFI_INVALID_PARAMETER;\r
501 }\r
502\r
6ed1ec59
SZ
503 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
504 \r
8a2d4996 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
9d00d20e 509 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;\r
5c7fa429 510 Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);\r
8a2d4996 511 if (EFI_ERROR (Status)) {\r
6ed1ec59 512 goto Done;\r
8a2d4996 513 }\r
514 ASSERT (SmmVariableHeader != NULL);\r
515\r
516 CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);\r
517 SmmVariableHeader->DataSize = DataSize;\r
9d00d20e 518 SmmVariableHeader->NameSize = VariableNameSize;\r
8a2d4996 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
6ed1ec59
SZ
527\r
528Done:\r
529 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
8a2d4996 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
6ed1ec59
SZ
567\r
568 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
569\r
8a2d4996 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
d00ed85e 574 PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);\r
5c7fa429 575 Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);\r
8a2d4996 576 if (EFI_ERROR (Status)) {\r
6ed1ec59 577 goto Done;\r
8a2d4996 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
6ed1ec59 588 goto Done;\r
8a2d4996 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
6ed1ec59
SZ
597\r
598Done:\r
599 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
aab9212f 600 return Status;\r
8a2d4996 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
5e5bb2a9 709 // Allocate memory for variable communicate buffer.\r
8a2d4996 710 //\r
5e5bb2a9
SZ
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
8a2d4996 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
d00ed85e 760 Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);\r
8a2d4996 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
d00ed85e 778 for variable read and write services being available. It also registers\r
8a2d4996 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
ff843847 794 EFI_STATUS Status;\r
8a2d4996 795 VOID *SmmVariableRegistration;\r
796 VOID *SmmVariableWriteRegistration;\r
797 EFI_EVENT OnReadyToBootEvent;\r
798 EFI_EVENT ExitBootServiceEvent;\r
6ed1ec59
SZ
799\r
800 EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);\r
801\r
ff843847
RN
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
8a2d4996 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
d00ed85e 826 &gSmmVariableWriteGuid, \r
8a2d4996 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