/** 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); }
/** 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; }
/** 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; }
/** 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); }
/** 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; }
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; }
/** 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; }
/** 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 ); }
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; }
/** 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; }
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; }
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; }