VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxVariable/InitVariable.c@ 43212

Last change on this file since 43212 was 43212, checked in by vboxsync, 13 years ago

EFI/OVMF: Modification of EmuVariableRuntimeDxe module to use VBox NVRAM.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.0 KB
Line 
1/* $Id: InitVariable.c 43212 2012-09-06 05:49:10Z vboxsync $ */
2/** @file
3 * InitVariable.h
4 */
5
6/*
7 * Copyright (C) 2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/** @file
19
20 Implment all four UEFI runtime variable services and
21 install variable architeture protocol.
22
23Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
24This program and the accompanying materials
25are licensed and made available under the terms and conditions of the BSD License
26which accompanies this distribution. The full text of the license may be found at
27http://opensource.org/licenses/bsd-license.php
28
29THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
30WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
31
32**/
33
34#include "Variable.h"
35
36
37EFI_EVENT mVirtualAddressChangeEvent = NULL;
38
39#ifdef VBOX
40# include <Library/PrintLib.h>
41# include <Library/TimerLib.h>
42# include "VBoxPkg.h"
43# include "DevEFI.h"
44# include "iprt/asm.h"
45
46
47static inline UINT32 VBoxReadNVRAM(UINT8 *pu8Buffer, UINT32 cbBuffer)
48{
49 UINT32 idxBuffer = 0;
50 for (idxBuffer = 0; idxBuffer < cbBuffer; ++idxBuffer)
51 pu8Buffer[idxBuffer] = ASMInU8(EFI_VARIABLE_OP);
52 return idxBuffer;
53}
54
55static inline void VBoxWriteNVRAMU32Param(UINT32 u32CodeParam, UINT32 u32Param)
56{
57 ASMOutU32(EFI_VARIABLE_OP, u32CodeParam);
58 ASMOutU32(EFI_VARIABLE_PARAM, u32Param);
59}
60
61static inline UINT32 VBoxWriteNVRAMByteArrayParam(const UINT8 *pu8Param, UINT32 cbParam)
62{
63 UINT32 idxParam = 0;
64 for (idxParam = 0; idxParam < cbParam; ++idxParam)
65 ASMOutU8(EFI_VARIABLE_PARAM, pu8Param[idxParam]);
66 return idxParam;
67}
68
69static inline UINT32 VBoxWriteNVRAMStringParam(const CHAR16 *ps16VariableName)
70{
71 CHAR8 szVarName[512];
72 UINT32 cbVarName = StrLen(ps16VariableName);
73 LogFlowFuncEnter();
74 ASSERT (cbVarName < 512);
75 if (cbVarName > 512)
76 {
77 LogFlowFuncMarkVar(cbVarName, "%d");
78 LogFlowFuncLeave();
79 return 0;
80 }
81 UnicodeStrToAsciiStr(ps16VariableName, szVarName);
82
83 VBoxWriteNVRAMU32Param(EFI_VM_VARIABLE_OP_NAME_LENGTH, cbVarName);
84
85 ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_NAME);
86 cbVarName = VBoxWriteNVRAMByteArrayParam((UINT8 *)szVarName, cbVarName);
87
88 LogFlowFuncMarkVar(cbVarName, "%d");
89 LogFlowFuncLeave();
90 return cbVarName;
91}
92
93static inline UINT32 VBoxWriteNVRAMGuidParam(const EFI_GUID *pGuid)
94{
95 ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_GUID);
96 return VBoxWriteNVRAMByteArrayParam((UINT8 *)pGuid, sizeof(EFI_GUID));
97}
98
99static inline UINT32 VBoxWriteNVRAMDoOp(UINT32 u32Operation)
100{
101 UINT32 u32Rc;
102 LogFlowFuncEnter();
103 LogFlowFuncMarkVar(u32Operation, "%x");
104 VBoxWriteNVRAMU32Param(EFI_VM_VARIABLE_OP_START, u32Operation);
105
106 while((u32Rc = ASMInU32(EFI_VARIABLE_OP)) == EFI_VARIABLE_OP_STATUS_BSY)
107 {
108#if 0
109 MicroSecondDelay (400);
110#endif
111 /* @todo: sleep here */
112 }
113 LogFlowFuncMarkVar(u32Rc, "%x");
114 LogFlowFuncLeave();
115 return u32Rc;
116}
117#endif
118
119/**
120
121 This code finds variable in storage blocks (Volatile or Non-Volatile).
122
123 @param VariableName Name of Variable to be found.
124 @param VendorGuid Variable vendor GUID.
125 @param Attributes Attribute value of the variable found.
126 @param DataSize Size of Data found. If size is less than the
127 data, this value contains the required size.
128 @param Data Data pointer.
129
130 @return EFI_INVALID_PARAMETER Invalid parameter
131 @return EFI_SUCCESS Find the specified variable
132 @return EFI_NOT_FOUND Not found
133 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result
134
135**/
136EFI_STATUS
137EFIAPI
138RuntimeServiceGetVariable (
139 IN CHAR16 *VariableName,
140 IN EFI_GUID *VendorGuid,
141 OUT UINT32 *Attributes OPTIONAL,
142 IN OUT UINTN *DataSize,
143 OUT VOID *Data
144 )
145{
146#ifndef VBOX
147 return EmuGetVariable (
148 VariableName,
149 VendorGuid,
150 Attributes OPTIONAL,
151 DataSize,
152 Data,
153 &mVariableModuleGlobal->VariableGlobal[Physical]
154 );
155#else
156 UINT32 VarLen;
157 UINT32 u32Rc = 0;
158
159 LogFlowFuncEnter();
160 /* set uuid */
161 ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_GUID);
162 VBoxWriteNVRAMGuidParam(VendorGuid);
163
164 /* set name */
165 VBoxWriteNVRAMStringParam(VariableName);
166
167 /* start operation */
168 u32Rc = VBoxWriteNVRAMDoOp(EFI_VARIABLE_OP_QUERY);
169
170 ASSERT (u32Rc != EFI_VARIABLE_OP_STATUS_ERROR);
171 switch(u32Rc)
172 {
173 case EFI_VARIABLE_OP_STATUS_ERROR: /* for release build */
174 case EFI_VARIABLE_OP_STATUS_NOT_FOUND:
175 LogFlowFuncLeaveRC(EFI_NOT_FOUND);
176 return EFI_NOT_FOUND;
177 case EFI_VARIABLE_OP_STATUS_OK:
178 {
179 ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_VALUE_LENGTH);
180 VarLen = ASMInU32(EFI_VARIABLE_OP);
181 LogFlowFuncMarkVar(*DataSize, "%d");
182 LogFlowFuncMarkVar(VarLen, "%d");
183 if ( VarLen > *DataSize
184 || !Data)
185 {
186 *DataSize = VarLen;
187 /* @todo: should we end op ? */
188 LogFlowFuncLeave();
189 return EFI_BUFFER_TOO_SMALL;
190 }
191 ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_VALUE);
192 *DataSize = VBoxReadNVRAM((UINT8 *)Data, VarLen);
193 if (Attributes)
194 {
195 ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_ATTRIBUTE);
196 *Attributes = ASMInU32(EFI_VARIABLE_OP);
197 LogFlowFuncMarkVar(Attributes, "%x");
198 }
199 LogFlowFuncLeaveRC((EFI_SUCCESS));
200 return EFI_SUCCESS;
201 }
202 }
203#endif
204 return EFI_SUCCESS;
205}
206
207/**
208
209 This code Finds the Next available variable.
210
211 @param VariableNameSize Size of the variable name
212 @param VariableName Pointer to variable name
213 @param VendorGuid Variable Vendor Guid
214
215 @return EFI_INVALID_PARAMETER Invalid parameter
216 @return EFI_SUCCESS Find the specified variable
217 @return EFI_NOT_FOUND Not found
218 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result
219
220**/
221EFI_STATUS
222EFIAPI
223RuntimeServiceGetNextVariableName (
224 IN OUT UINTN *VariableNameSize,
225 IN OUT CHAR16 *VariableName,
226 IN OUT EFI_GUID *VendorGuid
227 )
228{
229#ifndef VBOX
230 return EmuGetNextVariableName (
231 VariableNameSize,
232 VariableName,
233 VendorGuid,
234 &mVariableModuleGlobal->VariableGlobal[Physical]
235 );
236#else
237 uint32_t u32Rc = 0;
238 EFI_STATUS rc = EFI_NOT_FOUND;
239 CHAR8 szVariableName[512];
240 int cbVarName = 0;
241
242 LogFlowFuncEnter();
243
244 SetMem(szVariableName, 512, 0);
245 u32Rc = VBoxWriteNVRAMDoOp(EFI_VARIABLE_OP_QUERY_NEXT);
246 switch (u32Rc)
247 {
248 case EFI_VARIABLE_OP_STATUS_OK:
249 {
250 ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_NAME_LENGTH);
251 cbVarName = ASMInU32(EFI_VARIABLE_OP);
252
253 ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_GUID);
254 VBoxReadNVRAM((UINT8 *)VendorGuid, sizeof(EFI_GUID));
255
256 ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_NAME);
257 VBoxReadNVRAM((UINT8 *)szVariableName, cbVarName);
258
259 if (cbVarName < *VariableNameSize)
260 {
261 UnicodeSPrintAsciiFormat(VariableName, cbVarName, "%a", szVariableName);
262 LogFlowFuncMarkVar(*VariableNameSize, "%d");
263 LogFlowFuncMarkVar(VariableName, "%s");
264 LogFlowFuncMarkVar(VendorGuid, "%g");
265 *VariableNameSize = cbVarName;
266 LogFlowFuncMarkVar(*VariableNameSize, "%d");
267 rc = EFI_SUCCESS;
268 }
269 else
270 rc = EFI_BUFFER_TOO_SMALL;
271 }
272 case EFI_VARIABLE_OP_STATUS_ERROR:
273 case EFI_VARIABLE_OP_STATUS_NOT_FOUND:
274 case EFI_VARIABLE_OP_STATUS_NOT_WP:
275 rc = EFI_NOT_FOUND;
276 }
277 LogFlowFuncLeaveRC(rc);
278 return rc;
279#endif
280}
281
282/**
283
284 This code sets variable in storage blocks (Volatile or Non-Volatile).
285
286 @param VariableName Name of Variable to be found
287 @param VendorGuid Variable vendor GUID
288 @param Attributes Attribute value of the variable found
289 @param DataSize Size of Data found. If size is less than the
290 data, this value contains the required size.
291 @param Data Data pointer
292
293 @return EFI_INVALID_PARAMETER Invalid parameter
294 @return EFI_SUCCESS Set successfully
295 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable
296 @return EFI_NOT_FOUND Not found
297 @return EFI_WRITE_PROTECTED Variable is read-only
298
299**/
300EFI_STATUS
301EFIAPI
302RuntimeServiceSetVariable (
303 IN CHAR16 *VariableName,
304 IN EFI_GUID *VendorGuid,
305 IN UINT32 Attributes,
306 IN UINTN DataSize,
307 IN VOID *Data
308 )
309{
310#ifndef VBOX
311 return EmuSetVariable (
312 VariableName,
313 VendorGuid,
314 Attributes,
315 DataSize,
316 Data,
317 &mVariableModuleGlobal->VariableGlobal[Physical],
318 &mVariableModuleGlobal->VolatileLastVariableOffset,
319 &mVariableModuleGlobal->NonVolatileLastVariableOffset
320 );
321#else
322 UINT32 u32Rc;
323 LogFlowFuncEnter();
324 LogFlowFuncMarkVar(VendorGuid, "%g");
325 LogFlowFuncMarkVar(VariableName, "%s");
326 LogFlowFuncMarkVar(DataSize, "%d");
327 /* set guid */
328 VBoxWriteNVRAMGuidParam(VendorGuid);
329 /* set name */
330 VBoxWriteNVRAMStringParam(VariableName);
331 /* set attribute */
332 VBoxWriteNVRAMU32Param(EFI_VM_VARIABLE_OP_ATTRIBUTE, Attributes);
333 /* set value length */
334 VBoxWriteNVRAMU32Param(EFI_VM_VARIABLE_OP_VALUE_LENGTH, DataSize);
335 /* fill value bytes */
336 ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_VALUE);
337 VBoxWriteNVRAMByteArrayParam(Data, DataSize);
338 /* start fetch operation */
339 u32Rc = VBoxWriteNVRAMDoOp(EFI_VARIABLE_OP_ADD);
340 /* process errors */
341 LogFlowFuncLeave();
342 switch(u32Rc)
343 {
344 case EFI_VARIABLE_OP_STATUS_OK:
345 return EFI_SUCCESS;
346 case EFI_VARIABLE_OP_STATUS_NOT_WP:
347 default:
348 return EFI_WRITE_PROTECTED;
349 }
350#endif
351}
352
353/**
354
355 This code returns information about the EFI variables.
356
357 @param Attributes Attributes bitmask to specify the type of variables
358 on which to return information.
359 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
360 for the EFI variables associated with the attributes specified.
361 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
362 for EFI variables associated with the attributes specified.
363 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
364 associated with the attributes specified.
365
366 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
367 @return EFI_SUCCESS Query successfully.
368 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
369
370**/
371EFI_STATUS
372EFIAPI
373RuntimeServiceQueryVariableInfo (
374 IN UINT32 Attributes,
375 OUT UINT64 *MaximumVariableStorageSize,
376 OUT UINT64 *RemainingVariableStorageSize,
377 OUT UINT64 *MaximumVariableSize
378 )
379{
380#ifndef VBOX
381 return EmuQueryVariableInfo (
382 Attributes,
383 MaximumVariableStorageSize,
384 RemainingVariableStorageSize,
385 MaximumVariableSize,
386 &mVariableModuleGlobal->VariableGlobal[Physical]
387 );
388#else
389 *MaximumVariableStorageSize = 64 * 1024 * 1024;
390 *MaximumVariableSize = 1024;
391 *RemainingVariableStorageSize = 32 * 1024 * 1024;
392 return EFI_SUCCESS;
393#endif
394}
395
396/**
397 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
398
399 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
400 It convers pointer to new virtual address.
401
402 @param Event Event whose notification function is being invoked.
403 @param Context Pointer to the notification function's context.
404
405**/
406VOID
407EFIAPI
408VariableClassAddressChangeEvent (
409 IN EFI_EVENT Event,
410 IN VOID *Context
411 )
412{
413#ifndef VBOX
414 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes);
415 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->LangCodes);
416 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLang);
417 EfiConvertPointer (
418 0x0,
419 (VOID **) &mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase
420 );
421 EfiConvertPointer (
422 0x0,
423 (VOID **) &mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase
424 );
425 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);
426#endif
427}
428
429/**
430 EmuVariable Driver main entry point. The Variable driver places the 4 EFI
431 runtime services in the EFI System Table and installs arch protocols
432 for variable read and write services being available. It also registers
433 notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
434
435 @param[in] ImageHandle The firmware allocated handle for the EFI image.
436 @param[in] SystemTable A pointer to the EFI System Table.
437
438 @retval EFI_SUCCESS Variable service successfully initialized.
439
440**/
441EFI_STATUS
442EFIAPI
443VariableServiceInitialize (
444 IN EFI_HANDLE ImageHandle,
445 IN EFI_SYSTEM_TABLE *SystemTable
446 )
447{
448 EFI_HANDLE NewHandle;
449 EFI_STATUS Status;
450
451 Status = VariableCommonInitialize (ImageHandle, SystemTable);
452 ASSERT_EFI_ERROR (Status);
453
454 SystemTable->RuntimeServices->GetVariable = RuntimeServiceGetVariable;
455 SystemTable->RuntimeServices->GetNextVariableName = RuntimeServiceGetNextVariableName;
456 SystemTable->RuntimeServices->SetVariable = RuntimeServiceSetVariable;
457 SystemTable->RuntimeServices->QueryVariableInfo = RuntimeServiceQueryVariableInfo;
458
459 //
460 // Now install the Variable Runtime Architectural Protocol on a new handle
461 //
462 NewHandle = NULL;
463 Status = gBS->InstallMultipleProtocolInterfaces (
464 &NewHandle,
465 &gEfiVariableArchProtocolGuid,
466 NULL,
467 &gEfiVariableWriteArchProtocolGuid,
468 NULL,
469 NULL
470 );
471 ASSERT_EFI_ERROR (Status);
472
473 Status = gBS->CreateEventEx (
474 EVT_NOTIFY_SIGNAL,
475 TPL_NOTIFY,
476 VariableClassAddressChangeEvent,
477 NULL,
478 &gEfiEventVirtualAddressChangeGuid,
479 &mVirtualAddressChangeEvent
480 );
481 ASSERT_EFI_ERROR (Status);
482
483 /* Self Test */
484 {
485 EFI_GUID TestUUID = {0xe660597e, 0xb94d, 0x4209, {0x9c, 0x80, 0x18, 0x05, 0xb5, 0xd1, 0x9b, 0x69}};
486 const char *pszVariable0 = "This is test!!!";
487 const CHAR16 *pszVariable1 = L"This is test!!!";
488 char szTestVariable[512];
489#if 0
490 rc = runtime->SetVariable(&TestUUID,
491 NULL ,
492 (EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS| EFI_VARIABLE_RUNTIME_ACCESS),
493 0,
494 NULL );
495 ASSERT(rc == EFI_INVALID_PARAMETER);
496#endif
497 UINTN size = sizeof(szTestVariable),
498 rc = RuntimeServiceSetVariable(
499 L"Test0" ,
500 &TestUUID,
501 (EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS| EFI_VARIABLE_RUNTIME_ACCESS),
502 AsciiStrSize(pszVariable0),
503 (void *)pszVariable0);
504 ASSERT_EFI_ERROR(rc);
505 SetMem(szTestVariable, 512, 0);
506 rc = RuntimeServiceGetVariable(
507 L"Test0" ,
508 &TestUUID,
509 NULL,
510 &size,
511 (void *)szTestVariable);
512 LogFlowFuncMarkVar(szTestVariable, "%a");
513
514 ASSERT(CompareMem(szTestVariable, pszVariable0, size) == 0);
515
516 rc = RuntimeServiceSetVariable(
517 L"Test1" ,
518 &TestUUID,
519 (EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS| EFI_VARIABLE_RUNTIME_ACCESS),
520 StrSize(pszVariable1),
521 (void *)pszVariable1);
522 ASSERT_EFI_ERROR(rc);
523 SetMem(szTestVariable, 512, 0);
524 size = StrSize(pszVariable1);
525 rc = RuntimeServiceGetVariable(
526 L"Test1" ,
527 &TestUUID,
528 NULL,
529 &size,
530 (void *)szTestVariable);
531 LogFlowFuncMarkVar((CHAR16 *)szTestVariable, "%s");
532 ASSERT(CompareMem(szTestVariable, pszVariable1, size) == 0);
533 }
534
535 return EFI_SUCCESS;
536}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette