| /** @file | |
| Variable services implemented from system memory | |
| There is just a single runtime memory buffer that contans all the data. | |
| Copyright (c) 2007, Intel Corporation. All rights reserved.<BR> | |
| Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| UINT64 mMaximumVariableStorageSize; | |
| UINT64 mRemainingVariableStorageSize; | |
| UINT64 mMaximumVariableSize; | |
| typedef struct { | |
| EFI_GUID VendorGuid; | |
| UINT32 Attribute; | |
| UINTN DataSize; | |
| } VARIABLE_ARRAY_ENTRY; | |
| // CHAR16 VariableName[] | |
| // UINT8 Data[] | |
| VARIABLE_ARRAY_ENTRY *mVariableArray = NULL; | |
| VARIABLE_ARRAY_ENTRY *mVariableArrayNextFree = NULL; | |
| VARIABLE_ARRAY_ENTRY *mVariableArrayEnd = NULL; | |
| VARIABLE_ARRAY_ENTRY * | |
| AddEntry ( | |
| IN CHAR16 *VariableName, | |
| IN EFI_GUID *VendorGuid, | |
| IN UINT32 Attributes, | |
| IN UINTN DataSize, | |
| IN VOID *Data | |
| ) | |
| { | |
| UINTN Size; | |
| UINTN SizeOfString; | |
| VARIABLE_ARRAY_ENTRY *Entry; | |
| EFI_TPL CurrentTpl; | |
| SizeOfString = StrSize (VariableName); | |
| Size = SizeOfString + sizeof (VARIABLE_ARRAY_ENTRY) + DataSize; | |
| if ((VARIABLE_ARRAY_ENTRY *)(((UINT8 *)mVariableArrayNextFree) + Size) > mVariableArrayEnd) { | |
| // ran out of space | |
| return NULL; | |
| } | |
| if (!EfiAtRuntime ()) { | |
| // Enter critical section | |
| CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); | |
| } | |
| Entry = mVariableArrayNextFree; | |
| CopyGuid (&Entry->VendorGuid, VendorGuid); | |
| Entry->Attribute = Attributes; | |
| Entry->DataSize = DataSize; | |
| StrCpy ((CHAR16 *)++mVariableArrayNextFree, VariableName); | |
| mVariableArrayNextFree = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)mVariableArrayNextFree) + SizeOfString); | |
| CopyMem (mVariableArrayNextFree, Data, DataSize); | |
| mVariableArrayNextFree = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)mVariableArrayNextFree) + DataSize); | |
| if (!EfiAtRuntime ()) { | |
| // Exit Critical section | |
| gBS->RestoreTPL (CurrentTpl); | |
| } | |
| return Entry; | |
| } | |
| VOID | |
| DeleteEntry ( | |
| IN VARIABLE_ARRAY_ENTRY *Entry | |
| ) | |
| { | |
| UINTN Size; | |
| UINT8 *Data; | |
| EFI_TPL CurrentTpl; | |
| Size = StrSize ((CHAR16 *)(Entry + 1)) + sizeof (VARIABLE_ARRAY_ENTRY) + Entry->DataSize; | |
| Data = ((UINT8 *)Entry) + Size; | |
| CopyMem (Entry, Data, (UINTN)mVariableArrayNextFree - (UINTN)Data); | |
| if (!EfiAtRuntime ()) { | |
| // Enter critical section | |
| CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); | |
| } | |
| mVariableArrayNextFree = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)mVariableArrayNextFree) - Size); | |
| if (!EfiAtRuntime ()) { | |
| // Exit Critical section | |
| gBS->RestoreTPL (CurrentTpl); | |
| } | |
| } | |
| VARIABLE_ARRAY_ENTRY * | |
| GetVariableArrayEntry ( | |
| IN CHAR16 *VariableName, | |
| IN EFI_GUID *VendorGuid, | |
| OUT VOID **Data OPTIONAL | |
| ) | |
| { | |
| VARIABLE_ARRAY_ENTRY *Entry; | |
| UINTN Size; | |
| if (*VariableName == L'\0') { | |
| // by definition first entry is null-terminated string | |
| if (mVariableArray == mVariableArrayNextFree) { | |
| return NULL; | |
| } | |
| return mVariableArray; | |
| } | |
| for (Entry = mVariableArray; Entry < mVariableArrayEnd;) { | |
| if (CompareGuid (VendorGuid, &Entry->VendorGuid)) { | |
| if (StrCmp (VariableName, (CHAR16 *)(Entry + 1))) { | |
| Size = StrSize ((CHAR16 *)(Entry + 1)); | |
| if (Data != NULL) { | |
| *Data = (VOID *)(((UINT8 *)Entry) + (Size + sizeof (VARIABLE_ARRAY_ENTRY))); | |
| } | |
| return Entry; | |
| } | |
| } | |
| Size = StrSize ((CHAR16 *)(Entry + 1)) + sizeof (VARIABLE_ARRAY_ENTRY) + Entry->DataSize; | |
| Entry = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)Entry) + Size); | |
| } | |
| return NULL; | |
| } | |
| EFI_STATUS | |
| LibGetVariable ( | |
| IN CHAR16 *VariableName, | |
| IN EFI_GUID *VendorGuid, | |
| OUT UINT32 *Attributes OPTIONAL, | |
| IN OUT UINTN *DataSize, | |
| OUT VOID *Data | |
| ) | |
| { | |
| VARIABLE_ARRAY_ENTRY *Entry; | |
| VOID *InternalData; | |
| if (EfiAtRuntime () && (Attributes != NULL)) { | |
| if ((*Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) { | |
| return EFI_NOT_FOUND; | |
| } | |
| } | |
| Entry = GetVariableArrayEntry (VariableName, VendorGuid, &InternalData); | |
| if (Entry == NULL) { | |
| return EFI_NOT_FOUND; | |
| } | |
| if (*DataSize < Entry->DataSize) { | |
| *DataSize = Entry->DataSize; | |
| return EFI_BUFFER_TOO_SMALL; | |
| } | |
| *DataSize = Entry->DataSize; | |
| if (Attributes != NULL) { | |
| *Attributes = Entry->Attribute; | |
| } | |
| CopyMem (Data, InternalData, *DataSize); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| LibGetNextVariableName ( | |
| IN OUT UINTN *VariableNameSize, | |
| IN OUT CHAR16 *VariableName, | |
| IN OUT EFI_GUID *VendorGuid | |
| ) | |
| { | |
| VARIABLE_ARRAY_ENTRY *Entry; | |
| VOID *InternalData; | |
| UINTN StringSize; | |
| BOOLEAN Done; | |
| for (Done = FALSE; !Done; ) { | |
| Entry = GetVariableArrayEntry (VariableName, VendorGuid, &InternalData); | |
| if (Entry == NULL) { | |
| return EFI_NOT_FOUND; | |
| } | |
| // If we are at runtime skip variables that do not have the Runitme attribute set. | |
| Done = (EfiAtRuntime () && ((Entry->Attribute & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) ? FALSE : TRUE; | |
| } | |
| StringSize = StrSize ((CHAR16 *)(Entry + 1)); | |
| Entry = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)Entry) + (StringSize + sizeof (VARIABLE_ARRAY_ENTRY) + Entry->DataSize)); | |
| if (Entry >= mVariableArrayEnd) { | |
| return EFI_NOT_FOUND; | |
| } | |
| if (*VariableNameSize < StringSize) { | |
| *VariableNameSize = StringSize; | |
| return EFI_BUFFER_TOO_SMALL; | |
| } | |
| *VariableNameSize = StringSize; | |
| CopyMem (VariableName, (CHAR16 *)(Entry + 1), StringSize); | |
| CopyMem (VendorGuid, &Entry->VendorGuid, sizeof (EFI_GUID)); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| LibSetVariable ( | |
| IN CHAR16 *VariableName, | |
| IN EFI_GUID *VendorGuid, | |
| IN UINT32 Attributes, | |
| IN UINTN DataSize, | |
| IN VOID *Data | |
| ) | |
| { | |
| VARIABLE_ARRAY_ENTRY *Entry; | |
| VOID *InternalData; | |
| if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) { | |
| return EFI_NOT_FOUND; | |
| } | |
| Entry = GetVariableArrayEntry (VariableName, VendorGuid, &InternalData); | |
| if (Entry == NULL) { | |
| if (DataSize == 0) { | |
| return EFI_NOT_FOUND; | |
| } | |
| Entry = AddEntry (VariableName, VendorGuid, Attributes, DataSize, Data); | |
| return (Entry == NULL) ? EFI_OUT_OF_RESOURCES : EFI_SUCCESS; | |
| } else if (DataSize == 0) { | |
| // DataSize is zero so delete | |
| DeleteEntry (Entry); | |
| } else if (DataSize == Entry->DataSize) { | |
| // No change is size so just update the store | |
| Entry->Attribute |= Attributes; | |
| CopyMem (InternalData, Data, DataSize); | |
| } else { | |
| // Grow the entry by deleting and adding back. Don't lose previous Attributes | |
| Attributes |= Entry->Attribute; | |
| DeleteEntry (Entry); | |
| Entry = AddEntry (VariableName, VendorGuid, Attributes, DataSize, Data); | |
| return (Entry == NULL) ? EFI_OUT_OF_RESOURCES : EFI_SUCCESS; | |
| } | |
| } | |
| EFI_STATUS | |
| LibQueryVariableInfo ( | |
| IN UINT32 Attributes, | |
| OUT UINT64 *MaximumVariableStorageSize, | |
| OUT UINT64 *RemainingVariableStorageSize, | |
| OUT UINT64 *MaximumVariableSize | |
| ) | |
| { | |
| *MaximumVariableStorageSize = mMaximumVariableStorageSize; | |
| *RemainingVariableStorageSize = mRemainingVariableStorageSize; | |
| *MaximumVariableStorageSize = mRemainingVariableStorageSize; | |
| return EFI_SUCCESS; | |
| } | |
| VOID | |
| LibVariableVirtualAddressChangeEvent (VOID) | |
| { | |
| EfiConvertPointer (0, (VOID **)&mVariableArray); | |
| EfiConvertPointer (0, (VOID **)&mVariableArrayNextFree); | |
| EfiConvertPointer (0, (VOID **)&mVariableArrayEnd); | |
| } | |
| VOID | |
| LibVariableInitialize (VOID) | |
| { | |
| UINTN Size; | |
| Size = PcdGet32 (PcdEmbeddedMemVariableStoreSize); | |
| mVariableArray = mVariableArrayNextFree = (VARIABLE_ARRAY_ENTRY *)AllocateRuntimePool (Size); | |
| ASSERT (mVariableArray != NULL); | |
| mVariableArrayEnd = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)mVariableArray) + Size); | |
| mMaximumVariableStorageSize = Size - sizeof (VARIABLE_ARRAY_ENTRY); | |
| mRemainingVariableStorageSize = mMaximumVariableStorageSize; | |
| mMaximumVariableSize = mMaximumVariableStorageSize; | |
| } | |