/*++ | |
Copyright (c) 2004 - 2009, 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 | |
// | |
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 | |
--*/ | |
; | |
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 | |
--*/ | |
; | |
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 | |
--*/ | |
; | |
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 | |
// | |
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 | |
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 | |
--*/ | |
; | |
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 | |
--*/ | |
; | |
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 | |
--*/ | |
; | |
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, | |
0xa, | |
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; | |
} | |
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; | |
} | |
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, 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_ERROR, "BlockDevice added: %s\n", Filename)); | |
} | |
return Status; | |
} | |
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 %a\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 %a\n", Private->Filename)); | |
Status = EFI_UNSUPPORTED; | |
goto Done; | |
} | |
if (Private->NumberOfBlocks == 0) { | |
Private->NumberOfBlocks = DivU64x32 (FileSize, Private->BlockSize); | |
Private->LastBlock = Private->NumberOfBlocks - 1; | |
Private->Media.LastBlock = Private->LastBlock; | |
} | |
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 %a%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; | |
} | |
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 | |
} | |
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; | |
} | |
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; | |
EFI_TPL OldTpl; | |
OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This); | |
Status = UnixBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "UnixReadBlocks"); | |
if (EFI_ERROR (Status)) { | |
goto Done; | |
} | |
len = Private->UnixThunk->Read (Private->fd, Buffer, BufferSize); | |
if (len != BufferSize) { | |
DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed.\n")); | |
Status = UnixBlockIoError (Private); | |
goto Done; | |
} | |
// | |
// If we wrote then media is present. | |
// | |
This->Media->MediaPresent = TRUE; | |
Status = EFI_SUCCESS; | |
Done: | |
gBS->RestoreTPL (OldTpl); | |
return Status; | |
} | |
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; | |
EFI_TPL OldTpl; | |
OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This); | |
Status = UnixBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "UnixWriteBlocks"); | |
if (EFI_ERROR (Status)) { | |
goto Done; | |
} | |
len = Private->UnixThunk->Write (Private->fd, Buffer, BufferSize); | |
if (len != BufferSize) { | |
DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed.\n")); | |
Status = UnixBlockIoError (Private); | |
goto Done; | |
} | |
// | |
// If the write succeeded, we are not write protected and media is present. | |
// | |
This->Media->MediaPresent = TRUE; | |
This->Media->ReadOnly = FALSE; | |
Status = EFI_SUCCESS; | |
Done: | |
gBS->RestoreTPL (OldTpl); | |
return Status; | |
} | |
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; | |
} | |
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; | |
EFI_TPL OldTpl; | |
OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This); | |
if (Private->fd >= 0) { | |
Private->UnixThunk->Close (Private->fd); | |
Private->fd = -1; | |
} | |
gBS->RestoreTPL (OldTpl); | |
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; | |
Status = EFI_SUCCESS; | |
res = Private->UnixThunk->Lseek(Private->fd, DistanceToMove, MoveMethod); | |
if (res == -1) { | |
Status = EFI_INVALID_PARAMETER; | |
} | |
if (NewFilePointer != NULL) { | |
*NewFilePointer = res; | |
} | |
return Status; | |
} |