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
InitializeWinNtBlockIo(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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
WinNtBlockIoDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Handle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
WinNtBlockIoDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Handle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
WinNtBlockIoDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Handle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)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 *
GetNextElementPastTerminator(IN CHAR16 * EnvironmentVariable,IN CHAR16 Terminator)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
WinNtBlockIoCreateMapping(IN EFI_WIN_NT_IO_PROTOCOL * WinNtIo,IN EFI_HANDLE EfiDeviceHandle,IN CHAR16 * Filename,IN BOOLEAN ReadOnly,IN BOOLEAN RemovableMedia,IN UINTN NumberOfBlocks,IN UINTN BlockSize,IN WIN_NT_RAW_DISK_DEVICE_TYPE DeviceType)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
WinNtBlockIoOpenDevice(WIN_NT_BLOCK_IO_PRIVATE * Private)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
WinNtBlockIoError(IN WIN_NT_BLOCK_IO_PRIVATE * Private)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
WinNtBlockIoReadWriteCommon(IN WIN_NT_BLOCK_IO_PRIVATE * Private,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,IN VOID * Buffer,IN CHAR8 * CallerName)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
WinNtBlockIoReadBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,OUT VOID * Buffer)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
WinNtBlockIoWriteBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,IN VOID * Buffer)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
WinNtBlockIoFlushBlocks(IN EFI_BLOCK_IO_PROTOCOL * This)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
WinNtBlockIoResetBlock(IN EFI_BLOCK_IO_PROTOCOL * This,IN BOOLEAN ExtendedVerification)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
SetFilePointer64(IN WIN_NT_BLOCK_IO_PRIVATE * Private,IN INT64 DistanceToMove,OUT UINT64 * NewFilePointer,IN DWORD MoveMethod)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