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)
9 /* INCLUDES ******************************************************************/
13 /* DATA VARIABLES ************************************************************/
15 typedef struct _BL_DEVICE_IO_INFORMATION
19 } BL_DEVICE_IO_INFORMATION
, *PBL_DEVICE_IO_INFORMATION
;
21 LIST_ENTRY DmRegisteredDevices
;
23 LIST_ENTRY DmRegisteredDevices
;
26 BL_DEVICE_IO_INFORMATION DmDeviceIoInformation
;
28 /* FUNCTIONS *****************************************************************/
30 typedef struct _BL_REGISTERED_DEVICE
33 BL_DEVICE_CALLBACKS Callbacks
;
34 } BL_REGISTERED_DEVICE
, *PBL_REGISTERED_DEVICE
;
36 PVOID
* BlockIoDeviceTable
;
37 ULONG BlockIoDeviceTableEntries
;
39 ULONG BlockIoFirmwareRemovableDiskCount
;
40 ULONG BlockIoFirmwareRawDiskCount
;
41 ULONG BlockIoFirmwareCdromCount
;
43 PVOID BlockIopAlignedBuffer
;
44 ULONG BlockIopAlignedBufferSize
;
46 PVOID BlockIopPartialBlockBuffer
;
47 ULONG BlockIopPartialBlockBufferSize
;
49 PVOID BlockIopPrefetchBuffer
;
51 PVOID BlockIopReadBlockBuffer
;
52 ULONG BlockIopReadBlockBufferSize
;
56 BOOLEAN BlockIoInitialized
;
60 _In_ PBL_DEVICE_DESCRIPTOR Device
,
61 _In_ PBL_DEVICE_ENTRY DeviceEntry
65 BlockIoGetInformation (
66 _In_ PBL_DEVICE_ENTRY DeviceEntry
,
67 _Out_ PBL_DEVICE_INFORMATION DeviceInformation
71 BlockIoSetInformation (
72 _In_ PBL_DEVICE_ENTRY DeviceEntry
,
73 _Out_ PBL_DEVICE_INFORMATION DeviceInformation
78 _In_ PBL_DEVICE_ENTRY DeviceEntry
,
81 _Out_ PULONG BytesRead
84 BL_DEVICE_CALLBACKS BlockIoDeviceFunctionTable
=
91 BlockIoGetInformation
,
96 BlockIoFirmwareWrite (
97 _In_ PBL_BLOCK_DEVICE BlockDevice
,
100 _In_ ULONGLONG BlockCount
103 return STATUS_NOT_IMPLEMENTED
;
107 BlockIoFirmwareRead (
108 _In_ PBL_BLOCK_DEVICE BlockDevice
,
110 _In_ ULONGLONG Block
,
111 _In_ ULONGLONG BlockCount
115 EFI_BLOCK_IO
*BlockProtocol
;
116 BL_ARCH_MODE OldMode
;
117 EFI_STATUS EfiStatus
;
120 for (FailureCount
= 0, Status
= STATUS_SUCCESS
;
121 FailureCount
< 2 && NT_SUCCESS(Status
);
124 BlockProtocol
= BlockDevice
->Protocol
;
126 OldMode
= CurrentExecutionContext
->Mode
;
127 if (CurrentExecutionContext
->Mode
!= 1)
129 Status
= STATUS_NOT_IMPLEMENTED
;
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
,
138 BlockProtocol
->Media
->BlockSize
* BlockCount
,
140 if (EfiStatus
== EFI_SUCCESS
)
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));
148 BlpArchSwitchContext(OldMode
);
151 Status
= EfiGetNtStatusCode(EfiStatus
);
152 if (Status
!= STATUS_MEDIA_CHANGED
)
157 EfiCloseProtocol(BlockDevice
->Handle
, &EfiBlockIoProtocol
);
159 Status
= EfiOpenProtocol(BlockDevice
->Handle
,
161 (PVOID
*)BlockDevice
->Protocol
);
168 BlockIopFirmwareOperation (
169 PBL_DEVICE_ENTRY DeviceEntry
,
171 _In_ ULONGLONG Block
,
172 _In_ ULONGLONG BlockCount
,
173 _In_ ULONG OperationType
177 PBL_BLOCK_DEVICE BlockDevice
;
180 BlockDevice
= DeviceEntry
->DeviceSpecificData
;
182 if (OperationType
== 1)
184 for (FailureCount
= 0; FailureCount
< 3; FailureCount
++)
186 Status
= BlockIoFirmwareWrite(BlockDevice
, Buffer
, Block
, BlockCount
);
195 for (FailureCount
= 0; FailureCount
< 3; FailureCount
++)
197 Status
= BlockIoFirmwareRead(BlockDevice
, Buffer
, Block
, BlockCount
);
208 BlockIopFreeAlignedBuffer (
209 _Inout_ PVOID
* Buffer
,
210 _Inout_ PULONG BufferSize
217 Status
= MmPapFreePages(*Buffer
, BL_MM_INCLUDE_MAPPED_ALLOCATED
);
224 Status
= STATUS_SUCCESS
;
231 BlockIopAllocateAlignedBuffer (
232 _Inout_ PVOID
* Buffer
,
233 _Inout_ PULONG BufferSize
,
245 Status
= STATUS_SUCCESS
;
246 if ((Size
> *BufferSize
) || ((Alignment
- 1) & (ULONG_PTR
)*Buffer
))
248 BlockIopFreeAlignedBuffer(Buffer
, BufferSize
);
250 *BufferSize
= ROUND_TO_PAGES(Size
);
252 Status
= MmPapAllocatePagesInRange(Buffer
,
253 BlLoaderDeviceMemory
,
254 *BufferSize
>> PAGE_SHIFT
,
256 Alignment
>> PAGE_SHIFT
,
259 if (!NT_SUCCESS(Status
))
269 BlockIopReadUsingPrefetch (
270 _In_ PBL_DEVICE_ENTRY DeviceEntry
,
272 _In_ ULONG BlockCount
275 EfiPrintf(L
"No prefetch support\r\n");
276 return STATUS_NOT_IMPLEMENTED
;
281 _In_ PBL_DEVICE_ENTRY DeviceEntry
,
283 _In_ ULONG BlockCount
,
284 _In_ ULONG OperationType
287 PBL_BLOCK_DEVICE BlockDevice
;
288 ULONG BufferSize
, Alignment
;
292 BlockDevice
= DeviceEntry
->DeviceSpecificData
;
293 BufferSize
= BlockDevice
->BlockSize
* BlockCount
;
294 Offset
= BlockDevice
->Block
+ BlockDevice
->StartOffset
;
295 if ((BlockDevice
->LastBlock
+ 1) < (BlockDevice
->Block
+ BlockCount
))
297 EfiPrintf(L
"Read past end of device\r\n");
298 return STATUS_INVALID_PARAMETER
;
301 Alignment
= BlockDevice
->Alignment
;
302 if (!(Alignment
) || !((Alignment
- 1) & (ULONG_PTR
)Buffer
))
304 Status
= BlockIopFirmwareOperation(DeviceEntry
,
309 if (!NT_SUCCESS(Status
))
311 EfiPrintf(L
"EFI op failed: %lx\r\n", Status
);
315 return STATUS_SUCCESS
;
318 Status
= BlockIopAllocateAlignedBuffer(&BlockIopAlignedBuffer
,
319 &BlockIopAlignedBufferSize
,
321 BlockDevice
->Alignment
);
322 if (!NT_SUCCESS(Status
))
324 EfiPrintf(L
"No memory for align\r\n");
325 return STATUS_NO_MEMORY
;
328 if (OperationType
== 1)
330 RtlCopyMemory(BlockIopAlignedBuffer
, Buffer
, BufferSize
);
333 Status
= BlockIopFirmwareOperation(DeviceEntry
,
334 BlockIopAlignedBuffer
,
338 if (!NT_SUCCESS(Status
))
345 RtlCopyMemory(Buffer
, BlockIopAlignedBuffer
, BufferSize
);
348 return STATUS_SUCCESS
;
352 BlockIopReadWriteVirtualDevice (
353 _In_ PBL_DEVICE_ENTRY DeviceEntry
,
356 _In_ ULONG Operation
,
357 _Out_ PULONG BytesRead
360 return STATUS_NOT_IMPLEMENTED
;
364 BlockIopReadPhysicalDevice (
365 _In_ PBL_DEVICE_ENTRY DeviceEntry
,
368 _Out_ PULONG BytesRead
371 PBL_BLOCK_DEVICE BlockDevice
;
373 ULONGLONG OffsetEnd
, AlignedOffsetEnd
, Offset
;
376 BlockDevice
= DeviceEntry
->DeviceSpecificData
;
378 OffsetEnd
= Size
+ BlockDevice
->Offset
;
379 if (OffsetEnd
< Size
)
382 return STATUS_INTEGER_OVERFLOW
;
385 AlignedOffsetEnd
= ~(BlockDevice
->BlockSize
- 1) & (OffsetEnd
+ BlockDevice
->BlockSize
- 1);
386 if (AlignedOffsetEnd
< OffsetEnd
)
388 return STATUS_INTEGER_OVERFLOW
;
391 if ((BlockDevice
->Offset
) || (Size
!= AlignedOffsetEnd
))
393 Status
= BlockIopAllocateAlignedBuffer(&BlockIopReadBlockBuffer
,
394 &BlockIopReadBlockBufferSize
,
396 BlockDevice
->Alignment
);
397 if (!NT_SUCCESS(Status
))
399 EfiPrintf(L
"Failed to allocate buffer: %lx\r\n", Status
);
403 ReadBuffer
= BlockIopReadBlockBuffer
;
406 Offset
= AlignedOffsetEnd
/ BlockDevice
->BlockSize
;
408 if (BlockDevice
->Unknown
& 2)
410 Status
= BlockIopReadUsingPrefetch(DeviceEntry
,
412 AlignedOffsetEnd
/ BlockDevice
->BlockSize
);
413 if (NT_SUCCESS(Status
))
419 Status
= BlockIopOperation(DeviceEntry
, ReadBuffer
, Offset
, 0);
420 if (!NT_SUCCESS(Status
))
422 EfiPrintf(L
"Block I/O failed: %lx\r\n", Status
);
426 BlockDevice
->Block
+= Offset
;
429 if (ReadBuffer
!= Buffer
)
431 RtlCopyMemory(Buffer
,
432 (PVOID
)((ULONG_PTR
)ReadBuffer
+
433 (ULONG_PTR
)BlockDevice
->Offset
),
442 return STATUS_SUCCESS
;
446 BlockIopBlockInformationCheck (
447 _In_ PBL_BLOCK_DEVICE BlockDevice
,
448 _In_opt_ PULONG DesiredSize
,
449 _Out_opt_ PULONG Size
,
450 _Out_opt_ PULONG OutputAdjustedSize
454 ULONGLONG Offset
, LastOffset
, RemainingOffset
, MaxOffset
;
459 Offset
= (BlockDevice
->Offset
* BlockDevice
->BlockSize
) + BlockDevice
->Block
;
461 if (Offset
> ((BlockDevice
->LastBlock
+ 1) * BlockDevice
->BlockSize
))
463 Status
= STATUS_INVALID_PARAMETER
;
467 LastOffset
= (BlockDevice
->LastBlock
* BlockDevice
->BlockSize
) + BlockDevice
->BlockSize
- 1;
469 MaxOffset
= BlockDevice
->LastBlock
;
470 if (MaxOffset
< BlockDevice
->BlockSize
)
472 MaxOffset
= BlockDevice
->BlockSize
;
475 if (LastOffset
< MaxOffset
)
478 Status
= STATUS_INVALID_PARAMETER
;
482 if (Offset
> LastOffset
)
484 Status
= STATUS_INVALID_PARAMETER
;
488 RemainingOffset
= LastOffset
- Offset
+ 1;
490 if (DesiredSize
!= FALSE
)
492 RealSize
= *DesiredSize
;
496 RealSize
= ULONG_MAX
;
499 if (RemainingOffset
< RealSize
)
504 Status
= STATUS_INVALID_PARAMETER
;
508 RealSize
= RemainingOffset
;
511 Status
= STATUS_SUCCESS
;
524 _In_ PBL_DEVICE_ENTRY DeviceEntry
,
527 _Out_ PULONG BytesRead
530 PBL_BLOCK_DEVICE BlockDevice
;
533 /* Get the device-specific data, which is our block device descriptor */
534 BlockDevice
= DeviceEntry
->DeviceSpecificData
;
536 /* Make sure that the buffer and size is valid */
537 Status
= BlockIopBlockInformationCheck(BlockDevice
, &Size
, BytesRead
, &Size
);
538 if (NT_SUCCESS(Status
))
540 /* Check if this is a virtual device or a physical device */
541 if (BlockDevice
->DeviceFlags
& BL_BLOCK_DEVICE_VIRTUAL_FLAG
)
543 /* Do a virtual read or write */
544 Status
= BlockIopReadWriteVirtualDevice(DeviceEntry
, Buffer
, Size
, 0, BytesRead
);
548 /* Do a physical read or write */
549 Status
= BlockIopReadPhysicalDevice(DeviceEntry
, Buffer
, Size
, BytesRead
);
554 /* We failed, if the caller wanted bytes read, return 0 */
558 /* Return back to the caller */
563 BlockIoSetInformation (
564 _In_ PBL_DEVICE_ENTRY DeviceEntry
,
565 _Out_ PBL_DEVICE_INFORMATION DeviceInformation
568 PBL_BLOCK_DEVICE BlockDevice
;
571 BlockDevice
= DeviceEntry
->DeviceSpecificData
;
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
;
577 /* Make sure that the full offset is still within the bounds of the device */
578 if (Offset
> ((BlockDevice
->LastBlock
+ 1) * BlockDevice
->BlockSize
- 1))
580 EfiPrintf(L
"Offset out of bounds\r\n");
581 return STATUS_INVALID_PARAMETER
;
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
;
588 /* Return the unknown */
589 BlockDevice
->Unknown
= DeviceInformation
->BlockDeviceInfo
.Unknown
;
592 return STATUS_SUCCESS
;
596 BlockIoGetInformation (
597 _In_ PBL_DEVICE_ENTRY DeviceEntry
,
598 _Out_ PBL_DEVICE_INFORMATION DeviceInformation
601 /* Copy the device specific data into the block device information */
602 RtlCopyMemory(&DeviceInformation
->BlockDeviceInfo
,
603 DeviceEntry
->DeviceSpecificData
,
604 sizeof(DeviceInformation
->BlockDeviceInfo
));
606 /* Hardcode the device type */
607 DeviceInformation
->DeviceType
= DiskDevice
;
608 return STATUS_SUCCESS
;
612 BlDeviceIsVirtualPartitionDevice (
613 _In_ PBL_DEVICE_DESCRIPTOR InputDevice
,
614 _Outptr_ PBL_DEVICE_DESCRIPTOR
* VirtualDevice
618 PBL_LOCAL_DEVICE ParentDisk
;
620 /* Assume it isn't */
623 /* Check if this is a partition device */
624 if ((InputDevice
->DeviceType
== LegacyPartitionDevice
) ||
625 (InputDevice
->DeviceType
== PartitionDevice
))
627 /* Check if the parent disk is a VHD */
628 ParentDisk
= &InputDevice
->Partition
.Disk
;
629 if (ParentDisk
->Type
== VirtualDiskDevice
)
631 /* This is a virtual partition device -- does the caller want it? */
635 *VirtualDevice
= (PBL_DEVICE_DESCRIPTOR
)(&ParentDisk
->VirtualHardDisk
+ 1);
645 BlDeviceSetInformation (
647 _Out_ PBL_DEVICE_INFORMATION DeviceInformation
650 PBL_DEVICE_ENTRY DeviceEntry
;
652 /* This parameter is not optional */
653 if (!DeviceInformation
)
655 return STATUS_INVALID_PARAMETER
;
658 /* Make sure the device ID is valid */
659 if (DmTableEntries
<= DeviceId
)
661 return STATUS_INVALID_PARAMETER
;
664 /* Get the device entry */
665 DeviceEntry
= DmDeviceTable
[DeviceId
];
668 return STATUS_INVALID_PARAMETER
;
671 /* Make sure the device is open */
672 if (!(DeviceEntry
->Flags
& BL_DEVICE_ENTRY_OPENED
))
674 return STATUS_INVALID_PARAMETER
;
677 /* Set the device information */
678 return DeviceEntry
->Callbacks
.SetInformation(DeviceEntry
, DeviceInformation
);
682 BlDeviceGetInformation (
684 _Out_ PBL_DEVICE_INFORMATION DeviceInformation
687 PBL_DEVICE_ENTRY DeviceEntry
;
689 /* This parameter is not optional */
690 if (!DeviceInformation
)
692 return STATUS_INVALID_PARAMETER
;
695 /* Make sure the device ID is valid */
696 if (DmTableEntries
<= DeviceId
)
698 return STATUS_INVALID_PARAMETER
;
701 /* Get the device entry */
702 DeviceEntry
= DmDeviceTable
[DeviceId
];
705 return STATUS_INVALID_PARAMETER
;
708 /* Make sure the device is open */
709 if (!(DeviceEntry
->Flags
& BL_DEVICE_ENTRY_OPENED
))
711 return STATUS_INVALID_PARAMETER
;
714 /* Return the device information */
715 DeviceInformation
->DeviceType
= DeviceEntry
->DeviceDescriptor
->DeviceType
;
716 return DeviceEntry
->Callbacks
.GetInformation(DeviceEntry
, DeviceInformation
);
724 _Out_opt_ PULONG BytesRead
727 PBL_DEVICE_ENTRY DeviceEntry
;
729 ULONG BytesTransferred
;
731 /* Make sure we have a buffer, and the device ID is valid */
732 if (!(Buffer
) || (DmTableEntries
<= DeviceId
))
734 return STATUS_INVALID_PARAMETER
;
737 /* Get the device entry for it */
738 DeviceEntry
= DmDeviceTable
[DeviceId
];
741 return STATUS_INVALID_PARAMETER
;
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
))
748 return STATUS_INVALID_PARAMETER
;
752 Status
= DeviceEntry
->Callbacks
.Read(DeviceEntry
,
756 if (!DeviceEntry
->Unknown
)
758 /* Update performance counters */
759 DmDeviceIoInformation
.ReadCount
+= BytesTransferred
;
762 /* Return back how many bytes were read, if caller wants to know */
765 *BytesRead
= BytesTransferred
;
768 /* Return read result */
773 BlDeviceReadAtOffset (
776 _In_ ULONGLONG Offset
,
778 _Out_ PULONG BytesRead
782 BL_DEVICE_INFORMATION DeviceInfo
;
784 /* Get the current block and offset */
785 Status
= BlDeviceGetInformation(DeviceId
, &DeviceInfo
);
786 if (!NT_SUCCESS(Status
))
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
;
795 /* Update the block and offset */
796 Status
= BlDeviceSetInformation(DeviceId
, &DeviceInfo
);
797 if (NT_SUCCESS(Status
))
799 /* Now issue a read, with this block and offset configured */
800 Status
= BlDeviceRead(DeviceId
, Buffer
, Size
, BytesRead
);
803 /* All good, return the caller */
809 _In_ PBL_DEVICE_DESCRIPTOR Device1
,
810 _In_ PBL_DEVICE_DESCRIPTOR Device2
819 /* Check if the two devices exist and are identical in type */
820 if ((Device1
) && (Device2
) && (Device1
->DeviceType
== Device2
->DeviceType
))
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
))
826 /* Compare the two devices up to their size */
827 if (RtlEqualMemory(&Device1
->Local
,
829 DeviceSize
- FIELD_OFFSET(BL_DEVICE_DESCRIPTOR
, Local
)))
837 /* Return matching state */
842 BlockIopFreeAllocations (
843 _In_ PBL_BLOCK_DEVICE BlockDevice
846 /* If a block device was passed in, free it */
849 BlMmFreeHeap(BlockDevice
);
852 /* Nothing else to do */
853 return STATUS_SUCCESS
;
857 BlockIoEfiGetBlockIoInformation (
858 _In_ PBL_BLOCK_DEVICE BlockDevice
862 EFI_BLOCK_IO_MEDIA
*Media
;
864 /* Open the Block I/O protocol on this device */
865 Status
= EfiOpenProtocol(BlockDevice
->Handle
,
867 (PVOID
*)&BlockDevice
->Protocol
);
868 if (!NT_SUCCESS(Status
))
873 /* Get information on the block media */
874 Media
= BlockDevice
->Protocol
->Media
;
876 /* Set the appropriate device flags */
877 BlockDevice
->DeviceFlags
= 0;
878 if (Media
->RemovableMedia
)
880 BlockDevice
->DeviceFlags
= BL_BLOCK_DEVICE_REMOVABLE_FLAG
;
882 if (Media
->MediaPresent
)
884 BlockDevice
->DeviceFlags
|= BL_BLOCK_DEVICE_PRESENT_FLAG
;
888 BlockDevice
->Unknown
= 0;
890 /* Set the block size */
891 BlockDevice
->BlockSize
= Media
->BlockSize
;
893 /* Make sure there's a last block value */
894 if (!Media
->LastBlock
)
896 return STATUS_INVALID_PARAMETER
;
899 /* Don't let it be too high */
900 if (Media
->LastBlock
> 0xFFFFFFFFFFE)
902 BlockDevice
->LastBlock
= 0xFFFFFFFFFFE;
906 BlockDevice
->LastBlock
= Media
->LastBlock
;
909 /* Make the alignment the smaller of the I/O alignment or the block size */
910 if (Media
->IoAlign
>= Media
->BlockSize
)
912 BlockDevice
->Alignment
= Media
->IoAlign
;
916 BlockDevice
->Alignment
= Media
->BlockSize
;
920 return STATUS_SUCCESS
;
924 BlockIoEfiGetChildHandle (
925 _In_ PBL_PROTOCOL_HANDLE ProtocolInterface
,
926 _In_ PBL_PROTOCOL_HANDLE ChildProtocolInterface
)
929 ULONG i
, DeviceCount
;
930 EFI_DEVICE_PATH
*DevicePath
, *ParentDevicePath
;
931 EFI_HANDLE
*DeviceHandles
;
934 /* Find all the Block I/O device handles on the system */
937 Status
= EfiLocateHandleBuffer(ByProtocol
,
941 if (!NT_SUCCESS(Status
))
943 /* Failed to enumerate, bail out */
947 /* Loop all the handles */
948 for (i
= 0; i
< DeviceCount
; i
++)
950 /* Check if this is the device itself */
951 Handle
= DeviceHandles
[i
];
952 if (Handle
== ProtocolInterface
->Handle
)
958 /* Get the device path of this device */
959 Status
= EfiOpenProtocol(Handle
,
960 &EfiDevicePathProtocol
,
961 (PVOID
*)&DevicePath
);
962 if (!NT_SUCCESS(Status
))
964 /* We failed, skip it */
968 /* See if we are its parent */
969 ParentDevicePath
= EfiIsDevicePathParent(ProtocolInterface
->Interface
,
971 if (ParentDevicePath
== ProtocolInterface
->Interface
)
973 /* Yup, return back to caller */
974 ChildProtocolInterface
->Handle
= Handle
;
975 ChildProtocolInterface
->Interface
= DevicePath
;
976 Status
= STATUS_SUCCESS
;
980 /* Close the device path */
981 EfiCloseProtocol(Handle
, &EfiDevicePathProtocol
);
984 /* If we got here, nothing was found */
985 Status
= STATUS_NO_SUCH_DEVICE
;
988 /* Free the handle array buffer */
989 BlMmFreeHeap(DeviceHandles
);
994 BlockIoGetGPTDiskSignature (
995 _In_ PBL_DEVICE_ENTRY DeviceEntry
,
996 _Out_ PGUID DiskSignature
999 EfiPrintf(L
"GPT not supported\r\n");
1000 return STATUS_NOT_IMPLEMENTED
;
1004 BlockIoEfiGetDeviceInformation (
1005 _In_ PBL_DEVICE_ENTRY DeviceEntry
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
;
1018 /* Extract the identifier, and the block device object */
1019 Device
= DeviceEntry
->DeviceDescriptor
;
1020 BlockDevice
= (PBL_BLOCK_DEVICE
)DeviceEntry
->DeviceSpecificData
;
1022 /* Initialize protocol handles */
1023 Protocol
[0].Handle
= BlockDevice
->Handle
;
1024 Protocol
[1].Handle
= 0;
1026 /* Open this device */
1027 Status
= EfiOpenProtocol(Protocol
[0].Handle
,
1028 &EfiDevicePathProtocol
,
1029 &Protocol
[0].Interface
);
1030 if (!NT_SUCCESS(Status
))
1036 /* Iterate twice -- once for the top level, once for the bottom */
1037 for (i
= 0, Found
= FALSE
; Found
== FALSE
&& Protocol
[i
].Handle
; i
++)
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
)
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)))
1049 /* Set the boot library specific device types */
1050 Device
->DeviceType
= LocalDevice
;
1051 Device
->Local
.Type
= FloppyDevice
;
1053 /* The ACPI UID is the drive number */
1054 Device
->Local
.FloppyDisk
.DriveNumber
= AcpiPath
->UID
;
1056 /* We found a match */
1060 else if ((LeafNode
->Type
== MEDIA_DEVICE_PATH
) && (i
== 1))
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
)
1067 /* Set this as a local device */
1068 Device
->Local
.Type
= LocalDevice
;
1070 /* Check if this is an MBR partition */
1071 if (DiskPath
->SignatureType
== SIGNATURE_TYPE_MBR
)
1073 /* Set that this is a local partition */
1074 Device
->DeviceType
= LegacyPartitionDevice
;
1075 Device
->Partition
.Disk
.Type
= LocalDevice
;
1077 /* Write the MBR partition signature */
1078 BlockDevice
->PartitionType
= MbrPartition
;
1079 BlockDevice
->Disk
.Mbr
.Signature
= *(PULONG
)&DiskPath
->Signature
[0];
1082 else if (DiskPath
->SignatureType
== SIGNATURE_TYPE_GUID
)
1084 /* Set this as a GPT partition */
1085 BlockDevice
->PartitionType
= GptPartition
;
1086 Device
->Local
.HardDisk
.PartitionType
= GptPartition
;
1088 /* Get the GPT signature */
1089 Status
= BlockIoGetGPTDiskSignature(DeviceEntry
,
1090 &Device
->Local
.HardDisk
.Gpt
.PartitionSignature
);
1091 if (NT_SUCCESS(Status
))
1094 RtlCopyMemory(&BlockDevice
->Disk
.Gpt
.Signature
,
1095 &Device
->Local
.HardDisk
.Gpt
.PartitionSignature
,
1096 sizeof(BlockDevice
->Disk
.Gpt
.Signature
));
1101 /* Otherwise, this is a raw disk */
1102 BlockDevice
->PartitionType
= RawPartition
;
1103 Device
->Local
.HardDisk
.PartitionType
= RawPartition
;
1104 Device
->Local
.HardDisk
.Raw
.DiskNumber
= BlockIoFirmwareRawDiskCount
++;
1106 else if (LeafNode
->SubType
== MEDIA_CDROM_DP
)
1108 /* Set block device information */
1109 EfiPrintf(L
"Found CD-ROM\r\n");
1110 BlockDevice
->PartitionType
= RawPartition
;
1111 BlockDevice
->Type
= CdRomDevice
;
1113 /* Set CDROM data */
1114 Device
->Local
.Type
= CdRomDevice
;
1115 Device
->Local
.FloppyDisk
.DriveNumber
= 0;
1119 else if ((LeafNode
->Type
!= MEDIA_DEVICE_PATH
) &&
1120 (LeafNode
->Type
!= ACPI_DEVICE_PATH
) &&
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
))
1128 /* We're not. So this must be a raw device */
1129 Device
->DeviceType
= LocalDevice
;
1132 /* Is it a removable raw device? */
1133 if (BlockDevice
->DeviceFlags
& BL_BLOCK_DEVICE_REMOVABLE_FLAG
)
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");
1143 /* It's a fixed device */
1144 BlockDevice
->Type
= DiskDevice
;
1145 Device
->Local
.Type
= DiskDevice
;
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");
1156 /* Close any protocols that we opened for each handle */
1159 EfiCloseProtocol(Protocol
[--i
].Handle
, &EfiDevicePathProtocol
);
1162 /* Return appropriate status */
1163 return Found
? STATUS_SUCCESS
: STATUS_NOT_SUPPORTED
;
1171 EfiPrintf(L
"not implemented\r\n");
1172 return STATUS_NOT_IMPLEMENTED
;
1180 EfiPrintf(L
"not implemented\r\n");
1181 return STATUS_NOT_IMPLEMENTED
;
1185 BlockIoEfiCreateDeviceEntry (
1186 _In_ PBL_DEVICE_ENTRY
*DeviceEntry
,
1190 PBL_DEVICE_ENTRY IoDeviceEntry
;
1191 PBL_BLOCK_DEVICE BlockDevice
;
1193 PBL_DEVICE_DESCRIPTOR Device
;
1195 /* Allocate the entry for this device and zero it out */
1196 IoDeviceEntry
= BlMmAllocateHeap(sizeof(*IoDeviceEntry
));
1199 return STATUS_NO_MEMORY
;
1201 RtlZeroMemory(IoDeviceEntry
, sizeof(*IoDeviceEntry
));
1203 /* Allocate the device descriptor for this device and zero it out */
1204 Device
= BlMmAllocateHeap(sizeof(*Device
));
1207 return STATUS_NO_MEMORY
;
1209 RtlZeroMemory(Device
, sizeof(*Device
));
1211 /* Allocate the block device specific data, and zero it out */
1212 BlockDevice
= BlMmAllocateHeap(sizeof(*BlockDevice
));
1215 return STATUS_NO_MEMORY
;
1217 RtlZeroMemory(BlockDevice
, sizeof(*BlockDevice
));
1219 /* Save the descriptor and block device specific data */
1220 IoDeviceEntry
->DeviceSpecificData
= BlockDevice
;
1221 IoDeviceEntry
->DeviceDescriptor
= Device
;
1223 /* Set the size of the descriptor */
1224 Device
->Size
= sizeof(*Device
);
1226 /* Copy the standard I/O callbacks */
1227 RtlCopyMemory(&IoDeviceEntry
->Callbacks
,
1228 &BlockIoDeviceFunctionTable
,
1229 sizeof(IoDeviceEntry
->Callbacks
));
1231 /* Add the two that are firmware specific */
1232 IoDeviceEntry
->Callbacks
.Reset
= BlockIoEfiReset
;
1233 IoDeviceEntry
->Callbacks
.Flush
= BlockIoEfiFlush
;
1235 /* Save the EFI handle */
1236 BlockDevice
->Handle
= Handle
;
1238 /* Get information on this device from EFI, caching it in the device */
1239 Status
= BlockIoEfiGetBlockIoInformation(BlockDevice
);
1240 if (NT_SUCCESS(Status
))
1242 /* Build the descriptor structure for this device */
1243 Status
= BlockIoEfiGetDeviceInformation(IoDeviceEntry
);
1244 if (NT_SUCCESS(Status
))
1246 /* We have a fully constructed device, return it */
1247 *DeviceEntry
= IoDeviceEntry
;
1248 return STATUS_SUCCESS
;
1252 /* Failure path, free the descriptor if we allocated one */
1253 if (IoDeviceEntry
->DeviceDescriptor
)
1255 BlMmFreeHeap(IoDeviceEntry
->DeviceDescriptor
);
1258 /* Free any other specific allocations */
1259 BlockIopFreeAllocations(IoDeviceEntry
->DeviceSpecificData
);
1261 /* Free the device entry itself and return the failure code */
1262 BlMmFreeHeap(IoDeviceEntry
);
1263 EfiPrintf(L
"Failed: %lx\r\n", Status
);
1268 BlockIoEfiCompareDevice (
1269 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1270 _In_ EFI_HANDLE Handle
1273 PBL_LOCAL_DEVICE LocalDeviceInfo
, EfiLocalDeviceInfo
;
1274 PBL_DEVICE_ENTRY DeviceEntry
;
1275 PBL_DEVICE_DESCRIPTOR EfiDevice
;
1280 /* Check if no device was given */
1283 /* Fail the comparison */
1284 Status
= STATUS_INVALID_PARAMETER
;
1288 /* Check if this is a local disk device */
1289 if (Device
->DeviceType
!= DiskDevice
)
1291 /* Nope -- is it a partition device? */
1292 if ((Device
->DeviceType
!= LegacyPartitionDevice
) &&
1293 (Device
->DeviceType
!= PartitionDevice
))
1295 /* Nope, so we can't compare */
1296 Status
= STATUS_INVALID_PARAMETER
;
1300 /* If so, return the device information for the parent disk */
1301 LocalDeviceInfo
= &Device
->Partition
.Disk
;
1305 /* Just return the disk information itself */
1306 LocalDeviceInfo
= &Device
->Local
;
1309 /* Create an EFI device entry for the EFI device handle */
1310 Status
= BlockIoEfiCreateDeviceEntry(&DeviceEntry
, Handle
);
1311 if (!NT_SUCCESS(Status
))
1316 /* Read the descriptor and assume failure for now */
1317 EfiDevice
= DeviceEntry
->DeviceDescriptor
;
1318 Status
= STATUS_UNSUCCESSFUL
;
1320 /* Check if the EFI device is a disk */
1321 if (EfiDevice
->DeviceType
!= DiskDevice
)
1323 /* Nope, is it a partition? */
1324 if ((EfiDevice
->DeviceType
!= LegacyPartitionDevice
) &&
1325 (EfiDevice
->DeviceType
!= PartitionDevice
))
1327 /* Neither, invalid handle so bail out */
1328 Status
= STATUS_INVALID_PARAMETER
;
1332 /* Yes, so get the information of the parent disk */
1333 EfiLocalDeviceInfo
= &EfiDevice
->Partition
.Disk
;
1337 /* It's a disk, so get the disk information itself */
1338 EfiLocalDeviceInfo
= &EfiDevice
->Local
;
1341 /* Are the two devices the same type? */
1342 if (EfiLocalDeviceInfo
->Type
!= LocalDeviceInfo
->Type
)
1344 /* Nope, that was easy */
1348 /* Yes, what kind of device is the EFI side? */
1349 switch (EfiLocalDeviceInfo
->Type
)
1353 /* Local hard drive, compare the signature */
1354 if (RtlCompareMemory(&EfiLocalDeviceInfo
->HardDisk
,
1355 &LocalDeviceInfo
->HardDisk
,
1356 sizeof(LocalDeviceInfo
->HardDisk
)) ==
1357 sizeof(LocalDeviceInfo
->HardDisk
))
1359 Status
= STATUS_SUCCESS
;
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
))
1372 Status
= STATUS_SUCCESS
;
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
))
1384 Status
= STATUS_SUCCESS
;
1390 /* File, compare the file identifier */
1391 if (RtlCompareMemory(&EfiLocalDeviceInfo
->File
,
1392 &LocalDeviceInfo
->File
,
1393 sizeof(LocalDeviceInfo
->File
)) ==
1394 sizeof(LocalDeviceInfo
->File
))
1396 Status
= STATUS_SUCCESS
;
1400 /* Something else we don't support */
1406 /* All done, did we have an EFI device entry? */
1409 /* Free it, since we only needed it locally for comparison */
1410 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
1411 BlockIopFreeAllocations(DeviceEntry
->DeviceSpecificData
);
1412 BlMmFreeHeap(DeviceEntry
);
1415 /* Return back to the caller */
1420 BlockIoFirmwareOpen (
1421 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1422 _In_ PBL_BLOCK_DEVICE BlockIoDevice
1426 BOOLEAN DeviceMatch
;
1427 BL_HASH_ENTRY HashEntry
;
1428 ULONG i
, Id
, DeviceCount
;
1429 PBL_DEVICE_ENTRY DeviceEntry
;
1430 EFI_HANDLE
* DeviceHandles
;
1432 /* Initialize everything */
1438 /* Ask EFI for handles to all block devices */
1439 Status
= EfiLocateHandleBuffer(ByProtocol
,
1440 &EfiBlockIoProtocol
,
1443 if (!NT_SUCCESS(Status
))
1445 return STATUS_NO_SUCH_DEVICE
;
1448 /* Build a hash entry, with the value inline */
1449 HashEntry
.Flags
= BL_HT_VALUE_IS_INLINE
;
1450 HashEntry
.Size
= sizeof(EFI_HANDLE
);
1452 /* Loop each device we got */
1453 DeviceMatch
= FALSE
;
1454 Status
= STATUS_NO_SUCH_DEVICE
;
1455 for (i
= 0; i
< DeviceCount
; i
++)
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
))
1462 /* We already know about this device */
1463 EfiPrintf(L
"Device is known\r\n");
1467 /* New device, store it in the hash table */
1468 Status
= BlHtStore(HashTableId
,
1471 sizeof(DeviceHandles
[i
]));
1472 if (!NT_SUCCESS(Status
))
1474 /* Free the array and fail */
1475 BlMmFreeHeap(DeviceHandles
);
1479 /* Create an entry for this device*/
1480 Status
= BlockIoEfiCreateDeviceEntry(&DeviceEntry
, DeviceHandles
[i
]);
1481 if (!NT_SUCCESS(Status
))
1483 EfiPrintf(L
"EFI create failed: %lx\r\n", Status
);
1487 /* Add the device entry to the device table */
1488 Status
= BlTblSetEntry(&BlockIoDeviceTable
,
1489 &BlockIoDeviceTableEntries
,
1492 TblDoNotPurgeEntry
);
1493 if (!NT_SUCCESS(Status
))
1495 /* Remove it from teh hash table */
1496 BlHtDelete(HashTableId
, &HashEntry
);
1498 /* Free the block I/O device data */
1499 BlockIopFreeAllocations(DeviceEntry
->DeviceSpecificData
);
1501 /* Free the descriptor */
1502 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
1504 /* Free the entry */
1505 BlMmFreeHeap(DeviceEntry
);
1509 /* Does this device match what we're looking for? */
1510 DeviceMatch
= BlpDeviceCompare(DeviceEntry
->DeviceDescriptor
, Device
);
1513 /* Yep, return the data back */
1514 RtlCopyMemory(BlockIoDevice
,
1515 DeviceEntry
->DeviceSpecificData
,
1516 sizeof(*BlockIoDevice
));
1517 Status
= STATUS_SUCCESS
;
1522 /* Free the device handle buffer array */
1523 BlMmFreeHeap(DeviceHandles
);
1531 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1532 _In_ PBL_DEVICE_ENTRY DeviceEntry
1535 EfiPrintf(L
"Not implemented!\r\n");
1536 return STATUS_NOT_IMPLEMENTED
;
1541 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1542 _In_ PBL_DEVICE_ENTRY DeviceEntry
1545 EfiPrintf(L
"Not implemented!\r\n");
1546 return STATUS_NOT_IMPLEMENTED
;
1551 _In_ PBL_DEVICE_ENTRY DeviceEntry
1554 NTSTATUS Status
, LocalStatus
;
1555 PBL_BLOCK_DEVICE BlockDevice
;
1557 /* Assume success */
1558 Status
= STATUS_SUCCESS
;
1559 BlockDevice
= DeviceEntry
->DeviceSpecificData
;
1561 /* Close the protocol */
1562 LocalStatus
= EfiCloseProtocol(BlockDevice
->Handle
, &EfiBlockIoProtocol
);
1563 if (!NT_SUCCESS(LocalStatus
))
1565 /* Only inherit failures */
1566 Status
= LocalStatus
;
1569 /* Free the block device allocations */
1570 LocalStatus
= BlockIopFreeAllocations(BlockDevice
);
1571 if (!NT_SUCCESS(LocalStatus
))
1573 /* Only inherit failures */
1574 Status
= LocalStatus
;
1577 /* Return back to caller */
1583 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1584 _In_ PBL_DEVICE_ENTRY DeviceEntry
1589 /* Use firmware-specific functions to open the disk */
1590 Status
= BlockIoFirmwareOpen(Device
, DeviceEntry
->DeviceSpecificData
);
1591 if (NT_SUCCESS(Status
))
1593 /* Overwrite with our own close routine */
1594 DeviceEntry
->Callbacks
.Close
= DiskClose
;
1597 /* Return back to caller */
1603 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1604 _In_ PBL_DEVICE_ENTRY DeviceEntry
1607 EfiPrintf(L
"Not implemented!\r\n");
1608 return STATUS_NOT_IMPLEMENTED
;
1613 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1614 _In_ PBL_DEVICE_ENTRY DeviceEntry
1617 EfiPrintf(L
"Not implemented!\r\n");
1618 return STATUS_NOT_IMPLEMENTED
;
1623 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1624 _In_ PBL_DEVICE_ENTRY DeviceEntry
1627 EfiPrintf(L
"Not implemented!\r\n");
1628 return STATUS_NOT_IMPLEMENTED
;
1633 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1634 _In_ PBL_DEVICE_ENTRY DeviceEntry
1637 EfiPrintf(L
"Not implemented!\r\n");
1638 return STATUS_NOT_IMPLEMENTED
;
1641 BL_DEVICE_CALLBACKS FileDeviceFunctionTable
=
1648 BL_DEVICE_CALLBACKS PartitionDeviceFunctionTable
=
1655 BL_DEVICE_CALLBACKS RamDiskDeviceFunctionTable
=
1662 BL_DEVICE_CALLBACKS DiskDeviceFunctionTable
=
1669 BL_DEVICE_CALLBACKS VirtualDiskDeviceFunctionTable
=
1676 BL_DEVICE_CALLBACKS UdpFunctionTable
=
1683 BL_DEVICE_CALLBACKS SerialPortFunctionTable
=
1691 DeviceTableCompare (
1693 _In_ PVOID Argument1
,
1694 _In_ PVOID Argument2
,
1695 _Inout_ PVOID Argument3
,
1696 _Inout_ PVOID Argument4
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
;
1705 /* Assume failure */
1708 /* Compare the device descriptor */
1709 if (BlpDeviceCompare(DeviceEntry
->DeviceDescriptor
, Device
))
1711 /* Compare something */
1712 if (DeviceEntry
->Unknown
== Unknown
)
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
)))
1718 /* And more flags */
1719 if (((Flags
& 8) || !(DeviceEntry
->Flags
& 8)) &&
1720 (!(Flags
& 8) || (DeviceEntry
->Flags
& 8)))
1722 /* Found a match! */
1729 /* Return matching state */
1734 DeviceTableDestroyEntry (
1739 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Entry
;
1742 /* Call the close routine for this entry */
1743 Status
= DeviceEntry
->Callbacks
.Close(DmDeviceTable
[DeviceId
]);
1745 /* Free the descriptor, and the device itself */
1746 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
1747 BlMmFreeHeap(DeviceEntry
);
1749 /* Clear out the netry, and return */
1750 DmDeviceTable
[DeviceId
] = NULL
;
1759 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Entry
;
1762 /* Check if the device is opened */
1763 if (DeviceEntry
->Flags
& BL_DEVICE_ENTRY_OPENED
)
1765 /* It is, so can't purge it */
1766 Status
= STATUS_UNSUCCESSFUL
;
1770 /* It isn't, so destroy the entry */
1771 Status
= DeviceTableDestroyEntry(DeviceEntry
, DeviceEntry
->DeviceId
);
1774 /* Return back to caller */
1779 BlockIoDeviceTableDestroyEntry (
1784 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Entry
;
1787 /* Call the close routine for this entry */
1788 Status
= DeviceEntry
->Callbacks
.Close(DeviceEntry
);
1790 /* Free the descriptor, and the device itself */
1791 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
1792 BlMmFreeHeap(DeviceEntry
);
1794 /* Clear out the netry, and return */
1795 BlockIoDeviceTable
[DeviceId
] = NULL
;
1800 BlockIoDeviceTableDestroy (
1806 /* Call the entry destructor on each entry in the table */
1807 Status
= BlTblMap(BlockIoDeviceTable
,
1808 BlockIoDeviceTableEntries
,
1809 BlockIoDeviceTableDestroyEntry
);
1811 /* Free the table and return */
1812 BlMmFreeHeap(BlockIoDeviceTable
);
1821 /* Free the prefetch buffer */
1822 BlMmFreeHeap(BlockIopPrefetchBuffer
);
1824 /* Set state to non initialized */
1825 BlockIoInitialized
= FALSE
;
1828 return STATUS_SUCCESS
;
1832 BlockIoEfiHashFunction (
1833 _In_ PBL_HASH_ENTRY Entry
,
1834 _In_ ULONG TableSize
1837 /* Get rid of the alignment bits to have a more unique number */
1838 return ((ULONG_PTR
)Entry
->Value
>> 3) % TableSize
;
1842 BlockIopInitialize (
1848 /* Allocate the block device table and zero it out */
1849 BlockIoDeviceTableEntries
= 8;
1850 BlockIoDeviceTable
= BlMmAllocateHeap(sizeof(PVOID
) *
1851 BlockIoDeviceTableEntries
);
1852 if (!BlockIoDeviceTableEntries
)
1854 return STATUS_NO_MEMORY
;
1856 RtlZeroMemory(BlockIoDeviceTable
, sizeof(PVOID
) * BlockIoDeviceTableEntries
);
1858 /* Register our destructor */
1859 Status
= BlpIoRegisterDestroyRoutine(BlockIoDeviceTableDestroy
);
1860 if (!NT_SUCCESS(Status
))
1865 /* Initialize all counters */
1866 BlockIoFirmwareRemovableDiskCount
= 0;
1867 BlockIoFirmwareRawDiskCount
= 0;
1868 BlockIoFirmwareCdromCount
= 0;
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;
1879 /* Allocate the prefetch buffer */
1880 Status
= MmPapAllocatePagesInRange(&BlockIopPrefetchBuffer
,
1881 BlLoaderDeviceMemory
,
1887 if (NT_SUCCESS(Status
))
1889 /* Initialize the block cache */
1890 Status
= BcInitialize();
1891 if (NT_SUCCESS(Status
))
1893 /* Initialize the block device hash table */
1894 Status
= BlHtCreate(29, BlockIoEfiHashFunction
, NULL
, &HashTableId
);
1895 if (NT_SUCCESS(Status
))
1897 /* Register our destructor */
1898 Status
= BlpIoRegisterDestroyRoutine(BlockIopDestroy
);
1899 if (NT_SUCCESS(Status
))
1902 BlockIoInitialized
= TRUE
;
1908 /* Check if this is the failure path */
1909 if (!NT_SUCCESS(Status
))
1911 /* Free the prefetch buffer is one was allocated */
1912 if (BlockIopPrefetchBuffer
)
1914 MmPapFreePages(BlockIopPrefetchBuffer
, BL_MM_INCLUDE_MAPPED_ALLOCATED
);
1918 /* Return back to the caller */
1923 BlockIoDeviceTableCompare (
1925 _In_ PVOID Argument1
,
1926 _In_ PVOID Argument2
,
1927 _In_ PVOID Argument3
,
1928 _In_ PVOID Argument4
1931 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Entry
;
1932 PBL_DEVICE_DESCRIPTOR Device
= (PBL_DEVICE_DESCRIPTOR
)Argument1
;
1934 /* Compare the two devices */
1935 return BlpDeviceCompare(DeviceEntry
->DeviceDescriptor
, Device
);
1940 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1941 _In_ PBL_DEVICE_ENTRY DeviceEntry
1945 PBL_BLOCK_DEVICE BlockDevice
;
1946 PBL_DEVICE_ENTRY FoundDeviceEntry
;
1949 /* Check if the block I/O manager is initialized */
1950 if (!BlockIoInitialized
)
1952 /* First call, initialize it now */
1953 Status
= BlockIopInitialize();
1954 if (!NT_SUCCESS(Status
))
1956 /* Failed to initialize block I/O */
1961 /* Copy a function table for block I/O devices */
1962 RtlCopyMemory(&DeviceEntry
->Callbacks
,
1963 &BlockIoDeviceFunctionTable
,
1964 sizeof(DeviceEntry
->Callbacks
));
1966 /* Allocate a block I/O device */
1967 BlockDevice
= BlMmAllocateHeap(sizeof(*BlockDevice
));
1970 return STATUS_NO_MEMORY
;
1973 /* Set this as the device-specific data for this device entry */
1974 Status
= STATUS_SUCCESS
;
1975 DeviceEntry
->DeviceSpecificData
= BlockDevice
;
1977 /* Check if we already have this device in our device table */
1978 FoundDeviceEntry
= BlTblFindEntry(BlockIoDeviceTable
,
1979 BlockIoDeviceTableEntries
,
1981 BlockIoDeviceTableCompare
,
1986 if (FoundDeviceEntry
)
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
));
1997 /* Zero out the device for now */
1998 RtlZeroMemory(BlockDevice
, sizeof(*BlockDevice
));
2000 /* Is this a disk? */
2001 if (Device
->DeviceType
== DiskDevice
)
2003 /* What type of disk is it? */
2004 switch (Device
->Local
.Type
)
2006 /* Is it a raw physical disk? */
2010 /* Open a disk device */
2011 Status
= DiskDeviceFunctionTable
.Open(Device
, DeviceEntry
);
2014 /* Is it a RAM disk? */
2016 /* Open a RAM disk */
2017 Status
= RamDiskDeviceFunctionTable
.Open(Device
, DeviceEntry
);
2023 Status
= FileDeviceFunctionTable
.Open(Device
, DeviceEntry
);
2027 case VirtualDiskDevice
:
2028 /* Open a virtual disk */
2029 Status
= VirtualDiskDeviceFunctionTable
.Open(Device
, DeviceEntry
);
2032 /* Is it something else? */
2035 Status
= STATUS_INVALID_PARAMETER
;
2039 else if ((Device
->DeviceType
== LegacyPartitionDevice
) ||
2040 (Device
->DeviceType
== PartitionDevice
))
2042 /* This is a partition on a disk, open it as such */
2043 Status
= PartitionDeviceFunctionTable
.Open(Device
, DeviceEntry
);
2047 /* Other devices are not supported */
2048 Status
= STATUS_INVALID_PARAMETER
;
2051 /* Check for failure */
2052 if (!NT_SUCCESS(Status
))
2054 /* Free any allocations for this device */
2055 BlockIopFreeAllocations(BlockDevice
);
2058 /* Return back to the caller */
2063 BlpDeviceResolveLocate (
2064 _In_ PBL_DEVICE_DESCRIPTOR InputDevice
,
2065 _Out_ PBL_DEVICE_DESCRIPTOR
* LocateDevice
2068 EfiPrintf(L
"Not implemented!\r\n");
2069 return STATUS_NOT_IMPLEMENTED
;
2077 PBL_DEVICE_ENTRY DeviceEntry
;
2079 /* Validate the device ID */
2080 if (DmTableEntries
<= DeviceId
)
2082 return STATUS_INVALID_PARAMETER
;
2085 /* Make sure there's a device there */
2086 DeviceEntry
= DmDeviceTable
[DeviceId
];
2087 if (DeviceEntry
== NULL
)
2089 return STATUS_INVALID_PARAMETER
;
2092 /* Make sure the device is active */
2093 if (!(DeviceEntry
->Flags
& BL_DEVICE_ENTRY_OPENED
))
2095 return STATUS_INVALID_PARAMETER
;
2098 /* Drop a reference and check if it's the last one */
2099 DeviceEntry
->ReferenceCount
--;
2100 if (!DeviceEntry
->ReferenceCount
)
2102 /* Mark the device as inactive */
2103 DeviceEntry
->Flags
= ~BL_DEVICE_ENTRY_OPENED
;
2107 return STATUS_SUCCESS
;
2112 _In_ PBL_DEVICE_DESCRIPTOR Device
,
2115 _Out_ PULONG DeviceId
2119 PBL_DEVICE_ENTRY DeviceEntry
;
2120 PBL_DEVICE_DESCRIPTOR LocateDeviceDescriptor
;
2121 PBL_REGISTERED_DEVICE RegisteredDevice
;
2122 PLIST_ENTRY NextEntry
, ListHead
;
2126 /* Check for missing parameters */
2127 if (!(Device
) || !(DeviceId
) || !(Device
->Size
))
2130 Status
= STATUS_INVALID_PARAMETER
;
2134 /* Make sure both read and write access are set */
2135 if (!(Flags
& (BL_DEVICE_READ_ACCESS
| BL_DEVICE_WRITE_ACCESS
)))
2138 Status
= STATUS_INVALID_PARAMETER
;
2142 /* Check if the boot device is being opened */
2143 if (Device
->DeviceType
== BootDevice
)
2146 Device
= BlpBootDevice
;
2149 /* Check if the 'locate' device is being opened */
2150 if (Device
->DeviceType
== LocateDevice
)
2153 Status
= BlpDeviceResolveLocate(Device
, &LocateDeviceDescriptor
);
2154 if (!NT_SUCCESS(Status
))
2156 /* Not found, bail out */
2161 Device
= LocateDeviceDescriptor
;
2164 /* Check if the device isn't ready yet */
2165 if (Device
->Flags
& 1)
2167 /* Return a failure */
2168 Status
= STATUS_DEVICE_NOT_READY
;
2172 /* Check if we already have an entry for the device */
2173 DeviceEntry
= BlTblFindEntry(DmDeviceTable
,
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
;
2190 /* We don't, allocate one */
2191 DeviceEntry
= BlMmAllocateHeap(sizeof(*DeviceEntry
));
2194 Status
= STATUS_NO_MEMORY
;
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
;
2206 /* Save flag 8 if needed */
2209 DeviceEntry
->Flags
|= 8;
2212 /* Allocate a device descriptor for the device */
2213 DeviceEntry
->DeviceDescriptor
= BlMmAllocateHeap(Device
->Size
);
2214 if (!DeviceEntry
->DeviceDescriptor
)
2216 Status
= STATUS_NO_MEMORY
;
2220 /* Copy the descriptor that was passed in */
2221 RtlCopyMemory(DeviceEntry
->DeviceDescriptor
, Device
, Device
->Size
);
2223 /* Now loop the list of dynamically registered devices */
2224 ListHead
= &DmRegisteredDevices
;
2225 NextEntry
= ListHead
->Flink
;
2226 while (NextEntry
!= ListHead
)
2228 /* Get the device */
2229 RegisteredDevice
= CONTAINING_RECORD(NextEntry
,
2230 BL_REGISTERED_DEVICE
,
2233 /* Open the device */
2234 Status
= RegisteredDevice
->Callbacks
.Open(Device
, DeviceEntry
);
2235 if (NT_SUCCESS(Status
))
2237 /* The device was opened, so we have the right one */
2241 /* Nope, keep trying */
2242 NextEntry
= NextEntry
->Flink
;
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
))
2250 /* Call the Block I/O handler */
2251 Status
= BlockIoDeviceFunctionTable
.Open(Device
, DeviceEntry
);
2253 else if (Device
->DeviceType
== SerialDevice
)
2255 /* It's a serial device, call the serial device handler */
2256 Status
= SerialPortFunctionTable
.Open(Device
, DeviceEntry
);
2258 else if (Device
->DeviceType
== UdpDevice
)
2260 /* It's a network device, call the UDP device handler */
2261 Status
= UdpFunctionTable
.Open(Device
, DeviceEntry
);
2265 /* Unsupported type of device */
2266 Status
= STATUS_NOT_IMPLEMENTED
;
2269 /* Check if the device was opened successfully */
2270 if (NT_SUCCESS(Status
))
2273 /* Save the entry in the device table */
2274 Status
= BlTblSetEntry(&DmDeviceTable
,
2279 if (NT_SUCCESS(Status
))
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
;
2289 /* Failure path -- did we allocate a device entry? */
2290 EfiPrintf(L
"Block failure: %lx\r\n", Status
);
2293 /* Yep -- did it have a descriptor? */
2294 if (DeviceEntry
->DeviceDescriptor
)
2297 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
2300 /* Free the entry */
2301 BlMmFreeHeap(DeviceEntry
);
2304 /* Return the failure */
2309 BlpDeviceInitialize (
2315 /* Initialize the table count and list of devices */
2317 InitializeListHead(&DmRegisteredDevices
);
2319 /* Initialize device information */
2320 DmDeviceIoInformation
.ReadCount
= 0;
2321 DmDeviceIoInformation
.WriteCount
= 0;
2323 /* Allocate the device table */
2324 DmDeviceTable
= BlMmAllocateHeap(DmTableEntries
* sizeof(PVOID
));
2328 RtlZeroMemory(DmDeviceTable
, DmTableEntries
* sizeof(PVOID
));
2329 #if BL_BITLOCKER_SUPPORT
2330 /* Initialize BitLocker support */
2331 Status
= FvebInitialize();
2333 Status
= STATUS_SUCCESS
;
2338 /* No memory, we'll fail */
2339 Status
= STATUS_NO_MEMORY
;
2342 /* Return initialization state */