Beispiel #1
0
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);
  }
}
Beispiel #2
0
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);
  }
}
Beispiel #3
0
/**
  Return TRUE if ExitBootServices () has been called.

  @retval TRUE If ExitBootServices () has been called.
**/
BOOLEAN
AtRuntime (
  VOID
  )
{
  return EfiAtRuntime ();
}
Beispiel #4
0
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);
  }
}
Beispiel #7
0
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;
}
Beispiel #8
0
/**
 * 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;
}
Beispiel #9
0
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;
}
Beispiel #11
0
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;
}
Beispiel #12
0
/**
  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);
    }
  }
}
Beispiel #13
0
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;
}
Beispiel #14
0
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;
}
Beispiel #15
0
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;
}
Beispiel #16
0
//
// 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;
}
Beispiel #17
0
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;
}
Beispiel #18
0
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;
}
Beispiel #19
0
//
// 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);
  }
}
Beispiel #20
0
/**
  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;
}
Beispiel #21
0
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);
}