blob: 4fbbb1f3b431760304cf45cfef84eac31d359310 [file] [log] [blame]
/** @file
Produce EFI_BLOCK_IO_PROTOCOL on a RAM disk device.
Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "RamDiskImpl.h"
//
// The EFI_BLOCK_IO_PROTOCOL instances that is installed onto the handle
// for newly registered RAM disks
//
EFI_BLOCK_IO_PROTOCOL mRamDiskBlockIoTemplate = {
EFI_BLOCK_IO_PROTOCOL_REVISION,
(EFI_BLOCK_IO_MEDIA *)0,
RamDiskBlkIoReset,
RamDiskBlkIoReadBlocks,
RamDiskBlkIoWriteBlocks,
RamDiskBlkIoFlushBlocks
};
//
// The EFI_BLOCK_IO_PROTOCOL2 instances that is installed onto the handle
// for newly registered RAM disks
//
EFI_BLOCK_IO2_PROTOCOL mRamDiskBlockIo2Template = {
(EFI_BLOCK_IO_MEDIA *)0,
RamDiskBlkIo2Reset,
RamDiskBlkIo2ReadBlocksEx,
RamDiskBlkIo2WriteBlocksEx,
RamDiskBlkIo2FlushBlocksEx
};
/**
Initialize the BlockIO & BlockIO2 protocol of a RAM disk device.
@param[in] PrivateData Points to RAM disk private data.
**/
VOID
RamDiskInitBlockIo (
IN RAM_DISK_PRIVATE_DATA *PrivateData
)
{
EFI_BLOCK_IO_PROTOCOL *BlockIo;
EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
EFI_BLOCK_IO_MEDIA *Media;
UINT32 Remainder;
BlockIo = &PrivateData->BlockIo;
BlockIo2 = &PrivateData->BlockIo2;
Media = &PrivateData->Media;
CopyMem (BlockIo, &mRamDiskBlockIoTemplate, sizeof (EFI_BLOCK_IO_PROTOCOL));
CopyMem (BlockIo2, &mRamDiskBlockIo2Template, sizeof (EFI_BLOCK_IO2_PROTOCOL));
BlockIo->Media = Media;
BlockIo2->Media = Media;
Media->RemovableMedia = FALSE;
Media->MediaPresent = TRUE;
Media->LogicalPartition = FALSE;
Media->ReadOnly = FALSE;
Media->WriteCaching = FALSE;
for (Media->BlockSize = RAM_DISK_DEFAULT_BLOCK_SIZE;
Media->BlockSize >= 1;
Media->BlockSize = Media->BlockSize >> 1)
{
Media->LastBlock = DivU64x32Remainder (PrivateData->Size, Media->BlockSize, &Remainder) - 1;
if (Remainder == 0) {
break;
}
}
ASSERT (Media->BlockSize != 0);
return;
}
/**
Reset the Block Device.
@param This Indicates a pointer to the calling context.
@param ExtendedVerification Driver may perform diagnostics on reset.
@retval EFI_SUCCESS The device was reset.
@retval EFI_DEVICE_ERROR The device is not functioning properly and could
not be reset.
**/
EFI_STATUS
EFIAPI
RamDiskBlkIoReset (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
)
{
return EFI_SUCCESS;
}
/**
Read BufferSize bytes from Lba into Buffer.
@param[in] This Indicates a pointer to the calling context.
@param[in] MediaId Id of the media, changes every time the media is
replaced.
@param[in] Lba The starting Logical Block Address to read from.
@param[in] BufferSize Size of Buffer, must be a multiple of device block
size.
@param[out] 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 matched 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
RamDiskBlkIoReadBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
OUT VOID *Buffer
)
{
RAM_DISK_PRIVATE_DATA *PrivateData;
UINTN NumberOfBlocks;
PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO (This);
if (MediaId != PrivateData->Media.MediaId) {
return EFI_MEDIA_CHANGED;
}
if (Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
if (BufferSize == 0) {
return EFI_SUCCESS;
}
if ((BufferSize % PrivateData->Media.BlockSize) != 0) {
return EFI_BAD_BUFFER_SIZE;
}
if (Lba > PrivateData->Media.LastBlock) {
return EFI_INVALID_PARAMETER;
}
NumberOfBlocks = BufferSize / PrivateData->Media.BlockSize;
if ((Lba + NumberOfBlocks - 1) > PrivateData->Media.LastBlock) {
return EFI_INVALID_PARAMETER;
}
CopyMem (
Buffer,
(VOID *)(UINTN)(PrivateData->StartingAddr + MultU64x32 (Lba, PrivateData->Media.BlockSize)),
BufferSize
);
return EFI_SUCCESS;
}
/**
Write BufferSize bytes from Lba into Buffer.
@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] 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 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_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
RamDiskBlkIoWriteBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
IN VOID *Buffer
)
{
RAM_DISK_PRIVATE_DATA *PrivateData;
UINTN NumberOfBlocks;
PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO (This);
if (MediaId != PrivateData->Media.MediaId) {
return EFI_MEDIA_CHANGED;
}
if (TRUE == PrivateData->Media.ReadOnly) {
return EFI_WRITE_PROTECTED;
}
if (Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
if (BufferSize == 0) {
return EFI_SUCCESS;
}
if ((BufferSize % PrivateData->Media.BlockSize) != 0) {
return EFI_BAD_BUFFER_SIZE;
}
if (Lba > PrivateData->Media.LastBlock) {
return EFI_INVALID_PARAMETER;
}
NumberOfBlocks = BufferSize / PrivateData->Media.BlockSize;
if ((Lba + NumberOfBlocks - 1) > PrivateData->Media.LastBlock) {
return EFI_INVALID_PARAMETER;
}
CopyMem (
(VOID *)(UINTN)(PrivateData->StartingAddr + MultU64x32 (Lba, PrivateData->Media.BlockSize)),
Buffer,
BufferSize
);
return EFI_SUCCESS;
}
/**
Flush the Block Device.
@param[in] 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 writting
back the data
@retval EFI_NO_MEDIA There is no media in the device.
**/
EFI_STATUS
EFIAPI
RamDiskBlkIoFlushBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This
)
{
return EFI_SUCCESS;
}
/**
Resets the block device hardware.
@param[in] This The pointer of EFI_BLOCK_IO2_PROTOCOL.
@param[in] ExtendedVerification The flag about if extend verificate.
@retval EFI_SUCCESS The device was reset.
@retval EFI_DEVICE_ERROR The block device is not functioning correctly
and could not be reset.
**/
EFI_STATUS
EFIAPI
RamDiskBlkIo2Reset (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
)
{
return EFI_SUCCESS;
}
/**
Reads the requested number of blocks from the device.
@param[in] This Indicates a pointer to the calling context.
@param[in] MediaId The media ID that the read request is for.
@param[in] Lba The starting logical block address to read
from on the device.
@param[in, out] Token A pointer to the token associated with the
transaction.
@param[in] BufferSize The size of the Buffer in bytes. This must be
a multiple of the intrinsic block size of the
device.
@param[out] 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 read request was queued if Token->Event
is not NULL. The data was read correctly from
the device if the Token->Event is NULL.
@retval EFI_DEVICE_ERROR The device reported an error while attempting
to perform the read operation.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
the intrinsic 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.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
lack of resources.
**/
EFI_STATUS
EFIAPI
RamDiskBlkIo2ReadBlocksEx (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
IN UINTN BufferSize,
OUT VOID *Buffer
)
{
RAM_DISK_PRIVATE_DATA *PrivateData;
EFI_STATUS Status;
PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This);
Status = RamDiskBlkIoReadBlocks (
&PrivateData->BlockIo,
MediaId,
Lba,
BufferSize,
Buffer
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// If caller's event is given, signal it after the memory read completes.
//
if ((Token != NULL) && (Token->Event != NULL)) {
Token->TransactionStatus = EFI_SUCCESS;
gBS->SignalEvent (Token->Event);
}
return EFI_SUCCESS;
}
/**
Writes a specified number of blocks to the device.
@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 The size in bytes of Buffer. This must be a
multiple of the intrinsic block size of the
device.
@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 cannot be written to.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
@retval EFI_DEVICE_ERROR The device reported an error while attempting
to perform the write operation.
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
the intrinsic 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
RamDiskBlkIo2WriteBlocksEx (
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
)
{
RAM_DISK_PRIVATE_DATA *PrivateData;
EFI_STATUS Status;
PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This);
Status = RamDiskBlkIoWriteBlocks (
&PrivateData->BlockIo,
MediaId,
Lba,
BufferSize,
Buffer
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// If caller's event is given, signal it after the memory write completes.
//
if ((Token != NULL) && (Token->Event != NULL)) {
Token->TransactionStatus = EFI_SUCCESS;
gBS->SignalEvent (Token->Event);
}
return EFI_SUCCESS;
}
/**
Flushes all modified data to a physical block device.
@param[in] This Indicates a pointer to the calling context.
@param[in, out] Token A pointer to the token associated with the
transaction.
@retval EFI_SUCCESS The flush request was queued if Event is not
NULL. All outstanding data was written
correctly to the device if the Event is NULL.
@retval EFI_DEVICE_ERROR The device reported an error while attempting
to write data.
@retval EFI_WRITE_PROTECTED The device cannot be written to.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
lack of resources.
**/
EFI_STATUS
EFIAPI
RamDiskBlkIo2FlushBlocksEx (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN OUT EFI_BLOCK_IO2_TOKEN *Token
)
{
RAM_DISK_PRIVATE_DATA *PrivateData;
PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This);
if (TRUE == PrivateData->Media.ReadOnly) {
return EFI_WRITE_PROTECTED;
}
//
// If caller's event is given, signal it directly.
//
if ((Token != NULL) && (Token->Event != NULL)) {
Token->TransactionStatus = EFI_SUCCESS;
gBS->SignalEvent (Token->Event);
}
return EFI_SUCCESS;
}