123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- /** @file
- BlockIo implementation for Xen PV Block driver.
- This file is implementing the interface between the actual driver in
- BlockFront.c to the BlockIo protocol.
- Copyright (C) 2014, Citrix Ltd.
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "XenPvBlkDxe.h"
- #include "BlockFront.h"
- ///
- /// Block I/O Media structure
- ///
- GLOBAL_REMOVE_IF_UNREFERENCED
- EFI_BLOCK_IO_MEDIA gXenPvBlkDxeBlockIoMedia = {
- 0, // MediaId
- FALSE, // RemovableMedia
- FALSE, // MediaPresent
- FALSE, // LogicalPartition
- TRUE, // ReadOnly
- FALSE, // WriteCaching
- 512, // BlockSize
- 512, // IoAlign, BlockFront does not support less than 512 bits-aligned.
- 0, // LastBlock
- 0, // LowestAlignedLba
- 0, // LogicalBlocksPerPhysicalBlock
- 0 // OptimalTransferLengthGranularity
- };
- ///
- /// Block I/O Protocol instance
- ///
- GLOBAL_REMOVE_IF_UNREFERENCED
- EFI_BLOCK_IO_PROTOCOL gXenPvBlkDxeBlockIo = {
- EFI_BLOCK_IO_PROTOCOL_REVISION3, // Revision
- &gXenPvBlkDxeBlockIoMedia, // Media
- XenPvBlkDxeBlockIoReset, // Reset
- XenPvBlkDxeBlockIoReadBlocks, // ReadBlocks
- XenPvBlkDxeBlockIoWriteBlocks, // WriteBlocks
- XenPvBlkDxeBlockIoFlushBlocks // FlushBlocks
- };
- /**
- Read/Write BufferSize bytes from Lba into Buffer.
- This function is common to XenPvBlkDxeBlockIoReadBlocks and
- XenPvBlkDxeBlockIoWriteBlocks.
- @param This Indicates a pointer to the calling context.
- @param MediaId Id of the media, changes every time the media is replaced.
- @param Lba The starting Logical Block Address to read from/write to.
- @param BufferSize Size of Buffer, must be a multiple of device block size.
- @param Buffer A pointer to the destination/source buffer for the data.
- @param IsWrite Indicate if the operation is write or read.
- @return See description of XenPvBlkDxeBlockIoReadBlocks and
- XenPvBlkDxeBlockIoWriteBlocks.
- **/
- STATIC
- EFI_STATUS
- XenPvBlkDxeBlockIoReadWriteBlocks (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- IN UINT32 MediaId,
- IN EFI_LBA Lba,
- IN UINTN BufferSize,
- IN OUT VOID *Buffer,
- IN BOOLEAN IsWrite
- )
- {
- XEN_BLOCK_FRONT_IO IoData;
- EFI_BLOCK_IO_MEDIA *Media = This->Media;
- UINTN Sector;
- EFI_STATUS Status;
- if (Buffer == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- if (BufferSize == 0) {
- return EFI_SUCCESS;
- }
- if (BufferSize % Media->BlockSize != 0) {
- DEBUG ((
- DEBUG_ERROR,
- "XenPvBlkDxe: Bad buffer size: 0x%Lx\n",
- (UINT64)BufferSize
- ));
- return EFI_BAD_BUFFER_SIZE;
- }
- if ((Lba > Media->LastBlock) ||
- ((BufferSize / Media->BlockSize) - 1 > Media->LastBlock - Lba))
- {
- DEBUG ((
- DEBUG_ERROR,
- "XenPvBlkDxe: %a with invalid LBA: 0x%Lx, size: 0x%Lx\n",
- IsWrite ? "Write" : "Read",
- Lba,
- (UINT64)BufferSize
- ));
- return EFI_INVALID_PARAMETER;
- }
- if (IsWrite && Media->ReadOnly) {
- return EFI_WRITE_PROTECTED;
- }
- if ((Media->IoAlign > 1) && (UINTN)Buffer & (Media->IoAlign - 1)) {
- //
- // Grub2 does not appear to respect IoAlign of 512, so reallocate the
- // buffer here.
- //
- VOID *NewBuffer;
- //
- // Try again with a properly aligned buffer.
- //
- NewBuffer = AllocateAlignedPages (
- (BufferSize + EFI_PAGE_SIZE) / EFI_PAGE_SIZE,
- Media->IoAlign
- );
- if (!IsWrite) {
- Status = XenPvBlkDxeBlockIoReadBlocks (
- This,
- MediaId,
- Lba,
- BufferSize,
- NewBuffer
- );
- CopyMem (Buffer, NewBuffer, BufferSize);
- } else {
- CopyMem (NewBuffer, Buffer, BufferSize);
- Status = XenPvBlkDxeBlockIoWriteBlocks (
- This,
- MediaId,
- Lba,
- BufferSize,
- NewBuffer
- );
- }
- FreeAlignedPages (NewBuffer, (BufferSize + EFI_PAGE_SIZE) / EFI_PAGE_SIZE);
- return Status;
- }
- IoData.Dev = XEN_BLOCK_FRONT_FROM_BLOCK_IO (This);
- Sector = (UINTN)MultU64x32 (Lba, Media->BlockSize / 512);
- while (BufferSize > 0) {
- if (((UINTN)Buffer & EFI_PAGE_MASK) == 0) {
- IoData.Size = MIN (
- BLKIF_MAX_SEGMENTS_PER_REQUEST * EFI_PAGE_SIZE,
- BufferSize
- );
- } else {
- IoData.Size = MIN (
- (BLKIF_MAX_SEGMENTS_PER_REQUEST - 1) * EFI_PAGE_SIZE,
- BufferSize
- );
- }
- IoData.Buffer = Buffer;
- IoData.Sector = Sector;
- BufferSize -= IoData.Size;
- Buffer = (VOID *)((UINTN)Buffer + IoData.Size);
- Sector += IoData.Size / 512;
- Status = XenPvBlockIo (&IoData, IsWrite);
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "XenPvBlkDxe: Error during %a operation.\n",
- IsWrite ? "write" : "read"
- ));
- return Status;
- }
- }
- return EFI_SUCCESS;
- }
- /**
- Read BufferSize bytes from Lba into Buffer.
- @param This Indicates a pointer to the calling context.
- @param MediaId Id of the media, changes every time the media is replaced.
- @param Lba The starting Logical Block Address to read from
- @param BufferSize Size of Buffer, must be a multiple of device block size.
- @param Buffer A pointer to the destination buffer for the data. The caller is
- responsible for either having implicit or explicit ownership of the buffer.
- @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_CHANGED The MediaId does not match the current device.
- @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
- @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
- or the buffer is not on proper alignment.
- **/
- EFI_STATUS
- EFIAPI
- XenPvBlkDxeBlockIoReadBlocks (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- IN UINT32 MediaId,
- IN EFI_LBA Lba,
- IN UINTN BufferSize,
- OUT VOID *Buffer
- )
- {
- return XenPvBlkDxeBlockIoReadWriteBlocks (
- This,
- MediaId,
- Lba,
- BufferSize,
- Buffer,
- FALSE
- );
- }
- /**
- Write BufferSize bytes from Lba into Buffer.
- @param This Indicates a pointer to the calling context.
- @param MediaId The media ID that the write request is for.
- @param Lba The starting logical block address to be written. The caller is
- responsible for writing to only legitimate locations.
- @param BufferSize Size of Buffer, must be a multiple of device block size.
- @param Buffer A pointer to the source buffer for the data.
- @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_CHANGED The MediaId does not match the current device.
- @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.
- **/
- EFI_STATUS
- EFIAPI
- XenPvBlkDxeBlockIoWriteBlocks (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- IN UINT32 MediaId,
- IN EFI_LBA Lba,
- IN UINTN BufferSize,
- IN VOID *Buffer
- )
- {
- return XenPvBlkDxeBlockIoReadWriteBlocks (
- This,
- MediaId,
- Lba,
- BufferSize,
- Buffer,
- TRUE
- );
- }
- /**
- Flush the Block Device.
- @param This Indicates a pointer to the calling context.
- @retval EFI_SUCCESS All outstanding data was written to the device
- @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
- @retval EFI_NO_MEDIA There is no media in the device.
- **/
- EFI_STATUS
- EFIAPI
- XenPvBlkDxeBlockIoFlushBlocks (
- IN EFI_BLOCK_IO_PROTOCOL *This
- )
- {
- XenPvBlockSync (XEN_BLOCK_FRONT_FROM_BLOCK_IO (This));
- return EFI_SUCCESS;
- }
- /**
- Reset the block device hardware.
- @param[in] This Indicates a pointer to the calling context.
- @param[in] ExtendedVerification Not used.
- @retval EFI_SUCCESS The device was reset.
- **/
- EFI_STATUS
- EFIAPI
- XenPvBlkDxeBlockIoReset (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- IN BOOLEAN ExtendedVerification
- )
- {
- //
- // Since the initialization of the devices is done, then the device is
- // working correctly.
- //
- return EFI_SUCCESS;
- }
|