diff options
Diffstat (limited to 'UnixPkg/UnixBlockIoDxe/UnixBlockIo.c')
-rw-r--r-- | UnixPkg/UnixBlockIoDxe/UnixBlockIo.c | 1307 |
1 files changed, 1307 insertions, 0 deletions
diff --git a/UnixPkg/UnixBlockIoDxe/UnixBlockIo.c b/UnixPkg/UnixBlockIoDxe/UnixBlockIo.c new file mode 100644 index 0000000..d92ab72 --- /dev/null +++ b/UnixPkg/UnixBlockIoDxe/UnixBlockIo.c @@ -0,0 +1,1307 @@ +/*++
+
+Copyright (c) 2004 - 2007, 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,
+ 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;
+}
+
+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, 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;
+}
+
+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;
+ 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;
+}
+
+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;
+ 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;
+}
+
+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;
+ 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;
+
+ res = Private->UnixThunk->Lseek(Private->fd, DistanceToMove, MoveMethod);
+ if (res == -1) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ if (NewFilePointer != NULL) {
+ *NewFilePointer = res;
+ }
+
+ return Status;
+}
|