]> git.proxmox.com Git - mirror_edk2.git/blob - EdkNt32Pkg/Dxe/WinNtThunk/Bus/BlockIo/WinNtBlockIo.c
Add some definitions for efi event in Uefi/UefiSpec.h to follow spec.
[mirror_edk2.git] / EdkNt32Pkg / Dxe / WinNtThunk / Bus / BlockIo / WinNtBlockIo.c
1 /*++
2
3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 WinNtBlockIo.c
15
16 Abstract:
17
18 Produce block IO abstractions for real devices on your PC using Win32 APIs.
19 The configuration of what devices to mount or emulate comes from NT
20 environment variables. The variables must be visible to the Microsoft*
21 Developer Studio for them to work.
22
23 <F>ixed - Fixed disk like a hard drive.
24 <R>emovable - Removable media like a floppy or CD-ROM.
25 Read <O>nly - Write protected device.
26 Read <W>rite - Read write device.
27 <block count> - Decimal number of blocks a device supports.
28 <block size> - Decimal number of bytes per block.
29
30 NT envirnonment variable contents. '<' and '>' are not part of the variable,
31 they are just used to make this help more readable. There should be no
32 spaces between the ';'. Extra spaces will break the variable. A '!' is
33 used to seperate multiple devices in a variable.
34
35 EFI_WIN_NT_VIRTUAL_DISKS =
36 <F | R><O | W>;<block count>;<block size>[!...]
37
38 EFI_WIN_NT_PHYSICAL_DISKS =
39 <drive letter>:<F | R><O | W>;<block count>;<block size>[!...]
40
41 Virtual Disks: These devices use a file to emulate a hard disk or removable
42 media device.
43
44 Thus a 20 MB emulated hard drive would look like:
45 EFI_WIN_NT_VIRTUAL_DISKS=FW;40960;512
46
47 A 1.44MB emulated floppy with a block size of 1024 would look like:
48 EFI_WIN_NT_VIRTUAL_DISKS=RW;1440;1024
49
50 Physical Disks: These devices use NT to open a real device in your system
51
52 Thus a 120 MB floppy would look like:
53 EFI_WIN_NT_PHYSICAL_DISKS=B:RW;245760;512
54
55 Thus a standard CD-ROM floppy would look like:
56 EFI_WIN_NT_PHYSICAL_DISKS=Z:RO;307200;2048
57
58
59 * Other names and brands may be claimed as the property of others.
60
61 --*/
62
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 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 Private = AllocatePool (sizeof (WIN_NT_BLOCK_IO_PRIVATE));
434 ASSERT (Private != NULL);
435
436 EfiInitializeLock (&Private->Lock, TPL_NOTIFY);
437
438 Private->WinNtThunk = WinNtIo->WinNtThunk;
439
440 Private->Signature = WIN_NT_BLOCK_IO_PRIVATE_SIGNATURE;
441 Private->LastBlock = NumberOfBlocks - 1;
442 Private->BlockSize = BlockSize;
443
444 for (Index = 0; Filename[Index] != 0; Index++) {
445 Private->Filename[Index] = Filename[Index];
446 }
447
448 Private->Filename[Index] = 0;
449
450 Private->ReadMode = GENERIC_READ | (ReadOnly ? 0 : GENERIC_WRITE);
451 Private->ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
452
453 Private->NumberOfBlocks = NumberOfBlocks;
454 Private->DeviceType = DeviceType;
455 Private->NtHandle = INVALID_HANDLE_VALUE;
456
457 Private->ControllerNameTable = NULL;
458
459 AddUnicodeString (
460 "eng",
461 gWinNtBlockIoComponentName.SupportedLanguages,
462 &Private->ControllerNameTable,
463 Private->Filename
464 );
465
466 BlockIo = &Private->BlockIo;
467 BlockIo->Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
468 BlockIo->Media = &Private->Media;
469 BlockIo->Media->BlockSize = Private->BlockSize;
470 BlockIo->Media->LastBlock = Private->NumberOfBlocks - 1;
471 BlockIo->Media->MediaId = 0;;
472
473 BlockIo->Reset = WinNtBlockIoResetBlock;
474 BlockIo->ReadBlocks = WinNtBlockIoReadBlocks;
475 BlockIo->WriteBlocks = WinNtBlockIoWriteBlocks;
476 BlockIo->FlushBlocks = WinNtBlockIoFlushBlocks;
477
478 BlockIo->Media->ReadOnly = ReadOnly;
479 BlockIo->Media->RemovableMedia = RemovableMedia;
480 BlockIo->Media->LogicalPartition = FALSE;
481 BlockIo->Media->MediaPresent = TRUE;
482 BlockIo->Media->WriteCaching = FALSE;
483
484 if (DeviceType == EfiWinNtVirtualDisks) {
485 BlockIo->Media->IoAlign = 1;
486
487 //
488 // Create a file to use for a virtual disk even if it does not exist.
489 //
490 Private->OpenMode = OPEN_ALWAYS;
491 } else if (DeviceType == EfiWinNtPhysicalDisks) {
492 //
493 // Physical disk and floppy devices require 4 byte alignment.
494 //
495 BlockIo->Media->IoAlign = 4;
496
497 //
498 // You can only open a physical device if it exists.
499 //
500 Private->OpenMode = OPEN_EXISTING;
501 } else {
502 ASSERT (FALSE);
503 }
504
505 Private->EfiHandle = EfiDeviceHandle;
506 Status = WinNtBlockIoOpenDevice (Private);
507 if (!EFI_ERROR (Status)) {
508
509 Status = gBS->InstallMultipleProtocolInterfaces (
510 &Private->EfiHandle,
511 &gEfiBlockIoProtocolGuid,
512 &Private->BlockIo,
513 NULL
514 );
515 if (EFI_ERROR (Status)) {
516 FreeUnicodeStringTable (Private->ControllerNameTable);
517 FreePool (Private);
518 }
519
520 DEBUG ((EFI_D_INIT, "BlockDevice added: %s\n", Filename));
521 }
522
523 return Status;
524 }
525
526 STATIC
527 EFI_STATUS
528 WinNtBlockIoOpenDevice (
529 WIN_NT_BLOCK_IO_PRIVATE *Private
530 )
531 /*++
532
533 Routine Description:
534
535 TODO: Add function description
536
537 Arguments:
538
539 Private - TODO: add argument description
540
541 Returns:
542
543 TODO: add return values
544
545 --*/
546 {
547 EFI_STATUS Status;
548 UINT64 FileSize;
549 UINT64 EndOfFile;
550 EFI_BLOCK_IO_PROTOCOL *BlockIo;
551
552 BlockIo = &Private->BlockIo;
553 EfiAcquireLock (&Private->Lock);
554
555 //
556 // If the device is already opened, close it
557 //
558 if (Private->NtHandle != INVALID_HANDLE_VALUE) {
559 BlockIo->Reset (BlockIo, FALSE);
560 }
561
562 //
563 // Open the device
564 //
565 Private->NtHandle = Private->WinNtThunk->CreateFile (
566 Private->Filename,
567 Private->ReadMode,
568 Private->ShareMode,
569 NULL,
570 Private->OpenMode,
571 0,
572 NULL
573 );
574
575 Status = Private->WinNtThunk->GetLastError ();
576
577 if (Private->NtHandle == INVALID_HANDLE_VALUE) {
578 DEBUG ((EFI_D_INFO, "PlOpenBlock: Could not open %s, %x\n", Private->Filename, Private->WinNtThunk->GetLastError ()));
579 BlockIo->Media->MediaPresent = FALSE;
580 Status = EFI_NO_MEDIA;
581 goto Done;
582 }
583
584 if (!BlockIo->Media->MediaPresent) {
585 //
586 // BugBug: try to emulate if a CD appears - notify drivers to check it out
587 //
588 BlockIo->Media->MediaPresent = TRUE;
589 EfiReleaseLock (&Private->Lock);
590 EfiAcquireLock (&Private->Lock);
591 }
592
593 //
594 // get the size of the file
595 //
596 Status = SetFilePointer64 (Private, 0, &FileSize, FILE_END);
597
598 if (EFI_ERROR (Status)) {
599 FileSize = MultU64x32 (Private->NumberOfBlocks, Private->BlockSize);
600 if (Private->DeviceType == EfiWinNtVirtualDisks) {
601 DEBUG ((EFI_D_ERROR, "PlOpenBlock: Could not get filesize of %s\n", Private->Filename));
602 Status = EFI_UNSUPPORTED;
603 goto Done;
604 }
605 }
606
607 if (Private->NumberOfBlocks == 0) {
608 Private->NumberOfBlocks = DivU64x32 (FileSize, Private->BlockSize);
609 }
610
611 EndOfFile = MultU64x32 (Private->NumberOfBlocks, Private->BlockSize);
612
613 if (FileSize != EndOfFile) {
614 //
615 // file is not the proper size, change it
616 //
617 DEBUG ((EFI_D_INIT, "PlOpenBlock: Initializing block device: %hs\n", Private->Filename));
618
619 //
620 // first set it to 0
621 //
622 SetFilePointer64 (Private, 0, NULL, FILE_BEGIN);
623 Private->WinNtThunk->SetEndOfFile (Private->NtHandle);
624
625 //
626 // then set it to the needed file size (OS will zero fill it)
627 //
628 SetFilePointer64 (Private, EndOfFile, NULL, FILE_BEGIN);
629 Private->WinNtThunk->SetEndOfFile (Private->NtHandle);
630 }
631
632 DEBUG ((EFI_D_INIT, "%HPlOpenBlock: opened %s%N\n", Private->Filename));
633 Status = EFI_SUCCESS;
634
635 Done:
636 if (EFI_ERROR (Status)) {
637 if (Private->NtHandle != INVALID_HANDLE_VALUE) {
638 BlockIo->Reset (BlockIo, FALSE);
639 }
640 }
641
642 EfiReleaseLock (&Private->Lock);
643 return Status;
644 }
645
646 STATIC
647 EFI_STATUS
648 WinNtBlockIoError (
649 IN WIN_NT_BLOCK_IO_PRIVATE *Private
650 )
651 /*++
652
653 Routine Description:
654
655 TODO: Add function description
656
657 Arguments:
658
659 Private - TODO: add argument description
660
661 Returns:
662
663 TODO: add return values
664
665 --*/
666 {
667 EFI_BLOCK_IO_PROTOCOL *BlockIo;
668 EFI_STATUS Status;
669 BOOLEAN ReinstallBlockIoFlag;
670
671 BlockIo = &Private->BlockIo;
672
673 switch (Private->WinNtThunk->GetLastError ()) {
674
675 case ERROR_NOT_READY:
676 Status = EFI_NO_MEDIA;
677 BlockIo->Media->ReadOnly = FALSE;
678 BlockIo->Media->MediaPresent = FALSE;
679 ReinstallBlockIoFlag = FALSE;
680 break;
681
682 case ERROR_WRONG_DISK:
683 BlockIo->Media->ReadOnly = FALSE;
684 BlockIo->Media->MediaPresent = TRUE;
685 BlockIo->Media->MediaId += 1;
686 ReinstallBlockIoFlag = TRUE;
687 Status = EFI_MEDIA_CHANGED;
688 break;
689
690 case ERROR_WRITE_PROTECT:
691 BlockIo->Media->ReadOnly = TRUE;
692 ReinstallBlockIoFlag = FALSE;
693 Status = EFI_WRITE_PROTECTED;
694 break;
695
696 default:
697 ReinstallBlockIoFlag = FALSE;
698 Status = EFI_DEVICE_ERROR;
699 break;
700 }
701
702 if (ReinstallBlockIoFlag) {
703 BlockIo->Reset (BlockIo, FALSE);
704
705 gBS->ReinstallProtocolInterface (
706 Private->EfiHandle,
707 &gEfiBlockIoProtocolGuid,
708 BlockIo,
709 BlockIo
710 );
711 }
712
713 return Status;
714 }
715
716 STATIC
717 EFI_STATUS
718 WinNtBlockIoReadWriteCommon (
719 IN WIN_NT_BLOCK_IO_PRIVATE *Private,
720 IN UINT32 MediaId,
721 IN EFI_LBA Lba,
722 IN UINTN BufferSize,
723 IN VOID *Buffer,
724 IN CHAR8 *CallerName
725 )
726 /*++
727
728 Routine Description:
729
730 TODO: Add function description
731
732 Arguments:
733
734 Private - TODO: add argument description
735 MediaId - TODO: add argument description
736 Lba - TODO: add argument description
737 BufferSize - TODO: add argument description
738 Buffer - TODO: add argument description
739 CallerName - TODO: add argument description
740
741 Returns:
742
743 EFI_NO_MEDIA - TODO: Add description for return value
744 EFI_MEDIA_CHANGED - TODO: Add description for return value
745 EFI_INVALID_PARAMETER - TODO: Add description for return value
746 EFI_SUCCESS - TODO: Add description for return value
747 EFI_BAD_BUFFER_SIZE - 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
751 --*/
752 {
753 EFI_STATUS Status;
754 UINTN BlockSize;
755 UINT64 LastBlock;
756 INT64 DistanceToMove;
757 UINT64 DistanceMoved;
758
759 if (Private->NtHandle == INVALID_HANDLE_VALUE) {
760 Status = WinNtBlockIoOpenDevice (Private);
761 if (EFI_ERROR (Status)) {
762 return Status;
763 }
764 }
765
766 if (!Private->Media.MediaPresent) {
767 DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName));
768 return EFI_NO_MEDIA;
769 }
770
771 if (Private->Media.MediaId != MediaId) {
772 return EFI_MEDIA_CHANGED;
773 }
774
775 if ((UINT32) Buffer % Private->Media.IoAlign != 0) {
776 return EFI_INVALID_PARAMETER;
777 }
778
779 //
780 // Verify buffer size
781 //
782 BlockSize = Private->BlockSize;
783 if (BufferSize == 0) {
784 DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName));
785 return EFI_SUCCESS;
786 }
787
788 if ((BufferSize % BlockSize) != 0) {
789 DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName));
790 return EFI_BAD_BUFFER_SIZE;
791 }
792
793 LastBlock = Lba + (BufferSize / BlockSize) - 1;
794 if (LastBlock > Private->LastBlock) {
795 DEBUG ((EFI_D_INIT, "ReadBlocks: Attempted to read off end of device\n"));
796 return EFI_INVALID_PARAMETER;
797 }
798 //
799 // Seek to End of File
800 //
801 DistanceToMove = MultU64x32 (Lba, BlockSize);
802 Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, FILE_BEGIN);
803
804 if (EFI_ERROR (Status)) {
805 DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n"));
806 return WinNtBlockIoError (Private);
807 }
808
809 return EFI_SUCCESS;
810 }
811
812 STATIC
813 EFI_STATUS
814 EFIAPI
815 WinNtBlockIoReadBlocks (
816 IN EFI_BLOCK_IO_PROTOCOL *This,
817 IN UINT32 MediaId,
818 IN EFI_LBA Lba,
819 IN UINTN BufferSize,
820 OUT VOID *Buffer
821 )
822 /*++
823
824 Routine Description:
825 Read BufferSize bytes from Lba into Buffer.
826
827 Arguments:
828 This - Protocol instance pointer.
829 MediaId - Id of the media, changes every time the media is replaced.
830 Lba - The starting Logical Block Address to read from
831 BufferSize - Size of Buffer, must be a multiple of device block size.
832 Buffer - Buffer containing read data
833
834 Returns:
835 EFI_SUCCESS - The data was read correctly from the device.
836 EFI_DEVICE_ERROR - The device reported an error while performing the read.
837 EFI_NO_MEDIA - There is no media in the device.
838 EFI_MEDIA_CHANGED - The MediaId does not matched the current device.
839 EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the
840 device.
841 EFI_INVALID_PARAMETER - The read request contains device addresses that are not
842 valid for the device.
843
844 --*/
845 {
846 WIN_NT_BLOCK_IO_PRIVATE *Private;
847 BOOL Flag;
848 EFI_STATUS Status;
849 DWORD BytesRead;
850 EFI_TPL OldTpl;
851
852 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
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 goto Done;
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 Status = WinNtBlockIoError (Private);
865 goto Done;
866 }
867
868 //
869 // If we wrote then media is present.
870 //
871 This->Media->MediaPresent = TRUE;
872 Status = EFI_SUCCESS;
873
874 Done:
875 gBS->RestoreTPL (OldTpl);
876 return Status;
877 }
878
879 STATIC
880 EFI_STATUS
881 EFIAPI
882 WinNtBlockIoWriteBlocks (
883 IN EFI_BLOCK_IO_PROTOCOL *This,
884 IN UINT32 MediaId,
885 IN EFI_LBA Lba,
886 IN UINTN BufferSize,
887 IN VOID *Buffer
888 )
889 /*++
890
891 Routine Description:
892 Write BufferSize bytes from Lba into Buffer.
893
894 Arguments:
895 This - Protocol instance pointer.
896 MediaId - Id of the media, changes every time the media is replaced.
897 Lba - The starting Logical Block Address to read from
898 BufferSize - Size of Buffer, must be a multiple of device block size.
899 Buffer - Buffer containing read data
900
901 Returns:
902 EFI_SUCCESS - The data was written correctly to the device.
903 EFI_WRITE_PROTECTED - The device can not be written to.
904 EFI_DEVICE_ERROR - The device reported an error while performing the write.
905 EFI_NO_MEDIA - There is no media in the device.
906 EFI_MEDIA_CHNAGED - The MediaId does not matched the current device.
907 EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the
908 device.
909 EFI_INVALID_PARAMETER - The write request contains a LBA that is not
910 valid for the device.
911
912 --*/
913 {
914 WIN_NT_BLOCK_IO_PRIVATE *Private;
915 UINTN BytesWritten;
916 BOOL Flag;
917 EFI_STATUS Status;
918 EFI_TPL OldTpl;
919
920 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
921
922 Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
923
924 Status = WinNtBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "WinNtWriteBlocks");
925 if (EFI_ERROR (Status)) {
926 goto Done;
927 }
928
929 Flag = Private->WinNtThunk->WriteFile (Private->NtHandle, Buffer, (DWORD) BufferSize, (LPDWORD) &BytesWritten, NULL);
930 if (!Flag || (BytesWritten != BufferSize)) {
931 DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed. (%d)\n", Private->WinNtThunk->GetLastError ()));
932 Status = WinNtBlockIoError (Private);
933 goto Done;
934 }
935
936 //
937 // If the write succeeded, we are not write protected and media is present.
938 //
939 This->Media->MediaPresent = TRUE;
940 This->Media->ReadOnly = FALSE;
941 Status = EFI_SUCCESS;
942
943 Done:
944 gBS->RestoreTPL (OldTpl);
945 return Status;
946
947 }
948
949 STATIC
950 EFI_STATUS
951 EFIAPI
952 WinNtBlockIoFlushBlocks (
953 IN EFI_BLOCK_IO_PROTOCOL *This
954 )
955 /*++
956
957 Routine Description:
958 Flush the Block Device.
959
960 Arguments:
961 This - Protocol instance pointer.
962
963 Returns:
964 EFI_SUCCESS - All outstanding data was written to the device
965 EFI_DEVICE_ERROR - The device reported an error while writting back the data
966 EFI_NO_MEDIA - There is no media in the device.
967
968 --*/
969 {
970 return EFI_SUCCESS;
971 }
972
973 STATIC
974 EFI_STATUS
975 EFIAPI
976 WinNtBlockIoResetBlock (
977 IN EFI_BLOCK_IO_PROTOCOL *This,
978 IN BOOLEAN ExtendedVerification
979 )
980 /*++
981
982 Routine Description:
983 Reset the Block Device.
984
985 Arguments:
986 This - Protocol instance pointer.
987 ExtendedVerification - Driver may perform diagnostics on reset.
988
989 Returns:
990 EFI_SUCCESS - The device was reset.
991 EFI_DEVICE_ERROR - The device is not functioning properly and could
992 not be reset.
993
994 --*/
995 {
996 WIN_NT_BLOCK_IO_PRIVATE *Private;
997 EFI_TPL OldTpl;
998
999 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1000
1001 Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
1002
1003 if (Private->NtHandle != INVALID_HANDLE_VALUE) {
1004 Private->WinNtThunk->CloseHandle (Private->NtHandle);
1005 Private->NtHandle = INVALID_HANDLE_VALUE;
1006 }
1007
1008 gBS->RestoreTPL (OldTpl);
1009
1010 return EFI_SUCCESS;
1011 }
1012
1013 UINTN
1014 Atoi (
1015 CHAR16 *String
1016 )
1017 /*++
1018
1019 Routine Description:
1020
1021 Convert a unicode string to a UINTN
1022
1023 Arguments:
1024
1025 String - Unicode string.
1026
1027 Returns:
1028
1029 UINTN of the number represented by String.
1030
1031 --*/
1032 {
1033 UINTN Number;
1034 CHAR16 *Str;
1035
1036 //
1037 // skip preceeding white space
1038 //
1039 Str = String;
1040 while ((*Str) && (*Str == ' ')) {
1041 Str++;
1042 }
1043 //
1044 // Convert ot a Number
1045 //
1046 Number = 0;
1047 while (*Str != '\0') {
1048 if ((*Str >= '0') && (*Str <= '9')) {
1049 Number = (Number * 10) +*Str - '0';
1050 } else {
1051 break;
1052 }
1053
1054 Str++;
1055 }
1056
1057 return Number;
1058 }
1059
1060 EFI_STATUS
1061 SetFilePointer64 (
1062 IN WIN_NT_BLOCK_IO_PRIVATE *Private,
1063 IN INT64 DistanceToMove,
1064 OUT UINT64 *NewFilePointer,
1065 IN DWORD MoveMethod
1066 )
1067 /*++
1068
1069 This function extends the capability of SetFilePointer to accept 64 bit parameters
1070
1071 --*/
1072 // TODO: function comment is missing 'Routine Description:'
1073 // TODO: function comment is missing 'Arguments:'
1074 // TODO: function comment is missing 'Returns:'
1075 // TODO: Private - add argument and description to function comment
1076 // TODO: DistanceToMove - add argument and description to function comment
1077 // TODO: NewFilePointer - add argument and description to function comment
1078 // TODO: MoveMethod - add argument and description to function comment
1079 {
1080 EFI_STATUS Status;
1081 LARGE_INTEGER LargeInt;
1082 UINT32 ErrorCode;
1083
1084 LargeInt.QuadPart = DistanceToMove;
1085 Status = EFI_SUCCESS;
1086
1087 LargeInt.LowPart = Private->WinNtThunk->SetFilePointer (
1088 Private->NtHandle,
1089 LargeInt.LowPart,
1090 &LargeInt.HighPart,
1091 MoveMethod
1092 );
1093
1094 if (LargeInt.LowPart == -1 &&
1095 (ErrorCode = Private->WinNtThunk->GetLastError ()) != NO_ERROR) {
1096 Status = EFI_INVALID_PARAMETER;
1097 }
1098
1099 if (NewFilePointer != NULL) {
1100 *NewFilePointer = LargeInt.QuadPart;
1101 }
1102
1103 return Status;
1104 }