2011-05-31 22:23:36 +02:00
|
|
|
/**@file
|
|
|
|
|
|
|
|
Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>
|
2011-06-28 18:50:26 +02:00
|
|
|
This program and the accompanying materials
|
|
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
2011-05-31 22:23:36 +02:00
|
|
|
|
|
|
|
**/
|
|
|
|
|
2011-06-29 07:13:33 +02:00
|
|
|
#include "Host.h"
|
2011-05-31 22:23:36 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
#define EMU_BLOCK_IO_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'M', 'b', 'k')
|
|
|
|
typedef struct {
|
|
|
|
UINTN Signature;
|
2011-05-31 22:23:36 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
EMU_IO_THUNK_PROTOCOL *Thunk;
|
2011-05-31 22:23:36 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
char *Filename;
|
|
|
|
UINTN ReadMode;
|
|
|
|
UINTN Mode;
|
2011-05-31 22:23:36 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
int fd;
|
2011-05-31 22:23:36 +02:00
|
|
|
|
|
|
|
BOOLEAN RemovableMedia;
|
|
|
|
BOOLEAN WriteProtected;
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
UINT64 NumberOfBlocks;
|
2011-06-17 18:18:14 +02:00
|
|
|
UINT32 BlockSize;
|
2011-05-31 22:23:36 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
EMU_BLOCK_IO_PROTOCOL EmuBlockIo;
|
|
|
|
EFI_BLOCK_IO_MEDIA *Media;
|
2011-05-31 22:23:36 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
} EMU_BLOCK_IO_PRIVATE;
|
2011-05-31 22:23:36 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
#define EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS(a) \
|
|
|
|
CR(a, EMU_BLOCK_IO_PRIVATE, EmuBlockIo, EMU_BLOCK_IO_PRIVATE_SIGNATURE)
|
2011-05-31 22:23:36 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
EFI_STATUS
|
2011-06-03 05:31:32 +02:00
|
|
|
EmuBlockIoReset (
|
|
|
|
IN EMU_BLOCK_IO_PROTOCOL *This,
|
|
|
|
IN BOOLEAN ExtendedVerification
|
|
|
|
);
|
2011-05-31 22:23:36 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
This function extends the capability of SetFilePointer to accept 64 bit parameters
|
2011-05-31 22:23:36 +02:00
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
2011-06-03 05:31:32 +02:00
|
|
|
SetFilePointer64 (
|
|
|
|
IN EMU_BLOCK_IO_PRIVATE *Private,
|
|
|
|
IN INT64 DistanceToMove,
|
|
|
|
OUT UINT64 *NewFilePointer,
|
|
|
|
IN INT32 MoveMethod
|
2011-05-31 22:23:36 +02:00
|
|
|
)
|
|
|
|
{
|
2011-06-03 05:31:32 +02:00
|
|
|
EFI_STATUS Status;
|
|
|
|
off_t res;
|
2011-06-07 04:28:08 +02:00
|
|
|
off_t offset = DistanceToMove;
|
2011-05-31 22:23:36 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
Status = EFI_SUCCESS;
|
2011-06-07 04:28:08 +02:00
|
|
|
res = lseek (Private->fd, offset, (int)MoveMethod);
|
2011-06-03 05:31:32 +02:00
|
|
|
if (res == -1) {
|
|
|
|
Status = EFI_INVALID_PARAMETER;
|
2011-06-28 18:50:26 +02:00
|
|
|
}
|
2011-05-31 22:23:36 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
if (NewFilePointer != NULL) {
|
|
|
|
*NewFilePointer = res;
|
2011-05-31 22:23:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
|
2011-05-31 22:23:36 +02:00
|
|
|
EFI_STATUS
|
2011-06-03 05:31:32 +02:00
|
|
|
EmuBlockIoOpenDevice (
|
|
|
|
IN EMU_BLOCK_IO_PRIVATE *Private
|
2011-05-31 22:23:36 +02:00
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINT64 FileSize;
|
2011-06-07 04:28:08 +02:00
|
|
|
struct statfs buf;
|
2011-05-31 22:23:36 +02:00
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// If the device is already opened, close it
|
|
|
|
//
|
|
|
|
if (Private->fd >= 0) {
|
2011-06-03 05:31:32 +02:00
|
|
|
EmuBlockIoReset (&Private->EmuBlockIo, FALSE);
|
2011-05-31 22:23:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Open the device
|
|
|
|
//
|
2011-06-03 05:31:32 +02:00
|
|
|
Private->fd = open (Private->Filename, Private->Mode, 0644);
|
2011-05-31 22:23:36 +02:00
|
|
|
if (Private->fd < 0) {
|
2011-06-07 04:28:08 +02:00
|
|
|
printf ("EmuOpenBlock: Could not open %s: %s\n", Private->Filename, strerror(errno));
|
2011-06-03 05:31:32 +02:00
|
|
|
Private->Media->MediaPresent = FALSE;
|
2011-06-07 04:28:08 +02:00
|
|
|
Status = EFI_NO_MEDIA;
|
2011-05-31 22:23:36 +02:00
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
if (!Private->Media->MediaPresent) {
|
2011-05-31 22:23:36 +02:00
|
|
|
//
|
|
|
|
// BugBug: try to emulate if a CD appears - notify drivers to check it out
|
|
|
|
//
|
2011-06-03 05:31:32 +02:00
|
|
|
Private->Media->MediaPresent = TRUE;
|
2011-05-31 22:23:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// get the size of the file
|
|
|
|
//
|
|
|
|
Status = SetFilePointer64 (Private, 0, &FileSize, SEEK_END);
|
|
|
|
if (EFI_ERROR (Status)) {
|
2011-06-07 04:28:08 +02:00
|
|
|
printf ("EmuOpenBlock: Could not get filesize of %s\n", Private->Filename);
|
2011-05-31 22:23:36 +02:00
|
|
|
Status = EFI_UNSUPPORTED;
|
|
|
|
goto Done;
|
|
|
|
}
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-07 04:28:08 +02:00
|
|
|
if (FileSize == 0) {
|
|
|
|
// lseek fails on a real device. ioctl calls are OS specific
|
|
|
|
#if __APPLE__
|
|
|
|
{
|
|
|
|
UINT32 BlockSize;
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-07 04:28:08 +02:00
|
|
|
if (ioctl (Private->fd, DKIOCGETBLOCKSIZE, &BlockSize) == 0) {
|
|
|
|
Private->Media->BlockSize = BlockSize;
|
|
|
|
}
|
|
|
|
if (ioctl (Private->fd, DKIOCGETBLOCKCOUNT, &Private->NumberOfBlocks) == 0) {
|
|
|
|
if ((Private->NumberOfBlocks == 0) && (BlockSize == 0x800)) {
|
|
|
|
// A DVD is ~ 4.37 GB so make up a number
|
|
|
|
Private->Media->LastBlock = (0x100000000ULL/0x800) - 1;
|
|
|
|
} else {
|
|
|
|
Private->Media->LastBlock = Private->NumberOfBlocks - 1;
|
|
|
|
}
|
|
|
|
}
|
2011-06-28 18:50:26 +02:00
|
|
|
ioctl (Private->fd, DKIOCGETMAXBLOCKCOUNTWRITE, &Private->Media->OptimalTransferLengthGranularity);
|
2011-06-07 04:28:08 +02:00
|
|
|
}
|
2011-06-28 18:50:26 +02:00
|
|
|
#else
|
2011-06-07 04:28:08 +02:00
|
|
|
{
|
|
|
|
size_t BlockSize;
|
|
|
|
UINT64 DiskSize;
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-07 04:28:08 +02:00
|
|
|
if (ioctl (Private->fd, BLKSSZGET, &BlockSize) == 0) {
|
|
|
|
Private->Media->BlockSize = BlockSize;
|
|
|
|
}
|
|
|
|
if (ioctl (Private->fd, BLKGETSIZE64, &DiskSize) == 0) {
|
|
|
|
Private->NumberOfBlocks = DivU64x32 (DiskSize, (UINT32)BlockSize);
|
|
|
|
Private->Media->LastBlock = Private->NumberOfBlocks - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-17 18:18:14 +02:00
|
|
|
} else {
|
|
|
|
Private->Media->BlockSize = Private->BlockSize;
|
2011-06-07 04:28:08 +02:00
|
|
|
Private->NumberOfBlocks = DivU64x32 (FileSize, Private->Media->BlockSize);
|
|
|
|
Private->Media->LastBlock = Private->NumberOfBlocks - 1;
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-17 18:18:14 +02:00
|
|
|
if (fstatfs (Private->fd, &buf) == 0) {
|
2011-06-17 23:43:45 +02:00
|
|
|
#if __APPLE__
|
2011-06-17 18:18:14 +02:00
|
|
|
Private->Media->OptimalTransferLengthGranularity = buf.f_iosize/buf.f_bsize;
|
2011-06-17 23:43:45 +02:00
|
|
|
#else
|
|
|
|
Private->Media->OptimalTransferLengthGranularity = buf.f_bsize/buf.f_bsize;
|
|
|
|
#endif
|
2011-06-17 18:18:14 +02:00
|
|
|
}
|
2011-06-28 18:50:26 +02:00
|
|
|
}
|
2011-05-31 22:23:36 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
DEBUG ((EFI_D_INIT, "%HEmuOpenBlock: opened %a%N\n", Private->Filename));
|
2011-05-31 22:23:36 +02:00
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
|
|
|
|
Done:
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
if (Private->fd >= 0) {
|
2011-06-03 05:31:32 +02:00
|
|
|
EmuBlockIoReset (&Private->EmuBlockIo, FALSE);
|
2011-05-31 22:23:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
|
2011-05-31 22:23:36 +02:00
|
|
|
EFI_STATUS
|
2011-06-03 05:31:32 +02:00
|
|
|
EmuBlockIoCreateMapping (
|
|
|
|
IN EMU_BLOCK_IO_PROTOCOL *This,
|
|
|
|
IN EFI_BLOCK_IO_MEDIA *Media
|
2011-05-31 22:23:36 +02:00
|
|
|
)
|
|
|
|
{
|
2011-06-03 05:31:32 +02:00
|
|
|
EFI_STATUS Status;
|
|
|
|
EMU_BLOCK_IO_PRIVATE *Private;
|
|
|
|
|
|
|
|
Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
|
|
|
|
Private->Media = Media;
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
Media->MediaId = 0;
|
|
|
|
Media->RemovableMedia = Private->RemovableMedia;
|
|
|
|
Media->MediaPresent = TRUE;
|
|
|
|
Media->LogicalPartition = FALSE;
|
|
|
|
Media->ReadOnly = Private->WriteProtected;
|
|
|
|
Media->WriteCaching = FALSE;
|
|
|
|
Media->IoAlign = 1;
|
|
|
|
Media->LastBlock = 0; // Filled in by OpenDevice
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
// EFI_BLOCK_IO_PROTOCOL_REVISION2
|
|
|
|
Media->LowestAlignedLba = 0;
|
2011-06-28 18:50:26 +02:00
|
|
|
Media->LogicalBlocksPerPhysicalBlock = 0;
|
|
|
|
|
2011-06-07 04:28:08 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
// EFI_BLOCK_IO_PROTOCOL_REVISION3
|
|
|
|
Media->OptimalTransferLengthGranularity = 0;
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
Status = EmuBlockIoOpenDevice (Private);
|
|
|
|
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2011-05-31 22:23:36 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
EFI_STATUS
|
|
|
|
EmuBlockIoError (
|
|
|
|
IN EMU_BLOCK_IO_PRIVATE *Private
|
|
|
|
)
|
|
|
|
{
|
2011-05-31 22:23:36 +02:00
|
|
|
EFI_STATUS Status;
|
|
|
|
BOOLEAN ReinstallBlockIoFlag;
|
|
|
|
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
switch (errno) {
|
2011-05-31 22:23:36 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
case EAGAIN:
|
2011-05-31 22:23:36 +02:00
|
|
|
Status = EFI_NO_MEDIA;
|
2011-06-03 05:31:32 +02:00
|
|
|
Private->Media->ReadOnly = FALSE;
|
|
|
|
Private->Media->MediaPresent = FALSE;
|
2011-05-31 22:23:36 +02:00
|
|
|
ReinstallBlockIoFlag = FALSE;
|
|
|
|
break;
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
case EACCES:
|
|
|
|
Private->Media->ReadOnly = FALSE;
|
|
|
|
Private->Media->MediaPresent = TRUE;
|
|
|
|
Private->Media->MediaId += 1;
|
2011-05-31 22:23:36 +02:00
|
|
|
ReinstallBlockIoFlag = TRUE;
|
|
|
|
Status = EFI_MEDIA_CHANGED;
|
|
|
|
break;
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
case EROFS:
|
|
|
|
Private->Media->ReadOnly = TRUE;
|
2011-05-31 22:23:36 +02:00
|
|
|
ReinstallBlockIoFlag = FALSE;
|
|
|
|
Status = EFI_WRITE_PROTECTED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ReinstallBlockIoFlag = FALSE;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2011-06-16 20:28:12 +02:00
|
|
|
|
2011-05-31 22:23:36 +02:00
|
|
|
EFI_STATUS
|
2011-06-03 05:31:32 +02:00
|
|
|
EmuBlockIoReadWriteCommon (
|
|
|
|
IN EMU_BLOCK_IO_PRIVATE *Private,
|
2011-05-31 22:23:36 +02:00
|
|
|
IN UINT32 MediaId,
|
|
|
|
IN EFI_LBA Lba,
|
|
|
|
IN UINTN BufferSize,
|
|
|
|
IN VOID *Buffer,
|
|
|
|
IN CHAR8 *CallerName
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINTN BlockSize;
|
|
|
|
UINT64 LastBlock;
|
|
|
|
INT64 DistanceToMove;
|
|
|
|
UINT64 DistanceMoved;
|
|
|
|
|
|
|
|
if (Private->fd < 0) {
|
2011-06-03 05:31:32 +02:00
|
|
|
Status = EmuBlockIoOpenDevice (Private);
|
2011-05-31 22:23:36 +02:00
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
if (!Private->Media->MediaPresent) {
|
2011-05-31 22:23:36 +02:00
|
|
|
DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName));
|
|
|
|
return EFI_NO_MEDIA;
|
|
|
|
}
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
if (Private->Media->MediaId != MediaId) {
|
2011-05-31 22:23:36 +02:00
|
|
|
return EFI_MEDIA_CHANGED;
|
|
|
|
}
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
if ((UINTN) Buffer % Private->Media->IoAlign != 0) {
|
2011-05-31 22:23:36 +02:00
|
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
}
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-05-31 22:23:36 +02:00
|
|
|
//
|
|
|
|
// Verify buffer size
|
|
|
|
//
|
2011-06-07 04:28:08 +02:00
|
|
|
BlockSize = Private->Media->BlockSize;
|
2011-05-31 22:23:36 +02:00
|
|
|
if (BufferSize == 0) {
|
|
|
|
DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName));
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((BufferSize % BlockSize) != 0) {
|
|
|
|
DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName));
|
|
|
|
return EFI_BAD_BUFFER_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
LastBlock = Lba + (BufferSize / BlockSize) - 1;
|
2011-06-07 04:28:08 +02:00
|
|
|
if (LastBlock > Private->Media->LastBlock) {
|
2011-05-31 22:23:36 +02:00
|
|
|
DEBUG ((EFI_D_INIT, "ReadBlocks: Attempted to read off end of device\n"));
|
|
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// Seek to End of File
|
|
|
|
//
|
|
|
|
DistanceToMove = MultU64x32 (Lba, BlockSize);
|
|
|
|
Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, SEEK_SET);
|
|
|
|
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n"));
|
2011-06-03 05:31:32 +02:00
|
|
|
return EmuBlockIoError (Private);
|
2011-05-31 22:23:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
/**
|
|
|
|
Read BufferSize bytes from Lba into Buffer.
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
This function reads the requested number of blocks from the device. All the
|
|
|
|
blocks are read, or an error is returned.
|
|
|
|
If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_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.
|
2011-06-28 18:50:26 +02:00
|
|
|
@param[in] MediaId Id of the media, changes every time the media is
|
2011-06-03 05:31:32 +02:00
|
|
|
replaced.
|
|
|
|
@param[in] Lba The starting Logical Block Address to read from.
|
2018-08-29 05:39:06 +02:00
|
|
|
@param[in, out] Token A pointer to the token associated with the transaction.
|
2011-06-28 18:50:26 +02:00
|
|
|
@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
|
2011-06-03 05:31:32 +02:00
|
|
|
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 performing
|
|
|
|
the read.
|
|
|
|
@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.
|
2011-06-28 18:50:26 +02:00
|
|
|
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
|
2011-06-03 05:31:32 +02:00
|
|
|
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.
|
2011-05-31 22:23:36 +02:00
|
|
|
**/
|
2011-06-03 05:31:32 +02:00
|
|
|
EFI_STATUS
|
|
|
|
EmuBlockIoReadBlocks (
|
|
|
|
IN EMU_BLOCK_IO_PROTOCOL *This,
|
|
|
|
IN UINT32 MediaId,
|
|
|
|
IN EFI_LBA LBA,
|
|
|
|
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
|
|
|
|
IN UINTN BufferSize,
|
|
|
|
OUT VOID *Buffer
|
|
|
|
)
|
2011-05-31 22:23:36 +02:00
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
2011-06-03 05:31:32 +02:00
|
|
|
EMU_BLOCK_IO_PRIVATE *Private;
|
|
|
|
ssize_t len;
|
2011-05-31 22:23:36 +02:00
|
|
|
|
|
|
|
Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
Status = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixReadBlocks");
|
2011-05-31 22:23:36 +02:00
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
len = read (Private->fd, Buffer, BufferSize);
|
2011-05-31 22:23:36 +02:00
|
|
|
if (len != BufferSize) {
|
|
|
|
DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed.\n"));
|
2011-06-03 05:31:32 +02:00
|
|
|
Status = EmuBlockIoError (Private);
|
2011-05-31 22:23:36 +02:00
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
2011-06-03 05:31:32 +02:00
|
|
|
// If we read then media is present.
|
2011-05-31 22:23:36 +02:00
|
|
|
//
|
2011-06-03 05:31:32 +02:00
|
|
|
Private->Media->MediaPresent = TRUE;
|
2011-05-31 22:23:36 +02:00
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
|
|
|
|
Done:
|
2011-06-03 05:31:32 +02:00
|
|
|
if (Token != NULL) {
|
|
|
|
if (Token->Event != NULL) {
|
|
|
|
// Caller is responcible for signaling EFI Event
|
|
|
|
Token->TransactionStatus = Status;
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
2011-05-31 22:23:36 +02:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
/**
|
|
|
|
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.
|
2011-06-28 18:50:26 +02:00
|
|
|
@retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
|
2011-06-03 05:31:32 +02:00
|
|
|
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.
|
2011-05-31 22:23:36 +02:00
|
|
|
|
|
|
|
**/
|
2011-06-03 05:31:32 +02:00
|
|
|
EFI_STATUS
|
|
|
|
EmuBlockIoWriteBlocks (
|
|
|
|
IN EMU_BLOCK_IO_PROTOCOL *This,
|
|
|
|
IN UINT32 MediaId,
|
|
|
|
IN EFI_LBA LBA,
|
|
|
|
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
|
|
|
|
IN UINTN BufferSize,
|
|
|
|
IN VOID *Buffer
|
|
|
|
)
|
2011-05-31 22:23:36 +02:00
|
|
|
{
|
2011-06-03 05:31:32 +02:00
|
|
|
EMU_BLOCK_IO_PRIVATE *Private;
|
2011-05-31 22:23:36 +02:00
|
|
|
ssize_t len;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
|
|
|
|
Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
Status = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixWriteBlocks");
|
2011-05-31 22:23:36 +02:00
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
len = write (Private->fd, Buffer, BufferSize);
|
2011-05-31 22:23:36 +02:00
|
|
|
if (len != BufferSize) {
|
|
|
|
DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed.\n"));
|
2011-06-03 05:31:32 +02:00
|
|
|
Status = EmuBlockIoError (Private);
|
2011-05-31 22:23:36 +02:00
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// If the write succeeded, we are not write protected and media is present.
|
|
|
|
//
|
2011-06-03 05:31:32 +02:00
|
|
|
Private->Media->MediaPresent = TRUE;
|
|
|
|
Private->Media->ReadOnly = FALSE;
|
2011-05-31 22:23:36 +02:00
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
|
|
|
|
Done:
|
2011-06-03 05:31:32 +02:00
|
|
|
if (Token != NULL) {
|
|
|
|
if (Token->Event != NULL) {
|
|
|
|
// Caller is responcible for signaling EFI Event
|
|
|
|
Token->TransactionStatus = Status;
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-31 22:23:36 +02:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
/**
|
|
|
|
Flush the Block Device.
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
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
|
2011-06-28 18:50:26 +02:00
|
|
|
this request will not be signaled.
|
2011-06-03 05:31:32 +02:00
|
|
|
|
|
|
|
@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 writting back
|
|
|
|
the 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.
|
2011-05-31 22:23:36 +02:00
|
|
|
|
|
|
|
**/
|
2011-06-03 05:31:32 +02:00
|
|
|
EFI_STATUS
|
|
|
|
EmuBlockIoFlushBlocks (
|
|
|
|
IN EMU_BLOCK_IO_PROTOCOL *This,
|
|
|
|
IN OUT EFI_BLOCK_IO2_TOKEN *Token
|
|
|
|
)
|
2011-05-31 22:23:36 +02:00
|
|
|
{
|
2011-06-03 05:31:32 +02:00
|
|
|
EMU_BLOCK_IO_PRIVATE *Private;
|
|
|
|
|
|
|
|
Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
|
|
|
|
if (Private->fd >= 0) {
|
2011-06-17 23:43:45 +02:00
|
|
|
fsync (Private->fd);
|
|
|
|
#if __APPLE__
|
|
|
|
fcntl (Private->fd, F_FULLFSYNC);
|
|
|
|
#endif
|
2011-06-03 05:31:32 +02:00
|
|
|
}
|
2011-06-28 18:50:26 +02:00
|
|
|
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
if (Token != NULL) {
|
|
|
|
if (Token->Event != NULL) {
|
|
|
|
// Caller is responcible for signaling EFI Event
|
|
|
|
Token->TransactionStatus = EFI_SUCCESS;
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-05-31 22:23:36 +02:00
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
Reset the block device hardware.
|
|
|
|
|
|
|
|
@param[in] This Indicates a pointer to the calling context.
|
|
|
|
@param[in] ExtendedVerification Indicates that the driver may perform a more
|
|
|
|
exhausive verfication operation of the device
|
|
|
|
during reset.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS The device was reset.
|
|
|
|
@retval EFI_DEVICE_ERROR The device is not functioning properly and could
|
|
|
|
not be reset.
|
|
|
|
|
|
|
|
**/
|
2011-05-31 22:23:36 +02:00
|
|
|
EFI_STATUS
|
2011-06-03 05:31:32 +02:00
|
|
|
EmuBlockIoReset (
|
|
|
|
IN EMU_BLOCK_IO_PROTOCOL *This,
|
|
|
|
IN BOOLEAN ExtendedVerification
|
2011-05-31 22:23:36 +02:00
|
|
|
)
|
|
|
|
{
|
|
|
|
EMU_BLOCK_IO_PRIVATE *Private;
|
|
|
|
|
|
|
|
Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
|
|
|
|
if (Private->fd >= 0) {
|
2011-06-03 05:31:32 +02:00
|
|
|
close (Private->fd);
|
2011-05-31 22:23:36 +02:00
|
|
|
Private->fd = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
char *
|
|
|
|
StdDupUnicodeToAscii (
|
|
|
|
IN CHAR16 *Str
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN Size;
|
|
|
|
char *Ascii;
|
|
|
|
char *Ptr;
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
Size = StrLen (Str) + 1;
|
|
|
|
Ascii = malloc (Size);
|
|
|
|
if (Ascii == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
for (Ptr = Ascii; *Str != '\0'; Ptr++, Str++) {
|
|
|
|
*Ptr = *Str;
|
|
|
|
}
|
|
|
|
*Ptr = 0;
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
return Ascii;
|
|
|
|
}
|
2011-05-31 22:23:36 +02:00
|
|
|
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
EMU_BLOCK_IO_PROTOCOL gEmuBlockIoProtocol = {
|
|
|
|
GasketEmuBlockIoReset,
|
|
|
|
GasketEmuBlockIoReadBlocks,
|
|
|
|
GasketEmuBlockIoWriteBlocks,
|
|
|
|
GasketEmuBlockIoFlushBlocks,
|
|
|
|
GasketEmuBlockIoCreateMapping
|
|
|
|
};
|
2011-05-31 22:23:36 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
EFI_STATUS
|
|
|
|
EmuBlockIoThunkOpen (
|
|
|
|
IN EMU_IO_THUNK_PROTOCOL *This
|
|
|
|
)
|
2011-05-31 22:23:36 +02:00
|
|
|
{
|
2011-06-03 05:31:32 +02:00
|
|
|
EMU_BLOCK_IO_PRIVATE *Private;
|
|
|
|
char *Str;
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
if (This->Private != NULL) {
|
|
|
|
return EFI_ALREADY_STARTED;
|
2011-05-31 22:23:36 +02:00
|
|
|
}
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {
|
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
Private = malloc (sizeof (EMU_BLOCK_IO_PRIVATE));
|
|
|
|
if (Private == NULL) {
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
2011-05-31 22:23:36 +02:00
|
|
|
}
|
|
|
|
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
Private->Signature = EMU_BLOCK_IO_PRIVATE_SIGNATURE;
|
|
|
|
Private->Thunk = This;
|
|
|
|
CopyMem (&Private->EmuBlockIo, &gEmuBlockIoProtocol, sizeof (gEmuBlockIoProtocol));
|
2011-06-17 18:18:14 +02:00
|
|
|
Private->fd = -1;
|
|
|
|
Private->BlockSize = 512;
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
Private->Filename = StdDupUnicodeToAscii (This->ConfigString);
|
|
|
|
if (Private->Filename == NULL) {
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
}
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
Str = strstr (Private->Filename, ":");
|
|
|
|
if (Str == NULL) {
|
|
|
|
Private->RemovableMedia = FALSE;
|
|
|
|
Private->WriteProtected = FALSE;
|
|
|
|
} else {
|
|
|
|
for (*Str++ = '\0'; *Str != 0; Str++) {
|
|
|
|
if (*Str == 'R' || *Str == 'F') {
|
|
|
|
Private->RemovableMedia = (BOOLEAN) (*Str == 'R');
|
|
|
|
}
|
|
|
|
if (*Str == 'O' || *Str == 'W') {
|
|
|
|
Private->WriteProtected = (BOOLEAN) (*Str == 'O');
|
|
|
|
}
|
2011-06-17 18:18:14 +02:00
|
|
|
if (*Str == ':') {
|
|
|
|
Private->BlockSize = strtol (++Str, NULL, 0);
|
|
|
|
break;
|
|
|
|
}
|
2011-06-03 05:31:32 +02:00
|
|
|
}
|
|
|
|
}
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2012-01-07 01:30:52 +01:00
|
|
|
Private->Mode = Private->WriteProtected ? O_RDONLY : O_RDWR;
|
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
This->Interface = &Private->EmuBlockIo;
|
|
|
|
This->Private = Private;
|
|
|
|
return EFI_SUCCESS;
|
2011-05-31 22:23:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EFI_STATUS
|
2011-06-03 05:31:32 +02:00
|
|
|
EmuBlockIoThunkClose (
|
|
|
|
IN EMU_IO_THUNK_PROTOCOL *This
|
2011-05-31 22:23:36 +02:00
|
|
|
)
|
|
|
|
{
|
2011-06-03 05:31:32 +02:00
|
|
|
EMU_BLOCK_IO_PRIVATE *Private;
|
2011-05-31 22:23:36 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {
|
|
|
|
return EFI_UNSUPPORTED;
|
2011-05-31 22:23:36 +02:00
|
|
|
}
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
Private = This->Private;
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
if (This->Private != NULL) {
|
|
|
|
if (Private->Filename != NULL) {
|
|
|
|
free (Private->Filename);
|
2011-06-28 18:50:26 +02:00
|
|
|
}
|
2011-06-03 05:31:32 +02:00
|
|
|
free (This->Private);
|
2011-06-09 00:31:29 +02:00
|
|
|
This->Private = NULL;
|
2011-05-31 22:23:36 +02:00
|
|
|
}
|
2011-06-28 18:50:26 +02:00
|
|
|
|
2011-06-03 05:31:32 +02:00
|
|
|
return EFI_SUCCESS;
|
2011-05-31 22:23:36 +02:00
|
|
|
}
|
2011-06-03 05:31:32 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
EMU_IO_THUNK_PROTOCOL gBlockIoThunkIo = {
|
|
|
|
&gEmuBlockIoProtocolGuid,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
GasketBlockIoThunkOpen,
|
|
|
|
GasketBlockIoThunkClose,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
|