1e12dd5204e46ce9c124d669da2e26aee6c30543
[mirror_edk2.git] / Nt32Pkg / WinNtBlockIoDxe / WinNtBlockIo.c
1 /**@file
2
3 Copyright (c) 2006 - 2012, 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 = 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 Private->ReadMode,
630 Private->ShareMode,
631 NULL,
632 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, 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, Private->BlockSize);
671 }
672
673 EndOfFile = MultU64x32 (Private->NumberOfBlocks, 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 ((UINT32) 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, 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 Locked = Private->WinNtThunk->DeviceIoControl (Private->NtHandle, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &BytesReturned, NULL);
994 if (Locked == 0) {
995 DEBUG ((EFI_D_INIT, "ReadBlocks: Lock volume failed. (%d)\n", Private->WinNtThunk->GetLastError ()));
996 Status = WinNtBlockIoError (Private);
997 goto Done;
998 }
999 Flag = Private->WinNtThunk->WriteFile (Private->NtHandle, Buffer, (DWORD) BufferSize, (LPDWORD) &BytesWritten, NULL);
1000 if (Locked != 0) {
1001 Private->WinNtThunk->DeviceIoControl (Private->NtHandle, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &BytesReturned, NULL);
1002 }
1003 if (!Flag || (BytesWritten != BufferSize)) {
1004 DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed. (%d)\n", Private->WinNtThunk->GetLastError ()));
1005 Status = WinNtBlockIoError (Private);
1006 goto Done;
1007 }
1008
1009 //
1010 // If the write succeeded, we are not write protected and media is present.
1011 //
1012 This->Media->MediaPresent = TRUE;
1013 This->Media->ReadOnly = FALSE;
1014 Status = EFI_SUCCESS;
1015
1016 Done:
1017 gBS->RestoreTPL (OldTpl);
1018 return Status;
1019
1020 }
1021
1022 EFI_STATUS
1023 EFIAPI
1024 WinNtBlockIoFlushBlocks (
1025 IN EFI_BLOCK_IO_PROTOCOL *This
1026 )
1027 /*++
1028
1029 Routine Description:
1030 Flush the Block Device.
1031
1032 Arguments:
1033 This - Protocol instance pointer.
1034
1035 Returns:
1036 EFI_SUCCESS - All outstanding data was written to the device
1037 EFI_DEVICE_ERROR - The device reported an error while writting back the data
1038 EFI_NO_MEDIA - There is no media in the device.
1039
1040 --*/
1041 {
1042 return EFI_SUCCESS;
1043 }
1044
1045 EFI_STATUS
1046 EFIAPI
1047 WinNtBlockIoResetBlock (
1048 IN EFI_BLOCK_IO_PROTOCOL *This,
1049 IN BOOLEAN ExtendedVerification
1050 )
1051 /*++
1052
1053 Routine Description:
1054 Reset the Block Device.
1055
1056 Arguments:
1057 This - Protocol instance pointer.
1058 ExtendedVerification - Driver may perform diagnostics on reset.
1059
1060 Returns:
1061 EFI_SUCCESS - The device was reset.
1062 EFI_DEVICE_ERROR - The device is not functioning properly and could
1063 not be reset.
1064
1065 --*/
1066 {
1067 WIN_NT_BLOCK_IO_PRIVATE *Private;
1068 EFI_TPL OldTpl;
1069
1070 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1071
1072 Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
1073
1074 if (Private->NtHandle != INVALID_HANDLE_VALUE) {
1075 Private->WinNtThunk->CloseHandle (Private->NtHandle);
1076 Private->NtHandle = INVALID_HANDLE_VALUE;
1077 }
1078
1079 gBS->RestoreTPL (OldTpl);
1080
1081 return EFI_SUCCESS;
1082 }
1083
1084
1085 EFI_STATUS
1086 SetFilePointer64 (
1087 IN WIN_NT_BLOCK_IO_PRIVATE *Private,
1088 IN INT64 DistanceToMove,
1089 OUT UINT64 *NewFilePointer,
1090 IN DWORD MoveMethod
1091 )
1092 /*++
1093
1094 This function extends the capability of SetFilePointer to accept 64 bit parameters
1095
1096 --*/
1097 // TODO: function comment is missing 'Routine Description:'
1098 // TODO: function comment is missing 'Arguments:'
1099 // TODO: function comment is missing 'Returns:'
1100 // TODO: Private - add argument and description to function comment
1101 // TODO: DistanceToMove - add argument and description to function comment
1102 // TODO: NewFilePointer - add argument and description to function comment
1103 // TODO: MoveMethod - add argument and description to function comment
1104 {
1105 EFI_STATUS Status;
1106 LARGE_INTEGER LargeInt;
1107
1108 LargeInt.QuadPart = DistanceToMove;
1109 Status = EFI_SUCCESS;
1110
1111 LargeInt.LowPart = Private->WinNtThunk->SetFilePointer (
1112 Private->NtHandle,
1113 LargeInt.LowPart,
1114 &LargeInt.HighPart,
1115 MoveMethod
1116 );
1117
1118 if (LargeInt.LowPart == -1 && Private->WinNtThunk->GetLastError () != NO_ERROR) {
1119 Status = EFI_INVALID_PARAMETER;
1120 }
1121
1122 if (NewFilePointer != NULL) {
1123 *NewFilePointer = LargeInt.QuadPart;
1124 }
1125
1126 return Status;
1127 }