⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 varapi.c

📁 Next BIOS Source code : Extensible Firmware Interface
💻 C
字号:
/*++

Copyright (c)  1999 - 2002 Intel Corporation. All rights reserved
This software and associated documentation (if any) is furnished
under a license and may only be used or copied in accordance
with the terms of the license. Except as permitted by such
license, no part of this software or documentation may be
reproduced, stored in a retrieval system, or transmitted in any
form or by any means without the express written consent of
Intel Corporation.


Module Name:

Abstract:




Revision History

--*/

#include "ivar.h"

//
//
//
#pragma RUNTIME_CODE(RtAcquireStoreLock)
VOID
INTERNAL RUNTIMEFUNCTION
RtAcquireStoreLock (
    VOID
    )
{
    AcquireLock (&VariableStoreLock);
}

#pragma RUNTIME_CODE(RtReleaseStoreLock)
VOID
INTERNAL RUNTIMEFUNCTION
RtReleaseStoreLock (
    VOID
    )
{
    RtReleaseLock (&VariableStoreLock);
}

#pragma RUNTIME_CODE(RtVarFind)
EFI_STATUS
INTERNAL RUNTIMEFUNCTION
RtVarFind (
    IN CHAR16               *Name,
    IN EFI_GUID             *VendorGuid,
    OUT VARIABLE_INFO       *VarInfo
    )
{
    VARIABLE_STORE          *VarStore;
    LIST_ENTRY              *Link;

    ASSERT_LOCKED (&VariableStoreLock);

    //
    // Search all variable stores
    //

    for (VarStore=VariableStore; VarStore; VarStore=VarStore->Next) {

        //
        // If this is runtime, only skip any non-runtime variable store
        //

        if (EfiAtRuntime && VarStore->MemoryType != EfiRuntimeServicesData) {
            continue;
        }

        //
        // Search all banks in this store
        //

        for (Link=VarStore->Active.Flink; Link != &VarStore->Active; Link=Link->Flink) {
            VarInfo->Bank = CR(Link, STORAGE_BANK, Link, STORAGE_BANK_SIGNATURE);

            //
            // Search all variables in this bank
            //

            VarInfo->NextVarOffset = FIRST_VARIABLE_OFFSET;
            while (RtVarParseStore (VarInfo)) {

                //
                // If it's a valid entry, and it's not an obsolete entry,
                // or being transitioned to obslete, and the name & guid
                // matches the request - then this the entry we're looking
                // for.
                //

                if (VarInfo->Valid &&
                    !(VarInfo->State & VAR_OBSOLETE_TRANSITION) &&
                    StrCmp(Name, VarInfo->Name) == 0 &&
                    CompareGuid(VendorGuid, VarInfo->VendorGuid) == 0) {

                    if (!EfiAtRuntime || (EfiAtRuntime && (VarInfo->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) {

                        //
                        // Got a match
                        //

                        return EFI_SUCCESS;
                    }
                }
            }
        }
    }

    //
    // Variable was not found
    //

    VarInfo->Valid = FALSE;
    return EFI_NOT_FOUND;
}


#pragma RUNTIME_CODE(RtVarFindFreeSpace)
STORAGE_BANK *
STATIC RUNTIMEFUNCTION
RtVarFindFreeSpace (
    IN VARIABLE_STORE           *VarStore,
    IN UINTN                    Size,
    OUT BOOLEAN                 *GarbageCollected
    )
{
    LIST_ENTRY                  *Link;
    STORAGE_BANK                *Bank;
    BOOLEAN                     Updated;

    *GarbageCollected = FALSE;

    for (; ;) {
        //
        // Search the active banks for the available space
        //

        for (Link=VarStore->Active.Flink; Link != &VarStore->Active; Link=Link->Flink) {
            Bank = CR(Link, STORAGE_BANK, Link, STORAGE_BANK_SIGNATURE);

            if (!Bank->DeviceError  && 
                Bank->Tail + Size  < Bank->BankSize  &&
                Bank->InUse + Size < *Bank->TSize) {
                // There's enough space in this bank, use it
                return Bank;
            }
        }

        //
        // Perform some garbage collection to make some space
        //

        Updated = RtVarGarbageCollect (VarStore);

        //
        // If there were no updates from the garbage collection 
        // then there is no space.
        //

        if (!Updated) {
            Bank = NULL;
            break;
        }

        //
        // Inform the caller that garbage collection was done
        //

        *GarbageCollected = TRUE;
    }

    DEBUG((D_VAR|D_WARN, "VarFindFreeSpace: no space found for %a (needed %d)\n", VarStore->Type, Size));
    return NULL;
}

#pragma RUNTIME_CODE(RtGetVariable)
EFI_STATUS
RUNTIMESERVICE
RtGetVariable (
    IN CHAR16                       *VariableName,
    IN EFI_GUID                     *VendorGuid,
    OUT UINT32                      *Attributes OPTIONAL,
    IN OUT UINTN                    *DataSize,
    OUT VOID                        *Data
    )
{
    VARIABLE_INFO                   VarInfo;
    EFI_STATUS                      Status;

    if (VariableName == NULL || VendorGuid == NULL) {
      return EFI_INVALID_PARAMETER;
    }

    RtAcquireStoreLock(); 

    Status = RtVarFind (VariableName, VendorGuid, &VarInfo);
    if( !EFI_ERROR(Status) )
		{
        ASSERT (VarInfo.Valid);

        if( DataSize == NULL )
				{
            Status = EFI_INVALID_PARAMETER;
        }
        else
        {
          if( *DataSize < VarInfo.DataSize )
          {
           Status = EFI_BUFFER_TOO_SMALL;
          }
          else
          {
            if( Data == NULL )
            {
              Status = EFI_INVALID_PARAMETER;
            }
            else
            {
              CopyMem (Data, VarInfo.Data, VarInfo.DataSize);
              if( Attributes )
              {
                *Attributes = VarInfo.Attributes;
              }
            }
          }
            
          *DataSize = VarInfo.DataSize;
        }
    }
    
    RtReleaseStoreLock ();
    return Status;
}


#pragma RUNTIME_CODE(RtGetNextVariableName)
EFI_STATUS
RUNTIMESERVICE
RtGetNextVariableName (
    IN OUT UINTN                    *VariableNameSize,
    IN OUT CHAR16                   *VariableName,
    IN OUT EFI_GUID                 *VendorGuid
    )
{
    VARIABLE_INFO                   VarInfo;
    VARIABLE_STORE                  *VarStore;
    EFI_STATUS                      Status;
    LIST_ENTRY                      *Link;

    if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
      return EFI_INVALID_PARAMETER;
    }

    RtAcquireStoreLock ();

    //
    // Get last position
    //

    if (*VariableName) {

        //
        // Find last position
        //

        Status = RtVarFind (VariableName, VendorGuid, &VarInfo);
        if (EFI_ERROR(Status)) {
            goto Done;
        }

        Link = &VarInfo.Bank->Link;
        VarStore = VarInfo.Bank->VarStore;

    } else {

        // 
        // Set to first entry
        //

        VarStore = VariableStore;
        if (EfiAtRuntime) {
            while (VarStore && VarStore->MemoryType != EfiRuntimeServicesData) {
                VarStore = VarStore->Next;
            }
        }
        Link = NULL;
    }

    //
    // Advance to next position
    //

    Status = EFI_NOT_FOUND;
    while (VarStore) {

        //
        // If we don't have a bank position, set to head of current store
        //

        if (!Link) {
            Link = VarStore->Active.Flink;
            VarInfo.NextVarOffset = FIRST_VARIABLE_OFFSET;
        }

        //
        // If we're off the end of this var store, adcance to the next one
        //

        if (Link == &VarStore->Active) {
            VarStore = VarStore->Next;
            if (EfiAtRuntime) {
                while (VarStore && VarStore->MemoryType != EfiRuntimeServicesData) {
                    VarStore = VarStore->Next;
                }
            }
            Link = NULL;
            continue;
        }

        //
        // Check the entry at the current location
        //

        VarInfo.Bank = CR(Link, STORAGE_BANK, Link, STORAGE_BANK_SIGNATURE);
        if (!RtVarParseStore (&VarInfo)) {
            //
            // End of bank hit, try the next one
            //

            Link = Link->Flink;
            VarInfo.NextVarOffset = FIRST_VARIABLE_OFFSET;
            continue;
        }

        //
        // If this is a valid entry, return it
        //
        if (VarInfo.Valid) {

            if (!EfiAtRuntime || (EfiAtRuntime && (VarInfo.Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) {

                Status = EFI_BUFFER_TOO_SMALL;
                if (*VariableNameSize >= VarInfo.NameSize) {
                    CopyMem (VariableName, VarInfo.Name, VarInfo.NameSize);
                    CopyMem (VendorGuid, VarInfo.VendorGuid, sizeof(EFI_GUID));
                    Status = EFI_SUCCESS;        
                }

                *VariableNameSize = VarInfo.NameSize;
                break;
            }
        }
    }

Done:    
    RtReleaseStoreLock ();
    return Status;
}

#pragma RUNTIME_CODE(RtSetVariable)
EFI_STATUS
RUNTIMESERVICE
RtSetVariable (
    IN CHAR16                       *VariableName,
    IN EFI_GUID                     *VendorGuid,
    IN UINT32                       Attributes,
    IN UINTN                        DataSize,
    IN VOID                         *Data
    )
{
    VARIABLE_STORE                  *VarStore;
    VARIABLE_INFO                   OldVar, NewVar;
    UINTN                           NameSize,VarSize, PadSize;
    BOOLEAN                         Failed, Junk;
    VARIABLE                        *Var;
    EFI_STATUS                      Status;
    CHAR8                           *Buffer;

    Failed = FALSE;
    Status = EFI_SUCCESS;

    //
    // Make sure VariableName is valid
    //

    if (VariableName == NULL) {
      return EFI_INVALID_PARAMETER;
    }

    if (VariableName[0] == 0x0000) {
      return EFI_INVALID_PARAMETER;
    }

    //
    // Make sure that the input variable does not exceed the maximum size
    //

    if (DataSize > EFI_MAXIMUM_VARIABLE_SIZE) {
        return EFI_INVALID_PARAMETER;
    }

    //
    // Make sure reserved bits aren't set
    //

    if (Attributes & ~EFI_VARIABLE_VALID_ATTRIBUTES) {
        return EFI_INVALID_PARAMETER;
    }
    
    //
    // Make sure if runtime bit is set, boot service bit is set also
    //
    if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS ) {
        return EFI_INVALID_PARAMETER;
    }

    //
    // Determine which store to save the variable in
    //

    VarStore = VariableStoreType[Attributes & VAR_ATTRIBUTE_TYPE];
    if (VarStore) {
        if (IsListEmpty(&VarStore->Active) && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
            VarStore = VariableStoreType[(Attributes | EFI_VARIABLE_RUNTIME_ACCESS) & VAR_ATTRIBUTE_TYPE];
        }
    }
    if (!DataSize) {
        VarStore = NULL;
    }

    //
    // If this is runtime, make sure variable store is accessible
    //

    if (EfiAtRuntime && VarStore && !VarStore->RuntimeUpdate) {
        return EFI_UNSUPPORTED;
    }
    
    //
    // Lock the variable store and make the update
    //

    RtAcquireStoreLock ();

    //
    // If we're going to save an update, compute the amount of space 
    // and locate the bank to write it too
    //

    if (VarStore) {
        NameSize = StrSize(VariableName);
        VarSize = sizeof(VARIABLE) + sizeof(UINT8) + NameSize + DataSize;
        PadSize = (sizeof(UINT32) - VarSize % sizeof(UINT32)) & (sizeof(UINT32)-1);

        NewVar.Bank = RtVarFindFreeSpace (VarStore, VarSize + PadSize, &Junk);
        if (!NewVar.Bank) {
            Status = EFI_OUT_OF_RESOURCES;
            goto Done;
        }
    }

    //
    // Lookup the existing value
    //

    RtVarFind (VariableName, VendorGuid, &OldVar);

    //
    // If not saving a new value, then we can skip the
    // transistion and just mark the old value as obsolete
    //
    
    if (VarStore) {

        //
        // Mark the old variable as in transistion
        //
    
        if (OldVar.Valid) {

            //
            // If this is a set for the same value as the current
            // value, then we don't need to update the store
            //

            if (OldVar.Bank->VarStore == VarStore &&
                CompareGuid (OldVar.VendorGuid, VendorGuid) == 0 &&
                OldVar.DataSize == DataSize &&
                CompareMem (OldVar.Data, Data, DataSize) == 0) {

                goto Done2;
            }

            //
            // Mark the old entry as obsolete transition
            //

            Failed = RtVarUpdateState (&OldVar, VAR_OBSOLETE_TRANSITION);
            if (Failed) {
                goto Done;
            }
        }
    
        //
        //  Write the updated record
        //

        NewVar.NextVarOffset = NewVar.Bank->Tail;
        Buffer = NewVar.Bank->u.Data + NewVar.NextVarOffset;
        Var = (VARIABLE *) Buffer;

        // Fill in the header
        Var->Size = (UINT16) VarSize;
        Var->Attributes = (UINT16) Attributes;
        CopyMem (&Var->VendorGuid, VendorGuid, sizeof(EFI_GUID));
        Buffer += sizeof (VARIABLE);

        // append the variable name
        CopyMem (Buffer, VariableName, NameSize);
        Buffer += NameSize;

        // append the variable data
        CopyMem (Buffer, Data, DataSize);
        Buffer += DataSize;

        // append the variable state
        Buffer[0] = 0xFF ^ VAR_ADDED;

        // write it, and calculate the new bank tail
        VarSize = VarSize + PadSize;
        RtVarUpdateStore (NewVar.Bank, NewVar.NextVarOffset, VarSize);
        NewVar.Bank->Tail  += VarSize;
        NewVar.Bank->InUse += VarSize;

#if EFI_DEBUG
        RtVarParseStore (&NewVar);
        ASSERT (NewVar.Valid);
        ASSERT (VarSize == NewVar.VarSize);
        ASSERT (NewVar.Bank->Tail == NewVar.NextVarOffset);
#endif
        //
        // If there was an update error, abort
        //

        Failed = NewVar.Bank->DeviceError;
        if (Failed) {
            goto Done;
        }

    } else {
        if (!OldVar.Valid) {
            Status = EFI_NOT_FOUND;
            goto Done2;
        }
    }

    //
    // Mark the old variable entry as obsolete
    //

    if (OldVar.Valid) {
        Failed = RtVarUpdateState (&OldVar, VAR_OBSOLETE_TRANSITION | VAR_OBSOLETE);
        OldVar.Bank->InUse -= OldVar.VarSize;
    }

    //
    // Done
    //  

Done:    
    DEBUG((D_VAR, "SetVariable: %s variable '%hg:%hs' %a %es\n", 
            VarStore ? L"setting" : L"removing",
            VendorGuid, 
            VariableName,
            VarStore ? VarStore->Type : "",
            Failed ? L"failed" : L""
            ));

Done2:
    RtReleaseStoreLock ();

    if (Failed) {
        Status = EFI_DEVICE_ERROR;
    }

    return Status;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -