Home | History | Annotate | Download | only in WinNtBlockIoDxe
      1 /**@file
      2 
      3 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 Module Name:
     13 
     14   WinNtBlockIo.c
     15 
     16 Abstract:
     17 
     18   Produce block IO abstractions for real devices on your PC using Win32 APIs.
     19   The configuration of what devices to mount or emulate comes from NT
     20   environment variables. The variables must be visible to the Microsoft*
     21   Developer Studio for them to work.
     22 
     23   <F>ixed       - Fixed disk like a hard drive.
     24   <R>emovable   - Removable media like a floppy or CD-ROM.
     25   Read <O>nly   - Write protected device.
     26   Read <W>rite  - Read write device.
     27   <block count> - Decimal number of blocks a device supports.
     28   <block size>  - Decimal number of bytes per block.
     29 
     30   NT envirnonment variable contents. '<' and '>' are not part of the variable,
     31   they are just used to make this help more readable. There should be no
     32   spaces between the ';'. Extra spaces will break the variable. A '!' is
     33   used to seperate multiple devices in a variable.
     34 
     35   EFI_WIN_NT_VIRTUAL_DISKS =
     36     <F | R><O | W>;<block count>;<block size>[!...]
     37 
     38   EFI_WIN_NT_PHYSICAL_DISKS =
     39     <drive letter>:<F | R><O | W>;<block count>;<block size>[!...]
     40 
     41   Virtual Disks: These devices use a file to emulate a hard disk or removable
     42                  media device.
     43 
     44     Thus a 20 MB emulated hard drive would look like:
     45     EFI_WIN_NT_VIRTUAL_DISKS=FW;40960;512
     46 
     47     A 1.44MB emulated floppy with a block size of 1024 would look like:
     48     EFI_WIN_NT_VIRTUAL_DISKS=RW;1440;1024
     49 
     50   Physical Disks: These devices use NT to open a real device in your system
     51 
     52     Thus a 120 MB floppy would look like:
     53     EFI_WIN_NT_PHYSICAL_DISKS=B:RW;245760;512
     54 
     55     Thus a standard CD-ROM floppy would look like:
     56     EFI_WIN_NT_PHYSICAL_DISKS=Z:RO;307200;2048
     57 
     58 
     59   * Other names and brands may be claimed as the property of others.
     60 
     61 **/
     62 #include <Uefi.h>
     63 #include <WinNtDxe.h>
     64 #include <Protocol/WinNtThunk.h>
     65 #include <Protocol/WinNtIo.h>
     66 #include <Protocol/BlockIo.h>
     67 #include <Protocol/ComponentName.h>
     68 #include <Protocol/DriverBinding.h>
     69 //
     70 // The Library classes this module consumes
     71 //
     72 #include <Library/DebugLib.h>
     73 #include <Library/BaseLib.h>
     74 #include <Library/UefiDriverEntryPoint.h>
     75 #include <Library/UefiLib.h>
     76 #include <Library/BaseMemoryLib.h>
     77 #include <Library/UefiBootServicesTableLib.h>
     78 #include <Library/MemoryAllocationLib.h>
     79 
     80 #include "WinNtBlockIo.h"
     81 
     82 EFI_DRIVER_BINDING_PROTOCOL gWinNtBlockIoDriverBinding = {
     83   WinNtBlockIoDriverBindingSupported,
     84   WinNtBlockIoDriverBindingStart,
     85   WinNtBlockIoDriverBindingStop,
     86   0xa,
     87   NULL,
     88   NULL
     89 };
     90 
     91 /**
     92   The user Entry Point for module WinNtBlockIo. The user code starts with this function.
     93 
     94   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
     95   @param[in] SystemTable    A pointer to the EFI System Table.
     96 
     97   @retval EFI_SUCCESS       The entry point is executed successfully.
     98   @retval other             Some error occurs when executing this entry point.
     99 
    100 **/
    101 EFI_STATUS
    102 EFIAPI
    103 InitializeWinNtBlockIo(
    104   IN EFI_HANDLE           ImageHandle,
    105   IN EFI_SYSTEM_TABLE     *SystemTable
    106   )
    107 {
    108   EFI_STATUS              Status;
    109 
    110   //
    111   // Install driver model protocol(s).
    112   //
    113   Status = EfiLibInstallAllDriverProtocols2 (
    114              ImageHandle,
    115              SystemTable,
    116              &gWinNtBlockIoDriverBinding,
    117              ImageHandle,
    118              &gWinNtBlockIoComponentName,
    119              &gWinNtBlockIoComponentName2,
    120              NULL,
    121              NULL,
    122              &gWinNtBlockIoDriverDiagnostics,
    123              &gWinNtBlockIoDriverDiagnostics2
    124              );
    125   ASSERT_EFI_ERROR (Status);
    126 
    127 
    128   return Status;
    129 }
    130 
    131 EFI_STATUS
    132 EFIAPI
    133 WinNtBlockIoDriverBindingSupported (
    134   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
    135   IN  EFI_HANDLE                   Handle,
    136   IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    137   )
    138 /*++
    139 
    140 Routine Description:
    141 
    142 Arguments:
    143 
    144 Returns:
    145 
    146   None
    147 
    148 --*/
    149 // TODO:    This - add argument and description to function comment
    150 // TODO:    Handle - add argument and description to function comment
    151 // TODO:    RemainingDevicePath - add argument and description to function comment
    152 {
    153   EFI_STATUS              Status;
    154   EFI_WIN_NT_IO_PROTOCOL  *WinNtIo;
    155 
    156   //
    157   // Open the IO Abstraction(s) needed to perform the supported test
    158   //
    159   Status = gBS->OpenProtocol (
    160                   Handle,
    161                   &gEfiWinNtIoProtocolGuid,
    162                   (VOID **) &WinNtIo,
    163                   This->DriverBindingHandle,
    164                   Handle,
    165                   EFI_OPEN_PROTOCOL_BY_DRIVER
    166                   );
    167   if (EFI_ERROR (Status)) {
    168     return Status;
    169   }
    170 
    171   //
    172   // Make sure the WinNtThunkProtocol is valid
    173   //
    174   Status = EFI_UNSUPPORTED;
    175   if (WinNtIo->WinNtThunk->Signature == EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) {
    176 
    177     //
    178     // Check the GUID to see if this is a handle type the driver supports
    179     //
    180     if (CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtVirtualDisksGuid) ||
    181         CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtPhysicalDisksGuid) ) {
    182       Status = EFI_SUCCESS;
    183     }
    184   }
    185 
    186   //
    187   // Close the I/O Abstraction(s) used to perform the supported test
    188   //
    189   gBS->CloseProtocol (
    190         Handle,
    191         &gEfiWinNtIoProtocolGuid,
    192         This->DriverBindingHandle,
    193         Handle
    194         );
    195 
    196   return Status;
    197 }
    198 
    199 EFI_STATUS
    200 EFIAPI
    201 WinNtBlockIoDriverBindingStart (
    202   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
    203   IN  EFI_HANDLE                    Handle,
    204   IN  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath
    205   )
    206 /*++
    207 
    208 Routine Description:
    209 
    210 Arguments:
    211 
    212 Returns:
    213 
    214   None
    215 
    216 --*/
    217 // TODO:    This - add argument and description to function comment
    218 // TODO:    Handle - add argument and description to function comment
    219 // TODO:    RemainingDevicePath - add argument and description to function comment
    220 {
    221   EFI_STATUS                  Status;
    222   EFI_WIN_NT_IO_PROTOCOL      *WinNtIo;
    223   WIN_NT_RAW_DISK_DEVICE_TYPE DiskType;
    224   UINT16                      Buffer[FILENAME_BUFFER_SIZE];
    225   CHAR16                      *Str;
    226   BOOLEAN                     RemovableMedia;
    227   BOOLEAN                     WriteProtected;
    228   UINTN                       NumberOfBlocks;
    229   UINTN                       BlockSize;
    230 
    231   //
    232   // Grab the protocols we need
    233   //
    234   Status = gBS->OpenProtocol (
    235                   Handle,
    236                   &gEfiWinNtIoProtocolGuid,
    237                   (VOID **) &WinNtIo,
    238                   This->DriverBindingHandle,
    239                   Handle,
    240                   EFI_OPEN_PROTOCOL_BY_DRIVER
    241                   );
    242   if (EFI_ERROR (Status)) {
    243     return Status;
    244   }
    245 
    246   //
    247   // Set DiskType
    248   //
    249   if (CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtVirtualDisksGuid)) {
    250     DiskType = EfiWinNtVirtualDisks;
    251   } else if (CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtPhysicalDisksGuid)) {
    252     DiskType = EfiWinNtPhysicalDisks;
    253   } else {
    254     Status = EFI_UNSUPPORTED;
    255     goto Done;
    256   }
    257 
    258   Status  = EFI_NOT_FOUND;
    259   Str     = WinNtIo->EnvString;
    260   if (DiskType == EfiWinNtVirtualDisks) {
    261     WinNtIo->WinNtThunk->SPrintf (
    262                           Buffer,
    263                           sizeof (Buffer),
    264                           L"Diskfile%d",
    265                           WinNtIo->InstanceNumber
    266                           );
    267   } else {
    268     if (*Str >= 'A' && *Str <= 'Z' || *Str >= 'a' && *Str <= 'z') {
    269       WinNtIo->WinNtThunk->SPrintf (Buffer, sizeof (Buffer), L"\\\\.\\%c:", *Str);
    270     } else {
    271       WinNtIo->WinNtThunk->SPrintf (Buffer, sizeof (Buffer), L"\\\\.\\PHYSICALDRIVE%c", *Str);
    272     }
    273 
    274     Str++;
    275     if (*Str != ':') {
    276       Status = EFI_NOT_FOUND;
    277       goto Done;
    278     }
    279 
    280     Str++;
    281   }
    282 
    283   if (*Str == 'R' || *Str == 'F') {
    284     RemovableMedia = (BOOLEAN) (*Str == 'R');
    285     Str++;
    286     if (*Str == 'O' || *Str == 'W') {
    287       WriteProtected  = (BOOLEAN) (*Str == 'O');
    288       Str             = GetNextElementPastTerminator (Str, ';');
    289 
    290       NumberOfBlocks  = StrDecimalToUintn (Str);
    291       if (NumberOfBlocks != 0) {
    292         Str       = GetNextElementPastTerminator (Str, ';');
    293         BlockSize = StrDecimalToUintn (Str);
    294         if (BlockSize != 0) {
    295           //
    296           // If we get here the variable is valid so do the work.
    297           //
    298           Status = WinNtBlockIoCreateMapping (
    299                     WinNtIo,
    300                     Handle,
    301                     Buffer,
    302                     WriteProtected,
    303                     RemovableMedia,
    304                     NumberOfBlocks,
    305                     BlockSize,
    306                     DiskType
    307                     );
    308 
    309         }
    310       }
    311     }
    312   }
    313 
    314 Done:
    315   if (EFI_ERROR (Status)) {
    316     gBS->CloseProtocol (
    317           Handle,
    318           &gEfiWinNtIoProtocolGuid,
    319           This->DriverBindingHandle,
    320           Handle
    321           );
    322   }
    323 
    324   return Status;
    325 }
    326 
    327 EFI_STATUS
    328 EFIAPI
    329 WinNtBlockIoDriverBindingStop (
    330   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
    331   IN  EFI_HANDLE                   Handle,
    332   IN  UINTN                        NumberOfChildren,
    333   IN  EFI_HANDLE                   *ChildHandleBuffer
    334   )
    335 /*++
    336 
    337 Routine Description:
    338 
    339   TODO: Add function description
    340 
    341 Arguments:
    342 
    343   This              - TODO: add argument description
    344   Handle            - TODO: add argument description
    345   NumberOfChildren  - TODO: add argument description
    346   ChildHandleBuffer - TODO: add argument description
    347 
    348 Returns:
    349 
    350   EFI_UNSUPPORTED - TODO: Add description for return value
    351 
    352 --*/
    353 {
    354   EFI_BLOCK_IO_PROTOCOL   *BlockIo;
    355   EFI_STATUS              Status;
    356   WIN_NT_BLOCK_IO_PRIVATE *Private;
    357 
    358   //
    359   // Get our context back
    360   //
    361   Status = gBS->OpenProtocol (
    362                   Handle,
    363                   &gEfiBlockIoProtocolGuid,
    364                   (VOID **) &BlockIo,
    365                   This->DriverBindingHandle,
    366                   Handle,
    367                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    368                   );
    369   if (EFI_ERROR (Status)) {
    370     return EFI_UNSUPPORTED;
    371   }
    372 
    373   Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (BlockIo);
    374 
    375   //
    376   // BugBug: If we need to kick people off, we need to make Uninstall Close the handles.
    377   //         We could pass in our image handle or FLAG our open to be closed via
    378   //         Unistall (== to saying any CloseProtocol will close our open)
    379   //
    380   Status = gBS->UninstallMultipleProtocolInterfaces (
    381                   Private->EfiHandle,
    382                   &gEfiBlockIoProtocolGuid,
    383                   &Private->BlockIo,
    384                   NULL
    385                   );
    386   if (!EFI_ERROR (Status)) {
    387 
    388     Status = gBS->CloseProtocol (
    389                     Handle,
    390                     &gEfiWinNtIoProtocolGuid,
    391                     This->DriverBindingHandle,
    392                     Handle
    393                     );
    394 
    395     //
    396     // Shut down our device
    397     //
    398     Private->WinNtThunk->CloseHandle (Private->NtHandle);
    399 
    400     //
    401     // Free our instance data
    402     //
    403     FreeUnicodeStringTable (Private->ControllerNameTable);
    404 
    405     FreePool (Private);
    406   }
    407 
    408   return Status;
    409 }
    410 
    411 CHAR16 *
    412 GetNextElementPastTerminator (
    413   IN  CHAR16  *EnvironmentVariable,
    414   IN  CHAR16  Terminator
    415   )
    416 /*++
    417 
    418 Routine Description:
    419 
    420   Worker function to parse environment variables.
    421 
    422 Arguments:
    423   EnvironmentVariable - Envirnment variable to parse.
    424 
    425   Terminator          - Terminator to parse for.
    426 
    427 Returns:
    428 
    429   Pointer to next eliment past the first occurence of Terminator or the '\0'
    430   at the end of the string.
    431 
    432 --*/
    433 {
    434   CHAR16  *Ptr;
    435 
    436   for (Ptr = EnvironmentVariable; *Ptr != '\0'; Ptr++) {
    437     if (*Ptr == Terminator) {
    438       Ptr++;
    439       break;
    440     }
    441   }
    442 
    443   return Ptr;
    444 }
    445 
    446 EFI_STATUS
    447 WinNtBlockIoCreateMapping (
    448   IN EFI_WIN_NT_IO_PROTOCOL             *WinNtIo,
    449   IN EFI_HANDLE                         EfiDeviceHandle,
    450   IN CHAR16                             *Filename,
    451   IN BOOLEAN                            ReadOnly,
    452   IN BOOLEAN                            RemovableMedia,
    453   IN UINTN                              NumberOfBlocks,
    454   IN UINTN                              BlockSize,
    455   IN WIN_NT_RAW_DISK_DEVICE_TYPE        DeviceType
    456   )
    457 /*++
    458 
    459 Routine Description:
    460 
    461   TODO: Add function description
    462 
    463 Arguments:
    464 
    465   WinNtIo         - TODO: add argument description
    466   EfiDeviceHandle - TODO: add argument description
    467   Filename        - TODO: add argument description
    468   ReadOnly        - TODO: add argument description
    469   RemovableMedia  - TODO: add argument description
    470   NumberOfBlocks  - TODO: add argument description
    471   BlockSize       - TODO: add argument description
    472   DeviceType      - TODO: add argument description
    473 
    474 Returns:
    475 
    476   TODO: add return values
    477 
    478 --*/
    479 {
    480   EFI_STATUS              Status;
    481   EFI_BLOCK_IO_PROTOCOL   *BlockIo;
    482   WIN_NT_BLOCK_IO_PRIVATE *Private;
    483   UINTN                   Index;
    484 
    485   WinNtIo->WinNtThunk->SetErrorMode (SEM_FAILCRITICALERRORS);
    486 
    487   Private = AllocatePool (sizeof (WIN_NT_BLOCK_IO_PRIVATE));
    488   ASSERT (Private != NULL);
    489 
    490   EfiInitializeLock (&Private->Lock, TPL_NOTIFY);
    491 
    492   Private->WinNtThunk = WinNtIo->WinNtThunk;
    493 
    494   Private->Signature  = WIN_NT_BLOCK_IO_PRIVATE_SIGNATURE;
    495   Private->LastBlock  = NumberOfBlocks - 1;
    496   Private->BlockSize  = BlockSize;
    497 
    498   for (Index = 0; Filename[Index] != 0; Index++) {
    499     Private->Filename[Index] = Filename[Index];
    500   }
    501 
    502   Private->Filename[Index]      = 0;
    503 
    504   Private->ReadMode             = GENERIC_READ | (ReadOnly ? 0 : GENERIC_WRITE);
    505   Private->ShareMode            = FILE_SHARE_READ | FILE_SHARE_WRITE;
    506 
    507   Private->NumberOfBlocks       = NumberOfBlocks;
    508   Private->DeviceType           = DeviceType;
    509   Private->NtHandle             = INVALID_HANDLE_VALUE;
    510 
    511   Private->ControllerNameTable  = NULL;
    512 
    513   AddUnicodeString2 (
    514     "eng",
    515     gWinNtBlockIoComponentName.SupportedLanguages,
    516     &Private->ControllerNameTable,
    517     Private->Filename,
    518     TRUE
    519     );
    520   AddUnicodeString2 (
    521     "en",
    522     gWinNtBlockIoComponentName2.SupportedLanguages,
    523     &Private->ControllerNameTable,
    524     Private->Filename,
    525     FALSE
    526     );
    527 
    528 
    529   BlockIo = &Private->BlockIo;
    530   BlockIo->Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
    531   BlockIo->Media = &Private->Media;
    532   BlockIo->Media->BlockSize = (UINT32)Private->BlockSize;
    533   BlockIo->Media->LastBlock = Private->NumberOfBlocks - 1;
    534   BlockIo->Media->MediaId = 0;;
    535 
    536   BlockIo->Reset = WinNtBlockIoResetBlock;
    537   BlockIo->ReadBlocks = WinNtBlockIoReadBlocks;
    538   BlockIo->WriteBlocks = WinNtBlockIoWriteBlocks;
    539   BlockIo->FlushBlocks = WinNtBlockIoFlushBlocks;
    540 
    541   BlockIo->Media->ReadOnly = ReadOnly;
    542   BlockIo->Media->RemovableMedia = RemovableMedia;
    543   BlockIo->Media->LogicalPartition = FALSE;
    544   BlockIo->Media->MediaPresent = TRUE;
    545   BlockIo->Media->WriteCaching = FALSE;
    546 
    547   if (DeviceType == EfiWinNtVirtualDisks) {
    548     BlockIo->Media->IoAlign = 1;
    549 
    550     //
    551     // Create a file to use for a virtual disk even if it does not exist.
    552     //
    553     Private->OpenMode = OPEN_ALWAYS;
    554   } else if (DeviceType == EfiWinNtPhysicalDisks) {
    555     //
    556     // Physical disk and floppy devices require 4 byte alignment.
    557     //
    558     BlockIo->Media->IoAlign = 4;
    559 
    560     //
    561     // You can only open a physical device if it exists.
    562     //
    563     Private->OpenMode = OPEN_EXISTING;
    564   } else {
    565     ASSERT (FALSE);
    566   }
    567 
    568   Private->EfiHandle  = EfiDeviceHandle;
    569   Status              = WinNtBlockIoOpenDevice (Private);
    570   if (!EFI_ERROR (Status)) {
    571 
    572     Status = gBS->InstallMultipleProtocolInterfaces (
    573                     &Private->EfiHandle,
    574                     &gEfiBlockIoProtocolGuid,
    575                     &Private->BlockIo,
    576                     NULL
    577                     );
    578     if (EFI_ERROR (Status)) {
    579       FreeUnicodeStringTable (Private->ControllerNameTable);
    580       FreePool (Private);
    581     }
    582 
    583     DEBUG ((EFI_D_INIT, "BlockDevice added: %s\n", Filename));
    584   }
    585 
    586   return Status;
    587 }
    588 
    589 EFI_STATUS
    590 WinNtBlockIoOpenDevice (
    591   WIN_NT_BLOCK_IO_PRIVATE                 *Private
    592   )
    593 /*++
    594 
    595 Routine Description:
    596 
    597   TODO: Add function description
    598 
    599 Arguments:
    600 
    601   Private - TODO: add argument description
    602 
    603 Returns:
    604 
    605   TODO: add return values
    606 
    607 --*/
    608 {
    609   EFI_STATUS            Status;
    610   UINT64                FileSize;
    611   UINT64                EndOfFile;
    612   EFI_BLOCK_IO_PROTOCOL *BlockIo;
    613 
    614   BlockIo = &Private->BlockIo;
    615   EfiAcquireLock (&Private->Lock);
    616 
    617   //
    618   // If the device is already opened, close it
    619   //
    620   if (Private->NtHandle != INVALID_HANDLE_VALUE) {
    621     BlockIo->Reset (BlockIo, FALSE);
    622   }
    623 
    624   //
    625   // Open the device
    626   //
    627   Private->NtHandle = Private->WinNtThunk->CreateFile (
    628                                             Private->Filename,
    629                                             (DWORD)Private->ReadMode,
    630                                             (DWORD)Private->ShareMode,
    631                                             NULL,
    632                                             (DWORD)Private->OpenMode,
    633                                             0,
    634                                             NULL
    635                                             );
    636 
    637   Status = Private->WinNtThunk->GetLastError ();
    638 
    639   if (Private->NtHandle == INVALID_HANDLE_VALUE) {
    640     DEBUG ((EFI_D_INFO, "PlOpenBlock: Could not open %s, %x\n", Private->Filename, Private->WinNtThunk->GetLastError ()));
    641     BlockIo->Media->MediaPresent  = FALSE;
    642     Status                        = EFI_NO_MEDIA;
    643     goto Done;
    644   }
    645 
    646   if (!BlockIo->Media->MediaPresent) {
    647     //
    648     // BugBug: try to emulate if a CD appears - notify drivers to check it out
    649     //
    650     BlockIo->Media->MediaPresent = TRUE;
    651     EfiReleaseLock (&Private->Lock);
    652     EfiAcquireLock (&Private->Lock);
    653   }
    654 
    655   //
    656   // get the size of the file
    657   //
    658   Status = SetFilePointer64 (Private, 0, &FileSize, FILE_END);
    659 
    660   if (EFI_ERROR (Status)) {
    661     FileSize = MultU64x32 (Private->NumberOfBlocks, (UINT32)Private->BlockSize);
    662     if (Private->DeviceType == EfiWinNtVirtualDisks) {
    663       DEBUG ((EFI_D_ERROR, "PlOpenBlock: Could not get filesize of %s\n", Private->Filename));
    664       Status = EFI_UNSUPPORTED;
    665       goto Done;
    666     }
    667   }
    668 
    669   if (Private->NumberOfBlocks == 0) {
    670     Private->NumberOfBlocks = DivU64x32 (FileSize, (UINT32)Private->BlockSize);
    671   }
    672 
    673   EndOfFile = MultU64x32 (Private->NumberOfBlocks, (UINT32)Private->BlockSize);
    674 
    675   if (FileSize != EndOfFile) {
    676     //
    677     // file is not the proper size, change it
    678     //
    679     DEBUG ((EFI_D_INIT, "PlOpenBlock: Initializing block device: %hs\n", Private->Filename));
    680 
    681     //
    682     // first set it to 0
    683     //
    684     SetFilePointer64 (Private, 0, NULL, FILE_BEGIN);
    685     Private->WinNtThunk->SetEndOfFile (Private->NtHandle);
    686 
    687     //
    688     // then set it to the needed file size (OS will zero fill it)
    689     //
    690     SetFilePointer64 (Private, EndOfFile, NULL, FILE_BEGIN);
    691     Private->WinNtThunk->SetEndOfFile (Private->NtHandle);
    692   }
    693 
    694   DEBUG ((EFI_D_INIT, "%HPlOpenBlock: opened %s%N\n", Private->Filename));
    695   Status = EFI_SUCCESS;
    696 
    697 Done:
    698   if (EFI_ERROR (Status)) {
    699     if (Private->NtHandle != INVALID_HANDLE_VALUE) {
    700       BlockIo->Reset (BlockIo, FALSE);
    701     }
    702   }
    703 
    704   EfiReleaseLock (&Private->Lock);
    705   return Status;
    706 }
    707 
    708 EFI_STATUS
    709 WinNtBlockIoError (
    710   IN WIN_NT_BLOCK_IO_PRIVATE      *Private
    711   )
    712 /*++
    713 
    714 Routine Description:
    715 
    716   TODO: Add function description
    717 
    718 Arguments:
    719 
    720   Private - TODO: add argument description
    721 
    722 Returns:
    723 
    724   TODO: add return values
    725 
    726 --*/
    727 {
    728   EFI_BLOCK_IO_PROTOCOL *BlockIo;
    729   EFI_STATUS            Status;
    730   BOOLEAN               ReinstallBlockIoFlag;
    731 
    732   BlockIo = &Private->BlockIo;
    733 
    734   switch (Private->WinNtThunk->GetLastError ()) {
    735 
    736   case ERROR_NOT_READY:
    737     Status                        = EFI_NO_MEDIA;
    738     BlockIo->Media->ReadOnly      = FALSE;
    739     BlockIo->Media->MediaPresent  = FALSE;
    740     ReinstallBlockIoFlag          = FALSE;
    741     break;
    742 
    743   case ERROR_WRONG_DISK:
    744     BlockIo->Media->ReadOnly      = FALSE;
    745     BlockIo->Media->MediaPresent  = TRUE;
    746     BlockIo->Media->MediaId += 1;
    747     ReinstallBlockIoFlag  = TRUE;
    748     Status                = EFI_MEDIA_CHANGED;
    749     break;
    750 
    751   case ERROR_WRITE_PROTECT:
    752     BlockIo->Media->ReadOnly  = TRUE;
    753     ReinstallBlockIoFlag      = FALSE;
    754     Status                    = EFI_WRITE_PROTECTED;
    755     break;
    756 
    757   default:
    758     ReinstallBlockIoFlag  = FALSE;
    759     Status                = EFI_DEVICE_ERROR;
    760     break;
    761   }
    762 
    763   if (ReinstallBlockIoFlag) {
    764     BlockIo->Reset (BlockIo, FALSE);
    765 
    766     gBS->ReinstallProtocolInterface (
    767           Private->EfiHandle,
    768           &gEfiBlockIoProtocolGuid,
    769           BlockIo,
    770           BlockIo
    771           );
    772   }
    773 
    774   return Status;
    775 }
    776 
    777 EFI_STATUS
    778 WinNtBlockIoReadWriteCommon (
    779   IN  WIN_NT_BLOCK_IO_PRIVATE     *Private,
    780   IN UINT32                       MediaId,
    781   IN EFI_LBA                      Lba,
    782   IN UINTN                        BufferSize,
    783   IN VOID                         *Buffer,
    784   IN CHAR8                        *CallerName
    785   )
    786 /*++
    787 
    788 Routine Description:
    789 
    790   TODO: Add function description
    791 
    792 Arguments:
    793 
    794   Private     - TODO: add argument description
    795   MediaId     - TODO: add argument description
    796   Lba         - TODO: add argument description
    797   BufferSize  - TODO: add argument description
    798   Buffer      - TODO: add argument description
    799   CallerName  - TODO: add argument description
    800 
    801 Returns:
    802 
    803   EFI_NO_MEDIA - TODO: Add description for return value
    804   EFI_MEDIA_CHANGED - TODO: Add description for return value
    805   EFI_INVALID_PARAMETER - TODO: Add description for return value
    806   EFI_SUCCESS - TODO: Add description for return value
    807   EFI_BAD_BUFFER_SIZE - TODO: Add description for return value
    808   EFI_INVALID_PARAMETER - TODO: Add description for return value
    809   EFI_SUCCESS - TODO: Add description for return value
    810 
    811 --*/
    812 {
    813   EFI_STATUS  Status;
    814   UINTN       BlockSize;
    815   UINT64      LastBlock;
    816   INT64       DistanceToMove;
    817   UINT64      DistanceMoved;
    818 
    819   if (Private->NtHandle == INVALID_HANDLE_VALUE) {
    820     Status = WinNtBlockIoOpenDevice (Private);
    821     if (EFI_ERROR (Status)) {
    822       return Status;
    823     }
    824   }
    825 
    826   if (!Private->Media.MediaPresent) {
    827     DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName));
    828     return EFI_NO_MEDIA;
    829   }
    830 
    831   if (Private->Media.MediaId != MediaId) {
    832     return EFI_MEDIA_CHANGED;
    833   }
    834 
    835   if ((UINTN) Buffer % Private->Media.IoAlign != 0) {
    836     return EFI_INVALID_PARAMETER;
    837   }
    838 
    839   //
    840   // Verify buffer size
    841   //
    842   BlockSize = Private->BlockSize;
    843   if (BufferSize == 0) {
    844     DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName));
    845     return EFI_SUCCESS;
    846   }
    847 
    848   if ((BufferSize % BlockSize) != 0) {
    849     DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName));
    850     return EFI_BAD_BUFFER_SIZE;
    851   }
    852 
    853   LastBlock = Lba + (BufferSize / BlockSize) - 1;
    854   if (LastBlock > Private->LastBlock) {
    855     DEBUG ((EFI_D_INIT, "ReadBlocks: Attempted to read off end of device\n"));
    856     return EFI_INVALID_PARAMETER;
    857   }
    858   //
    859   // Seek to End of File
    860   //
    861   DistanceToMove = MultU64x32 (Lba, (UINT32)BlockSize);
    862   Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, FILE_BEGIN);
    863 
    864   if (EFI_ERROR (Status)) {
    865     DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n"));
    866     return WinNtBlockIoError (Private);
    867   }
    868 
    869   return EFI_SUCCESS;
    870 }
    871 
    872 EFI_STATUS
    873 EFIAPI
    874 WinNtBlockIoReadBlocks (
    875   IN EFI_BLOCK_IO_PROTOCOL  *This,
    876   IN UINT32                 MediaId,
    877   IN EFI_LBA                Lba,
    878   IN UINTN                  BufferSize,
    879   OUT VOID                  *Buffer
    880   )
    881 /*++
    882 
    883   Routine Description:
    884     Read BufferSize bytes from Lba into Buffer.
    885 
    886   Arguments:
    887     This       - Protocol instance pointer.
    888     MediaId    - Id of the media, changes every time the media is replaced.
    889     Lba        - The starting Logical Block Address to read from
    890     BufferSize - Size of Buffer, must be a multiple of device block size.
    891     Buffer     - Buffer containing read data
    892 
    893   Returns:
    894     EFI_SUCCESS           - The data was read correctly from the device.
    895     EFI_DEVICE_ERROR      - The device reported an error while performing the read.
    896     EFI_NO_MEDIA          - There is no media in the device.
    897     EFI_MEDIA_CHANGED     - The MediaId does not matched the current device.
    898     EFI_BAD_BUFFER_SIZE   - The Buffer was not a multiple of the block size of the
    899                             device.
    900     EFI_INVALID_PARAMETER - The read request contains device addresses that are not
    901                             valid for the device.
    902 
    903 --*/
    904 {
    905   WIN_NT_BLOCK_IO_PRIVATE *Private;
    906   BOOL                    Flag;
    907   EFI_STATUS              Status;
    908   DWORD                   BytesRead;
    909   EFI_TPL                 OldTpl;
    910 
    911   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    912 
    913   Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
    914 
    915   Status  = WinNtBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "WinNtReadBlocks");
    916   if (EFI_ERROR (Status)) {
    917     goto Done;
    918   }
    919 
    920   Flag = Private->WinNtThunk->ReadFile (Private->NtHandle, Buffer, (DWORD) BufferSize, (LPDWORD) &BytesRead, NULL);
    921   if (!Flag || (BytesRead != BufferSize)) {
    922     DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed. (%d)\n", Private->WinNtThunk->GetLastError ()));
    923     Status = WinNtBlockIoError (Private);
    924     goto Done;
    925   }
    926 
    927   //
    928   // If we wrote then media is present.
    929   //
    930   This->Media->MediaPresent = TRUE;
    931   Status = EFI_SUCCESS;
    932 
    933 Done:
    934   gBS->RestoreTPL (OldTpl);
    935   return Status;
    936 }
    937 
    938 EFI_STATUS
    939 EFIAPI
    940 WinNtBlockIoWriteBlocks (
    941   IN EFI_BLOCK_IO_PROTOCOL  *This,
    942   IN UINT32                 MediaId,
    943   IN EFI_LBA                Lba,
    944   IN UINTN                  BufferSize,
    945   IN VOID                   *Buffer
    946   )
    947 /*++
    948 
    949   Routine Description:
    950     Write BufferSize bytes from Lba into Buffer.
    951 
    952   Arguments:
    953     This       - Protocol instance pointer.
    954     MediaId    - Id of the media, changes every time the media is replaced.
    955     Lba        - The starting Logical Block Address to read from
    956     BufferSize - Size of Buffer, must be a multiple of device block size.
    957     Buffer     - Buffer containing read data
    958 
    959   Returns:
    960     EFI_SUCCESS           - The data was written correctly to the device.
    961     EFI_WRITE_PROTECTED   - The device can not be written to.
    962     EFI_DEVICE_ERROR      - The device reported an error while performing the write.
    963     EFI_NO_MEDIA          - There is no media in the device.
    964     EFI_MEDIA_CHNAGED     - The MediaId does not matched the current device.
    965     EFI_BAD_BUFFER_SIZE   - The Buffer was not a multiple of the block size of the
    966                             device.
    967     EFI_INVALID_PARAMETER - The write request contains a LBA that is not
    968                             valid for the device.
    969 
    970 --*/
    971 {
    972   WIN_NT_BLOCK_IO_PRIVATE *Private;
    973   UINTN                   BytesWritten;
    974   BOOL                    Flag;
    975   BOOL                    Locked;
    976   EFI_STATUS              Status;
    977   EFI_TPL                 OldTpl;
    978   UINTN                   BytesReturned;
    979 
    980   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    981 
    982   Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
    983 
    984   Status  = WinNtBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "WinNtWriteBlocks");
    985   if (EFI_ERROR (Status)) {
    986     goto Done;
    987   }
    988 
    989   //
    990   // According the Windows requirement, first need to lock the volume before
    991   // write to it.
    992   //
    993   if (Private->DeviceType == EfiWinNtPhysicalDisks) {
    994     Locked = Private->WinNtThunk->DeviceIoControl (Private->NtHandle, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &BytesReturned, NULL);
    995     if (Locked == 0) {
    996       DEBUG ((EFI_D_INIT, "ReadBlocks: Lock volume failed. (%d)\n", Private->WinNtThunk->GetLastError ()));
    997       Status = WinNtBlockIoError (Private);
    998       goto Done;
    999     }
   1000   } else {
   1001     Locked = 0;
   1002   }
   1003   Flag = Private->WinNtThunk->WriteFile (Private->NtHandle, Buffer, (DWORD) BufferSize, (LPDWORD) &BytesWritten, NULL);
   1004   if (Locked != 0) {
   1005     Private->WinNtThunk->DeviceIoControl (Private->NtHandle, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &BytesReturned, NULL);
   1006   }
   1007   if (!Flag || (BytesWritten != BufferSize)) {
   1008     DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed. (%d)\n", Private->WinNtThunk->GetLastError ()));
   1009     Status = WinNtBlockIoError (Private);
   1010     goto Done;
   1011   }
   1012 
   1013   //
   1014   // If the write succeeded, we are not write protected and media is present.
   1015   //
   1016   This->Media->MediaPresent = TRUE;
   1017   This->Media->ReadOnly     = FALSE;
   1018   Status = EFI_SUCCESS;
   1019 
   1020 Done:
   1021   gBS->RestoreTPL (OldTpl);
   1022   return Status;
   1023 
   1024 }
   1025 
   1026 EFI_STATUS
   1027 EFIAPI
   1028 WinNtBlockIoFlushBlocks (
   1029   IN EFI_BLOCK_IO_PROTOCOL  *This
   1030   )
   1031 /*++
   1032 
   1033   Routine Description:
   1034     Flush the Block Device.
   1035 
   1036   Arguments:
   1037     This             - Protocol instance pointer.
   1038 
   1039   Returns:
   1040     EFI_SUCCESS      - All outstanding data was written to the device
   1041     EFI_DEVICE_ERROR - The device reported an error while writting back the data
   1042     EFI_NO_MEDIA     - There is no media in the device.
   1043 
   1044 --*/
   1045 {
   1046   return EFI_SUCCESS;
   1047 }
   1048 
   1049 EFI_STATUS
   1050 EFIAPI
   1051 WinNtBlockIoResetBlock (
   1052   IN EFI_BLOCK_IO_PROTOCOL  *This,
   1053   IN BOOLEAN                ExtendedVerification
   1054   )
   1055 /*++
   1056 
   1057   Routine Description:
   1058     Reset the Block Device.
   1059 
   1060   Arguments:
   1061     This                 - Protocol instance pointer.
   1062     ExtendedVerification - Driver may perform diagnostics on reset.
   1063 
   1064   Returns:
   1065     EFI_SUCCESS           - The device was reset.
   1066     EFI_DEVICE_ERROR      - The device is not functioning properly and could
   1067                             not be reset.
   1068 
   1069 --*/
   1070 {
   1071   WIN_NT_BLOCK_IO_PRIVATE *Private;
   1072   EFI_TPL                 OldTpl;
   1073 
   1074   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1075 
   1076   Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
   1077 
   1078   if (Private->NtHandle != INVALID_HANDLE_VALUE) {
   1079     Private->WinNtThunk->CloseHandle (Private->NtHandle);
   1080     Private->NtHandle = INVALID_HANDLE_VALUE;
   1081   }
   1082 
   1083   gBS->RestoreTPL (OldTpl);
   1084 
   1085   return EFI_SUCCESS;
   1086 }
   1087 
   1088 
   1089 EFI_STATUS
   1090 SetFilePointer64 (
   1091   IN  WIN_NT_BLOCK_IO_PRIVATE    *Private,
   1092   IN  INT64                      DistanceToMove,
   1093   OUT UINT64                     *NewFilePointer,
   1094   IN  DWORD                      MoveMethod
   1095   )
   1096 /*++
   1097 
   1098 This function extends the capability of SetFilePointer to accept 64 bit parameters
   1099 
   1100 --*/
   1101 // TODO: function comment is missing 'Routine Description:'
   1102 // TODO: function comment is missing 'Arguments:'
   1103 // TODO: function comment is missing 'Returns:'
   1104 // TODO:    Private - add argument and description to function comment
   1105 // TODO:    DistanceToMove - add argument and description to function comment
   1106 // TODO:    NewFilePointer - add argument and description to function comment
   1107 // TODO:    MoveMethod - add argument and description to function comment
   1108 {
   1109   EFI_STATUS    Status;
   1110   LARGE_INTEGER LargeInt;
   1111 
   1112   LargeInt.QuadPart = DistanceToMove;
   1113   Status            = EFI_SUCCESS;
   1114 
   1115   LargeInt.LowPart = Private->WinNtThunk->SetFilePointer (
   1116                                             Private->NtHandle,
   1117                                             LargeInt.LowPart,
   1118                                             &LargeInt.HighPart,
   1119                                             MoveMethod
   1120                                             );
   1121 
   1122   if (LargeInt.LowPart == -1 && Private->WinNtThunk->GetLastError () != NO_ERROR) {
   1123     Status = EFI_INVALID_PARAMETER;
   1124   }
   1125 
   1126   if (NewFilePointer != NULL) {
   1127     *NewFilePointer = LargeInt.QuadPart;
   1128   }
   1129 
   1130   return Status;
   1131 }
   1132