1 /* 2 * COPYRIGHT: See COPYING.ARM in the top level directory 3 * PROJECT: ReactOS UEFI Boot Library 4 * FILE: boot/environ/lib/io/device.c 5 * PURPOSE: Boot Library Device Management Routines 6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include "bl.h" 12 13 /* DATA VARIABLES ************************************************************/ 14 15 typedef struct _BL_DEVICE_IO_INFORMATION 16 { 17 ULONGLONG ReadCount; 18 ULONGLONG WriteCount; 19 } BL_DEVICE_IO_INFORMATION, *PBL_DEVICE_IO_INFORMATION; 20 21 LIST_ENTRY DmRegisteredDevices; 22 ULONG DmTableEntries; 23 LIST_ENTRY DmRegisteredDevices; 24 PVOID* DmDeviceTable; 25 26 BL_DEVICE_IO_INFORMATION DmDeviceIoInformation; 27 28 /* FUNCTIONS *****************************************************************/ 29 30 typedef struct _BL_REGISTERED_DEVICE 31 { 32 LIST_ENTRY ListEntry; 33 BL_DEVICE_CALLBACKS Callbacks; 34 } BL_REGISTERED_DEVICE, *PBL_REGISTERED_DEVICE; 35 36 PVOID* BlockIoDeviceTable; 37 ULONG BlockIoDeviceTableEntries; 38 39 ULONG BlockIoFirmwareRemovableDiskCount; 40 ULONG BlockIoFirmwareRawDiskCount; 41 ULONG BlockIoFirmwareCdromCount; 42 43 PVOID BlockIopAlignedBuffer; 44 ULONG BlockIopAlignedBufferSize; 45 46 PVOID BlockIopPartialBlockBuffer; 47 ULONG BlockIopPartialBlockBufferSize; 48 49 PVOID BlockIopPrefetchBuffer; 50 51 PVOID BlockIopReadBlockBuffer; 52 ULONG BlockIopReadBlockBufferSize; 53 54 ULONG HashTableId; 55 56 BOOLEAN BlockIoInitialized; 57 58 NTSTATUS 59 BlockIoOpen ( 60 _In_ PBL_DEVICE_DESCRIPTOR Device, 61 _In_ PBL_DEVICE_ENTRY DeviceEntry 62 ); 63 64 NTSTATUS 65 BlockIoGetInformation ( 66 _In_ PBL_DEVICE_ENTRY DeviceEntry, 67 _Out_ PBL_DEVICE_INFORMATION DeviceInformation 68 ); 69 70 NTSTATUS 71 BlockIoSetInformation ( 72 _In_ PBL_DEVICE_ENTRY DeviceEntry, 73 _Out_ PBL_DEVICE_INFORMATION DeviceInformation 74 ); 75 76 NTSTATUS 77 BlockIoRead ( 78 _In_ PBL_DEVICE_ENTRY DeviceEntry, 79 _In_ PVOID Buffer, 80 _In_ ULONG Size, 81 _Out_ PULONG BytesRead 82 ); 83 84 BL_DEVICE_CALLBACKS BlockIoDeviceFunctionTable = 85 { 86 NULL, 87 BlockIoOpen, 88 NULL, 89 BlockIoRead, 90 NULL, 91 BlockIoGetInformation, 92 BlockIoSetInformation 93 }; 94 95 NTSTATUS 96 BlockIoFirmwareWrite ( 97 _In_ PBL_BLOCK_DEVICE BlockDevice, 98 _In_ PVOID Buffer, 99 _In_ ULONGLONG Block, 100 _In_ ULONGLONG BlockCount 101 ) 102 { 103 return STATUS_NOT_IMPLEMENTED; 104 } 105 106 NTSTATUS 107 BlockIoFirmwareRead ( 108 _In_ PBL_BLOCK_DEVICE BlockDevice, 109 _In_ PVOID Buffer, 110 _In_ ULONGLONG Block, 111 _In_ ULONGLONG BlockCount 112 ) 113 { 114 NTSTATUS Status; 115 EFI_BLOCK_IO *BlockProtocol; 116 BL_ARCH_MODE OldMode; 117 EFI_STATUS EfiStatus; 118 ULONG FailureCount; 119 120 for (FailureCount = 0, Status = STATUS_SUCCESS; 121 FailureCount < 2 && NT_SUCCESS(Status); 122 FailureCount++) 123 { 124 BlockProtocol = BlockDevice->Protocol; 125 126 OldMode = CurrentExecutionContext->Mode; 127 if (CurrentExecutionContext->Mode != 1) 128 { 129 Status = STATUS_NOT_IMPLEMENTED; 130 break; 131 } 132 133 //EfiPrintf(L"EFI Reading BLOCK %d off media %lx (%d blocks)\r\n", 134 //Block, BlockProtocol->Media->MediaId, BlockCount); 135 EfiStatus = BlockProtocol->ReadBlocks(BlockProtocol, 136 BlockProtocol->Media->MediaId, 137 Block, 138 BlockProtocol->Media->BlockSize * BlockCount, 139 Buffer); 140 if (EfiStatus == EFI_SUCCESS) 141 { 142 //EfiPrintf(L"EFI Read complete into buffer\r\n"); 143 //EfiPrintf(L"Buffer data: %lx %lx %lx %lx\r\n", *(PULONG)Buffer, *((PULONG)Buffer + 1), *((PULONG)Buffer + 2), *((PULONG)Buffer + 3)); 144 } 145 146 if (OldMode != 1) 147 { 148 BlpArchSwitchContext(OldMode); 149 } 150 151 Status = EfiGetNtStatusCode(EfiStatus); 152 if (Status != STATUS_MEDIA_CHANGED) 153 { 154 break; 155 } 156 157 EfiCloseProtocol(BlockDevice->Handle, &EfiBlockIoProtocol); 158 159 Status = EfiOpenProtocol(BlockDevice->Handle, 160 &EfiBlockIoProtocol, 161 (PVOID*)BlockDevice->Protocol); 162 } 163 164 return Status; 165 } 166 167 NTSTATUS 168 BlockIopFirmwareOperation ( 169 PBL_DEVICE_ENTRY DeviceEntry, 170 _In_ PVOID Buffer, 171 _In_ ULONGLONG Block, 172 _In_ ULONGLONG BlockCount, 173 _In_ ULONG OperationType 174 ) 175 { 176 ULONG FailureCount; 177 PBL_BLOCK_DEVICE BlockDevice; 178 NTSTATUS Status; 179 180 BlockDevice = DeviceEntry->DeviceSpecificData; 181 182 if (OperationType == 1) 183 { 184 for (FailureCount = 0; FailureCount < 3; FailureCount++) 185 { 186 Status = BlockIoFirmwareWrite(BlockDevice, Buffer, Block, BlockCount); 187 if (Status >= 0) 188 { 189 break; 190 } 191 } 192 } 193 else 194 { 195 for (FailureCount = 0; FailureCount < 3; FailureCount++) 196 { 197 Status = BlockIoFirmwareRead(BlockDevice, Buffer, Block, BlockCount); 198 if (Status >= 0) 199 { 200 break; 201 } 202 } 203 } 204 return Status; 205 } 206 207 NTSTATUS 208 BlockIopFreeAlignedBuffer ( 209 _Inout_ PVOID* Buffer, 210 _Inout_ PULONG BufferSize 211 ) 212 { 213 NTSTATUS Status; 214 215 if (*BufferSize) 216 { 217 Status = MmPapFreePages(*Buffer, BL_MM_INCLUDE_MAPPED_ALLOCATED); 218 219 *Buffer = NULL; 220 *BufferSize = 0; 221 } 222 else 223 { 224 Status = STATUS_SUCCESS; 225 } 226 227 return Status; 228 } 229 230 NTSTATUS 231 BlockIopAllocateAlignedBuffer ( 232 _Inout_ PVOID* Buffer, 233 _Inout_ PULONG BufferSize, 234 _In_ ULONG Size, 235 _In_ ULONG Alignment 236 ) 237 { 238 NTSTATUS Status; 239 240 if (!Alignment) 241 { 242 ++Alignment; 243 } 244 245 Status = STATUS_SUCCESS; 246 if ((Size > *BufferSize) || ((Alignment - 1) & (ULONG_PTR)*Buffer)) 247 { 248 BlockIopFreeAlignedBuffer(Buffer, BufferSize); 249 250 *BufferSize = ROUND_TO_PAGES(Size); 251 252 Status = MmPapAllocatePagesInRange(Buffer, 253 BlLoaderDeviceMemory, 254 *BufferSize >> PAGE_SHIFT, 255 0, 256 Alignment >> PAGE_SHIFT, 257 NULL, 258 0); 259 if (!NT_SUCCESS(Status)) 260 { 261 *BufferSize = 0; 262 } 263 } 264 265 return Status; 266 } 267 268 NTSTATUS 269 BlockIopReadUsingPrefetch ( 270 _In_ PBL_DEVICE_ENTRY DeviceEntry, 271 _In_ PVOID Buffer, 272 _In_ ULONG BlockCount 273 ) 274 { 275 EfiPrintf(L"No prefetch support\r\n"); 276 return STATUS_NOT_IMPLEMENTED; 277 } 278 279 NTSTATUS 280 BlockIopOperation ( 281 _In_ PBL_DEVICE_ENTRY DeviceEntry, 282 _In_ PVOID Buffer, 283 _In_ ULONG BlockCount, 284 _In_ ULONG OperationType 285 ) 286 { 287 PBL_BLOCK_DEVICE BlockDevice; 288 ULONG BufferSize, Alignment; 289 ULONGLONG Offset; 290 NTSTATUS Status; 291 292 BlockDevice = DeviceEntry->DeviceSpecificData; 293 BufferSize = BlockDevice->BlockSize * BlockCount; 294 Offset = BlockDevice->Block + BlockDevice->StartOffset; 295 if ((BlockDevice->LastBlock + 1) < (BlockDevice->Block + BlockCount)) 296 { 297 EfiPrintf(L"Read past end of device\r\n"); 298 return STATUS_INVALID_PARAMETER; 299 } 300 301 Alignment = BlockDevice->Alignment; 302 if (!(Alignment) || !((Alignment - 1) & (ULONG_PTR)Buffer)) 303 { 304 Status = BlockIopFirmwareOperation(DeviceEntry, 305 Buffer, 306 Offset, 307 BlockCount, 308 OperationType); 309 if (!NT_SUCCESS(Status)) 310 { 311 EfiPrintf(L"EFI op failed: %lx\r\n", Status); 312 return Status; 313 } 314 315 return STATUS_SUCCESS; 316 } 317 318 Status = BlockIopAllocateAlignedBuffer(&BlockIopAlignedBuffer, 319 &BlockIopAlignedBufferSize, 320 BufferSize, 321 BlockDevice->Alignment); 322 if (!NT_SUCCESS(Status)) 323 { 324 EfiPrintf(L"No memory for align\r\n"); 325 return STATUS_NO_MEMORY; 326 } 327 328 if (OperationType == 1) 329 { 330 RtlCopyMemory(BlockIopAlignedBuffer, Buffer, BufferSize); 331 } 332 333 Status = BlockIopFirmwareOperation(DeviceEntry, 334 BlockIopAlignedBuffer, 335 Offset, 336 BlockCount, 337 OperationType); 338 if (!NT_SUCCESS(Status)) 339 { 340 return Status; 341 } 342 343 if (!OperationType) 344 { 345 RtlCopyMemory(Buffer, BlockIopAlignedBuffer, BufferSize); 346 } 347 348 return STATUS_SUCCESS; 349 } 350 351 NTSTATUS 352 BlockIopReadWriteVirtualDevice ( 353 _In_ PBL_DEVICE_ENTRY DeviceEntry, 354 _In_ PVOID Buffer, 355 _In_ ULONG Size, 356 _In_ ULONG Operation, 357 _Out_ PULONG BytesRead 358 ) 359 { 360 return STATUS_NOT_IMPLEMENTED; 361 } 362 363 NTSTATUS 364 BlockIopReadPhysicalDevice ( 365 _In_ PBL_DEVICE_ENTRY DeviceEntry, 366 _In_ PVOID Buffer, 367 _In_ ULONG Size, 368 _Out_ PULONG BytesRead 369 ) 370 { 371 PBL_BLOCK_DEVICE BlockDevice; 372 PVOID ReadBuffer; 373 ULONGLONG OffsetEnd, AlignedOffsetEnd, Offset; 374 NTSTATUS Status; 375 376 BlockDevice = DeviceEntry->DeviceSpecificData; 377 ReadBuffer = Buffer; 378 OffsetEnd = Size + BlockDevice->Offset; 379 if (OffsetEnd < Size) 380 { 381 OffsetEnd = -1; 382 return STATUS_INTEGER_OVERFLOW; 383 } 384 385 AlignedOffsetEnd = ~(BlockDevice->BlockSize - 1) & (OffsetEnd + BlockDevice->BlockSize - 1); 386 if (AlignedOffsetEnd < OffsetEnd) 387 { 388 return STATUS_INTEGER_OVERFLOW; 389 } 390 391 if ((BlockDevice->Offset) || (Size != AlignedOffsetEnd)) 392 { 393 Status = BlockIopAllocateAlignedBuffer(&BlockIopReadBlockBuffer, 394 &BlockIopReadBlockBufferSize, 395 AlignedOffsetEnd, 396 BlockDevice->Alignment); 397 if (!NT_SUCCESS(Status)) 398 { 399 EfiPrintf(L"Failed to allocate buffer: %lx\r\n", Status); 400 return Status; 401 } 402 403 ReadBuffer = BlockIopReadBlockBuffer; 404 } 405 406 Offset = AlignedOffsetEnd / BlockDevice->BlockSize; 407 408 if (BlockDevice->Unknown & 2) 409 { 410 Status = BlockIopReadUsingPrefetch(DeviceEntry, 411 ReadBuffer, 412 AlignedOffsetEnd / BlockDevice->BlockSize); 413 if (NT_SUCCESS(Status)) 414 { 415 goto ReadComplete; 416 } 417 } 418 419 Status = BlockIopOperation(DeviceEntry, ReadBuffer, Offset, 0); 420 if (!NT_SUCCESS(Status)) 421 { 422 EfiPrintf(L"Block I/O failed: %lx\r\n", Status); 423 return Status; 424 } 425 426 BlockDevice->Block += Offset; 427 428 ReadComplete: 429 if (ReadBuffer != Buffer) 430 { 431 RtlCopyMemory(Buffer, 432 (PVOID)((ULONG_PTR)ReadBuffer + 433 (ULONG_PTR)BlockDevice->Offset), 434 Size); 435 } 436 437 if (BytesRead) 438 { 439 *BytesRead = Size; 440 } 441 442 return STATUS_SUCCESS; 443 } 444 445 NTSTATUS 446 BlockIopBlockInformationCheck ( 447 _In_ PBL_BLOCK_DEVICE BlockDevice, 448 _In_opt_ PULONG DesiredSize, 449 _Out_opt_ PULONG Size, 450 _Out_opt_ PULONG OutputAdjustedSize 451 ) 452 { 453 ULONG RealSize; 454 ULONGLONG Offset, LastOffset, RemainingOffset, MaxOffset; 455 NTSTATUS Status; 456 457 RealSize = 0; 458 459 Offset = (BlockDevice->Offset * BlockDevice->BlockSize) + BlockDevice->Block; 460 461 if (Offset > ((BlockDevice->LastBlock + 1) * BlockDevice->BlockSize)) 462 { 463 Status = STATUS_INVALID_PARAMETER; 464 goto Quickie; 465 } 466 467 LastOffset = (BlockDevice->LastBlock * BlockDevice->BlockSize) + BlockDevice->BlockSize - 1; 468 469 MaxOffset = BlockDevice->LastBlock; 470 if (MaxOffset < BlockDevice->BlockSize) 471 { 472 MaxOffset = BlockDevice->BlockSize; 473 } 474 475 if (LastOffset < MaxOffset) 476 { 477 478 Status = STATUS_INVALID_PARAMETER; 479 goto Quickie; 480 } 481 482 if (Offset > LastOffset) 483 { 484 Status = STATUS_INVALID_PARAMETER; 485 goto Quickie; 486 } 487 488 RemainingOffset = LastOffset - Offset + 1; 489 490 if (DesiredSize != FALSE) 491 { 492 RealSize = *DesiredSize; 493 } 494 else 495 { 496 RealSize = ULONG_MAX; 497 } 498 499 if (RemainingOffset < RealSize) 500 { 501 if (Size == FALSE) 502 { 503 RealSize = 0; 504 Status = STATUS_INVALID_PARAMETER; 505 goto Quickie; 506 } 507 508 RealSize = RemainingOffset; 509 } 510 511 Status = STATUS_SUCCESS; 512 513 Quickie: 514 if (Size) 515 { 516 *Size = RealSize; 517 } 518 519 return Status; 520 } 521 522 NTSTATUS 523 BlockIoRead ( 524 _In_ PBL_DEVICE_ENTRY DeviceEntry, 525 _In_ PVOID Buffer, 526 _In_ ULONG Size, 527 _Out_ PULONG BytesRead 528 ) 529 { 530 PBL_BLOCK_DEVICE BlockDevice; 531 NTSTATUS Status; 532 533 /* Get the device-specific data, which is our block device descriptor */ 534 BlockDevice = DeviceEntry->DeviceSpecificData; 535 536 /* Make sure that the buffer and size is valid */ 537 Status = BlockIopBlockInformationCheck(BlockDevice, &Size, BytesRead, &Size); 538 if (NT_SUCCESS(Status)) 539 { 540 /* Check if this is a virtual device or a physical device */ 541 if (BlockDevice->DeviceFlags & BL_BLOCK_DEVICE_VIRTUAL_FLAG) 542 { 543 /* Do a virtual read or write */ 544 Status = BlockIopReadWriteVirtualDevice(DeviceEntry, Buffer, Size, 0, BytesRead); 545 } 546 else 547 { 548 /* Do a physical read or write */ 549 Status = BlockIopReadPhysicalDevice(DeviceEntry, Buffer, Size, BytesRead); 550 } 551 } 552 else if (BytesRead) 553 { 554 /* We failed, if the caller wanted bytes read, return 0 */ 555 *BytesRead = 0; 556 } 557 558 /* Return back to the caller */ 559 return Status; 560 } 561 562 NTSTATUS 563 BlockIoSetInformation ( 564 _In_ PBL_DEVICE_ENTRY DeviceEntry, 565 _Out_ PBL_DEVICE_INFORMATION DeviceInformation 566 ) 567 { 568 PBL_BLOCK_DEVICE BlockDevice; 569 ULONGLONG Offset; 570 571 BlockDevice = DeviceEntry->DeviceSpecificData; 572 573 /* Take the current block number and block-offset and conver to full offset */ 574 Offset = DeviceInformation->BlockDeviceInfo.Block * BlockDevice->BlockSize + 575 DeviceInformation->BlockDeviceInfo.Offset; 576 577 /* Make sure that the full offset is still within the bounds of the device */ 578 if (Offset > ((BlockDevice->LastBlock + 1) * BlockDevice->BlockSize - 1)) 579 { 580 EfiPrintf(L"Offset out of bounds\r\n"); 581 return STATUS_INVALID_PARAMETER; 582 } 583 584 /* Convery the full raw offset into a block number and block-offset */ 585 BlockDevice->Block = Offset / BlockDevice->BlockSize; 586 BlockDevice->Offset = Offset % BlockDevice->BlockSize; 587 588 /* Return the unknown */ 589 BlockDevice->Unknown = DeviceInformation->BlockDeviceInfo.Unknown; 590 591 /* All done */ 592 return STATUS_SUCCESS; 593 } 594 595 NTSTATUS 596 BlockIoGetInformation ( 597 _In_ PBL_DEVICE_ENTRY DeviceEntry, 598 _Out_ PBL_DEVICE_INFORMATION DeviceInformation 599 ) 600 { 601 /* Copy the device specific data into the block device information */ 602 RtlCopyMemory(&DeviceInformation->BlockDeviceInfo, 603 DeviceEntry->DeviceSpecificData, 604 sizeof(DeviceInformation->BlockDeviceInfo)); 605 606 /* Hardcode the device type */ 607 DeviceInformation->DeviceType = DiskDevice; 608 return STATUS_SUCCESS; 609 } 610 611 BOOLEAN 612 BlDeviceIsVirtualPartitionDevice ( 613 _In_ PBL_DEVICE_DESCRIPTOR InputDevice, 614 _Outptr_ PBL_DEVICE_DESCRIPTOR* VirtualDevice 615 ) 616 { 617 BOOLEAN IsVirtual; 618 PBL_LOCAL_DEVICE ParentDisk; 619 620 /* Assume it isn't */ 621 IsVirtual = FALSE; 622 623 /* Check if this is a partition device */ 624 if ((InputDevice->DeviceType == LegacyPartitionDevice) || 625 (InputDevice->DeviceType == PartitionDevice)) 626 { 627 /* Check if the parent disk is a VHD */ 628 ParentDisk = &InputDevice->Partition.Disk; 629 if (ParentDisk->Type == VirtualDiskDevice) 630 { 631 /* This is a virtual partition device -- does the caller want it? */ 632 IsVirtual = TRUE; 633 if (VirtualDevice) 634 { 635 *VirtualDevice = (PBL_DEVICE_DESCRIPTOR)(&ParentDisk->VirtualHardDisk + 1); 636 } 637 } 638 } 639 640 /* Return */ 641 return IsVirtual; 642 } 643 644 NTSTATUS 645 BlDeviceSetInformation ( 646 _In_ ULONG DeviceId, 647 _Out_ PBL_DEVICE_INFORMATION DeviceInformation 648 ) 649 { 650 PBL_DEVICE_ENTRY DeviceEntry; 651 652 /* This parameter is not optional */ 653 if (!DeviceInformation) 654 { 655 return STATUS_INVALID_PARAMETER; 656 } 657 658 /* Make sure the device ID is valid */ 659 if (DmTableEntries <= DeviceId) 660 { 661 return STATUS_INVALID_PARAMETER; 662 } 663 664 /* Get the device entry */ 665 DeviceEntry = DmDeviceTable[DeviceId]; 666 if (!DeviceEntry) 667 { 668 return STATUS_INVALID_PARAMETER; 669 } 670 671 /* Make sure the device is open */ 672 if (!(DeviceEntry->Flags & BL_DEVICE_ENTRY_OPENED)) 673 { 674 return STATUS_INVALID_PARAMETER; 675 } 676 677 /* Set the device information */ 678 return DeviceEntry->Callbacks.SetInformation(DeviceEntry, DeviceInformation); 679 } 680 681 NTSTATUS 682 BlDeviceGetInformation ( 683 _In_ ULONG DeviceId, 684 _Out_ PBL_DEVICE_INFORMATION DeviceInformation 685 ) 686 { 687 PBL_DEVICE_ENTRY DeviceEntry; 688 689 /* This parameter is not optional */ 690 if (!DeviceInformation) 691 { 692 return STATUS_INVALID_PARAMETER; 693 } 694 695 /* Make sure the device ID is valid */ 696 if (DmTableEntries <= DeviceId) 697 { 698 return STATUS_INVALID_PARAMETER; 699 } 700 701 /* Get the device entry */ 702 DeviceEntry = DmDeviceTable[DeviceId]; 703 if (!DeviceEntry) 704 { 705 return STATUS_INVALID_PARAMETER; 706 } 707 708 /* Make sure the device is open */ 709 if (!(DeviceEntry->Flags & BL_DEVICE_ENTRY_OPENED)) 710 { 711 return STATUS_INVALID_PARAMETER; 712 } 713 714 /* Return the device information */ 715 DeviceInformation->DeviceType = DeviceEntry->DeviceDescriptor->DeviceType; 716 return DeviceEntry->Callbacks.GetInformation(DeviceEntry, DeviceInformation); 717 } 718 719 NTSTATUS 720 BlDeviceRead ( 721 _In_ ULONG DeviceId, 722 _In_ PVOID Buffer, 723 _In_ ULONG Size, 724 _Out_opt_ PULONG BytesRead 725 ) 726 { 727 PBL_DEVICE_ENTRY DeviceEntry; 728 NTSTATUS Status; 729 ULONG BytesTransferred; 730 731 /* Make sure we have a buffer, and the device ID is valid */ 732 if (!(Buffer) || (DmTableEntries <= DeviceId)) 733 { 734 return STATUS_INVALID_PARAMETER; 735 } 736 737 /* Get the device entry for it */ 738 DeviceEntry = DmDeviceTable[DeviceId]; 739 if (!DeviceEntry) 740 { 741 return STATUS_INVALID_PARAMETER; 742 } 743 744 /* Make sure this is a device opened for read access */ 745 if (!(DeviceEntry->Flags & BL_DEVICE_ENTRY_OPENED) || 746 !(DeviceEntry->Flags & BL_DEVICE_ENTRY_READ_ACCESS)) 747 { 748 return STATUS_INVALID_PARAMETER; 749 } 750 751 /* Issue the read */ 752 Status = DeviceEntry->Callbacks.Read(DeviceEntry, 753 Buffer, 754 Size, 755 &BytesTransferred); 756 if (!DeviceEntry->Unknown) 757 { 758 /* Update performance counters */ 759 DmDeviceIoInformation.ReadCount += BytesTransferred; 760 } 761 762 /* Return back how many bytes were read, if caller wants to know */ 763 if (BytesRead) 764 { 765 *BytesRead = BytesTransferred; 766 } 767 768 /* Return read result */ 769 return Status; 770 } 771 772 NTSTATUS 773 BlDeviceReadAtOffset ( 774 _In_ ULONG DeviceId, 775 _In_ ULONG Size, 776 _In_ ULONGLONG Offset, 777 _In_ PVOID Buffer, 778 _Out_ PULONG BytesRead 779 ) 780 { 781 NTSTATUS Status; 782 BL_DEVICE_INFORMATION DeviceInfo; 783 784 /* Get the current block and offset */ 785 Status = BlDeviceGetInformation(DeviceId, &DeviceInfo); 786 if (!NT_SUCCESS(Status)) 787 { 788 return Status; 789 } 790 791 /* Get the block and block-offset based on the new raw offset */ 792 DeviceInfo.BlockDeviceInfo.Block = Offset / DeviceInfo.BlockDeviceInfo.BlockSize; 793 DeviceInfo.BlockDeviceInfo.Offset = Offset % DeviceInfo.BlockDeviceInfo.BlockSize; 794 795 /* Update the block and offset */ 796 Status = BlDeviceSetInformation(DeviceId, &DeviceInfo); 797 if (NT_SUCCESS(Status)) 798 { 799 /* Now issue a read, with this block and offset configured */ 800 Status = BlDeviceRead(DeviceId, Buffer, Size, BytesRead); 801 } 802 803 /* All good, return the caller */ 804 return Status; 805 } 806 807 BOOLEAN 808 BlpDeviceCompare ( 809 _In_ PBL_DEVICE_DESCRIPTOR Device1, 810 _In_ PBL_DEVICE_DESCRIPTOR Device2 811 ) 812 { 813 BOOLEAN DeviceMatch; 814 ULONG DeviceSize; 815 816 /* Assume failure */ 817 DeviceMatch = FALSE; 818 819 /* Check if the two devices exist and are identical in type */ 820 if ((Device1) && (Device2) && (Device1->DeviceType == Device2->DeviceType)) 821 { 822 /* Take the bigger of the two sizes */ 823 DeviceSize = max(Device1->Size, Device2->Size); 824 if (DeviceSize >= (ULONG)FIELD_OFFSET(BL_DEVICE_DESCRIPTOR, Local)) 825 { 826 /* Compare the two devices up to their size */ 827 if (RtlEqualMemory(&Device1->Local, 828 &Device2->Local, 829 DeviceSize - FIELD_OFFSET(BL_DEVICE_DESCRIPTOR, Local))) 830 { 831 /* They match! */ 832 DeviceMatch = TRUE; 833 } 834 } 835 } 836 837 /* Return matching state */ 838 return DeviceMatch; 839 } 840 841 NTSTATUS 842 BlockIopFreeAllocations ( 843 _In_ PBL_BLOCK_DEVICE BlockDevice 844 ) 845 { 846 /* If a block device was passed in, free it */ 847 if (BlockDevice) 848 { 849 BlMmFreeHeap(BlockDevice); 850 } 851 852 /* Nothing else to do */ 853 return STATUS_SUCCESS; 854 } 855 856 NTSTATUS 857 BlockIoEfiGetBlockIoInformation ( 858 _In_ PBL_BLOCK_DEVICE BlockDevice 859 ) 860 { 861 NTSTATUS Status; 862 EFI_BLOCK_IO_MEDIA *Media; 863 864 /* Open the Block I/O protocol on this device */ 865 Status = EfiOpenProtocol(BlockDevice->Handle, 866 &EfiBlockIoProtocol, 867 (PVOID*)&BlockDevice->Protocol); 868 if (!NT_SUCCESS(Status)) 869 { 870 return Status; 871 } 872 873 /* Get information on the block media */ 874 Media = BlockDevice->Protocol->Media; 875 876 /* Set the appropriate device flags */ 877 BlockDevice->DeviceFlags = 0; 878 if (Media->RemovableMedia) 879 { 880 BlockDevice->DeviceFlags = BL_BLOCK_DEVICE_REMOVABLE_FLAG; 881 } 882 if (Media->MediaPresent) 883 { 884 BlockDevice->DeviceFlags |= BL_BLOCK_DEVICE_PRESENT_FLAG; 885 } 886 887 /* No clue */ 888 BlockDevice->Unknown = 0; 889 890 /* Set the block size */ 891 BlockDevice->BlockSize = Media->BlockSize; 892 893 /* Make sure there's a last block value */ 894 if (!Media->LastBlock) 895 { 896 return STATUS_INVALID_PARAMETER; 897 } 898 899 /* Don't let it be too high */ 900 if (Media->LastBlock > 0xFFFFFFFFFFE) 901 { 902 BlockDevice->LastBlock = 0xFFFFFFFFFFE; 903 } 904 else 905 { 906 BlockDevice->LastBlock = Media->LastBlock; 907 } 908 909 /* Make the alignment the smaller of the I/O alignment or the block size */ 910 if (Media->IoAlign >= Media->BlockSize) 911 { 912 BlockDevice->Alignment = Media->IoAlign; 913 } 914 else 915 { 916 BlockDevice->Alignment = Media->BlockSize; 917 } 918 919 /* All good */ 920 return STATUS_SUCCESS; 921 } 922 923 NTSTATUS 924 BlockIoEfiGetChildHandle ( 925 _In_ PBL_PROTOCOL_HANDLE ProtocolInterface, 926 _In_ PBL_PROTOCOL_HANDLE ChildProtocolInterface) 927 { 928 NTSTATUS Status; 929 ULONG i, DeviceCount; 930 EFI_DEVICE_PATH *DevicePath, *ParentDevicePath; 931 EFI_HANDLE *DeviceHandles; 932 EFI_HANDLE Handle; 933 934 /* Find all the Block I/O device handles on the system */ 935 DeviceCount = 0; 936 DeviceHandles = 0; 937 Status = EfiLocateHandleBuffer(ByProtocol, 938 &EfiBlockIoProtocol, 939 &DeviceCount, 940 &DeviceHandles); 941 if (!NT_SUCCESS(Status)) 942 { 943 /* Failed to enumerate, bail out */ 944 return Status; 945 } 946 947 /* Loop all the handles */ 948 for (i = 0; i < DeviceCount; i++) 949 { 950 /* Check if this is the device itself */ 951 Handle = DeviceHandles[i]; 952 if (Handle == ProtocolInterface->Handle) 953 { 954 /* Skip it */ 955 continue; 956 } 957 958 /* Get the device path of this device */ 959 Status = EfiOpenProtocol(Handle, 960 &EfiDevicePathProtocol, 961 (PVOID*)&DevicePath); 962 if (!NT_SUCCESS(Status)) 963 { 964 /* We failed, skip it */ 965 continue; 966 } 967 968 /* See if we are its parent */ 969 ParentDevicePath = EfiIsDevicePathParent(ProtocolInterface->Interface, 970 DevicePath); 971 if (ParentDevicePath == ProtocolInterface->Interface) 972 { 973 /* Yup, return back to caller */ 974 ChildProtocolInterface->Handle = Handle; 975 ChildProtocolInterface->Interface = DevicePath; 976 Status = STATUS_SUCCESS; 977 goto Quickie; 978 } 979 980 /* Close the device path */ 981 EfiCloseProtocol(Handle, &EfiDevicePathProtocol); 982 } 983 984 /* If we got here, nothing was found */ 985 Status = STATUS_NO_SUCH_DEVICE; 986 987 Quickie: 988 /* Free the handle array buffer */ 989 BlMmFreeHeap(DeviceHandles); 990 return Status; 991 } 992 993 NTSTATUS 994 BlockIoGetGPTDiskSignature ( 995 _In_ PBL_DEVICE_ENTRY DeviceEntry, 996 _Out_ PGUID DiskSignature 997 ) 998 { 999 EfiPrintf(L"GPT not supported\r\n"); 1000 return STATUS_NOT_IMPLEMENTED; 1001 } 1002 1003 NTSTATUS 1004 BlockIoEfiGetDeviceInformation ( 1005 _In_ PBL_DEVICE_ENTRY DeviceEntry 1006 ) 1007 { 1008 NTSTATUS Status; 1009 PBL_DEVICE_DESCRIPTOR Device; 1010 PBL_BLOCK_DEVICE BlockDevice; 1011 EFI_DEVICE_PATH *LeafNode; 1012 BL_PROTOCOL_HANDLE Protocol[2]; 1013 ACPI_HID_DEVICE_PATH *AcpiPath; 1014 HARDDRIVE_DEVICE_PATH *DiskPath; 1015 BOOLEAN Found; 1016 ULONG i; 1017 1018 /* Extract the identifier, and the block device object */ 1019 Device = DeviceEntry->DeviceDescriptor; 1020 BlockDevice = (PBL_BLOCK_DEVICE)DeviceEntry->DeviceSpecificData; 1021 1022 /* Initialize protocol handles */ 1023 Protocol[0].Handle = BlockDevice->Handle; 1024 Protocol[1].Handle = 0; 1025 1026 /* Open this device */ 1027 Status = EfiOpenProtocol(Protocol[0].Handle, 1028 &EfiDevicePathProtocol, 1029 &Protocol[0].Interface); 1030 if (!NT_SUCCESS(Status)) 1031 { 1032 /* Fail */ 1033 return Status; 1034 } 1035 1036 /* Iterate twice -- once for the top level, once for the bottom */ 1037 for (i = 0, Found = FALSE; Found == FALSE && Protocol[i].Handle; i++) 1038 { 1039 /* Check what kind of leaf node device this is */ 1040 LeafNode = EfiGetLeafNode(Protocol[i].Interface); 1041 EfiPrintf(L"Pass %d, Leaf node: %p Type: %d\r\n", i, LeafNode, LeafNode->Type); 1042 if (LeafNode->Type == ACPI_DEVICE_PATH) 1043 { 1044 /* We only support floppy drives */ 1045 AcpiPath = (ACPI_HID_DEVICE_PATH*)LeafNode; 1046 if ((AcpiPath->HID == EISA_PNP_ID(0x604)) || 1047 (AcpiPath->HID == EISA_PNP_ID(0x700))) 1048 { 1049 /* Set the boot library specific device types */ 1050 Device->DeviceType = LocalDevice; 1051 Device->Local.Type = FloppyDevice; 1052 1053 /* The ACPI UID is the drive number */ 1054 Device->Local.FloppyDisk.DriveNumber = AcpiPath->UID; 1055 1056 /* We found a match */ 1057 Found = TRUE; 1058 } 1059 } 1060 else if ((LeafNode->Type == MEDIA_DEVICE_PATH) && (i == 1)) 1061 { 1062 /* Extract the disk path and check if it's a physical disk */ 1063 DiskPath = (HARDDRIVE_DEVICE_PATH*)LeafNode; 1064 EfiPrintf(L"Disk path: %p Type: %lx\r\n", DiskPath, LeafNode->SubType); 1065 if (LeafNode->SubType == MEDIA_HARDDRIVE_DP) 1066 { 1067 /* Set this as a local device */ 1068 Device->Local.Type = LocalDevice; 1069 1070 /* Check if this is an MBR partition */ 1071 if (DiskPath->SignatureType == SIGNATURE_TYPE_MBR) 1072 { 1073 /* Set that this is a local partition */ 1074 Device->DeviceType = LegacyPartitionDevice; 1075 Device->Partition.Disk.Type = LocalDevice; 1076 1077 /* Write the MBR partition signature */ 1078 BlockDevice->PartitionType = MbrPartition; 1079 BlockDevice->Disk.Mbr.Signature = *(PULONG)&DiskPath->Signature[0]; 1080 Found = TRUE; 1081 } 1082 else if (DiskPath->SignatureType == SIGNATURE_TYPE_GUID) 1083 { 1084 /* Set this as a GPT partition */ 1085 BlockDevice->PartitionType = GptPartition; 1086 Device->Local.HardDisk.PartitionType = GptPartition; 1087 1088 /* Get the GPT signature */ 1089 Status = BlockIoGetGPTDiskSignature(DeviceEntry, 1090 &Device->Local.HardDisk.Gpt.PartitionSignature); 1091 if (NT_SUCCESS(Status)) 1092 { 1093 /* Copy it */ 1094 RtlCopyMemory(&BlockDevice->Disk.Gpt.Signature, 1095 &Device->Local.HardDisk.Gpt.PartitionSignature, 1096 sizeof(BlockDevice->Disk.Gpt.Signature)); 1097 Found = TRUE; 1098 } 1099 } 1100 1101 /* Otherwise, this is a raw disk */ 1102 BlockDevice->PartitionType = RawPartition; 1103 Device->Local.HardDisk.PartitionType = RawPartition; 1104 Device->Local.HardDisk.Raw.DiskNumber = BlockIoFirmwareRawDiskCount++; 1105 } 1106 else if (LeafNode->SubType == MEDIA_CDROM_DP) 1107 { 1108 /* Set block device information */ 1109 EfiPrintf(L"Found CD-ROM\r\n"); 1110 BlockDevice->PartitionType = RawPartition; 1111 BlockDevice->Type = CdRomDevice; 1112 1113 /* Set CDROM data */ 1114 Device->Local.Type = CdRomDevice; 1115 Device->Local.FloppyDisk.DriveNumber = 0; 1116 Found = TRUE; 1117 } 1118 } 1119 else if ((LeafNode->Type != MEDIA_DEVICE_PATH) && 1120 (LeafNode->Type != ACPI_DEVICE_PATH) && 1121 (i == 0)) 1122 { 1123 /* This is probably a messaging device node. Are we under it? */ 1124 Status = BlockIoEfiGetChildHandle(Protocol, &Protocol[1]); 1125 EfiPrintf(L"Pass 0, non DP/ACPI path. Child handle obtained: %lx\r\n", Protocol[1].Handle); 1126 if (!NT_SUCCESS(Status)) 1127 { 1128 /* We're not. So this must be a raw device */ 1129 Device->DeviceType = LocalDevice; 1130 Found = TRUE; 1131 1132 /* Is it a removable raw device? */ 1133 if (BlockDevice->DeviceFlags & BL_BLOCK_DEVICE_REMOVABLE_FLAG) 1134 { 1135 /* This is a removable (CD or Floppy or USB) device */ 1136 BlockDevice->Type = FloppyDevice; 1137 Device->Local.Type = FloppyDevice; 1138 Device->Local.FloppyDisk.DriveNumber = BlockIoFirmwareRemovableDiskCount++; 1139 EfiPrintf(L"Found Floppy\r\n"); 1140 } 1141 else 1142 { 1143 /* It's a fixed device */ 1144 BlockDevice->Type = DiskDevice; 1145 Device->Local.Type = DiskDevice; 1146 1147 /* Set it as a raw partition */ 1148 Device->Local.HardDisk.PartitionType = RawPartition; 1149 Device->Local.HardDisk.Mbr.PartitionSignature = BlockIoFirmwareRawDiskCount++; 1150 EfiPrintf(L"Found raw disk\r\n"); 1151 } 1152 } 1153 } 1154 } 1155 1156 /* Close any protocols that we opened for each handle */ 1157 while (i) 1158 { 1159 EfiCloseProtocol(Protocol[--i].Handle, &EfiDevicePathProtocol); 1160 } 1161 1162 /* Return appropriate status */ 1163 return Found ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED; 1164 } 1165 1166 NTSTATUS 1167 BlockIoEfiReset ( 1168 VOID 1169 ) 1170 { 1171 EfiPrintf(L"not implemented\r\n"); 1172 return STATUS_NOT_IMPLEMENTED; 1173 } 1174 1175 NTSTATUS 1176 BlockIoEfiFlush ( 1177 VOID 1178 ) 1179 { 1180 EfiPrintf(L"not implemented\r\n"); 1181 return STATUS_NOT_IMPLEMENTED; 1182 } 1183 1184 NTSTATUS 1185 BlockIoEfiCreateDeviceEntry ( 1186 _In_ PBL_DEVICE_ENTRY *DeviceEntry, 1187 _Out_ PVOID Handle 1188 ) 1189 { 1190 PBL_DEVICE_ENTRY IoDeviceEntry; 1191 PBL_BLOCK_DEVICE BlockDevice; 1192 NTSTATUS Status; 1193 PBL_DEVICE_DESCRIPTOR Device; 1194 1195 /* Allocate the entry for this device and zero it out */ 1196 IoDeviceEntry = BlMmAllocateHeap(sizeof(*IoDeviceEntry)); 1197 if (!IoDeviceEntry) 1198 { 1199 return STATUS_NO_MEMORY; 1200 } 1201 RtlZeroMemory(IoDeviceEntry, sizeof(*IoDeviceEntry)); 1202 1203 /* Allocate the device descriptor for this device and zero it out */ 1204 Device = BlMmAllocateHeap(sizeof(*Device)); 1205 if (!Device) 1206 { 1207 return STATUS_NO_MEMORY; 1208 } 1209 RtlZeroMemory(Device, sizeof(*Device)); 1210 1211 /* Allocate the block device specific data, and zero it out */ 1212 BlockDevice = BlMmAllocateHeap(sizeof(*BlockDevice)); 1213 if (!BlockDevice) 1214 { 1215 return STATUS_NO_MEMORY; 1216 } 1217 RtlZeroMemory(BlockDevice, sizeof(*BlockDevice)); 1218 1219 /* Save the descriptor and block device specific data */ 1220 IoDeviceEntry->DeviceSpecificData = BlockDevice; 1221 IoDeviceEntry->DeviceDescriptor = Device; 1222 1223 /* Set the size of the descriptor */ 1224 Device->Size = sizeof(*Device); 1225 1226 /* Copy the standard I/O callbacks */ 1227 RtlCopyMemory(&IoDeviceEntry->Callbacks, 1228 &BlockIoDeviceFunctionTable, 1229 sizeof(IoDeviceEntry->Callbacks)); 1230 1231 /* Add the two that are firmware specific */ 1232 IoDeviceEntry->Callbacks.Reset = BlockIoEfiReset; 1233 IoDeviceEntry->Callbacks.Flush = BlockIoEfiFlush; 1234 1235 /* Save the EFI handle */ 1236 BlockDevice->Handle = Handle; 1237 1238 /* Get information on this device from EFI, caching it in the device */ 1239 Status = BlockIoEfiGetBlockIoInformation(BlockDevice); 1240 if (NT_SUCCESS(Status)) 1241 { 1242 /* Build the descriptor structure for this device */ 1243 Status = BlockIoEfiGetDeviceInformation(IoDeviceEntry); 1244 if (NT_SUCCESS(Status)) 1245 { 1246 /* We have a fully constructed device, return it */ 1247 *DeviceEntry = IoDeviceEntry; 1248 return STATUS_SUCCESS; 1249 } 1250 } 1251 1252 /* Failure path, free the descriptor if we allocated one */ 1253 if (IoDeviceEntry->DeviceDescriptor) 1254 { 1255 BlMmFreeHeap(IoDeviceEntry->DeviceDescriptor); 1256 } 1257 1258 /* Free any other specific allocations */ 1259 BlockIopFreeAllocations(IoDeviceEntry->DeviceSpecificData); 1260 1261 /* Free the device entry itself and return the failure code */ 1262 BlMmFreeHeap(IoDeviceEntry); 1263 EfiPrintf(L"Failed: %lx\r\n", Status); 1264 return Status; 1265 } 1266 1267 NTSTATUS 1268 BlockIoEfiCompareDevice ( 1269 _In_ PBL_DEVICE_DESCRIPTOR Device, 1270 _In_ EFI_HANDLE Handle 1271 ) 1272 { 1273 PBL_LOCAL_DEVICE LocalDeviceInfo, EfiLocalDeviceInfo; 1274 PBL_DEVICE_ENTRY DeviceEntry; 1275 PBL_DEVICE_DESCRIPTOR EfiDevice; 1276 NTSTATUS Status; 1277 1278 DeviceEntry = NULL; 1279 1280 /* Check if no device was given */ 1281 if (!Device) 1282 { 1283 /* Fail the comparison */ 1284 Status = STATUS_INVALID_PARAMETER; 1285 goto Quickie; 1286 } 1287 1288 /* Check if this is a local disk device */ 1289 if (Device->DeviceType != DiskDevice) 1290 { 1291 /* Nope -- is it a partition device? */ 1292 if ((Device->DeviceType != LegacyPartitionDevice) && 1293 (Device->DeviceType != PartitionDevice)) 1294 { 1295 /* Nope, so we can't compare */ 1296 Status = STATUS_INVALID_PARAMETER; 1297 goto Quickie; 1298 } 1299 1300 /* If so, return the device information for the parent disk */ 1301 LocalDeviceInfo = &Device->Partition.Disk; 1302 } 1303 else 1304 { 1305 /* Just return the disk information itself */ 1306 LocalDeviceInfo = &Device->Local; 1307 } 1308 1309 /* Create an EFI device entry for the EFI device handle */ 1310 Status = BlockIoEfiCreateDeviceEntry(&DeviceEntry, Handle); 1311 if (!NT_SUCCESS(Status)) 1312 { 1313 goto Quickie; 1314 } 1315 1316 /* Read the descriptor and assume failure for now */ 1317 EfiDevice = DeviceEntry->DeviceDescriptor; 1318 Status = STATUS_UNSUCCESSFUL; 1319 1320 /* Check if the EFI device is a disk */ 1321 if (EfiDevice->DeviceType != DiskDevice) 1322 { 1323 /* Nope, is it a partition? */ 1324 if ((EfiDevice->DeviceType != LegacyPartitionDevice) && 1325 (EfiDevice->DeviceType != PartitionDevice)) 1326 { 1327 /* Neither, invalid handle so bail out */ 1328 Status = STATUS_INVALID_PARAMETER; 1329 goto Quickie; 1330 } 1331 1332 /* Yes, so get the information of the parent disk */ 1333 EfiLocalDeviceInfo = &EfiDevice->Partition.Disk; 1334 } 1335 else 1336 { 1337 /* It's a disk, so get the disk information itself */ 1338 EfiLocalDeviceInfo = &EfiDevice->Local; 1339 } 1340 1341 /* Are the two devices the same type? */ 1342 if (EfiLocalDeviceInfo->Type != LocalDeviceInfo->Type) 1343 { 1344 /* Nope, that was easy */ 1345 goto Quickie; 1346 } 1347 1348 /* Yes, what kind of device is the EFI side? */ 1349 switch (EfiLocalDeviceInfo->Type) 1350 { 1351 case LocalDevice: 1352 1353 /* Local hard drive, compare the signature */ 1354 if (RtlCompareMemory(&EfiLocalDeviceInfo->HardDisk, 1355 &LocalDeviceInfo->HardDisk, 1356 sizeof(LocalDeviceInfo->HardDisk)) == 1357 sizeof(LocalDeviceInfo->HardDisk)) 1358 { 1359 Status = STATUS_SUCCESS; 1360 } 1361 break; 1362 1363 case FloppyDevice: 1364 case CdRomDevice: 1365 1366 /* Removable floppy or CD, compare the disk number */ 1367 if (RtlCompareMemory(&EfiLocalDeviceInfo->FloppyDisk, 1368 &LocalDeviceInfo->FloppyDisk, 1369 sizeof(LocalDeviceInfo->FloppyDisk)) == 1370 sizeof(LocalDeviceInfo->FloppyDisk)) 1371 { 1372 Status = STATUS_SUCCESS; 1373 } 1374 break; 1375 1376 case RamDiskDevice: 1377 1378 /* RAM disk, compare the size and base information */ 1379 if (RtlCompareMemory(&EfiLocalDeviceInfo->RamDisk, 1380 &LocalDeviceInfo->RamDisk, 1381 sizeof(LocalDeviceInfo->RamDisk)) == 1382 sizeof(LocalDeviceInfo->RamDisk)) 1383 { 1384 Status = STATUS_SUCCESS; 1385 } 1386 break; 1387 1388 case FileDevice: 1389 1390 /* File, compare the file identifier */ 1391 if (RtlCompareMemory(&EfiLocalDeviceInfo->File, 1392 &LocalDeviceInfo->File, 1393 sizeof(LocalDeviceInfo->File)) == 1394 sizeof(LocalDeviceInfo->File)) 1395 { 1396 Status = STATUS_SUCCESS; 1397 } 1398 break; 1399 1400 /* Something else we don't support */ 1401 default: 1402 break; 1403 } 1404 1405 Quickie: 1406 /* All done, did we have an EFI device entry? */ 1407 if (DeviceEntry) 1408 { 1409 /* Free it, since we only needed it locally for comparison */ 1410 BlMmFreeHeap(DeviceEntry->DeviceDescriptor); 1411 BlockIopFreeAllocations(DeviceEntry->DeviceSpecificData); 1412 BlMmFreeHeap(DeviceEntry); 1413 } 1414 1415 /* Return back to the caller */ 1416 return Status; 1417 } 1418 1419 NTSTATUS 1420 BlockIoFirmwareOpen ( 1421 _In_ PBL_DEVICE_DESCRIPTOR Device, 1422 _In_ PBL_BLOCK_DEVICE BlockIoDevice 1423 ) 1424 { 1425 NTSTATUS Status; 1426 BOOLEAN DeviceMatch; 1427 BL_HASH_ENTRY HashEntry; 1428 ULONG i, Id, DeviceCount; 1429 PBL_DEVICE_ENTRY DeviceEntry; 1430 EFI_HANDLE* DeviceHandles; 1431 1432 /* Initialize everything */ 1433 DeviceEntry = NULL; 1434 DeviceCount = 0; 1435 DeviceHandles = 0; 1436 DeviceEntry = NULL; 1437 1438 /* Ask EFI for handles to all block devices */ 1439 Status = EfiLocateHandleBuffer(ByProtocol, 1440 &EfiBlockIoProtocol, 1441 &DeviceCount, 1442 &DeviceHandles); 1443 if (!NT_SUCCESS(Status)) 1444 { 1445 return STATUS_NO_SUCH_DEVICE; 1446 } 1447 1448 /* Build a hash entry, with the value inline */ 1449 HashEntry.Flags = BL_HT_VALUE_IS_INLINE; 1450 HashEntry.Size = sizeof(EFI_HANDLE); 1451 1452 /* Loop each device we got */ 1453 DeviceMatch = FALSE; 1454 Status = STATUS_NO_SUCH_DEVICE; 1455 for (i = 0; i < DeviceCount; i++) 1456 { 1457 /* Check if we have a match in the device hash table */ 1458 HashEntry.Value = DeviceHandles[i]; 1459 Status = BlHtLookup(HashTableId, &HashEntry, 0); 1460 if (NT_SUCCESS(Status)) 1461 { 1462 /* We already know about this device */ 1463 EfiPrintf(L"Device is known\r\n"); 1464 continue; 1465 } 1466 1467 /* New device, store it in the hash table */ 1468 Status = BlHtStore(HashTableId, 1469 &HashEntry, 1470 DeviceHandles[i], 1471 sizeof(DeviceHandles[i])); 1472 if (!NT_SUCCESS(Status)) 1473 { 1474 /* Free the array and fail */ 1475 BlMmFreeHeap(DeviceHandles); 1476 break; 1477 } 1478 1479 /* Create an entry for this device*/ 1480 Status = BlockIoEfiCreateDeviceEntry(&DeviceEntry, DeviceHandles[i]); 1481 if (!NT_SUCCESS(Status)) 1482 { 1483 EfiPrintf(L"EFI create failed: %lx\r\n", Status); 1484 continue; 1485 } 1486 1487 /* Add the device entry to the device table */ 1488 Status = BlTblSetEntry(&BlockIoDeviceTable, 1489 &BlockIoDeviceTableEntries, 1490 DeviceEntry, 1491 &Id, 1492 TblDoNotPurgeEntry); 1493 if (!NT_SUCCESS(Status)) 1494 { 1495 /* Remove it from teh hash table */ 1496 BlHtDelete(HashTableId, &HashEntry); 1497 1498 /* Free the block I/O device data */ 1499 BlockIopFreeAllocations(DeviceEntry->DeviceSpecificData); 1500 1501 /* Free the descriptor */ 1502 BlMmFreeHeap(DeviceEntry->DeviceDescriptor); 1503 1504 /* Free the entry */ 1505 BlMmFreeHeap(DeviceEntry); 1506 break; 1507 } 1508 1509 /* Does this device match what we're looking for? */ 1510 DeviceMatch = BlpDeviceCompare(DeviceEntry->DeviceDescriptor, Device); 1511 if (DeviceMatch) 1512 { 1513 /* Yep, return the data back */ 1514 RtlCopyMemory(BlockIoDevice, 1515 DeviceEntry->DeviceSpecificData, 1516 sizeof(*BlockIoDevice)); 1517 Status = STATUS_SUCCESS; 1518 break; 1519 } 1520 } 1521 1522 /* Free the device handle buffer array */ 1523 BlMmFreeHeap(DeviceHandles); 1524 1525 /* Return status */ 1526 return Status; 1527 } 1528 1529 NTSTATUS 1530 PartitionOpen ( 1531 _In_ PBL_DEVICE_DESCRIPTOR Device, 1532 _In_ PBL_DEVICE_ENTRY DeviceEntry 1533 ) 1534 { 1535 EfiPrintf(L"Not implemented!\r\n"); 1536 return STATUS_NOT_IMPLEMENTED; 1537 } 1538 1539 NTSTATUS 1540 VhdFileDeviceOpen ( 1541 _In_ PBL_DEVICE_DESCRIPTOR Device, 1542 _In_ PBL_DEVICE_ENTRY DeviceEntry 1543 ) 1544 { 1545 EfiPrintf(L"Not implemented!\r\n"); 1546 return STATUS_NOT_IMPLEMENTED; 1547 } 1548 1549 NTSTATUS 1550 DiskClose ( 1551 _In_ PBL_DEVICE_ENTRY DeviceEntry 1552 ) 1553 { 1554 NTSTATUS Status, LocalStatus; 1555 PBL_BLOCK_DEVICE BlockDevice; 1556 1557 /* Assume success */ 1558 Status = STATUS_SUCCESS; 1559 BlockDevice = DeviceEntry->DeviceSpecificData; 1560 1561 /* Close the protocol */ 1562 LocalStatus = EfiCloseProtocol(BlockDevice->Handle, &EfiBlockIoProtocol); 1563 if (!NT_SUCCESS(LocalStatus)) 1564 { 1565 /* Only inherit failures */ 1566 Status = LocalStatus; 1567 } 1568 1569 /* Free the block device allocations */ 1570 LocalStatus = BlockIopFreeAllocations(BlockDevice); 1571 if (!NT_SUCCESS(LocalStatus)) 1572 { 1573 /* Only inherit failures */ 1574 Status = LocalStatus; 1575 } 1576 1577 /* Return back to caller */ 1578 return Status; 1579 } 1580 1581 NTSTATUS 1582 DiskOpen ( 1583 _In_ PBL_DEVICE_DESCRIPTOR Device, 1584 _In_ PBL_DEVICE_ENTRY DeviceEntry 1585 ) 1586 { 1587 NTSTATUS Status; 1588 1589 /* Use firmware-specific functions to open the disk */ 1590 Status = BlockIoFirmwareOpen(Device, DeviceEntry->DeviceSpecificData); 1591 if (NT_SUCCESS(Status)) 1592 { 1593 /* Overwrite with our own close routine */ 1594 DeviceEntry->Callbacks.Close = DiskClose; 1595 } 1596 1597 /* Return back to caller */ 1598 return Status; 1599 } 1600 1601 NTSTATUS 1602 RdDeviceOpen ( 1603 _In_ PBL_DEVICE_DESCRIPTOR Device, 1604 _In_ PBL_DEVICE_ENTRY DeviceEntry 1605 ) 1606 { 1607 EfiPrintf(L"Not implemented!\r\n"); 1608 return STATUS_NOT_IMPLEMENTED; 1609 } 1610 1611 NTSTATUS 1612 FileDeviceOpen ( 1613 _In_ PBL_DEVICE_DESCRIPTOR Device, 1614 _In_ PBL_DEVICE_ENTRY DeviceEntry 1615 ) 1616 { 1617 EfiPrintf(L"Not implemented!\r\n"); 1618 return STATUS_NOT_IMPLEMENTED; 1619 } 1620 1621 NTSTATUS 1622 SpOpen ( 1623 _In_ PBL_DEVICE_DESCRIPTOR Device, 1624 _In_ PBL_DEVICE_ENTRY DeviceEntry 1625 ) 1626 { 1627 EfiPrintf(L"Not implemented!\r\n"); 1628 return STATUS_NOT_IMPLEMENTED; 1629 } 1630 1631 NTSTATUS 1632 UdpOpen ( 1633 _In_ PBL_DEVICE_DESCRIPTOR Device, 1634 _In_ PBL_DEVICE_ENTRY DeviceEntry 1635 ) 1636 { 1637 EfiPrintf(L"Not implemented!\r\n"); 1638 return STATUS_NOT_IMPLEMENTED; 1639 } 1640 1641 BL_DEVICE_CALLBACKS FileDeviceFunctionTable = 1642 { 1643 NULL, 1644 FileDeviceOpen, 1645 NULL, 1646 }; 1647 1648 BL_DEVICE_CALLBACKS PartitionDeviceFunctionTable = 1649 { 1650 NULL, 1651 PartitionOpen, 1652 NULL, 1653 }; 1654 1655 BL_DEVICE_CALLBACKS RamDiskDeviceFunctionTable = 1656 { 1657 NULL, 1658 RdDeviceOpen, 1659 NULL, 1660 }; 1661 1662 BL_DEVICE_CALLBACKS DiskDeviceFunctionTable = 1663 { 1664 NULL, 1665 DiskOpen, 1666 NULL, 1667 }; 1668 1669 BL_DEVICE_CALLBACKS VirtualDiskDeviceFunctionTable = 1670 { 1671 NULL, 1672 VhdFileDeviceOpen, 1673 NULL, 1674 }; 1675 1676 BL_DEVICE_CALLBACKS UdpFunctionTable = 1677 { 1678 NULL, 1679 UdpOpen, 1680 NULL, 1681 }; 1682 1683 BL_DEVICE_CALLBACKS SerialPortFunctionTable = 1684 { 1685 NULL, 1686 SpOpen, 1687 NULL, 1688 }; 1689 1690 BOOLEAN 1691 DeviceTableCompare ( 1692 _In_ PVOID Entry, 1693 _In_ PVOID Argument1, 1694 _In_ PVOID Argument2, 1695 _Inout_ PVOID Argument3, 1696 _Inout_ PVOID Argument4 1697 ) 1698 { 1699 BOOLEAN Found; 1700 PBL_DEVICE_DESCRIPTOR Device = (PBL_DEVICE_DESCRIPTOR)Argument1; 1701 PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry; 1702 ULONG Flags = *(PULONG)Argument2; 1703 ULONG Unknown = *(PULONG)Argument3; 1704 1705 /* Assume failure */ 1706 Found = FALSE; 1707 1708 /* Compare the device descriptor */ 1709 if (BlpDeviceCompare(DeviceEntry->DeviceDescriptor, Device)) 1710 { 1711 /* Compare something */ 1712 if (DeviceEntry->Unknown == Unknown) 1713 { 1714 /* Compare flags */ 1715 if ((!(Flags & BL_DEVICE_READ_ACCESS) || (DeviceEntry->Flags & BL_DEVICE_ENTRY_READ_ACCESS)) && 1716 (!(Flags & BL_DEVICE_WRITE_ACCESS) || (DeviceEntry->Flags & BL_DEVICE_ENTRY_WRITE_ACCESS))) 1717 { 1718 /* And more flags */ 1719 if (((Flags & 8) || !(DeviceEntry->Flags & 8)) && 1720 (!(Flags & 8) || (DeviceEntry->Flags & 8))) 1721 { 1722 /* Found a match! */ 1723 Found = TRUE; 1724 } 1725 } 1726 } 1727 } 1728 1729 /* Return matching state */ 1730 return Found; 1731 } 1732 1733 NTSTATUS 1734 DeviceTableDestroyEntry ( 1735 _In_ PVOID Entry, 1736 _In_ ULONG DeviceId 1737 ) 1738 { 1739 PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry; 1740 NTSTATUS Status; 1741 1742 /* Call the close routine for this entry */ 1743 Status = DeviceEntry->Callbacks.Close(DmDeviceTable[DeviceId]); 1744 1745 /* Free the descriptor, and the device itself */ 1746 BlMmFreeHeap(DeviceEntry->DeviceDescriptor); 1747 BlMmFreeHeap(DeviceEntry); 1748 1749 /* Clear out the netry, and return */ 1750 DmDeviceTable[DeviceId] = NULL; 1751 return Status; 1752 } 1753 1754 NTSTATUS 1755 DeviceTablePurge ( 1756 _In_ PVOID Entry 1757 ) 1758 { 1759 PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry; 1760 NTSTATUS Status; 1761 1762 /* Check if the device is opened */ 1763 if (DeviceEntry->Flags & BL_DEVICE_ENTRY_OPENED) 1764 { 1765 /* It is, so can't purge it */ 1766 Status = STATUS_UNSUCCESSFUL; 1767 } 1768 else 1769 { 1770 /* It isn't, so destroy the entry */ 1771 Status = DeviceTableDestroyEntry(DeviceEntry, DeviceEntry->DeviceId); 1772 } 1773 1774 /* Return back to caller */ 1775 return Status; 1776 } 1777 1778 NTSTATUS 1779 BlockIoDeviceTableDestroyEntry ( 1780 _In_ PVOID Entry, 1781 _In_ ULONG DeviceId 1782 ) 1783 { 1784 PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry; 1785 NTSTATUS Status; 1786 1787 /* Call the close routine for this entry */ 1788 Status = DeviceEntry->Callbacks.Close(DeviceEntry); 1789 1790 /* Free the descriptor, and the device itself */ 1791 BlMmFreeHeap(DeviceEntry->DeviceDescriptor); 1792 BlMmFreeHeap(DeviceEntry); 1793 1794 /* Clear out the netry, and return */ 1795 BlockIoDeviceTable[DeviceId] = NULL; 1796 return Status; 1797 } 1798 1799 NTSTATUS 1800 BlockIoDeviceTableDestroy ( 1801 VOID 1802 ) 1803 { 1804 NTSTATUS Status; 1805 1806 /* Call the entry destructor on each entry in the table */ 1807 Status = BlTblMap(BlockIoDeviceTable, 1808 BlockIoDeviceTableEntries, 1809 BlockIoDeviceTableDestroyEntry); 1810 1811 /* Free the table and return */ 1812 BlMmFreeHeap(BlockIoDeviceTable); 1813 return Status; 1814 } 1815 1816 NTSTATUS 1817 BlockIopDestroy ( 1818 VOID 1819 ) 1820 { 1821 /* Free the prefetch buffer */ 1822 BlMmFreeHeap(BlockIopPrefetchBuffer); 1823 1824 /* Set state to non initialized */ 1825 BlockIoInitialized = FALSE; 1826 1827 /* Return back */ 1828 return STATUS_SUCCESS; 1829 } 1830 1831 ULONG 1832 BlockIoEfiHashFunction ( 1833 _In_ PBL_HASH_ENTRY Entry, 1834 _In_ ULONG TableSize 1835 ) 1836 { 1837 /* Get rid of the alignment bits to have a more unique number */ 1838 return ((ULONG_PTR)Entry->Value >> 3) % TableSize; 1839 } 1840 1841 NTSTATUS 1842 BlockIopInitialize ( 1843 VOID 1844 ) 1845 { 1846 NTSTATUS Status; 1847 1848 /* Allocate the block device table and zero it out */ 1849 BlockIoDeviceTableEntries = 8; 1850 BlockIoDeviceTable = BlMmAllocateHeap(sizeof(PVOID) * 1851 BlockIoDeviceTableEntries); 1852 if (!BlockIoDeviceTableEntries) 1853 { 1854 return STATUS_NO_MEMORY; 1855 } 1856 RtlZeroMemory(BlockIoDeviceTable, sizeof(PVOID) * BlockIoDeviceTableEntries); 1857 1858 /* Register our destructor */ 1859 Status = BlpIoRegisterDestroyRoutine(BlockIoDeviceTableDestroy); 1860 if (!NT_SUCCESS(Status)) 1861 { 1862 return Status; 1863 } 1864 1865 /* Initialize all counters */ 1866 BlockIoFirmwareRemovableDiskCount = 0; 1867 BlockIoFirmwareRawDiskCount = 0; 1868 BlockIoFirmwareCdromCount = 0; 1869 1870 /* Initialize the buffers and their sizes */ 1871 BlockIopAlignedBuffer = NULL; 1872 BlockIopAlignedBufferSize = 0; 1873 BlockIopPartialBlockBuffer = NULL; 1874 BlockIopPartialBlockBufferSize = 0; 1875 BlockIopPrefetchBuffer = NULL; 1876 BlockIopReadBlockBuffer = NULL; 1877 BlockIopReadBlockBufferSize = 0; 1878 1879 /* Allocate the prefetch buffer */ 1880 Status = MmPapAllocatePagesInRange(&BlockIopPrefetchBuffer, 1881 BlLoaderDeviceMemory, 1882 0x100, 1883 0, 1884 0, 1885 NULL, 1886 0); 1887 if (NT_SUCCESS(Status)) 1888 { 1889 /* Initialize the block cache */ 1890 Status = BcInitialize(); 1891 if (NT_SUCCESS(Status)) 1892 { 1893 /* Initialize the block device hash table */ 1894 Status = BlHtCreate(29, BlockIoEfiHashFunction, NULL, &HashTableId); 1895 if (NT_SUCCESS(Status)) 1896 { 1897 /* Register our destructor */ 1898 Status = BlpIoRegisterDestroyRoutine(BlockIopDestroy); 1899 if (NT_SUCCESS(Status)) 1900 { 1901 /* We're good */ 1902 BlockIoInitialized = TRUE; 1903 } 1904 } 1905 } 1906 } 1907 1908 /* Check if this is the failure path */ 1909 if (!NT_SUCCESS(Status)) 1910 { 1911 /* Free the prefetch buffer is one was allocated */ 1912 if (BlockIopPrefetchBuffer) 1913 { 1914 MmPapFreePages(BlockIopPrefetchBuffer, BL_MM_INCLUDE_MAPPED_ALLOCATED); 1915 } 1916 } 1917 1918 /* Return back to the caller */ 1919 return Status; 1920 } 1921 1922 BOOLEAN 1923 BlockIoDeviceTableCompare ( 1924 _In_ PVOID Entry, 1925 _In_ PVOID Argument1, 1926 _In_ PVOID Argument2, 1927 _In_ PVOID Argument3, 1928 _In_ PVOID Argument4 1929 ) 1930 { 1931 PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry; 1932 PBL_DEVICE_DESCRIPTOR Device = (PBL_DEVICE_DESCRIPTOR)Argument1; 1933 1934 /* Compare the two devices */ 1935 return BlpDeviceCompare(DeviceEntry->DeviceDescriptor, Device); 1936 } 1937 1938 NTSTATUS 1939 BlockIoOpen ( 1940 _In_ PBL_DEVICE_DESCRIPTOR Device, 1941 _In_ PBL_DEVICE_ENTRY DeviceEntry 1942 ) 1943 { 1944 NTSTATUS Status; 1945 PBL_BLOCK_DEVICE BlockDevice; 1946 PBL_DEVICE_ENTRY FoundDeviceEntry; 1947 ULONG Dummy; 1948 1949 /* Check if the block I/O manager is initialized */ 1950 if (!BlockIoInitialized) 1951 { 1952 /* First call, initialize it now */ 1953 Status = BlockIopInitialize(); 1954 if (!NT_SUCCESS(Status)) 1955 { 1956 /* Failed to initialize block I/O */ 1957 return Status; 1958 } 1959 } 1960 1961 /* Copy a function table for block I/O devices */ 1962 RtlCopyMemory(&DeviceEntry->Callbacks, 1963 &BlockIoDeviceFunctionTable, 1964 sizeof(DeviceEntry->Callbacks)); 1965 1966 /* Allocate a block I/O device */ 1967 BlockDevice = BlMmAllocateHeap(sizeof(*BlockDevice)); 1968 if (!BlockDevice) 1969 { 1970 return STATUS_NO_MEMORY; 1971 } 1972 1973 /* Set this as the device-specific data for this device entry */ 1974 Status = STATUS_SUCCESS; 1975 DeviceEntry->DeviceSpecificData = BlockDevice; 1976 1977 /* Check if we already have this device in our device table */ 1978 FoundDeviceEntry = BlTblFindEntry(BlockIoDeviceTable, 1979 BlockIoDeviceTableEntries, 1980 &Dummy, 1981 BlockIoDeviceTableCompare, 1982 Device, 1983 NULL, 1984 NULL, 1985 NULL); 1986 if (FoundDeviceEntry) 1987 { 1988 /* We already found a device, so copy its device data and callbacks */ 1989 //EfiPrintf(L"Block I/O Device entry found: %p\r\n", FoundDeviceEntry); 1990 RtlCopyMemory(BlockDevice, FoundDeviceEntry->DeviceSpecificData, sizeof(*BlockDevice)); 1991 RtlCopyMemory(&DeviceEntry->Callbacks, 1992 &FoundDeviceEntry->Callbacks, 1993 sizeof(DeviceEntry->Callbacks)); 1994 return Status; 1995 } 1996 1997 /* Zero out the device for now */ 1998 RtlZeroMemory(BlockDevice, sizeof(*BlockDevice)); 1999 2000 /* Is this a disk? */ 2001 if (Device->DeviceType == DiskDevice) 2002 { 2003 /* What type of disk is it? */ 2004 switch (Device->Local.Type) 2005 { 2006 /* Is it a raw physical disk? */ 2007 case LocalDevice: 2008 case FloppyDevice: 2009 case CdRomDevice: 2010 /* Open a disk device */ 2011 Status = DiskDeviceFunctionTable.Open(Device, DeviceEntry); 2012 break; 2013 2014 /* Is it a RAM disk? */ 2015 case RamDiskDevice: 2016 /* Open a RAM disk */ 2017 Status = RamDiskDeviceFunctionTable.Open(Device, DeviceEntry); 2018 break; 2019 2020 /* Is it a file? */ 2021 case FileDevice: 2022 /* Open a file */ 2023 Status = FileDeviceFunctionTable.Open(Device, DeviceEntry); 2024 break; 2025 2026 /* Is it a VHD? */ 2027 case VirtualDiskDevice: 2028 /* Open a virtual disk */ 2029 Status = VirtualDiskDeviceFunctionTable.Open(Device, DeviceEntry); 2030 break; 2031 2032 /* Is it something else? */ 2033 default: 2034 /* Not supported */ 2035 Status = STATUS_INVALID_PARAMETER; 2036 break; 2037 } 2038 } 2039 else if ((Device->DeviceType == LegacyPartitionDevice) || 2040 (Device->DeviceType == PartitionDevice)) 2041 { 2042 /* This is a partition on a disk, open it as such */ 2043 Status = PartitionDeviceFunctionTable.Open(Device, DeviceEntry); 2044 } 2045 else 2046 { 2047 /* Other devices are not supported */ 2048 Status = STATUS_INVALID_PARAMETER; 2049 } 2050 2051 /* Check for failure */ 2052 if (!NT_SUCCESS(Status)) 2053 { 2054 /* Free any allocations for this device */ 2055 BlockIopFreeAllocations(BlockDevice); 2056 } 2057 2058 /* Return back to the caller */ 2059 return Status; 2060 } 2061 2062 NTSTATUS 2063 BlpDeviceResolveLocate ( 2064 _In_ PBL_DEVICE_DESCRIPTOR InputDevice, 2065 _Out_ PBL_DEVICE_DESCRIPTOR* LocateDevice 2066 ) 2067 { 2068 EfiPrintf(L"Not implemented!\r\n"); 2069 return STATUS_NOT_IMPLEMENTED; 2070 } 2071 2072 NTSTATUS 2073 BlDeviceClose ( 2074 _In_ ULONG DeviceId 2075 ) 2076 { 2077 PBL_DEVICE_ENTRY DeviceEntry; 2078 2079 /* Validate the device ID */ 2080 if (DmTableEntries <= DeviceId) 2081 { 2082 return STATUS_INVALID_PARAMETER; 2083 } 2084 2085 /* Make sure there's a device there */ 2086 DeviceEntry = DmDeviceTable[DeviceId]; 2087 if (DeviceEntry == NULL) 2088 { 2089 return STATUS_INVALID_PARAMETER; 2090 } 2091 2092 /* Make sure the device is active */ 2093 if (!(DeviceEntry->Flags & BL_DEVICE_ENTRY_OPENED)) 2094 { 2095 return STATUS_INVALID_PARAMETER; 2096 } 2097 2098 /* Drop a reference and check if it's the last one */ 2099 DeviceEntry->ReferenceCount--; 2100 if (!DeviceEntry->ReferenceCount) 2101 { 2102 /* Mark the device as inactive */ 2103 DeviceEntry->Flags = ~BL_DEVICE_ENTRY_OPENED; 2104 } 2105 2106 /* We're good */ 2107 return STATUS_SUCCESS; 2108 } 2109 2110 NTSTATUS 2111 BlpDeviceOpen ( 2112 _In_ PBL_DEVICE_DESCRIPTOR Device, 2113 _In_ ULONG Flags, 2114 _In_ ULONG Unknown, 2115 _Out_ PULONG DeviceId 2116 ) 2117 { 2118 NTSTATUS Status; 2119 PBL_DEVICE_ENTRY DeviceEntry; 2120 PBL_DEVICE_DESCRIPTOR LocateDeviceDescriptor; 2121 PBL_REGISTERED_DEVICE RegisteredDevice; 2122 PLIST_ENTRY NextEntry, ListHead; 2123 2124 DeviceEntry = NULL; 2125 2126 /* Check for missing parameters */ 2127 if (!(Device) || !(DeviceId) || !(Device->Size)) 2128 { 2129 /* Bail out */ 2130 Status = STATUS_INVALID_PARAMETER; 2131 goto Quickie; 2132 } 2133 2134 /* Make sure both read and write access are set */ 2135 if (!(Flags & (BL_DEVICE_READ_ACCESS | BL_DEVICE_WRITE_ACCESS))) 2136 { 2137 /* Bail out */ 2138 Status = STATUS_INVALID_PARAMETER; 2139 goto Quickie; 2140 } 2141 2142 /* Check if the boot device is being opened */ 2143 if (Device->DeviceType == BootDevice) 2144 { 2145 /* Select it */ 2146 Device = BlpBootDevice; 2147 } 2148 2149 /* Check if the 'locate' device is being opened */ 2150 if (Device->DeviceType == LocateDevice) 2151 { 2152 /* Go find it */ 2153 Status = BlpDeviceResolveLocate(Device, &LocateDeviceDescriptor); 2154 if (!NT_SUCCESS(Status)) 2155 { 2156 /* Not found, bail out */ 2157 goto Quickie; 2158 } 2159 2160 /* Select it */ 2161 Device = LocateDeviceDescriptor; 2162 } 2163 2164 /* Check if the device isn't ready yet */ 2165 if (Device->Flags & 1) 2166 { 2167 /* Return a failure */ 2168 Status = STATUS_DEVICE_NOT_READY; 2169 goto Quickie; 2170 } 2171 2172 /* Check if we already have an entry for the device */ 2173 DeviceEntry = BlTblFindEntry(DmDeviceTable, 2174 DmTableEntries, 2175 DeviceId, 2176 DeviceTableCompare, 2177 Device, 2178 &Flags, 2179 &Unknown, 2180 NULL); 2181 if (DeviceEntry) 2182 { 2183 /* Return it, taking a reference on it */ 2184 *DeviceId = DeviceEntry->DeviceId; 2185 ++DeviceEntry->ReferenceCount; 2186 DeviceEntry->Flags |= BL_DEVICE_ENTRY_OPENED; 2187 return STATUS_SUCCESS; 2188 } 2189 2190 /* We don't, allocate one */ 2191 DeviceEntry = BlMmAllocateHeap(sizeof(*DeviceEntry)); 2192 if (!DeviceEntry) 2193 { 2194 Status = STATUS_NO_MEMORY; 2195 goto Quickie; 2196 } 2197 2198 /* Fill it out */ 2199 RtlZeroMemory(DeviceEntry, sizeof(*DeviceEntry)); 2200 DeviceEntry->ReferenceCount = 1; 2201 DeviceEntry->Flags |= (BL_DEVICE_ENTRY_OPENED | 2202 BL_DEVICE_ENTRY_READ_ACCESS | 2203 BL_DEVICE_ENTRY_WRITE_ACCESS); 2204 DeviceEntry->Unknown = Unknown; 2205 2206 /* Save flag 8 if needed */ 2207 if (Flags & 8) 2208 { 2209 DeviceEntry->Flags |= 8; 2210 } 2211 2212 /* Allocate a device descriptor for the device */ 2213 DeviceEntry->DeviceDescriptor = BlMmAllocateHeap(Device->Size); 2214 if (!DeviceEntry->DeviceDescriptor) 2215 { 2216 Status = STATUS_NO_MEMORY; 2217 goto Quickie; 2218 } 2219 2220 /* Copy the descriptor that was passed in */ 2221 RtlCopyMemory(DeviceEntry->DeviceDescriptor, Device, Device->Size); 2222 2223 /* Now loop the list of dynamically registered devices */ 2224 ListHead = &DmRegisteredDevices; 2225 NextEntry = ListHead->Flink; 2226 while (NextEntry != ListHead) 2227 { 2228 /* Get the device */ 2229 RegisteredDevice = CONTAINING_RECORD(NextEntry, 2230 BL_REGISTERED_DEVICE, 2231 ListEntry); 2232 2233 /* Open the device */ 2234 Status = RegisteredDevice->Callbacks.Open(Device, DeviceEntry); 2235 if (NT_SUCCESS(Status)) 2236 { 2237 /* The device was opened, so we have the right one */ 2238 goto DeviceOpened; 2239 } 2240 2241 /* Nope, keep trying */ 2242 NextEntry = NextEntry->Flink; 2243 } 2244 2245 /* Well, it wasn't a dynamic device. Is it a block device? */ 2246 if ((Device->DeviceType == PartitionDevice) || 2247 (Device->DeviceType == DiskDevice) || 2248 (Device->DeviceType == LegacyPartitionDevice)) 2249 { 2250 /* Call the Block I/O handler */ 2251 Status = BlockIoDeviceFunctionTable.Open(Device, DeviceEntry); 2252 } 2253 else if (Device->DeviceType == SerialDevice) 2254 { 2255 /* It's a serial device, call the serial device handler */ 2256 Status = SerialPortFunctionTable.Open(Device, DeviceEntry); 2257 } 2258 else if (Device->DeviceType == UdpDevice) 2259 { 2260 /* It's a network device, call the UDP device handler */ 2261 Status = UdpFunctionTable.Open(Device, DeviceEntry); 2262 } 2263 else 2264 { 2265 /* Unsupported type of device */ 2266 Status = STATUS_NOT_IMPLEMENTED; 2267 } 2268 2269 /* Check if the device was opened successfully */ 2270 if (NT_SUCCESS(Status)) 2271 { 2272 DeviceOpened: 2273 /* Save the entry in the device table */ 2274 Status = BlTblSetEntry(&DmDeviceTable, 2275 &DmTableEntries, 2276 DeviceEntry, 2277 DeviceId, 2278 DeviceTablePurge); 2279 if (NT_SUCCESS(Status)) 2280 { 2281 /* It worked -- return the ID in the table to the caller */ 2282 EfiPrintf(L"Device ID: %lx\r\n", *DeviceId); 2283 DeviceEntry->DeviceId = *DeviceId; 2284 return STATUS_SUCCESS; 2285 } 2286 } 2287 2288 Quickie: 2289 /* Failure path -- did we allocate a device entry? */ 2290 EfiPrintf(L"Block failure: %lx\r\n", Status); 2291 if (DeviceEntry) 2292 { 2293 /* Yep -- did it have a descriptor? */ 2294 if (DeviceEntry->DeviceDescriptor) 2295 { 2296 /* Free it */ 2297 BlMmFreeHeap(DeviceEntry->DeviceDescriptor); 2298 } 2299 2300 /* Free the entry */ 2301 BlMmFreeHeap(DeviceEntry); 2302 } 2303 2304 /* Return the failure */ 2305 return Status; 2306 } 2307 2308 NTSTATUS 2309 BlpDeviceInitialize ( 2310 VOID 2311 ) 2312 { 2313 NTSTATUS Status; 2314 2315 /* Initialize the table count and list of devices */ 2316 DmTableEntries = 8; 2317 InitializeListHead(&DmRegisteredDevices); 2318 2319 /* Initialize device information */ 2320 DmDeviceIoInformation.ReadCount = 0; 2321 DmDeviceIoInformation.WriteCount = 0; 2322 2323 /* Allocate the device table */ 2324 DmDeviceTable = BlMmAllocateHeap(DmTableEntries * sizeof(PVOID)); 2325 if (DmDeviceTable) 2326 { 2327 /* Clear it */ 2328 RtlZeroMemory(DmDeviceTable, DmTableEntries * sizeof(PVOID)); 2329 #if BL_BITLOCKER_SUPPORT 2330 /* Initialize BitLocker support */ 2331 Status = FvebInitialize(); 2332 #else 2333 Status = STATUS_SUCCESS; 2334 #endif 2335 } 2336 else 2337 { 2338 /* No memory, we'll fail */ 2339 Status = STATUS_NO_MEMORY; 2340 } 2341 2342 /* Return initialization state */ 2343 return Status; 2344 } 2345 2346