VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVariable/InitVariable.c@ 56292

Last change on this file since 56292 was 56292, checked in by vboxsync, 10 years ago

Devices: Updated (C) year.

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

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