Example #1
0
/**
  Read BufferSize bytes from Offset into Buffer.

  @param  This                  Protocol instance pointer.
  @param  MediaId               Id of the media, changes every time the media is replaced.
  @param  Offset                The starting byte offset to read from
  @param  BufferSize            Size of Buffer
  @param  Buffer                Buffer containing read data

  @retval EFI_SUCCESS           The data was read correctly from the device.
  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
  @retval EFI_NO_MEDIA          There is no media in the device.
  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
  @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
                                valid for the device.

**/
EFI_STATUS
EFIAPI
NorFlashDiskIoReadDisk (
  IN EFI_DISK_IO_PROTOCOL         *This,
  IN UINT32                       MediaId,
  IN UINT64                       DiskOffset,
  IN UINTN                        BufferSize,
  OUT VOID                        *Buffer
  )
{
  NOR_FLASH_INSTANCE *Instance;
  UINT32              BlockSize;
  UINT32              BlockOffset;
  EFI_LBA             Lba;

  Instance = INSTANCE_FROM_DISKIO_THIS(This);

  if (MediaId != Instance->Media.MediaId) {
    return EFI_MEDIA_CHANGED;
  }

  BlockSize = Instance->Media.BlockSize;
  Lba = (EFI_LBA) DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset);

  return NorFlashRead (Instance, Lba, BlockOffset, BufferSize, Buffer);
}
Example #2
0
/**
  Writes a specified number of bytes to a device.

  @param  This       Indicates a pointer to the calling context.
  @param  MediaId    ID of the medium to be written.
  @param  Offset     The starting byte offset on the logical block I/O device to write.
  @param  BufferSize The size in bytes of Buffer. The number of bytes to write to the device.
  @param  Buffer     A pointer to the buffer containing the data to be written.

  @retval EFI_SUCCESS           The data was written correctly to the device.
  @retval EFI_WRITE_PROTECTED   The device can not be written to.
  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
  @retval EFI_NO_MEDIA          There is no media in the device.
  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
  @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
                                 valid for the device.

**/
EFI_STATUS
EFIAPI
NorFlashDiskIoWriteDisk (
  IN EFI_DISK_IO_PROTOCOL         *This,
  IN UINT32                       MediaId,
  IN UINT64                       DiskOffset,
  IN UINTN                        BufferSize,
  IN VOID                         *Buffer
  )
{
  NOR_FLASH_INSTANCE *Instance;
  UINT32              BlockSize;
  UINT32              BlockOffset;
  EFI_LBA             Lba;
  UINTN               RemainingBytes;
  UINTN               WriteSize;
  EFI_STATUS          Status;

  Instance = INSTANCE_FROM_DISKIO_THIS(This);

  if (MediaId != Instance->Media.MediaId) {
    return EFI_MEDIA_CHANGED;
  }

  BlockSize = Instance->Media.BlockSize;
  Lba = (EFI_LBA) DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset);

  RemainingBytes = BufferSize;

  // Write either all the remaining bytes, or the number of bytes that bring
  // us up to a block boundary, whichever is less.
  // (DiskOffset | (BlockSize - 1)) + 1) rounds DiskOffset up to the next
  // block boundary (even if it is already on one).
  WriteSize = MIN (RemainingBytes, ((DiskOffset | (BlockSize - 1)) + 1) - DiskOffset);

  do {
    if (WriteSize == BlockSize) {
      // Write a full block
      Status = NorFlashWriteFullBlock (Instance, Lba, Buffer, BlockSize / sizeof (UINT32));
    } else {
      // Write a partial block
      Status = NorFlashWriteSingleBlock (Instance, Lba, BlockOffset, &WriteSize, Buffer);
    }
    if (EFI_ERROR (Status)) {
      return Status;
    }
    // Now continue writing either all the remaining bytes or single blocks.
    RemainingBytes -= WriteSize;
    Buffer = (UINT8 *) Buffer + WriteSize;
    Lba++;
    BlockOffset = 0;
    WriteSize = MIN (RemainingBytes, BlockSize);
  } while (RemainingBytes);

  return Status;
}
Example #3
0
/**
  Write BufferSize bytes from Lba into Buffer.

  This function writes the requested number of blocks to the device. All blocks
  are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
  EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
  being used, the Event associated with this request will not be signaled.

  @param[in]       This       Indicates a pointer to the calling context.
  @param[in]       MediaId    The media ID that the write request is for.
  @param[in]       Lba        The starting logical block address to be written. The
                              caller is responsible for writing to only legitimate
                              locations.
  @param[in, out]  Token      A pointer to the token associated with the transaction.
  @param[in]       BufferSize Size of Buffer, must be a multiple of device block size.
  @param[in]       Buffer     A pointer to the source buffer for the data.

  @retval EFI_SUCCESS           The write request was queued if Event is not NULL.
                                The data was written correctly to the device if
                                the Event is NULL.
  @retval EFI_WRITE_PROTECTED   The device can not be written to.
  @retval EFI_NO_MEDIA          There is no media in the device.
  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
                                or the buffer is not on proper alignment.
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack
                                of resources.

**/
EFI_STATUS
EFIAPI
PartitionWriteBlocksEx (
  IN     EFI_BLOCK_IO2_PROTOCOL *This,
  IN     UINT32                 MediaId,
  IN     EFI_LBA                Lba,
  IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
  IN     UINTN                  BufferSize,
  IN     VOID                   *Buffer
  )
{
  PARTITION_PRIVATE_DATA  *Private;
  UINT64                  Offset;
  UINT32                  UnderRun;

  Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);

  if (Token == NULL) {
    return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
  }

  if (BufferSize % Private->BlockSize != 0) {
    return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_BAD_BUFFER_SIZE);
  }

  Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
  if (Offset + BufferSize > Private->End) {
    return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_INVALID_PARAMETER);
  }

  //
  // Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must
  // be multiple of BlockSize. If the Spec will be updated the DiskIO to support
  // BlockIO2, this limitation will be removed and call DiskIO here.
  //
  Lba = DivU64x32Remainder (Offset, Private->BlockSize, &UnderRun);
  if (UnderRun != 0) {
    return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
  }

  //
  // Because some kinds of partition have different block size from their parent,
  // in that case it couldn't call parent Block I/O2.
  //
  if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
    return ProbeMediaStatusEx (Private->ParentBlockIo2, MediaId, EFI_UNSUPPORTED);
  }

  return Private->ParentBlockIo2->WriteBlocksEx (Private->ParentBlockIo2, MediaId, Lba, Token, BufferSize, Buffer);
}
/**
  Gets the next cluster in the cluster chain

  @param  PrivateData            Global memory map for accessing global variables
  @param  Volume                 The volume
  @param  Cluster                The cluster
  @param  NextCluster            The cluster number of the next cluster

  @retval EFI_SUCCESS            The address is got
  @retval EFI_INVALID_PARAMETER  ClusterNo exceeds the MaxCluster of the volume.
  @retval EFI_DEVICE_ERROR       Read disk error

**/
EFI_STATUS
FatGetNextCluster (
  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
  IN  PEI_FAT_VOLUME        *Volume,
  IN  UINT32                Cluster,
  OUT UINT32                *NextCluster
  )
{
  EFI_STATUS  Status;
  UINT64      FatEntryPos;
  UINT32      Dummy;

  *NextCluster = 0;

  if (Volume->FatType == Fat32) {
    FatEntryPos = Volume->FatPos + MultU64x32 (4, Cluster);

    Status      = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 4, NextCluster);
    *NextCluster &= 0x0fffffff;

    //
    // Pad high bits for our FAT_CLUSTER_... macro definitions to work
    //
    if ((*NextCluster) >= 0x0ffffff7) {
      *NextCluster |= (-1 &~0xf);
    }

  } else if (Volume->FatType == Fat16) {
    FatEntryPos = Volume->FatPos + MultU64x32 (2, Cluster);

    Status      = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);

    //
    // Pad high bits for our FAT_CLUSTER_... macro definitions to work
    //
    if ((*NextCluster) >= 0xfff7) {
      *NextCluster |= (-1 &~0xf);
    }

  } else {
    FatEntryPos = Volume->FatPos + DivU64x32Remainder (MultU64x32 (3, Cluster), 2, &Dummy);

    Status      = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);

    if ((Cluster & 0x01) != 0) {
      *NextCluster = (*NextCluster) >> 4;
    } else {
/**
  Converts a decimal value to a Null-terminated ascii string.

  @param  Buffer  Pointer to the output buffer for the produced Null-terminated
                  ASCII string.
  @param  Value   The 64-bit sgned value to convert to a string.

  @return The number of ASCII characters in Buffer not including the Null-terminator.

**/
UINTN
UpdateValueToString (
  IN  OUT UINT8                         *Buffer,
  IN      INT64                         Value
  )
{
  UINT8                                 TempBuffer[30];
  UINT8                                 *TempStr;
  UINT8                                 *BufferPtr;
  UINTN                                 Count;
  UINT32                                Remainder;

  TempStr           = TempBuffer;
  BufferPtr         = Buffer;
  Count             = 0;

  if (Value < 0) {
    *BufferPtr      = '-';
    BufferPtr++;
    Value           = -Value;
    Count++;
  }

  do {
    Value = (INT64) DivU64x32Remainder  ((UINT64)Value, 10, &Remainder);
    //
    // The first item of TempStr is not occupied. It's kind of flag
    //
    TempStr++;
    Count++;
    *TempStr        = (UINT8) ((UINT8)Remainder + '0');
  } while (Value != 0);

  //
  // Reverse temp string into Buffer.
  //
  while (TempStr != TempBuffer) {
    *BufferPtr      = *TempStr;
    BufferPtr++;
    TempStr --;
  }

  *BufferPtr = 0;

  return Count;
}
Example #6
0
/**
  Function to append a 64 bit number / 25 onto the string.

  @param[in, out] Str          The string so append onto.
  @param[in]      Num          The number to divide and append.

  @retval EFI_INVALID_PARAMETER   A parameter was NULL.
  @retval EFI_SUCCESS             The appending was successful.
**/
EFI_STATUS
EFIAPI
AppendCSDNum2 (
  IN OUT POOL_PRINT       *Str,
  IN UINT64               Num
  )
{
  UINT64  Result;
  UINT32   Rem;

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

  Result = DivU64x32Remainder (Num, 25, &Rem);
  if (Result > 0) {
    AppendCSDNum2 (Str, Result);
  }

  CatPrint (Str, L"%c", Rem + 'a');
  return (EFI_SUCCESS);
}
/**
  Internal function to add memory pool operation to the table.

  @param  Marker                The variable argument list to get the opcode
                                and associated attributes.

  @retval EFI_OUT_OF_RESOURCES  Not enough resource to do operation.
  @retval EFI_SUCCESS           Opcode is added.

**/
EFI_STATUS
BootScriptWriteMemPoll (
  IN VA_LIST                       Marker
  )
{
  S3_BOOT_SCRIPT_LIB_WIDTH   Width;
  UINT64                     Address;
  VOID                      *Data;
  VOID                      *DataMask;
  UINT64                    Delay;
  UINT64                    LoopTimes;
  UINT32                    Remainder;

  Width    = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
  Address  = VA_ARG (Marker, UINT64);
  Data     = VA_ARG (Marker, VOID *);
  DataMask = VA_ARG (Marker, VOID *);
  Delay    = VA_ARG (Marker, UINT64);
  //
  // According to the spec, the interval between 2 polls is 100ns,
  // but the unit of Duration for S3BootScriptSaveMemPoll() is microsecond(1000ns).
  // Duration * 1000ns * LoopTimes = Delay * 100ns
  // Duration will be minimum 1(microsecond) to be minimum deviation,
  // so LoopTimes = Delay / 10.
  //
  LoopTimes = DivU64x32Remainder (
                Delay,
                10,
                &Remainder
                );
  if (Remainder != 0) {
    //
    // If Remainder is not zero, LoopTimes will be rounded up by 1.
    //
    LoopTimes +=1;
  }
  return S3BootScriptSaveMemPoll (Width, Address, DataMask, Data, 1, LoopTimes);

}
Example #8
0
/**
  Introduces a fine-grained stall.

  @param  Microseconds           The number of microseconds to stall execution.

  @retval EFI_SUCCESS            Execution was stalled for at least the requested
                                 amount of microseconds.
  @retval EFI_NOT_AVAILABLE_YET  gMetronome is not available yet

**/
EFI_STATUS
EFIAPI
CoreStall (
  IN UINTN            Microseconds
  )
{
  UINT32  Counter;
  UINT32  Remainder;

  if (gMetronome == NULL) {
    return EFI_NOT_AVAILABLE_YET;
  }

  //
  // Calculate the number of ticks by dividing the number of microseconds by
  // the TickPeriod.
  // Calculation is based on 100ns unit.
  //
  Counter = (UINT32) DivU64x32Remainder (
                       Microseconds * 10,
                       gMetronome->TickPeriod,
                       &Remainder
                       );

  //
  // Call WaitForTick for Counter + 1 ticks to try to guarantee Counter tick
  // periods, thus attempting to ensure Microseconds of stall time.
  //
  if (Remainder != 0) {
    Counter++;
  }

  gMetronome->WaitForTick (gMetronome, Counter);

  return EFI_SUCCESS;
}
Example #9
0
EFI_STATUS
EFIAPI
RootBridgeIoPollIo (
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
  IN  UINT64                                 Address,
  IN  UINT64                                 Mask,
  IN  UINT64                                 Value,
  IN  UINT64                                 Delay,
  OUT UINT64                                 *Result
  )
/*++

Routine Description:

  Poll an address in I/O space until an exit condition is met
  or a timeout occurs.
  
Arguments:

  This     -  Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
  Width    -  Width of I/O operation.
  Address  -  The base address of the I/O operation.
  Mask     -  Mask used for polling criteria.
  Value    -  Comparison value used for polling exit criteria.
  Delay    -  Number of 100ns units to poll.
  Result   -  Pointer to the last value read from memory location.
  
Returns:

  EFI_SUCCESS            -  Success.
  EFI_INVALID_PARAMETER  -  Invalid parameter found.
  EFI_TIMEOUT            -  Delay expired before a match occurred.
  EFI_OUT_OF_RESOURCES   -  Fail due to lack of resources.
  
--*/
{
  EFI_STATUS  Status;
  UINT64      NumberOfTicks;
  UINT32       Remainder;

  //
  // No matter what, always do a single poll.
  //
  if (Result == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (Width < 0 || Width > EfiPciWidthUint64) {
    return EFI_INVALID_PARAMETER;
  }

  Status = This->Io.Read (
                      This,
                      Width,
                      Address,
                      1,
                      Result
                      );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  if ((*Result & Mask) == Value) {
    return EFI_SUCCESS;
  }

  if (Delay != 0) {
    //
    // Determine the proper # of metronome ticks to wait for polling the
    // location.  The number of ticks is Roundup (Delay / mMetronome->TickPeriod)+1
    // The "+1" to account for the possibility of the first tick being short
    // because we started in the middle of a tick.
    //
    NumberOfTicks = DivU64x32Remainder (
                      Delay,
                      (UINT32) mMetronome->TickPeriod,
                      &Remainder
                      );
    if (Remainder != 0) {
      NumberOfTicks += 1;
    }

    NumberOfTicks += 1;

    while (NumberOfTicks) {

      mMetronome->WaitForTick (mMetronome, 1);

      Status = This->Io.Read (
                          This,
                          Width,
                          Address,
                          1,
                          Result
                          );
      if (EFI_ERROR (Status)) {
        return Status;
      }

      if ((*Result & Mask) == Value) {
        return EFI_SUCCESS;
      }

      NumberOfTicks -= 1;
    }
  }

  return EFI_TIMEOUT;
}
Example #10
0
/**
  Introduces a fine-grained stall.

  @param  Microseconds           The number of microseconds to stall execution.

  @retval EFI_SUCCESS            Execution was stalled for at least the requested
                                 amount of microseconds.
  @retval EFI_NOT_AVAILABLE_YET  gMetronome is not available yet

**/
EFI_STATUS
EFIAPI
CoreStall (
  IN UINTN            Microseconds
  )
{
  UINT64  Counter;
  UINT32  Remainder;
  UINTN   Index;

  if (gMetronome == NULL) {
    return EFI_NOT_AVAILABLE_YET;
  }

  //
  // Counter = Microseconds * 10 / gMetronome->TickPeriod
  // 0x1999999999999999 = (2^64 - 1) / 10
  //
  if (Microseconds > 0x1999999999999999ULL) {
    //
    // Microseconds is too large to multiple by 10 first.  Perform the divide 
    // operation first and loop 10 times to avoid 64-bit math overflow.
    //
    Counter = DivU64x32Remainder (
                Microseconds,
                gMetronome->TickPeriod,
                &Remainder
                );
    for (Index = 0; Index < 10; Index++) {
      CoreInternalWaitForTick (Counter);
    }      

    if (Remainder != 0) {
      //
      // If Remainder was not zero, then normally, Counter would be rounded 
      // up by 1 tick.  In this case, since a loop for 10 counts was used
      // to emulate the multiply by 10 operation, Counter needs to be rounded
      // up by 10 counts.
      //
      CoreInternalWaitForTick (10);
    }
  } else {
    //
    // Calculate the number of ticks by dividing the number of microseconds by
    // the TickPeriod.  Calculation is based on 100ns unit.
    //
    Counter = DivU64x32Remainder (
                MultU64x32 (Microseconds, 10),
                gMetronome->TickPeriod,
                &Remainder
                );
    if (Remainder != 0) {
      //
      // If Remainder is not zero, then round Counter up by one tick.
      //
      Counter++;
    }
    CoreInternalWaitForTick (Counter);
  }

  return EFI_SUCCESS;
}
Example #11
0
/**
  Read data as fast as possible from a block I/O device

  The ShellCEntryLib library instance wrappers the actual UEFI application
  entry point and calls this ShellAppMain function.

  @param  ImageHandle  The image handle of the UEFI Application.
  @param  SystemTable  A pointer to the EFI System Table.

  @retval  0               The application exited normally.
  @retval  Other           An error occurred.

**/
INTN
EFIAPI 
ShellAppMain (
  IN UINTN Argc, 
  IN CHAR16 **Argv
  )
{
  BOOLEAN bBlockIo2;
  UINT32 BlockIoCount;
  UINT32 BlockIo2Count;
  UINT32 BlocksPerRead;
  UINT32 BlockSize;
  BOOLEAN bReadComplete;
  UINT32 BytesPerSecond;
  UINT32 BytesToRead;
  UINT64 DataRead;
  EFI_LBA Lba;
  EFI_LBA LbaMax;
  EFI_HANDLE Handle;
  UINTN HandleCount;
  UINTN Index;
  UINT64 MaxMBytes;
  UINT64 MaxReads;
  UINT64 MediaBytes;
  UINT32 MediaId;
  EFI_BLOCK_IO_PROTOCOL * pBlockIo;
  EFI_BLOCK_IO2_PROTOCOL * pBlockIo2;
  EFI_HANDLE * pBlockIoArray;
  EFI_HANDLE * pBlockIo2Array;
  EFI_HANDLE * pHandle;
  EFI_HANDLE * pHandleEnd;
  EFI_BLOCK_IO_MEDIA * pMedia;
  EFI_BLOCK_IO2_TOKEN * pToken;
  EFI_BLOCK_IO2_TOKEN * pTokenEnd;
  CHAR8 * pUnits;
  UINT32 Seconds;
  EFI_STATUS Status;
  UINT64 Timeout;
  EFI_EVENT TimeoutEvent;
  UINT32 TestCount;
  UINT32 WarmUpBlocks;

  //
  //  Display the help text
  //
  if ( 1 == Argc ) {
    Print ( L"%s   [/2]   <handle>\r\n", Argv[ 0 ]);
    Print ( L"\r\n" );
    Print ( L"/2 - Use Block I/O 2 protocol\r\n" );

    //
    //  Determine which handles have the block I/O protocol on them
    //
    Print ( L"Block I/O Handles\r\n" );
    Status = gBS->LocateHandleBuffer ( ByProtocol,
                                       &gEfiBlockIoProtocolGuid,
                                       NULL,
                                       &HandleCount,
                                       &pBlockIoArray );
    if ( !EFI_ERROR ( Status )) {
      pHandle = pBlockIoArray;
      BlockIoCount = (UINT32)HandleCount;
      pHandleEnd = &pHandle[ BlockIoCount ];
      while ( pHandleEnd > pHandle ) {
        Handle = *pHandle++;
        Status = gBS->OpenProtocol ( Handle,
                                     &gEfiBlockIoProtocolGuid,
                                     (VOID **)&pBlockIo,
                                     NULL,
                                     NULL,
                                     EFI_OPEN_PROTOCOL_GET_PROTOCOL );
        if ( !EFI_ERROR ( Status )) {
          if (( NULL != pBlockIo )
            && ( NULL != pBlockIo->Media )
            && ( pBlockIo->Media->MediaPresent )) {
            //
            //  Display the handle and device size
            //
            pUnits = "Bytes";
            MediaBytes = MultU64x32 ( pBlockIo->Media->LastBlock + 1,
                                      pBlockIo->Media->BlockSize );
            if ( KIBYTE <= MediaBytes ) {
              pUnits = "KiBytes";
              if ( MIBYTE <= MediaBytes ) {
                pUnits = "MiBytes";
                MediaBytes = DivU64x32 ( MediaBytes, 1024 );
                if ( MIBYTE <= MediaBytes ) {
                  pUnits = "GiBytes";
                  MediaBytes = DivU64x32 ( MediaBytes, 1024 );
                  if ( MIBYTE <= MediaBytes ) {
                    pUnits = "TiBytes";
                    MediaBytes = DivU64x32 ( MediaBytes, 1024 );
                    if ( MIBYTE <= MediaBytes ) {
                      pUnits = "PiBytes";
                      MediaBytes = DivU64x32 ( MediaBytes, 1024 );
                    }
                  }
                }
              }
              BytesToRead = (UINT32)MediaBytes;
              Print ( L"    0x%016Lx: %d.%03d %a\r\n",
                      (UINT64)(UINTN)Handle,
                      BytesToRead / 1024,
                      ( BytesToRead % 1024 ) * 1000 / 1024,
                      pUnits );
            }
            else {
              BytesToRead = (UINT32)MediaBytes;
              Print ( L"    0x%016Lx: %d %a\r\n",
                      (UINT64)(UINTN)Handle,
                      BytesToRead,
                      pUnits );
            }
          }
        }
      }

      //
      //  Free the handle buffer
      //
      gBS->FreePool ( pBlockIoArray );
    }
    else {
      Print ( L"    No block I/O handles found!\r\n" );
    }

    //
    //  Determine which handles have the block I/O 2 protocol on them
    //
    Print ( L"Block I/O 2 Handles\r\n" );
    Status = gBS->LocateHandleBuffer ( ByProtocol,
                                       &gEfiBlockIo2ProtocolGuid,
                                       NULL,
                                       &HandleCount,
                                       &pBlockIo2Array );
    if ( !EFI_ERROR ( Status )) {
      pHandle = pBlockIo2Array;
      BlockIo2Count = (UINT32)HandleCount;
      pHandleEnd = &pHandle[ BlockIo2Count ];
      while ( pHandleEnd > pHandle ) {
        Handle = *pHandle++;
        Status = gBS->OpenProtocol ( Handle,
                                     &gEfiBlockIoProtocolGuid,
                                     (VOID **)&pBlockIo,
                                     NULL,
                                     NULL,
                                     EFI_OPEN_PROTOCOL_GET_PROTOCOL );
        if ( !EFI_ERROR ( Status )) {
          if (( NULL != pBlockIo )
            && ( NULL != pBlockIo->Media )
            && ( pBlockIo->Media->MediaPresent )) {
            //
            //  Display the handle and device size
            //
            pUnits = "Bytes";
            MediaBytes = MultU64x32 ( pBlockIo->Media->LastBlock + 1,
                                      pBlockIo->Media->BlockSize );
            if ( KIBYTE <= MediaBytes ) {
              pUnits = "KiBytes";
              if ( MIBYTE <= MediaBytes ) {
                pUnits = "MiBytes";
                MediaBytes = DivU64x32 ( MediaBytes, 1024 );
                if ( MIBYTE <= MediaBytes ) {
                  pUnits = "GiBytes";
                  MediaBytes = DivU64x32 ( MediaBytes, 1024 );
                  if ( MIBYTE <= MediaBytes ) {
                    pUnits = "TiBytes";
                    MediaBytes = DivU64x32 ( MediaBytes, 1024 );
                    if ( MIBYTE <= MediaBytes ) {
                      pUnits = "PiBytes";
                      MediaBytes = DivU64x32 ( MediaBytes, 1024 );
                    }
                  }
                }
              }
              BytesToRead = (UINT32)MediaBytes;
              Print ( L"    0x%016Lx: %d.%03d %a\r\n",
                      (UINT64)(UINTN)Handle,
                      BytesToRead / 1024,
                      ( BytesToRead % 1024 ) * 1000 / 1024,
                      pUnits );
            }
            else {
              BytesToRead = (UINT32)MediaBytes;
              Print ( L"    0x%016Lx: %d %a\r\n",
                      (UINT64)(UINTN)Handle,
                      BytesToRead,
                      pUnits );
            }
          }
        }
      }

      //
      //  Free the handle buffer
      //
      gBS->FreePool ( pBlockIo2Array );
    }
    else {
      Print ( L"    No block I/O 2 handles found!\r\n" );
    }

    Print ( L"The test reads %d KiByte buffers as fast as it can for a total\r\n",
            BUFFER_LENGTH_IN_BYTES / 1024 );
    Print ( L"of %d seconds.  At the end of the time, the performance is computed\r\n",
            TEST_TIME_IN_SECONDS );
    Print ( L"by dividing the number of bytes received prior to the timer expiring\r\n" );
    Print ( L"by the test duration.  The test reads at most %d MiBytes from the\r\n",
            MAX_MBYTES );
    Print ( L"beginning of the media before wrapping around to the beginning again.\r\n" );
    Print ( L"As a warm-up, two buffers worth of data are read from the end of the\r\n" );
    Print ( L"%d MiByte region.\r\n",
            MAX_MBYTES );
    return EFI_NOT_STARTED;
  }

  //
  //  Determine if the block I/O 2 protocol should be used
  //
  bBlockIo2 = FALSE;
  pToken = &mTokens[ 0 ];
  pTokenEnd = &pToken[ DIM ( mTokens )];
  if ( 0 == StrCmp ( L"/2", Argv[ 1 ])) {
    bBlockIo2 = TRUE;
  }

  //
  //  Get the handle address
  //
  HandleCount = bBlockIo2 ? 2 : 1;
  Handle = (EFI_HANDLE)StrHexToUintn ( Argv[ HandleCount ]);
  if ( NULL == Handle ) {
    Print ( L"ERROR - Invalid handle value\r\n" );
    return EFI_INVALID_PARAMETER;
  }

  //
  //  Validate the handle
  //
  pBlockIo = NULL;
  pBlockIo2 = NULL;
  Status = gBS->OpenProtocol ( Handle,
                               bBlockIo2
                               ? &gEfiBlockIo2ProtocolGuid
                               : &gEfiBlockIoProtocolGuid,
                               bBlockIo2
                               ? (VOID *)&pBlockIo2
                               : (VOID *)&pBlockIo,
                               NULL,
                               NULL,
                               EFI_OPEN_PROTOCOL_GET_PROTOCOL );
  if ( EFI_ERROR ( Status )) {
    Print ( L"ERROR - %r\r\n", Status );
    return (( Status & MAX_BIT ) ? 0x80000000 : 0 )
            | ( Status & 0x7fffffff );
  }

  //
  //  Create the necessary events
  //
  Status = gBS->CreateEvent ( EVT_TIMER | EVT_NOTIFY_SIGNAL,
                              TPL_NOTIFY,
                              TestComplete,
                              NULL,
                              &TimeoutEvent );
  if ( EFI_ERROR ( Status )) {
    Print ( L"ERROR - Failed to create event, Status: %r\r\n",
             Status );
    return (( Status & MAX_BIT ) ? 0x80000000 : 0 )
            | ( Status & 0x7fffffff );
  }

  while ( pTokenEnd > pToken ) {
    Status = gBS->CreateEvent ( 0,
                                TPL_NOTIFY,
                                NULL,
                                NULL,
                                &pToken->Event );
    if ( EFI_ERROR ( Status )) {
      Print ( L"ERROR - Failed to create token event, Status: %r\r\n",
               Status );
      break;
    }
    pToken += 1;
  }
  if ( !EFI_ERROR ( Status )) {
    //
    //  Display the media parameters
    //
    pMedia = bBlockIo2 ? pBlockIo2->Media : pBlockIo->Media;
    Print ( L"\r\nMedia Parameters:\r\n" );
    Print ( L"  BlockSize: %d bytes\r\n", pMedia->BlockSize );
    Print ( L"  IoAlign: %d bytes\r\n", pMedia->IoAlign );
    Print ( L"  LastBlock: 0x%Lx\r\n", pMedia->LastBlock );
    Print ( L"  LogicalBlocksPerPhysicalBlock: %d\r\n", pMedia->LogicalBlocksPerPhysicalBlock );
    Print ( L"  LogicalPartition: %a\r\n", pMedia->LogicalPartition ? "TRUE" : "FALSE" );
    Print ( L"  LowestAlignedLba: 0x%Lx\r\n", pMedia->LowestAlignedLba );
    Print ( L"  MediaId: 0x%08x\r\n", pMedia->MediaId );
    Print ( L"  MediaPresent: %a\r\n", pMedia->MediaPresent ? "TRUE" : "FALSE" );
#ifdef  EFI_BLOCK_IO_PROTOCOL_REVISION3
    Print ( L"  OptimalTransferLengthGranularity: %d blocks\r\n", pMedia->OptimalTransferLengthGranularity );
#endif  //  EFI_BLOCK_IO_PROTOCOL_REVISION3
    Print ( L"  ReadOnly: %a\r\n", pMedia->ReadOnly ? "TRUE" : "FALSE" );
    Print ( L"  RemovableMedia: %a\r\n", pMedia->RemovableMedia ? "TRUE" : "FALSE" );
    Print ( L"  WriteCaching: %a\r\n", pMedia->WriteCaching ? "TRUE" : "FALSE" );
    Print ( L"\r\n" );

    //
    //  Locate the end of the media
    //
    BlockSize = pMedia->BlockSize;
    MediaBytes = pMedia->LastBlock + 1;
    MediaBytes = MultU64x32 ( MediaBytes, BlockSize );
    BlocksPerRead = sizeof ( mBuffer ) / BlockSize;
    BytesToRead = BlocksPerRead * BlockSize;
    ASSERT ( 0 < BlocksPerRead );
    LbaMax = MAX_MBYTES * 1024L * 1024L;
    LbaMax = DivU64x32 ( LbaMax, BlocksPerRead );
    LbaMax = MultU64x32 ( LbaMax, BlocksPerRead );
    LbaMax = DivU64x32 ( LbaMax, BlockSize );
    if ( LbaMax > pMedia->LastBlock ) {
      LbaMax = MultU64x32 ( DivU64x32 ( pMedia->LastBlock + 1,
                                        BlocksPerRead ),
                            BlocksPerRead );
    }
    MaxReads = DivU64x32 ( LbaMax, BlocksPerRead );
    MaxMBytes = DivU64x32 ( MultU64x32 ( MaxReads,
                                         BlocksPerRead * BlockSize ),
                            1024 * 1024 );
    WarmUpBlocks = WARM_UP_READS * BlocksPerRead;
    if ( LbaMax < WarmUpBlocks ) {
      WarmUpBlocks = ((UINT32)DivU64x32 ( LbaMax, BlocksPerRead )) * BlocksPerRead;
    }

    //
    //  Get the test duration
    //
    Seconds = TEST_TIME_IN_SECONDS;

    //
    //  Display the test parameters
    //
    Print ( L"Test Parameters:\r\n" );
    Print ( L"  Using: BlockIo%sProtocol\r\n", bBlockIo2 ? "2" : "" );
    Print ( L"  BlockSize: %d bytes\r\n", BlockSize );
    Print ( L"  Blocks/Read: %d\r\n", BlocksPerRead );
    Print ( L"  Duration: %d seconds\r\n", Seconds );
    Print ( L"  LBA max: %Ld\r\n", LbaMax );
    Print ( L"  Max data: %Ld MiBytes\r\n", MaxMBytes );
    Print ( L"  Max reads: %Ld\r\n", MaxReads );
    if (( 1000 * 1000 * 1000 ) <= MediaBytes ) {
      UINT32 Remainder;
      UINT64 GByte;
      GByte = DivU64x32Remainder ( MediaBytes,
                                   1000 * 1000 * 1000,
                                   &Remainder );
      Print ( L"  Media Size: %d.%03d GiBytes (%d.%03d GBytes)\r\n",
              (UINT32)( MediaBytes / GIBYTE ),
              ((UINT32)(( MediaBytes % GIBYTE ) / MIBYTE ) * 1000 ) / KIBYTE,
              (UINT32)GByte,
              Remainder / ( 1000 * 1000 ));
    }
    else {
      UINT32 Remainder;
      UINT64 MByte;
      MByte = DivU64x32Remainder ( MediaBytes,
                                   1000 * 1000,
                                   &Remainder );
      Print ( L"  Media Size: %d.%03d MiBytes (%d.%03d MBytes)\r\n",
              (UINT32)DivU64x32 ( MediaBytes, MIBYTE ),
              ((UINT32)(( MediaBytes % MIBYTE ) / KIBYTE ) * 1000 ) / KIBYTE,
              (UINT32)MByte,
              Remainder / 1000 );
    }
    Print ( L"  Test Count: %d runs\r\n", TEST_COUNT );
    Print ( L"  Warm-up reads: %d\r\n", WarmUpBlocks / BlocksPerRead );
    Print ( L"\r\n" );

    //
    //  Compute the timeout
    //
    Timeout = Seconds;
    Timeout *= 1000L * 1000L * 10L;

    //
    //  Get the media ID value
    //
    MediaId = pMedia->MediaId;

    //
    //  Warm-up the data path
    //
    Lba = LbaMax - WarmUpBlocks;
    while ( LbaMax > Lba ) {
      if ( bBlockIo2 ) {
        Status = pBlockIo2->ReadBlocksEx ( pBlockIo2,
                                           MediaId,
                                           Lba,
                                           NULL,
                                           BytesToRead,
                                           &mBuffer[ 0 ]);
      }
      else {
        Status = pBlockIo->ReadBlocks ( pBlockIo,
                                        MediaId,
                                        Lba,
                                        BytesToRead,
                                        &mBuffer[ 0 ]);
      }
      if ( EFI_ERROR ( Status )) {
        Print ( L"ERROR - Read failure during warm-up, Lba: 0x%016Lx, Status: %r\r\n",
                Lba,
                Status );
        break;
      }
      Lba += BlocksPerRead;
    }
    if ( !EFI_ERROR ( Status )) {
      //
      //  Perform each of the tests
      //
      for ( TestCount = 1; TEST_COUNT >= TestCount; TestCount++ ) {
        //
        //  Initialize the tokens
        //
        pToken = &mTokens[ 0 ];
        while ( pTokenEnd > pToken ) {
          gBS->SignalEvent ( pToken->Event );
          pToken->TransactionStatus = EFI_SUCCESS;
          pToken += 1;
        }
        pToken = &mTokens[ 0 ];

        //
        //  Start the timer
        //
        bTestRunning = TRUE;
        ReadCount = 0;
        bReadComplete = TRUE;
        gBS->CheckEvent ( TimeoutEvent );
        Status = gBS->SetTimer ( TimeoutEvent,
                                 TimerRelative,
                                 Timeout );
        ASSERT ( EFI_SUCCESS == Status );
        if ( bBlockIo2 ) {
          //
          //  Run the test using Block I/O 2 protocol
          //
          do {
            Lba = 0;
            while ( bTestRunning && ( LbaMax > Lba )) {
              //
              //  Wrap the token list if necessary
              //
              if ( pTokenEnd <= pToken ) {
                pToken = &mTokens[ 0 ];
              }

              //
              //  Wait for the next token
              //
              gBS->WaitForEvent ( 1, &pToken->Event, &Index );

              //
              //  Verify the read status
              //
              Status = pToken->TransactionStatus;
              if ( EFI_ERROR ( Status )) {
                break;
              }

              //
              //  Start the next read
              //
              Status = pBlockIo2->ReadBlocksEx ( pBlockIo2,
                                                 MediaId,
                                                 Lba,
                                                 pToken,
                                                 BytesToRead,
                                                 &mBuffer[ 0 ]);
              if ( EFI_ERROR ( Status )) {
                bReadComplete = FALSE;
                break;
              }

              //
              //  Account for this read
              //
              ReadCount += 1;
              Lba += BlocksPerRead;
              pToken += 1;
            }
          }while ( bTestRunning );

          //
          //  Wait for the rest of the reads to complete
          //
          pToken = &mTokens[ 0 ];
          while ( pTokenEnd > pToken ) {
            gBS->WaitForEvent ( 1,
                                &pToken->Event,
                                &Index );
            pToken += 1;
          }

          //
          //  Display any errors
          //
          if ( EFI_ERROR ( Status )) {
            Print ( L"ERROR - Read %afailure, Lba: 0x%016Lx, Status: %r\r\n",
                    bReadComplete ? "" : "queue ",
                    bReadComplete ? Lba - ( DIM ( mTokens ) * BlocksPerRead ) : Lba,
                    Status );
            break;
          }
        }
        else {
          //
          //  Run the test using Block I/O protocol
          //
          do {
            Lba = 0;
            while ( bTestRunning && ( LbaMax > Lba )) {
              Status = pBlockIo->ReadBlocks ( pBlockIo,
                                              MediaId,
                                              Lba,
                                              BytesToRead,
                                              &mBuffer[ 0 ]);
              if ( EFI_ERROR ( Status )) {
                Print ( L"ERROR - Read failure, Lba: 0x%016Lx, Status: %r\r\n",
                        Lba,
                        Status );
                return (( Status & MAX_BIT ) ? 0x80000000 : 0 )
                        | ( Status & 0x7fffffff );
              }
              ReadCount += 1;
              Lba += BlocksPerRead;
            }
          } while ( bTestRunning );
        }

        //
        //  Adjust the read count for the tokens
        //
        if ( bBlockIo2 ) {
          FinalReadCount = ( DIM ( mTokens ) >= FinalReadCount )
                         ? 0
                         : FinalReadCount - DIM ( mTokens );
        }

        //
        //  Compute the results
        //
        TotalReadCount += FinalReadCount;
        DataRead = FinalReadCount;
        DataRead = MultU64x32 ( DataRead, BytesToRead );
        BytesPerSecond = (UINT32)DivU64x32 ( DataRead, Seconds );

        //
        //  Display the test results
        //
        Print ( L"\r\nTest %d Results:\r\n", TestCount );
        Print ( L"  Reads: %d\r\n", FinalReadCount );
        Print ( L"  %d.%03d MiBytes/Second (%d.%03d Mbit/Second)\r\n",
                  BytesPerSecond / ( 1024 * 1024 ),
                  ((( BytesPerSecond % ( 1024 * 1024 )) / 1024 ) * 1000 ) / 1024,
                  ( BytesPerSecond * 8 ) / ( 1000 * 1000 ),
                  (( BytesPerSecond * 8 ) % ( 1000 * 1000 )) / 1000 );
      }

      //
      //  Compute the results
      //
      DataRead = TotalReadCount;
      DataRead = MultU64x32 ( DataRead, BytesToRead );
      DataRead = DivU64x32 ( DataRead, TEST_COUNT );
      BytesPerSecond = (UINT32)DivU64x32 ( DataRead, Seconds );

      //
      //  Display the test results
      //
      Print ( L"\r\nAverage Test Results:\r\n" );
      Print ( L"  Total Reads: %d\r\n", TotalReadCount );
      Print ( L"  %d.%03d MiBytes/Second (%d.%03d Mbit/Second)\r\n",
                BytesPerSecond / ( 1024 * 1024 ),
                ((( BytesPerSecond % ( 1024 * 1024 )) / 1024 ) * 1000 ) / 1024,
                ( BytesPerSecond * 8 ) / ( 1000 * 1000 ),
                (( BytesPerSecond * 8 ) % ( 1000 * 1000 )) / 1000 );
    }
  }

  //
  //  Done with the events
  //
  gBS->CloseEvent ( TimeoutEvent );
  pToken = &mTokens[ 0 ];
  while ( pTokenEnd > pToken ) {
    if ( NULL != pToken->Event ) {
      gBS->CloseEvent ( pToken->Event );
    }
    pToken += 1;
  }

  //
  //  Return the test status
  //
  return (( Status & MAX_BIT ) ? 0x80000000 : 0 )
          | ( Status & 0x7fffffff );
}
Example #12
0
EFI_STATUS
EFIAPI
RootBridgeIoPollIo ( 
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
  IN  UINT64                                 Address,
  IN  UINT64                                 Mask,
  IN  UINT64                                 Value,
  IN  UINT64                                 Delay,
  OUT UINT64                                 *Result
  )
/*++

Routine Description:
  Io Poll
  
Arguments:
    
Returns:

--*/  
{
  EFI_STATUS  Status;
  UINT64      NumberOfTicks;
  UINT32      Remainder;

  //
  // No matter what, always do a single poll.
  //

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

  if (Width < 0 || Width > EfiPciWidthUint64) {
    return EFI_INVALID_PARAMETER;
  }
  
  Status = This->Io.Read (This, Width, Address, 1, Result);
  if (EFI_ERROR (Status)) {
    return Status;
  }    
  if ((*Result & Mask) == Value) {
    return EFI_SUCCESS;
  }

  if (Delay == 0) {
    return EFI_SUCCESS;
  
  } else {

    //
    // Determine the proper # of metronome ticks to wait for polling the
    // location.  The number of ticks is Roundup (Delay / mMetronome->TickPeriod)+1
    // The "+1" to account for the possibility of the first tick being short
    // because we started in the middle of a tick.
    //
    NumberOfTicks = DivU64x32Remainder (Delay, (UINT32)mMetronome->TickPeriod, &Remainder);
    if (Remainder != 0) {
      NumberOfTicks += 1;
    }
    NumberOfTicks += 1;
  
    while (NumberOfTicks) {

      mMetronome->WaitForTick (mMetronome, 1);
    
      Status = This->Io.Read (This, Width, Address, 1, Result);
      if (EFI_ERROR (Status)) {
        return Status;
      }
    
      if ((*Result & Mask) == Value) {
        return EFI_SUCCESS;
      }

      NumberOfTicks -= 1;
    }
  }
  return EFI_TIMEOUT;
}
Example #13
0
/**
  Disk reading.

  @param  PrivateData       the global memory map; 
  @param  BlockDeviceNo     the block device to read; 
  @param  StartingAddress   the starting address. 
  @param  Size              the amount of data to read. 
  @param  Buffer            the buffer holding the data 

  @retval EFI_SUCCESS       The function completed successfully.
  @retval EFI_DEVICE_ERROR  Something error.

**/
EFI_STATUS
FatReadDisk (
  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
  IN  UINTN                 BlockDeviceNo,
  IN  UINT64                StartingAddress,
  IN  UINTN                 Size,
  OUT VOID                  *Buffer
  )
{
  EFI_STATUS  Status;
  UINT32      BlockSize;
  CHAR8       *BufferPtr;
  CHAR8       *CachePtr;
  UINT32      Offset;
  UINT64      Lba;
  UINT64      OverRunLba;
  UINTN       Amount;

  Status    = EFI_SUCCESS;
  BufferPtr = Buffer;
  BlockSize = PrivateData->BlockDevice[BlockDeviceNo].BlockSize;

  //
  // Read underrun
  //
  Lba     = DivU64x32Remainder (StartingAddress, BlockSize, &Offset);
  Status  = FatGetCacheBlock (PrivateData, BlockDeviceNo, Lba, &CachePtr);
  if (EFI_ERROR (Status)) {
    return EFI_DEVICE_ERROR;
  }

  Amount = Size < (BlockSize - Offset) ? Size : (BlockSize - Offset);
  CopyMem (BufferPtr, CachePtr + Offset, Amount);

  if (Size == Amount) {
    return EFI_SUCCESS;
  }

  Size -= Amount;
  BufferPtr += Amount;
  StartingAddress += Amount;
  Lba += 1;

  //
  // Read aligned parts
  //
  OverRunLba = Lba + DivU64x32Remainder (Size, BlockSize, &Offset);

  Size -= Offset;
  Status = FatReadBlock (PrivateData, BlockDeviceNo, Lba, Size, BufferPtr);
  if (EFI_ERROR (Status)) {
    return EFI_DEVICE_ERROR;
  }

  BufferPtr += Size;

  //
  // Read overrun
  //
  if (Offset != 0) {
    Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, OverRunLba, &CachePtr);
    if (EFI_ERROR (Status)) {
      return EFI_DEVICE_ERROR;
    }

    CopyMem (BufferPtr, CachePtr, Offset);
  }

  return Status;
}
Example #14
0
EFI_STATUS
EFIAPI
PcatRootBridgeIoPollIo ( 
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
  IN  UINT64                                 Address,
  IN  UINT64                                 Mask,
  IN  UINT64                                 Value,
  IN  UINT64                                 Delay,
  OUT UINT64                                 *Result
  )
{
  EFI_STATUS  Status;
  UINT64      NumberOfTicks;
  UINT32       Remainder;

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

  if ((UINT32)Width > EfiPciWidthUint64) {
    return EFI_INVALID_PARAMETER;
  }
  //
  // No matter what, always do a single poll.
  //
  Status = This->Io.Read (This, Width, Address, 1, Result);
  if ( EFI_ERROR(Status) ) {
    return Status;
  }    
  if ( (*Result & Mask) == Value ) {
    return EFI_SUCCESS;
  }

  if (Delay == 0) {
    return EFI_SUCCESS;
  } else {

    NumberOfTicks = DivU64x32Remainder (Delay, 100, &Remainder);
    if ( Remainder !=0 ) {
      NumberOfTicks += 1;
    }
    NumberOfTicks += 1;
  
    while ( NumberOfTicks ) {

      gBS->Stall(10);
    
      Status = This->Io.Read (This, Width, Address, 1, Result);
      if ( EFI_ERROR(Status) ) {
        return Status;
      }
    
      if ( (*Result & Mask) == Value ) {
        return EFI_SUCCESS;
      }

      NumberOfTicks -= 1;
    }
  }
  return EFI_TIMEOUT;
}
Example #15
0
EFI_STATUS
PciRbPollMem (
  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL           *This,
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
  IN  UINT64                                   Address,
  IN  UINT64                                   Mask,
  IN  UINT64                                   Value,
  IN  UINT64                                   Delay,
  OUT UINT64                                   *Result
  )
{
  EFI_STATUS                      Status;
  UINT64                          NumberOfTicks;
  UINT32                          Remainder;
  PCI_ROOT_BRIDGE_INSTANCE        *RootBridgeInstance;
  EFI_METRONOME_ARCH_PROTOCOL     *Metronome;

  PCI_TRACE ("PciRbPollMem()");

  RootBridgeInstance = INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This);
  Metronome = METRONOME_FROM_ROOT_BRIDGE_INSTANCE (RootBridgeInstance);

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

  if (Width > EfiPciWidthUint64) {
    return EFI_INVALID_PARAMETER;
  }

  // No matter what, always do a single poll.
  Status = This->Mem.Read (This, Width, Address, 1, Result);
  if (EFI_ERROR (Status)) {
    return Status;
  }
  if ((*Result & Mask) == Value) {
    return EFI_SUCCESS;
  }

  if (Delay == 0) {
    return EFI_SUCCESS;
  }

  NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) Metronome->TickPeriod, &Remainder);
  if (Remainder != 0) {
    NumberOfTicks += 1;
  }
  NumberOfTicks += 1;

  while (NumberOfTicks) {
    Metronome->WaitForTick (Metronome, 1);

    Status = This->Mem.Read (This, Width, Address, 1, Result);
    if (EFI_ERROR (Status)) {
      return Status;
    }

    if ((*Result & Mask) == Value) {
      return EFI_SUCCESS;
    }

    NumberOfTicks -= 1;
  }

  return EFI_TIMEOUT;
}