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