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); } }
VOID EfiReleaseLock ( IN EFI_LOCK *Lock ) /*++ Routine Description: Releases ownership of the mutual exclusion lock. Arguments: Lock - The lock to release Returns: Lock unowned --*/ { EFI_TPL Tpl; Tpl = Lock->OwnerTpl; ASSERT (Lock->Lock == 1); Lock->Lock -= 1; if (!EfiAtRuntime ()) { // // The check is just debug code for core inplementation. It must // always be true in a driver // gBS->RestoreTPL (Tpl); } }
/** Return TRUE if ExitBootServices () has been called. @retval TRUE If ExitBootServices () has been called. **/ BOOLEAN AtRuntime ( VOID ) { return EfiAtRuntime (); }
VOID EFIAPI RuntimeDriverExitBootServices ( IN EFI_EVENT Event, IN VOID *Context ) /*++ Routine Description: Set AtRuntime flag as TRUE after ExitBootServices Arguments: Event - The Event that is being processed Context - Event Context Returns: None --*/ { if (EfiAtRuntime()) { return; } }
/** Acquires lock only at boot time. Simply returns at runtime. This is a temperary function that will be removed when EfiAcquireLock() in UefiLib can handle the call in UEFI Runtimer driver in RT phase. It calls EfiAcquireLock() at boot time, and simply returns at runtime. @param Lock A pointer to the lock to acquire. **/ VOID AcquireLockOnlyAtBootTime ( IN EFI_LOCK *Lock ) { if (!EfiAtRuntime ()) { EfiAcquireLock (Lock); } }
/** Releases lock only at boot time. Simply returns at runtime. This is a temperary function which will be removed when EfiReleaseLock() in UefiLib can handle the call in UEFI Runtimer driver in RT phase. It calls EfiReleaseLock() at boot time and simply returns at runtime. @param Lock A pointer to the lock to release. **/ VOID ReleaseLockOnlyAtBootTime ( IN EFI_LOCK *Lock ) { if (!EfiAtRuntime ()) { EfiReleaseLock (Lock); } }
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; }
/** * This function unlock and erase an entire NOR Flash block. **/ EFI_STATUS NorFlashUnlockAndEraseSingleBlock ( IN NOR_FLASH_INSTANCE *Instance, IN UINTN BlockAddress ) { EFI_STATUS Status; UINTN Index; EFI_TPL OriginalTPL; if (!EfiAtRuntime ()) { // Raise TPL to TPL_HIGH to stop anyone from interrupting us. OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL); } else { // This initialization is only to prevent the compiler to complain about the // use of uninitialized variables OriginalTPL = TPL_HIGH_LEVEL; } Index = 0; // The block erase might fail a first time (SW bug ?). Retry it ... do { // Unlock the block if we have to Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress); if (EFI_ERROR (Status)) { break; } Status = NorFlashEraseSingleBlock (Instance, BlockAddress); Index++; } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED)); if (Index == NOR_FLASH_ERASE_RETRY) { DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", BlockAddress,Index)); } if (!EfiAtRuntime ()) { // Interruptions can resume. gBS->RestoreTPL (OriginalTPL); } return Status; }
EFI_STATUS EFIAPI LibMtcGetNextHighMonotonicCount ( OUT UINT32 *HighCount ) { EFI_STATUS Status; EFI_TPL OldTpl; // // Check input parameters // if (HighCount == NULL) { return EFI_INVALID_PARAMETER; } if (!EfiAtRuntime ()) { // Use a lock if called before ExitBootServices() OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); } *HighCount = (UINT32) RShiftU64 (mEfiMtc, 32) + 1; mEfiMtc = LShiftU64 (*HighCount, 32); if (!EfiAtRuntime ()) { gBS->RestoreTPL (OldTpl); } // // Update the NvRam store to match the new high part // Status = EfiSetVariable ( mEfiMtcName, &mEfiMtcGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, sizeof (UINT32), HighCount ); return Status; }
RETURN_STATUS AccessSysCfgRegister ( IN UINT32 ReadWrite, IN UINT32 Function, IN UINT32 Site, IN UINT32 Position, IN UINT32 Device, IN OUT UINT32* Data ) { UINT32 SysCfgCtrl; if (EfiAtRuntime ()) { return RETURN_UNSUPPORTED; } // Clear the COMPLETE bit MmioAnd32(ARM_VE_SYS_CFGSTAT_REG, ~SYS_CFGSTAT_COMPLETE); // If writing, then set the data value if(ReadWrite == SYS_CFGCTRL_WRITE) { MmioWrite32(ARM_VE_SYS_CFGDATA_REG, *Data); } // Set the control value SysCfgCtrl = SYS_CFGCTRL_START | ReadWrite | SYS_CFGCTRL_FUNCTION(Function) | SYS_CFGCTRL_SITE(Site) | SYS_CFGCTRL_POSITION(Position) | SYS_CFGCTRL_DEVICE(Device); MmioWrite32(ARM_VE_SYS_CFGCTRL_REG, SysCfgCtrl); // Wait until the COMPLETE bit is set while ((MmioRead32(ARM_VE_SYS_CFGSTAT_REG) & SYS_CFGSTAT_COMPLETE) == 0); // Check for errors if(MmioRead32(ARM_VE_SYS_CFGSTAT_REG) & SYS_CFGSTAT_ERROR) { return RETURN_DEVICE_ERROR; } // If reading then get the data value if(ReadWrite == SYS_CFGCTRL_READ) { *Data = MmioRead32(ARM_VE_SYS_CFGDATA_REG); } return RETURN_SUCCESS; }
EFI_STATUS EfiAcquireLockOrFail ( IN EFI_LOCK *Lock ) /*++ Routine Description: Initialize a basic mutual exclusion lock. Each lock provides mutual exclusion access at it's task priority level. Since there is no-premption (at any TPL) or multiprocessor support, acquiring the lock only consists of raising to the locks TPL. Arguments: Lock - The EFI_LOCK structure to initialize Returns: EFI_SUCCESS - Lock Owned. EFI_ACCESS_DENIED - Reentrant Lock Acquisition, Lock not Owned. --*/ { if (Lock->Lock != 0) { // // Lock is already owned, so bail out // return EFI_ACCESS_DENIED; } if (!EfiAtRuntime ()) { // // The check is just debug code for core inplementation. It must // always be true in a driver // Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl); } Lock->Lock += 1; return EFI_SUCCESS; }
/** This function will be called following a call to the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL Write function. @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. @param[in] Lba The starting logical block index to written to. @param[in] Offset Offset into the block at which to begin writing. @param[in] NumBytes The number of bytes written. @param[in] Buffer Pointer to the buffer that was written. **/ VOID EFIAPI PlatformFvbDataWritten ( IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, IN EFI_LBA Lba, IN UINTN Offset, IN UINTN NumBytes, IN UINT8 *Buffer ) { STATIC EFI_EVENT EventToSignal = NULL; if (!EfiAtRuntime ()) { if (EventToSignal == NULL) { EventToSignal = (EFI_EVENT)(UINTN) PcdGet64 (PcdEmuVariableEvent); } if (EventToSignal != NULL) { gBS->SignalEvent (EventToSignal); } } }
EFI_STATUS EfiAcquireLockOrFail ( IN EFI_LOCK *Lock ) /*++ Routine Description: Initialize a basic mutual exclusion lock. For now, only allow one level of nesting. Arguments: Lock - The EFI_LOCK structure to initialize Returns: EFI_SUCCESS - Lock Owned. EFI_ACCESS_DENIED - Reentrant Lock Acquisition, Lock not Owned. --*/ { if (Lock->Lock != 0) { // // Lock is already owned, so bail out // return EFI_ACCESS_DENIED; } if (!EfiAtRuntime ()) { // // The check is just debug code for core inplementation. It must // always be true in a driver // Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl); } Lock->Lock += 1; return EFI_SUCCESS; }
EFI_STATUS LibMtcGetNextMonotonicCount ( OUT UINT64 *Count ) { EFI_STATUS Status; EFI_TPL OldTpl; UINT32 HighCount; UINTN BufferSize; // // Can not be called after ExitBootServices() // if (EfiAtRuntime ()) { return EFI_UNSUPPORTED; } // // Check input parameters // if (Count == NULL) { return EFI_INVALID_PARAMETER; } if (mEfiMtc == 0) { // // If the MTC has not been initialized read the variable // // // Read the last high part // BufferSize = sizeof (UINT32); Status = EfiGetVariable ( mEfiMtcName, &mEfiMtcGuid, NULL, &BufferSize, &HighCount ); if (EFI_ERROR (Status)) { HighCount = 0; } // // Set the current value // mEfiMtc = LShiftU64 (HighCount, 32); // // Increment the upper 32 bits for this boot // Continue even if it fails. It will only fail if the variable services are // not functional. // Status = EfiGetNextHighMonotonicCount (&HighCount); } // // Update the monotonic counter with a lock // OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); *Count = mEfiMtc; mEfiMtc++; gBS->RestoreTPL (OldTpl); // // If the MSB bit of the low part toggled, then signal that the high // part needs updated now // if ((((UINT32) mEfiMtc) ^ ((UINT32) *Count)) & 0x80000000) { gBS->SignalEvent (mEfiMtcEvent); } return EFI_SUCCESS; }
EFI_RUNTIMESERVICE EFI_STATUS EFIAPI MonotonicCounterDriverGetNextHighMonotonicCount ( OUT UINT32 *HighCount ) /*++ Routine Description: Increase high 32bits and clear low 32bits. Arguments: HighCount - return the increased high 32bits Returns: --*/ { EFI_STATUS Status; EFI_TPL OldTpl; UINTN BufferSize; // // Check input parameters // if (HighCount == NULL) { return EFI_INVALID_PARAMETER; } // // Read the last high part // BufferSize = sizeof (UINT32); Status = EfiGetVariable ( mEfiMtcName, &mEfiMtcGuid, NULL, &BufferSize, HighCount ); if (EFI_ERROR (Status)) { *HighCount = 0; } if (!EfiAtRuntime ()) { OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); *HighCount += 1; mEfiMtc = LShiftU64 (*HighCount, 32); gBS->RestoreTPL (OldTpl); } else { *HighCount += 1; mEfiMtc = LShiftU64 (*HighCount, 32); } // // Update the NvRam store to match the new high part // Status = EfiSetVariable ( mEfiMtcName, &mEfiMtcGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, sizeof (UINT32), HighCount ); return Status; }
// // Worker functions // EFI_BOOTSERVICE EFI_STATUS EFIAPI MonotonicCounterDriverGetNextMonotonicCount ( OUT UINT64 *Count ) /*++ Routine Description: Increase low 32bits. Increase high 32bits and clear low 32bits if overflow. Arguments: Count - return the increased total 64 bits Returns: --*/ { EFI_TPL OldTpl; UINT32 HighCount; UINTN BufferSize; EFI_STATUS Status; // // Can not be called after ExitBootServices() // if (EfiAtRuntime ()) { return EFI_UNSUPPORTED; } // // Check input parameters // if (Count == NULL) { return EFI_INVALID_PARAMETER; } // // Read the last high part // BufferSize = sizeof (UINT32); Status = EfiGetVariable ( mEfiMtcName, &mEfiMtcGuid, NULL, &BufferSize, &HighCount ); if (EFI_ERROR (Status)) { HighCount = 0; } // // There is four reasons cause change of high 32bits of MTC // 1. It's first call to GetNextMTC // 2. Real NV is started, and MTC is patched // 3. GetNextHighMTC is called by user // 4. low 32bits overflow // of these, only the reason 1&2 can cause the difference between high 32bits of mEfiMtc and HighCount // if ((UINT32) RShiftU64 (mEfiMtc, 32) != HighCount) { mEfiMtc = LShiftU64 (HighCount, 32); } // // Update the monotonic counter with a lock // OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); *Count = mEfiMtc; mEfiMtc++; gBS->RestoreTPL (OldTpl); // // If the MSB bit of the low part toggled, then signal that the high // part needs updated now // if ((((UINT32) mEfiMtc) ^ ((UINT32) *Count)) & 0x80000000) { gBS->SignalEvent (mEfiMtcEvent); } return EFI_SUCCESS; }
STATIC EFI_STATUS NorFlashWriteFullBlock ( IN NOR_FLASH_INSTANCE *Instance, IN EFI_LBA Lba, IN UINT32 *DataBuffer, IN UINT32 BlockSizeInWords ) { EFI_STATUS Status; UINTN WordAddress; UINT32 WordIndex; UINTN BufferIndex; UINTN BlockAddress; UINTN BuffersInBlock; UINTN RemainingWords; EFI_TPL OriginalTPL; UINTN Cnt; Status = EFI_SUCCESS; // Get the physical address of the block BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSizeInWords * 4); // Start writing from the first address at the start of the block WordAddress = BlockAddress; if (!EfiAtRuntime ()) { // Raise TPL to TPL_HIGH to stop anyone from interrupting us. OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL); } else { // This initialization is only to prevent the compiler to complain about the // use of uninitialized variables OriginalTPL = TPL_HIGH_LEVEL; } Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress); if (EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR, "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", BlockAddress)); goto EXIT; } // To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method. // Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero if ((WordAddress & BOUNDARY_OF_32_WORDS) == 0x00) { // First, break the entire block into buffer-sized chunks. BuffersInBlock = (UINTN)(BlockSizeInWords * 4) / P30_MAX_BUFFER_SIZE_IN_BYTES; // Then feed each buffer chunk to the NOR Flash // If a buffer does not contain any data, don't write it. for(BufferIndex=0; BufferIndex < BuffersInBlock; BufferIndex++, WordAddress += P30_MAX_BUFFER_SIZE_IN_BYTES, DataBuffer += P30_MAX_BUFFER_SIZE_IN_WORDS ) { // Check the buffer to see if it contains any data (not set all 1s). for (Cnt = 0; Cnt < P30_MAX_BUFFER_SIZE_IN_WORDS; Cnt++) { if (~DataBuffer[Cnt] != 0 ) { // Some data found, write the buffer. Status = NorFlashWriteBuffer (Instance, WordAddress, P30_MAX_BUFFER_SIZE_IN_BYTES, DataBuffer); if (EFI_ERROR(Status)) { goto EXIT; } break; } } } // Finally, finish off any remaining words that are less than the maximum size of the buffer RemainingWords = BlockSizeInWords % P30_MAX_BUFFER_SIZE_IN_WORDS; if(RemainingWords != 0) { Status = NorFlashWriteBuffer (Instance, WordAddress, (RemainingWords * 4), DataBuffer); if (EFI_ERROR(Status)) { goto EXIT; } } } else { // For now, use the single word programming algorithm // It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range, // i.e. which ends in the range 0x......01 - 0x......7F. for(WordIndex=0; WordIndex<BlockSizeInWords; WordIndex++, DataBuffer++, WordAddress = WordAddress + 4) { Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer); if (EFI_ERROR(Status)) { goto EXIT; } } } EXIT: if (!EfiAtRuntime ()) { // Interruptions can resume. gBS->RestoreTPL (OriginalTPL); } if (EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR, "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", WordAddress, Status)); } return Status; }
EFI_STATUS LibUpdateCapsule ( IN UEFI_CAPSULE_HEADER **CapsuleHeaderArray, IN UINTN CapsuleCount, IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL ) /*++ Routine Description: This code finds if the capsule needs reset to update, if no, update immediately. Arguments: CapsuleHeaderArray A array of pointers to capsule headers passed in CapsuleCount The number of capsule ScatterGatherList Physical address of datablock list points to capsule Returns: EFI STATUS EFI_SUCCESS Valid capsule was passed.If CAPSULE_FLAG_PERSIT_ACROSS_RESET is not set, the capsule has been successfully processed by the firmware. If it set, the ScattlerGatherList is successfully to be set. EFI_INVALID_PARAMETER CapsuleCount is less than 1,CapsuleGuid is not supported. EFI_DEVICE_ERROR Failed to SetVariable or AllocatePool or ProcessFirmwareVolume. --*/ { UINTN CapsuleSize; UINTN ArrayNumber; VOID *BufferPtr; EFI_STATUS Status; EFI_HANDLE FvHandle; UEFI_CAPSULE_HEADER *CapsuleHeader; if ((CapsuleCount < 1) || (CapsuleCount > MAX_SUPPORT_CAPSULE_NUM)){ return EFI_INVALID_PARAMETER; } BufferPtr = NULL; CapsuleHeader = NULL; // //Compare GUIDs with EFI_CAPSULE_GUID, if capsule header contains CAPSULE_FLAGS_PERSIST_ACROSS_RESET //and CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flags,whatever the GUID is ,the service supports. // for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) { CapsuleHeader = CapsuleHeaderArray[ArrayNumber]; if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) { return EFI_INVALID_PARAMETER; } if (!CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiCapsuleGuid)) { if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) { return EFI_UNSUPPORTED; } } } // //Assume that capsules have the same flags on reseting or not. // CapsuleHeader = CapsuleHeaderArray[0]; if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) { // //Check if the platform supports update capsule across a system reset // if (!SupportUpdateCapsuleRest()) { return EFI_UNSUPPORTED; } if (ScatterGatherList == 0) { return EFI_INVALID_PARAMETER; } else { Status = EfiSetVariable ( EFI_CAPSULE_VARIABLE_NAME, &gEfiCapsuleVendorGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, sizeof (UINTN), (VOID *) &ScatterGatherList ); if (Status != EFI_SUCCESS) { return EFI_DEVICE_ERROR; } } return EFI_SUCCESS; } // //The rest occurs in the condition of non-reset mode // if (EfiAtRuntime ()) { return EFI_INVALID_PARAMETER; } // //Here should be in the boot-time // for (ArrayNumber = 0; ArrayNumber < CapsuleCount ; ArrayNumber++) { CapsuleHeader = CapsuleHeaderArray[ArrayNumber]; CapsuleSize = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize; Status = gBS->AllocatePool (EfiBootServicesData, CapsuleSize, &BufferPtr); if (Status != EFI_SUCCESS) { goto Done; } gBS->CopyMem (BufferPtr, (UINT8*)CapsuleHeader+ CapsuleHeader->HeaderSize, CapsuleSize); // //Call DXE service ProcessFirmwareVolume to process immediatelly // Status = gDS->ProcessFirmwareVolume (BufferPtr, CapsuleSize, &FvHandle); if (Status != EFI_SUCCESS) { gBS->FreePool (BufferPtr); return EFI_DEVICE_ERROR; } gDS->Dispatch (); gBS->FreePool (BufferPtr); } return EFI_SUCCESS; Done: if (BufferPtr != NULL) { gBS->FreePool (BufferPtr); } return EFI_DEVICE_ERROR; }
// // Delay Primative // VOID EfiStall ( IN UINTN Microseconds ) /*++ Routine Description: Delay for at least the request number of microseconds Arguments: Microseconds - Number of microseconds to delay. Returns: NONE --*/ { UINT8 Data; UINT8 InitialState; UINTN CycleIterations; CycleIterations = 0; Data = 0; InitialState = 0; if (EfiAtRuntime ()) { // // The time-source is 30 us granular, so calibrate the timing loop // based on this baseline // Error is possible 30us. // CycleIterations = (Microseconds - 1) / 30 + 1; // // Use the DMA Refresh timer in port 0x61. Cheap but effective. // The only issue is that the granularity is 30us, and we want to // guarantee "at least" one full transition to avoid races. // // // _____________/----------\__________/-------- // // |<--15us-->|<--15us-->| // // --------------------------------------------------> Time (us) // while (CycleIterations--) { EfiIoRead (EfiCpuIoWidthUint8, 0x61, 1, &Data); Data &= REFRESH_CYCLE_TOGGLE_BIT; InitialState = Data; // // Capture first transition (strictly less than one period) // while (InitialState == Data) { EfiIoRead (EfiCpuIoWidthUint8, 0x61, 1, &Data); Data &= REFRESH_CYCLE_TOGGLE_BIT; } InitialState = Data; // // Capture next transition (guarantee at least one full pulse) // while (InitialState == Data) { EfiIoRead (EfiCpuIoWidthUint8, 0x61, 1, &Data); Data &= REFRESH_CYCLE_TOGGLE_BIT; } } } else { gBS->Stall (Microseconds); } }
/** Passes capsules to the firmware with both virtual and physical mapping. Depending on the intended consumption, the firmware may process the capsule immediately. If the payload should persist across a system reset, the reset value returned from EFI_QueryCapsuleCapabilities must be passed into ResetSystem() and will cause the capsule to be processed by the firmware as part of the reset process. @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules being passed into update capsule. @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in CaspuleHeaderArray. @param ScatterGatherList Physical pointer to a set of EFI_CAPSULE_BLOCK_DESCRIPTOR that describes the location in physical memory of a set of capsules. @retval EFI_SUCCESS Valid capsule was passed. If CAPSULE_FLAGS_PERSIT_ACROSS_RESET is not set, the capsule has been successfully processed by the firmware. @retval EFI_DEVICE_ERROR The capsule update was started, but failed due to a device error. @retval EFI_INVALID_PARAMETER CapsuleSize is NULL, or an incompatible set of flags were set in the capsule header. @retval EFI_INVALID_PARAMETER CapsuleCount is Zero. @retval EFI_INVALID_PARAMETER For across reset capsule image, ScatterGatherList is NULL. @retval EFI_UNSUPPORTED CapsuleImage is not recognized by the firmware. @retval EFI_OUT_OF_RESOURCES When ExitBootServices() has been previously called this error indicates the capsule is compatible with this platform but is not capable of being submitted or processed in runtime. The caller may resubmit the capsule prior to ExitBootServices(). @retval EFI_OUT_OF_RESOURCES When ExitBootServices() has not been previously called then this error indicates the capsule is compatible with this platform but there are insufficient resources to process. **/ EFI_STATUS EFIAPI UpdateCapsule ( IN EFI_CAPSULE_HEADER **CapsuleHeaderArray, IN UINTN CapsuleCount, IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL ) { UINTN ArrayNumber; EFI_STATUS Status; EFI_CAPSULE_HEADER *CapsuleHeader; BOOLEAN NeedReset; BOOLEAN InitiateReset; CHAR16 CapsuleVarName[30]; CHAR16 *TempVarName; // // Capsule Count can't be less than one. // if (CapsuleCount < 1) { return EFI_INVALID_PARAMETER; } NeedReset = FALSE; InitiateReset = FALSE; CapsuleHeader = NULL; CapsuleVarName[0] = 0; for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) { // // A capsule which has the CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag must have // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well. // CapsuleHeader = CapsuleHeaderArray[ArrayNumber]; if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) { return EFI_INVALID_PARAMETER; } // // A capsule which has the CAPSULE_FLAGS_INITIATE_RESET flag must have // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well. // if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) { return EFI_INVALID_PARAMETER; } // // Check FMP capsule flag // if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid) && (CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0 ) { return EFI_INVALID_PARAMETER; } // // Check Capsule image without populate flag by firmware support capsule function // if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) { Status = SupportCapsuleImage (CapsuleHeader); if (EFI_ERROR(Status)) { return Status; } } } // // Walk through all capsules, record whether there is a capsule needs reset // or initiate reset. And then process capsules which has no reset flag directly. // for (ArrayNumber = 0; ArrayNumber < CapsuleCount ; ArrayNumber++) { CapsuleHeader = CapsuleHeaderArray[ArrayNumber]; // // Here should be in the boot-time for non-reset capsule image // Platform specific update for the non-reset capsule image. // if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) { if (EfiAtRuntime ()) { Status = EFI_OUT_OF_RESOURCES; } else { Status = ProcessCapsuleImage(CapsuleHeader); } if (EFI_ERROR(Status)) { return Status; } } else { NeedReset = TRUE; if ((CapsuleHeader->Flags & CAPSULE_FLAGS_INITIATE_RESET) != 0) { InitiateReset = TRUE; } } } // // After launching all capsules who has no reset flag, if no more capsules claims // for a system reset just return. // if (!NeedReset) { return EFI_SUCCESS; } // // ScatterGatherList is only referenced if the capsules are defined to persist across // system reset. // if (ScatterGatherList == (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) { return EFI_INVALID_PARAMETER; } // // Check if the platform supports update capsule across a system reset // if (!FeaturePcdGet(PcdSupportUpdateCapsuleReset)) { return EFI_UNSUPPORTED; } // // Construct variable name CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2... // if user calls UpdateCapsule multiple times. // StrCpy (CapsuleVarName, EFI_CAPSULE_VARIABLE_NAME); TempVarName = CapsuleVarName + StrLen (CapsuleVarName); if (mTimes > 0) { UnicodeValueToString (TempVarName, 0, mTimes, 0); } // // ScatterGatherList is only referenced if the capsules are defined to persist across // system reset. Set its value into NV storage to let pre-boot driver to pick it up // after coming through a system reset. // Status = EfiSetVariable ( CapsuleVarName, &gEfiCapsuleVendorGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, sizeof (UINTN), (VOID *) &ScatterGatherList ); if (!EFI_ERROR (Status)) { // // Variable has been set successfully, increase variable index. // mTimes++; if(InitiateReset) { // // Firmware that encounters a capsule which has the CAPSULE_FLAGS_INITIATE_RESET Flag set in its header // will initiate a reset of the platform which is compatible with the passed-in capsule request and will // not return back to the caller. // EfiResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL); } } return Status; }
BOOLEAN ReadUsingMmio ( IN UINTN SpiOffset ) { return (BOOLEAN) ((SpiOffset >= BIOS_REGION_FLASH_OFFSET) && (SpiOffset < (BIOS_REGION_FLASH_OFFSET + PcdGet32 (PcdBiosImageSize))) && (!EfiAtRuntime ())); }
RETURN_STATUS ArmPlatformSysConfigSetDevice ( IN SYS_CONFIG_FUNCTION Function, IN UINT32 Device, IN UINT32 Value ) { UINT32 Site; UINT32 Position; Position = 0; // Intercept some functions switch(Function) { case SYS_CFG_SCC: #ifdef ARM_VE_SCC_BASE if (EfiAtRuntime ()) { return RETURN_UNSUPPORTED; } MmioWrite32 ((ARM_VE_SCC_BASE + (Device * 4)),Value); return RETURN_SUCCESS; #else // There is no System Configuration Controller on the Model return RETURN_UNSUPPORTED; #endif case SYS_CFG_OSC_SITE1: Function = SYS_CFG_OSC; Site = ARM_VE_DAUGHTERBOARD_1_SITE; break; case SYS_CFG_OSC_SITE2: Function = SYS_CFG_OSC; Site = ARM_VE_DAUGHTERBOARD_2_SITE; break; case SYS_CFG_MUXFPGA: Site = Value; break; case SYS_CFG_RTC: return RETURN_UNSUPPORTED; //break; case SYS_CFG_OSC: case SYS_CFG_VOLT: case SYS_CFG_AMP: case SYS_CFG_TEMP: case SYS_CFG_RESET: case SYS_CFG_SHUTDOWN: case SYS_CFG_REBOOT: case SYS_CFG_DVIMODE: case SYS_CFG_POWER: Site = ARM_VE_MOTHERBOARD_SITE; break; default: return RETURN_UNSUPPORTED; } return AccessSysCfgRegister (SYS_CFGCTRL_WRITE, Function, Site, Position, Device, &Value); }