mirror of https://github.com/acidanthera/audk.git
1288 lines
31 KiB
C
1288 lines
31 KiB
C
/*++
|
|
|
|
Copyright (c) 2004 - 2005, Intel Corporation
|
|
All rights reserved. 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.
|
|
|
|
Module Name:
|
|
|
|
UnixBlockIo.c
|
|
|
|
Abstract:
|
|
|
|
Produce block IO abstractions for real devices on your PC using Posix APIs.
|
|
The configuration of what devices to mount or emulate comes from UNIX
|
|
environment variables. The variables must be visible to the Microsoft*
|
|
Developer Studio for them to work.
|
|
|
|
<F>ixed - Fixed disk like a hard drive.
|
|
<R>emovable - Removable media like a floppy or CD-ROM.
|
|
Read <O>nly - Write protected device.
|
|
Read <W>rite - Read write device.
|
|
<block count> - Decimal number of blocks a device supports.
|
|
<block size> - Decimal number of bytes per block.
|
|
|
|
UNIX envirnonment variable contents. '<' and '>' are not part of the variable,
|
|
they are just used to make this help more readable. There should be no
|
|
spaces between the ';'. Extra spaces will break the variable. A '!' is
|
|
used to seperate multiple devices in a variable.
|
|
|
|
EFI_UNIX_VIRTUAL_DISKS =
|
|
<F | R><O | W>;<block count>;<block size>[!...]
|
|
|
|
EFI_UNIX_PHYSICAL_DISKS =
|
|
<drive letter>:<F | R><O | W>;<block count>;<block size>[!...]
|
|
|
|
Virtual Disks: These devices use a file to emulate a hard disk or removable
|
|
media device.
|
|
|
|
Thus a 20 MB emulated hard drive would look like:
|
|
EFI_UNIX_VIRTUAL_DISKS=FW;40960;512
|
|
|
|
A 1.44MB emulated floppy with a block size of 1024 would look like:
|
|
EFI_UNIX_VIRTUAL_DISKS=RW;1440;1024
|
|
|
|
Physical Disks: These devices use UNIX to open a real device in your system
|
|
|
|
Thus a 120 MB floppy would look like:
|
|
EFI_UNIX_PHYSICAL_DISKS=B:RW;245760;512
|
|
|
|
Thus a standard CD-ROM floppy would look like:
|
|
EFI_UNIX_PHYSICAL_DISKS=Z:RO;307200;2048
|
|
|
|
|
|
* Other names and brands may be claimed as the property of others.
|
|
|
|
--*/
|
|
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include "UnixBlockIo.h"
|
|
|
|
//
|
|
// Block IO protocol member functions
|
|
//
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UnixBlockIoReadBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
IN UINT32 MediaId,
|
|
IN EFI_LBA Lba,
|
|
IN UINTN BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
This - TODO: add argument description
|
|
MediaId - TODO: add argument description
|
|
Lba - TODO: add argument description
|
|
BufferSize - TODO: add argument description
|
|
Buffer - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
;
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UnixBlockIoWriteBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
IN UINT32 MediaId,
|
|
IN EFI_LBA Lba,
|
|
IN UINTN BufferSize,
|
|
IN VOID *Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
This - TODO: add argument description
|
|
MediaId - TODO: add argument description
|
|
Lba - TODO: add argument description
|
|
BufferSize - TODO: add argument description
|
|
Buffer - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
;
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UnixBlockIoFlushBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
This - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
;
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UnixBlockIoResetBlock (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
IN BOOLEAN ExtendedVerification
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
This - TODO: add argument description
|
|
ExtendedVerification - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
;
|
|
|
|
//
|
|
// Private Worker functions
|
|
//
|
|
STATIC
|
|
EFI_STATUS
|
|
UnixBlockIoCreateMapping (
|
|
IN EFI_UNIX_IO_PROTOCOL *UnixIo,
|
|
IN EFI_HANDLE EfiDeviceHandle,
|
|
IN CHAR16 *Filename,
|
|
IN BOOLEAN ReadOnly,
|
|
IN BOOLEAN RemovableMedia,
|
|
IN UINTN NumberOfBlocks,
|
|
IN UINTN BlockSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
UnixIo - TODO: add argument description
|
|
EfiDeviceHandle - TODO: add argument description
|
|
Filename - TODO: add argument description
|
|
ReadOnly - TODO: add argument description
|
|
RemovableMedia - TODO: add argument description
|
|
NumberOfBlocks - TODO: add argument description
|
|
BlockSize - TODO: add argument description
|
|
DeviceType - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
;
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
UnixBlockIoReadWriteCommon (
|
|
IN UNIX_BLOCK_IO_PRIVATE *Private,
|
|
IN UINT32 MediaId,
|
|
IN EFI_LBA Lba,
|
|
IN UINTN BufferSize,
|
|
IN VOID *Buffer,
|
|
IN CHAR8 *CallerName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
Private - TODO: add argument description
|
|
MediaId - TODO: add argument description
|
|
Lba - TODO: add argument description
|
|
BufferSize - TODO: add argument description
|
|
Buffer - TODO: add argument description
|
|
CallerName - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
;
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
UnixBlockIoError (
|
|
IN UNIX_BLOCK_IO_PRIVATE *Private
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
Private - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
;
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
UnixBlockIoOpenDevice (
|
|
UNIX_BLOCK_IO_PRIVATE *Private
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
Private - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
;
|
|
|
|
STATIC
|
|
CHAR16 *
|
|
GetNextElementPastTerminator (
|
|
IN CHAR16 *EnvironmentVariable,
|
|
IN CHAR16 Terminator
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
EnvironmentVariable - TODO: add argument description
|
|
Terminator - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
;
|
|
EFI_DRIVER_BINDING_PROTOCOL gUnixBlockIoDriverBinding = {
|
|
UnixBlockIoDriverBindingSupported,
|
|
UnixBlockIoDriverBindingStart,
|
|
UnixBlockIoDriverBindingStop,
|
|
0x10,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UnixBlockIoDriverBindingSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Handle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: This - add argument and description to function comment
|
|
// TODO: Handle - add argument and description to function comment
|
|
// TODO: RemainingDevicePath - add argument and description to function comment
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_UNIX_IO_PROTOCOL *UnixIo;
|
|
|
|
//
|
|
// Open the IO Abstraction(s) needed to perform the supported test
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Handle,
|
|
&gEfiUnixIoProtocolGuid,
|
|
(VOID **)&UnixIo,
|
|
This->DriverBindingHandle,
|
|
Handle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Make sure the UnixThunkProtocol is valid
|
|
//
|
|
Status = EFI_UNSUPPORTED;
|
|
if (UnixIo->UnixThunk->Signature == EFI_UNIX_THUNK_PROTOCOL_SIGNATURE) {
|
|
|
|
//
|
|
// Check the GUID to see if this is a handle type the driver supports
|
|
//
|
|
if (CompareGuid (UnixIo->TypeGuid, &gEfiUnixVirtualDisksGuid) ) {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Close the I/O Abstraction(s) used to perform the supported test
|
|
//
|
|
gBS->CloseProtocol (
|
|
Handle,
|
|
&gEfiUnixIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Handle
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UnixBlockIoDriverBindingStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Handle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: This - add argument and description to function comment
|
|
// TODO: Handle - add argument and description to function comment
|
|
// TODO: RemainingDevicePath - add argument and description to function comment
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_UNIX_IO_PROTOCOL *UnixIo;
|
|
CHAR16 Buffer[FILENAME_BUFFER_SIZE];
|
|
CHAR16 *Str;
|
|
BOOLEAN RemovableMedia;
|
|
BOOLEAN WriteProtected;
|
|
UINTN NumberOfBlocks;
|
|
UINTN BlockSize;
|
|
INTN i;
|
|
|
|
//
|
|
// Grab the protocols we need
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Handle,
|
|
&gEfiUnixIoProtocolGuid,
|
|
(void *)&UnixIo,
|
|
This->DriverBindingHandle,
|
|
Handle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Set DiskType
|
|
//
|
|
if (!CompareGuid (UnixIo->TypeGuid, &gEfiUnixVirtualDisksGuid)) {
|
|
Status = EFI_UNSUPPORTED;
|
|
goto Done;
|
|
}
|
|
|
|
Status = EFI_NOT_FOUND;
|
|
// Extract filename.
|
|
Str = UnixIo->EnvString;
|
|
i = 0;
|
|
while (*Str && *Str != ':')
|
|
Buffer[i++] = *Str++;
|
|
Buffer[i] = 0;
|
|
if (*Str != ':') {
|
|
goto Done;
|
|
}
|
|
|
|
Str++;
|
|
|
|
RemovableMedia = FALSE;
|
|
WriteProtected = TRUE;
|
|
NumberOfBlocks = 0;
|
|
BlockSize = 512;
|
|
do {
|
|
if (*Str == 'R' || *Str == 'F') {
|
|
RemovableMedia = (BOOLEAN) (*Str == 'R');
|
|
Str++;
|
|
}
|
|
if (*Str == 'O' || *Str == 'W') {
|
|
WriteProtected = (BOOLEAN) (*Str == 'O');
|
|
Str++;
|
|
}
|
|
if (*Str == 0)
|
|
break;
|
|
if (*Str != ';')
|
|
goto Done;
|
|
Str++;
|
|
|
|
NumberOfBlocks = Atoi (Str);
|
|
Str = GetNextElementPastTerminator (Str, ';');
|
|
if (NumberOfBlocks == 0)
|
|
break;
|
|
|
|
BlockSize = Atoi (Str);
|
|
if (BlockSize != 0)
|
|
Str = GetNextElementPastTerminator (Str, ';');
|
|
} while (0);
|
|
|
|
//
|
|
// If we get here the variable is valid so do the work.
|
|
//
|
|
Status = UnixBlockIoCreateMapping (
|
|
UnixIo,
|
|
Handle,
|
|
Buffer,
|
|
WriteProtected,
|
|
RemovableMedia,
|
|
NumberOfBlocks,
|
|
BlockSize
|
|
);
|
|
|
|
Done:
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->CloseProtocol (
|
|
Handle,
|
|
&gEfiUnixIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Handle
|
|
);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UnixBlockIoDriverBindingStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Handle,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
This - TODO: add argument description
|
|
Handle - TODO: add argument description
|
|
NumberOfChildren - TODO: add argument description
|
|
ChildHandleBuffer - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_UNSUPPORTED - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
|
EFI_STATUS Status;
|
|
UNIX_BLOCK_IO_PRIVATE *Private;
|
|
|
|
//
|
|
// Get our context back
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Handle,
|
|
&gEfiBlockIoProtocolGuid,
|
|
(void *)&BlockIo,
|
|
This->DriverBindingHandle,
|
|
Handle,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (BlockIo);
|
|
|
|
//
|
|
// BugBug: If we need to kick people off, we need to make Uninstall Close the handles.
|
|
// We could pass in our image handle or FLAG our open to be closed via
|
|
// Unistall (== to saying any CloseProtocol will close our open)
|
|
//
|
|
Status = gBS->UninstallMultipleProtocolInterfaces (
|
|
Private->EfiHandle,
|
|
&gEfiBlockIoProtocolGuid,
|
|
&Private->BlockIo,
|
|
NULL
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
Status = gBS->CloseProtocol (
|
|
Handle,
|
|
&gEfiUnixIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Handle
|
|
);
|
|
|
|
//
|
|
// Shut down our device
|
|
//
|
|
Private->UnixThunk->Close (Private->fd);
|
|
|
|
//
|
|
// Free our instance data
|
|
//
|
|
FreeUnicodeStringTable (Private->ControllerNameTable);
|
|
|
|
gBS->FreePool (Private);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
CHAR16 *
|
|
GetNextElementPastTerminator (
|
|
IN CHAR16 *EnvironmentVariable,
|
|
IN CHAR16 Terminator
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Worker function to parse environment variables.
|
|
|
|
Arguments:
|
|
EnvironmentVariable - Envirnment variable to parse.
|
|
|
|
Terminator - Terminator to parse for.
|
|
|
|
Returns:
|
|
|
|
Pointer to next eliment past the first occurence of Terminator or the '\0'
|
|
at the end of the string.
|
|
|
|
--*/
|
|
{
|
|
CHAR16 *Ptr;
|
|
|
|
for (Ptr = EnvironmentVariable; *Ptr != '\0'; Ptr++) {
|
|
if (*Ptr == Terminator) {
|
|
Ptr++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Ptr;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
UnixBlockIoCreateMapping (
|
|
IN EFI_UNIX_IO_PROTOCOL *UnixIo,
|
|
IN EFI_HANDLE EfiDeviceHandle,
|
|
IN CHAR16 *Filename,
|
|
IN BOOLEAN ReadOnly,
|
|
IN BOOLEAN RemovableMedia,
|
|
IN UINTN NumberOfBlocks,
|
|
IN UINTN BlockSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
UnixIo - TODO: add argument description
|
|
EfiDeviceHandle - TODO: add argument description
|
|
Filename - TODO: add argument description
|
|
ReadOnly - TODO: add argument description
|
|
RemovableMedia - TODO: add argument description
|
|
NumberOfBlocks - TODO: add argument description
|
|
BlockSize - TODO: add argument description
|
|
DeviceType - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
|
UNIX_BLOCK_IO_PRIVATE *Private;
|
|
UINTN Index;
|
|
|
|
Status = gBS->AllocatePool (
|
|
EfiBootServicesData,
|
|
sizeof (UNIX_BLOCK_IO_PRIVATE),
|
|
(void *)&Private
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
EfiInitializeLock (&Private->Lock, EFI_TPL_NOTIFY);
|
|
|
|
Private->UnixThunk = UnixIo->UnixThunk;
|
|
|
|
Private->Signature = UNIX_BLOCK_IO_PRIVATE_SIGNATURE;
|
|
Private->LastBlock = NumberOfBlocks - 1;
|
|
Private->BlockSize = BlockSize;
|
|
|
|
for (Index = 0; Filename[Index] != 0; Index++) {
|
|
Private->Filename[Index] = Filename[Index];
|
|
}
|
|
|
|
Private->Filename[Index] = 0;
|
|
|
|
Private->Mode = (ReadOnly ? O_RDONLY : O_RDWR);
|
|
|
|
Private->NumberOfBlocks = NumberOfBlocks;
|
|
Private->fd = -1;
|
|
|
|
Private->ControllerNameTable = NULL;
|
|
|
|
AddUnicodeString (
|
|
"eng",
|
|
gUnixBlockIoComponentName.SupportedLanguages,
|
|
&Private->ControllerNameTable,
|
|
Filename
|
|
);
|
|
|
|
BlockIo = &Private->BlockIo;
|
|
BlockIo->Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
|
|
BlockIo->Media = &Private->Media;
|
|
BlockIo->Media->BlockSize = Private->BlockSize;
|
|
BlockIo->Media->LastBlock = Private->NumberOfBlocks - 1;
|
|
BlockIo->Media->MediaId = 0;;
|
|
|
|
BlockIo->Reset = UnixBlockIoResetBlock;
|
|
BlockIo->ReadBlocks = UnixBlockIoReadBlocks;
|
|
BlockIo->WriteBlocks = UnixBlockIoWriteBlocks;
|
|
BlockIo->FlushBlocks = UnixBlockIoFlushBlocks;
|
|
|
|
BlockIo->Media->ReadOnly = ReadOnly;
|
|
BlockIo->Media->RemovableMedia = RemovableMedia;
|
|
BlockIo->Media->LogicalPartition = FALSE;
|
|
BlockIo->Media->MediaPresent = TRUE;
|
|
BlockIo->Media->WriteCaching = FALSE;
|
|
|
|
BlockIo->Media->IoAlign = 1;
|
|
|
|
Private->EfiHandle = EfiDeviceHandle;
|
|
Status = UnixBlockIoOpenDevice (Private);
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&Private->EfiHandle,
|
|
&gEfiBlockIoProtocolGuid,
|
|
&Private->BlockIo,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
FreeUnicodeStringTable (Private->ControllerNameTable);
|
|
gBS->FreePool (Private);
|
|
}
|
|
|
|
DEBUG ((EFI_D_INIT, "BlockDevice added: %s\n", Filename));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
UnixBlockIoOpenDevice (
|
|
UNIX_BLOCK_IO_PRIVATE *Private
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
Private - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT64 FileSize;
|
|
UINT64 EndOfFile;
|
|
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
|
|
|
BlockIo = &Private->BlockIo;
|
|
EfiAcquireLock (&Private->Lock);
|
|
|
|
//
|
|
// If the device is already opened, close it
|
|
//
|
|
if (Private->fd >= 0) {
|
|
BlockIo->Reset (BlockIo, FALSE);
|
|
}
|
|
|
|
//
|
|
// Open the device
|
|
//
|
|
Private->fd = Private->UnixThunk->Open
|
|
(Private->Filename, Private->Mode, 0644);
|
|
|
|
if (Private->fd < 0) {
|
|
DEBUG ((EFI_D_INFO, "PlOpenBlock: Could not open %s\n",
|
|
Private->Filename));
|
|
BlockIo->Media->MediaPresent = FALSE;
|
|
Status = EFI_NO_MEDIA;
|
|
goto Done;
|
|
}
|
|
|
|
if (!BlockIo->Media->MediaPresent) {
|
|
//
|
|
// BugBug: try to emulate if a CD appears - notify drivers to check it out
|
|
//
|
|
BlockIo->Media->MediaPresent = TRUE;
|
|
EfiReleaseLock (&Private->Lock);
|
|
EfiAcquireLock (&Private->Lock);
|
|
}
|
|
|
|
//
|
|
// get the size of the file
|
|
//
|
|
Status = SetFilePointer64 (Private, 0, &FileSize, SEEK_END);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
FileSize = MultU64x32 (Private->NumberOfBlocks, Private->BlockSize);
|
|
DEBUG ((EFI_D_ERROR, "PlOpenBlock: Could not get filesize of %s\n", Private->Filename));
|
|
Status = EFI_UNSUPPORTED;
|
|
goto Done;
|
|
}
|
|
|
|
if (Private->NumberOfBlocks == 0) {
|
|
Private->NumberOfBlocks = DivU64x32 (FileSize, Private->BlockSize);
|
|
}
|
|
|
|
EndOfFile = MultU64x32 (Private->NumberOfBlocks, Private->BlockSize);
|
|
|
|
if (FileSize != EndOfFile) {
|
|
//
|
|
// file is not the proper size, change it
|
|
//
|
|
DEBUG ((EFI_D_INIT, "PlOpenBlock: Initializing block device: %a\n", Private->Filename));
|
|
|
|
//
|
|
// first set it to 0
|
|
//
|
|
Private->UnixThunk->FTruncate (Private->fd, 0);
|
|
|
|
//
|
|
// then set it to the needed file size (OS will zero fill it)
|
|
//
|
|
Private->UnixThunk->FTruncate (Private->fd, EndOfFile);
|
|
}
|
|
|
|
DEBUG ((EFI_D_INIT, "%HPlOpenBlock: opened %s%N\n", Private->Filename));
|
|
Status = EFI_SUCCESS;
|
|
|
|
Done:
|
|
if (EFI_ERROR (Status)) {
|
|
if (Private->fd >= 0) {
|
|
BlockIo->Reset (BlockIo, FALSE);
|
|
}
|
|
}
|
|
|
|
EfiReleaseLock (&Private->Lock);
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
UnixBlockIoError (
|
|
IN UNIX_BLOCK_IO_PRIVATE *Private
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
Private - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
return EFI_DEVICE_ERROR;
|
|
|
|
#if 0
|
|
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
|
EFI_STATUS Status;
|
|
BOOLEAN ReinstallBlockIoFlag;
|
|
|
|
|
|
BlockIo = &Private->BlockIo;
|
|
|
|
switch (Private->UnixThunk->GetLastError ()) {
|
|
|
|
case ERROR_NOT_READY:
|
|
Status = EFI_NO_MEDIA;
|
|
BlockIo->Media->ReadOnly = FALSE;
|
|
BlockIo->Media->MediaPresent = FALSE;
|
|
ReinstallBlockIoFlag = FALSE;
|
|
break;
|
|
|
|
case ERROR_WRONG_DISK:
|
|
BlockIo->Media->ReadOnly = FALSE;
|
|
BlockIo->Media->MediaPresent = TRUE;
|
|
BlockIo->Media->MediaId += 1;
|
|
ReinstallBlockIoFlag = TRUE;
|
|
Status = EFI_MEDIA_CHANGED;
|
|
break;
|
|
|
|
case ERROR_WRITE_PROTECT:
|
|
BlockIo->Media->ReadOnly = TRUE;
|
|
ReinstallBlockIoFlag = FALSE;
|
|
Status = EFI_WRITE_PROTECTED;
|
|
break;
|
|
|
|
default:
|
|
ReinstallBlockIoFlag = FALSE;
|
|
Status = EFI_DEVICE_ERROR;
|
|
break;
|
|
}
|
|
|
|
if (ReinstallBlockIoFlag) {
|
|
BlockIo->Reset (BlockIo, FALSE);
|
|
|
|
gBS->ReinstallProtocolInterface (
|
|
Private->EfiHandle,
|
|
&gEfiBlockIoProtocolGuid,
|
|
BlockIo,
|
|
BlockIo
|
|
);
|
|
}
|
|
|
|
return Status;
|
|
#endif
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
UnixBlockIoReadWriteCommon (
|
|
IN UNIX_BLOCK_IO_PRIVATE *Private,
|
|
IN UINT32 MediaId,
|
|
IN EFI_LBA Lba,
|
|
IN UINTN BufferSize,
|
|
IN VOID *Buffer,
|
|
IN CHAR8 *CallerName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
Private - TODO: add argument description
|
|
MediaId - TODO: add argument description
|
|
Lba - TODO: add argument description
|
|
BufferSize - TODO: add argument description
|
|
Buffer - TODO: add argument description
|
|
CallerName - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_NO_MEDIA - TODO: Add description for return value
|
|
EFI_MEDIA_CHANGED - TODO: Add description for return value
|
|
EFI_INVALID_PARAMETER - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
EFI_BAD_BUFFER_SIZE - TODO: Add description for return value
|
|
EFI_INVALID_PARAMETER - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN BlockSize;
|
|
UINT64 LastBlock;
|
|
INT64 DistanceToMove;
|
|
UINT64 DistanceMoved;
|
|
|
|
if (Private->fd < 0) {
|
|
Status = UnixBlockIoOpenDevice (Private);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
if (!Private->Media.MediaPresent) {
|
|
DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName));
|
|
return EFI_NO_MEDIA;
|
|
}
|
|
|
|
if (Private->Media.MediaId != MediaId) {
|
|
return EFI_MEDIA_CHANGED;
|
|
}
|
|
|
|
if ((UINT32) Buffer % Private->Media.IoAlign != 0) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Verify buffer size
|
|
//
|
|
BlockSize = Private->BlockSize;
|
|
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;
|
|
if (LastBlock > Private->LastBlock) {
|
|
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"));
|
|
return UnixBlockIoError (Private);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UnixBlockIoReadBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
IN UINT32 MediaId,
|
|
IN EFI_LBA Lba,
|
|
IN UINTN BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Read BufferSize bytes from Lba into Buffer.
|
|
|
|
Arguments:
|
|
This - Protocol instance pointer.
|
|
MediaId - Id of the media, changes every time the media is replaced.
|
|
Lba - The starting Logical Block Address to read from
|
|
BufferSize - Size of Buffer, must be a multiple of device block size.
|
|
Buffer - Buffer containing read data
|
|
|
|
Returns:
|
|
EFI_SUCCESS - The data was read correctly from the device.
|
|
EFI_DEVICE_ERROR - The device reported an error while performing the read.
|
|
EFI_NO_MEDIA - There is no media in the device.
|
|
EFI_MEDIA_CHANGED - The MediaId does not matched the current device.
|
|
EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the
|
|
device.
|
|
EFI_INVALID_PARAMETER - The read request contains device addresses that are not
|
|
valid for the device.
|
|
|
|
--*/
|
|
{
|
|
UNIX_BLOCK_IO_PRIVATE *Private;
|
|
ssize_t len;
|
|
EFI_STATUS Status;
|
|
|
|
Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
Status = UnixBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "UnixReadBlocks");
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
len = Private->UnixThunk->Read (Private->fd, Buffer, BufferSize);
|
|
if (len != BufferSize) {
|
|
DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed.\n"));
|
|
return UnixBlockIoError (Private);
|
|
}
|
|
|
|
//
|
|
// If we wrote then media is present.
|
|
//
|
|
This->Media->MediaPresent = TRUE;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UnixBlockIoWriteBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
IN UINT32 MediaId,
|
|
IN EFI_LBA Lba,
|
|
IN UINTN BufferSize,
|
|
IN VOID *Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Write BufferSize bytes from Lba into Buffer.
|
|
|
|
Arguments:
|
|
This - Protocol instance pointer.
|
|
MediaId - Id of the media, changes every time the media is replaced.
|
|
Lba - The starting Logical Block Address to read from
|
|
BufferSize - Size of Buffer, must be a multiple of device block size.
|
|
Buffer - Buffer containing read data
|
|
|
|
Returns:
|
|
EFI_SUCCESS - The data was written correctly to the device.
|
|
EFI_WRITE_PROTECTED - The device can not be written to.
|
|
EFI_DEVICE_ERROR - The device reported an error while performing the write.
|
|
EFI_NO_MEDIA - There is no media in the device.
|
|
EFI_MEDIA_CHNAGED - The MediaId does not matched the current device.
|
|
EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the
|
|
device.
|
|
EFI_INVALID_PARAMETER - The write request contains a LBA that is not
|
|
valid for the device.
|
|
|
|
--*/
|
|
{
|
|
UNIX_BLOCK_IO_PRIVATE *Private;
|
|
ssize_t len;
|
|
EFI_STATUS Status;
|
|
|
|
Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
Status = UnixBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "UnixWriteBlocks");
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
len = Private->UnixThunk->Write (Private->fd, Buffer, BufferSize);
|
|
if (len != BufferSize) {
|
|
DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed.\n"));
|
|
return UnixBlockIoError (Private);
|
|
}
|
|
|
|
//
|
|
// If the write succeeded, we are not write protected and media is present.
|
|
//
|
|
This->Media->MediaPresent = TRUE;
|
|
This->Media->ReadOnly = FALSE;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UnixBlockIoFlushBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Flush the Block Device.
|
|
|
|
Arguments:
|
|
This - Protocol instance pointer.
|
|
|
|
Returns:
|
|
EFI_SUCCESS - All outstanding data was written to the device
|
|
EFI_DEVICE_ERROR - The device reported an error while writting back the data
|
|
EFI_NO_MEDIA - There is no media in the device.
|
|
|
|
--*/
|
|
{
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UnixBlockIoResetBlock (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
IN BOOLEAN ExtendedVerification
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Reset the Block Device.
|
|
|
|
Arguments:
|
|
This - Protocol instance pointer.
|
|
ExtendedVerification - Driver may perform diagnostics on reset.
|
|
|
|
Returns:
|
|
EFI_SUCCESS - The device was reset.
|
|
EFI_DEVICE_ERROR - The device is not functioning properly and could
|
|
not be reset.
|
|
|
|
--*/
|
|
{
|
|
UNIX_BLOCK_IO_PRIVATE *Private;
|
|
|
|
Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
if (Private->fd >= 0) {
|
|
Private->UnixThunk->Close (Private->fd);
|
|
Private->fd = -1;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
UINTN
|
|
Atoi (
|
|
CHAR16 *String
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert a unicode string to a UINTN
|
|
|
|
Arguments:
|
|
|
|
String - Unicode string.
|
|
|
|
Returns:
|
|
|
|
UINTN of the number represented by String.
|
|
|
|
--*/
|
|
{
|
|
UINTN Number;
|
|
CHAR16 *Str;
|
|
|
|
//
|
|
// skip preceeding white space
|
|
//
|
|
Str = String;
|
|
while ((*Str) && (*Str == ' ')) {
|
|
Str++;
|
|
}
|
|
//
|
|
// Convert ot a Number
|
|
//
|
|
Number = 0;
|
|
while (*Str != '\0') {
|
|
if ((*Str >= '0') && (*Str <= '9')) {
|
|
Number = (Number * 10) +*Str - '0';
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
Str++;
|
|
}
|
|
|
|
return Number;
|
|
}
|
|
|
|
EFI_STATUS
|
|
SetFilePointer64 (
|
|
IN UNIX_BLOCK_IO_PRIVATE *Private,
|
|
IN INT64 DistanceToMove,
|
|
OUT UINT64 *NewFilePointer,
|
|
IN INTN MoveMethod
|
|
)
|
|
/*++
|
|
|
|
This function extends the capability of SetFilePointer to accept 64 bit parameters
|
|
|
|
--*/
|
|
// TODO: function comment is missing 'Routine Description:'
|
|
// TODO: function comment is missing 'Arguments:'
|
|
// TODO: function comment is missing 'Returns:'
|
|
// TODO: Private - add argument and description to function comment
|
|
// TODO: DistanceToMove - add argument and description to function comment
|
|
// TODO: NewFilePointer - add argument and description to function comment
|
|
// TODO: MoveMethod - add argument and description to function comment
|
|
{
|
|
EFI_STATUS Status;
|
|
off_t res;
|
|
|
|
res = Private->UnixThunk->Lseek(Private->fd, DistanceToMove, MoveMethod);
|
|
if (res == -1) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (NewFilePointer != NULL) {
|
|
*NewFilePointer = res;
|
|
}
|
|
|
|
return Status;
|
|
}
|