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