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