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