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