varinit.c

来自「Next BIOS Source code : Extensible Firmw」· C语言 代码 · 共 768 行 · 第 1/2 页

C
768
字号
        // 2. The operation stopped before the transaction bank was committed.
        //    To correct, restart the garbage collection operation on the 
        //    obsolete transition bank
        //
        // 3. The operation stopped during the switch over after the new bank
        //    was written, but before the obsolete bank was cleared.  To correct
        //    complete / redo the change over sequence for the bank.
        //
        // 4. The operation stopped during the switch over but after the obsolete
        //    bank was cleared.  To correct mark the new bank as now inuse
        //

        // Is this case #2?
        if (ObsoleteTransition && !InUseTransition) {
            ASSERT(FALSE);     // need to test
            DEBUG((D_VAR|D_WARN, "InitVarStore: restarting collection on bank %x:%d (%a)\n",
                                        ObsoleteTransition,
                                        ObsoleteTransition->BankNo,
                                        ObsoleteTransition->VarStore->Type
                                        ));
            RtVarGarbageCollectBank (ObsoleteTransition);
        }
        
        // Is this case #3?
        if (ObsoleteTransition && InUseTransition) {
            RtVarClearStore (ObsoleteTransition);
            ObsoleteTransition = NULL;          // now case 4
        }

        // Is this case #4?
        if (!ObsoleteTransition && InUseTransition) {
            DEBUG((D_VAR|D_WARN, "InitVarStore: committing transition bank %x:%d (%a)\n",
                            InUseTransition,
                            InUseTransition->BankNo,
                            InUseTransition->VarStore->Type
                            ));
            RtVarUpdateBankState (InUseTransition, VARH_INUSE);
        }

        // check next var store
    }

    //
    // Now that all the variable stores are recovered, check for
    // any partial variable updates that need to be completed
    //

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

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

            //
            // Check entries in this bank
            // 

            Restart = VarCheckBank (Bank);
            if (Restart) {
                Link = VarStore->Active.Flink;
            }
        }
    }

}


STATIC
BOOLEAN
VarCheckBank (
    IN STORAGE_BANK         *Bank
    )
{
    VARIABLE_INFO           VarInfo, NewVar;
    STORAGE_BANK            *NewBank;
    BOOLEAN                 GarbageCollected, RemoveVar;

    ASSERT_LOCKED (&VariableStoreLock);

    //
    // Check each variable in the bank
    //

    VarInfo.Bank = Bank;
    VarInfo.NextVarOffset = FIRST_VARIABLE_OFFSET;
    while (RtVarParseStore (&VarInfo)) {

        // If it's not a valid entry skip it
        if (!VarInfo.Valid) {
            continue;
        }

        //
        // Lookup this var.  In the case of obsolete transition, see if 
        // we find a new (valid) copy.  In the case of a normal variable,
        // see if we find some duplicate copy
        //
        
        RtVarFind (VarInfo.Name, VarInfo.VendorGuid, &NewVar);
        RemoveVar = FALSE;

        //
        // If this variable isn't in the obsolete transition state, skip it
        //

        if ((VarInfo.State & VAR_OBSOLETE_TRANSITION) && 
            !(VarInfo.State & VAR_OBSOLETE))  {

            //
            // We have a variable that's in the middle of being updated, we need to
            // recover it.  In any case, the current in transition var needs removed.
            //
            
            RemoveVar = TRUE;
            if (NewVar.Valid) {

                //
                // We have the old copy (which is being obsoleted) and the new
                // copy.  Just obsolete the old copy and leave the new one.
                //

                DEBUG((D_VAR|D_WARN, "VarCheckBank: Variable '%s' recovered to new copy\n", VarInfo.Name));

            } else {

                //
                // There is no new copy, restore the current copy.
                // To do this we need to re-add the value and then 
                // delete the entry that is in transition.
                //

                NewBank = RtVarFindFreeSpace (Bank->VarStore, VarInfo.VarSize, &GarbageCollected);

                //
                // If there was a garbage collection in response to the 
                // free space request, the bank data may have been mvoed.
                // Restart the search in the var store.
                //

                if (GarbageCollected) {
                    return TRUE;
                }

                //
                // Make a new copy of the variable in the free space
                //

                if (NewBank) {

                    RtVarMove (FALSE, &VarInfo, NewBank);
                    DEBUG((D_VAR|D_WARN, "VarCheckBank: Variable '%s' recovered to old copy\n", VarInfo.Name));

                } else {

                    DEBUG((D_VAR|D_ERROR, "VarCheckBank: Could not recover variable '%s'\n", VarInfo.Name));
                }
            }
        } else {
            //
            // Variable is not in transition; however, if we found a different
            // copy then remove the current one.
            //

            if (NewVar.Valid && 
                (NewVar.Bank  != VarInfo.Bank || NewVar.VarOffset != VarInfo.VarOffset)) {

                DEBUG((D_VAR|D_WARN, "VarCheckBank: Removed duplicate variable '%s'\n", VarInfo.Name));
                RemoveVar = TRUE;
            }
        }

        //
        // If we need to obsolete the transition copy, do so 
        //

        if (RemoveVar) {
            Bank->InUse -= VarInfo.VarSize;
            RtVarUpdateState (&VarInfo, VAR_OBSOLETE);
        }
    }

    return FALSE;
}



INTERNAL
EFI_STATUS
VarStoreAddBank (
    IN VARIABLE_STORE       *VarStore,
    IN EFI_VARIABLE_STORE   *Device,
    IN UINTN                BankNo
    )
{
    EFI_STATUS              Status;
    STORAGE_BANK            *Bank;
    VOID                    *Buffer;
    UINTN                   VarSize;
    VARIABLE                *Var;
    VARIABLE_INFO           VarInfo;


    Status = EFI_SUCCESS;

    ASSERT_LOCKED (&VariableStoreLock);

    Bank = NULL;

    //
    // Allocate memory to track this bank of storage
    // 

    Status = BS->AllocatePool (
                VarStore->MemoryType, 
                sizeof(STORAGE_BANK) + Device->BankSize,
                &Bank
                );

    if (EFI_ERROR(Status)) {
        DEBUG ((D_VAR, "VarStoreAddBank: allocate pool failed\n"));
        return Status;
    }

    //
    // Initialize the bank structure
    //

    ZeroMem (Bank, sizeof(STORAGE_BANK));
    Bank->Signature = STORAGE_BANK_SIGNATURE;
    Bank->Device = Device;
    Bank->BankNo = BankNo;
    Bank->BankSize = Device->BankSize;
    Bank->VarStore = VarStore;
    Bank->u.Data = (CHAR8 *) Bank + sizeof(STORAGE_BANK);
    Bank->TSize = &Bank->BankSize;

    //
    // Read the bank's header and get the banks' disposition
    //

    Buffer = RtVarReadStore (Bank, 0, sizeof(BANK_HEADER));
    Bank->State = Bank->u.Header->State ^ 0xFF;

    //
    // If there's not valid signature, or if the bank is in add transition
    // but hasn't made it to inuse transition, then there is nothing interesting
    // in the bank - clear it.
    //
    // The current store format is type 0.  Since this is the first type, there
    // is no code to migrate to a new type.  Just reset the store if it's a different
    // type.
    //


    if (Bank->u.Header->Signature != BANK_HEADER_SIGNATURE || Bank->u.Header->Format != VARH_FORMAT ||
        (Bank->State & VARH_ADD_TRANSITION) && !(Bank->State & VARH_INUSE_TRANSITION)) {

        RtVarClearStore(Bank);

    } else {

        //
        // Add the bank to the active list. Attempt to keep them
        // in oldest to youngest order such that we more or less
        // use them in order
        //

        if (Bank->u.Header->Sequence >= VarStore->Sequence) {

            InsertTailList (&VarStore->Active, &Bank->Link);
            VarStore->Sequence = Bank->u.Header->Sequence;

        } else {

            InsertHeadList (&VarStore->Active, &Bank->Link);
        }

    }

    //
    // Now we need to make a pass over the data in the bank 
    // and compute the dynamic values for the bank structure
    //

    VarInfo.Bank = Bank;
    VarInfo.NextVarOffset = FIRST_VARIABLE_OFFSET;
    VarInfo.Bank->InUse = FIRST_VARIABLE_OFFSET;
    VarInfo.Bank->Tail = VarInfo.Bank->BankSize;
    while (VarInfo.NextVarOffset < Bank->BankSize) {

        //
        // If we don't have enough space for an entry, don't read anymore
        //

        if (VarInfo.NextVarOffset + sizeof(VARIABLE) + sizeof(UINT8) + 2 + 1 > VarInfo.Bank->BankSize) {
            VarInfo.NextVarOffset = VarInfo.Bank->BankSize;
            break;
        }

        //
        // Read the header of the variable
        //
        
        Var = RtVarReadStore(VarInfo.Bank, VarInfo.NextVarOffset, sizeof(VARIABLE));
        if (Bank->DeviceError) {
            break;
        }

        //
        // If the first bytes of Variable header haven't been initialized,
        // then we've found the tail in the bank
        //

        if (Var->Size == 0xFFFF || Var->Size == 0x0000) {
            break;
        }

        //
        // Read the remaining bytes of this variable
        //

        VarSize = (Var->Size & VAR_SIZE_MASK) - sizeof(VARIABLE);
        if (VarSize + VarInfo.NextVarOffset > VarInfo.Bank->BankSize ||
            VarSize < sizeof(UINT8) + 2 + 1) {

            //
            // Due to the way data is written to the banks, a bank should never
            // become corrupt; however, if it is corrupt recover the variables 
            // up to the point of corruption in the bank.  Since this is 
            // not a designed recovery path the update is just done in place
            // 

            DEBUG ((D_VAR|D_ERROR, "InitVarStore: bank was corrupt. truncating it.\n"));
            RtVarClearStore (VarInfo.Bank);
            RtVarUpdateStore (VarInfo.Bank, 0, VarInfo.Bank->Tail);
            break;
        }

        RtVarReadStore (VarInfo.Bank, VarInfo.NextVarOffset + sizeof(VARIABLE), VarSize);

        //
        // Crack the variable entry
        //

        RtVarParseStore (&VarInfo);

        //
        // If it's a valid value that is not completely obsolete,
        // count it in InUse
        //

        if (VarInfo.Valid) {
            VarInfo.Bank->InUse += VarInfo.VarSize;
        }
    }

    VarInfo.Bank->Tail = VarInfo.NextVarOffset;

    //
    // If there's been an error, remove the bank
    //

    if (VarInfo.Bank->DeviceError) {

        RtVarBankError (VarInfo.Bank);

    } else {

        DEBUG ((D_VAR, "VarStoreAddBank: Added bank %X:%d (type %a)\n", Device, BankNo, VarStore->Type));

        //
        // If any bank on the store doesn't support transaction update,
        // then we need to allocate one of the bank to do our own
        // bank transactioning
        //

        if (!Bank->Device->TransactionUpdate) {
            VarStore->TBankRequired = TRUE;
        }
    }
    return Status;
}

⌨️ 快捷键说明

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