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_INFORMATION
21 } BL_DEVICE_INFORMATION
, *PBL_DEVICE_INFORMATION
;
23 LIST_ENTRY DmRegisteredDevices
;
25 LIST_ENTRY DmRegisteredDevices
;
28 BL_DEVICE_INFORMATION DmDeviceIoInformation
;
30 /* FUNCTIONS *****************************************************************/
32 struct _BL_DEVICE_ENTRY
;
36 (*PBL_DEVICE_ENUMERATE_DEVICE_CLASS
) (
43 _In_ PBL_DEVICE_DESCRIPTOR Device
,
44 _In_
struct _BL_DEVICE_ENTRY
* DeviceEntry
50 _In_
struct _BL_DEVICE_ENTRY
* DeviceEntry
67 (*PBL_DEVICE_GET_INFORMATION
) (
73 (*PBL_DEVICE_SET_INFORMATION
) (
91 (*PBL_DEVICE_CREATE
) (
95 typedef struct _BL_DEVICE_CALLBACKS
97 PBL_DEVICE_ENUMERATE_DEVICE_CLASS EnumerateDeviceClass
;
99 PBL_DEVICE_CLOSE Close
;
100 PBL_DEVICE_READ Read
;
101 PBL_DEVICE_WRITE Write
;
102 PBL_DEVICE_GET_INFORMATION GetInformation
;
103 PBL_DEVICE_SET_INFORMATION SetInformation
;
104 PBL_DEVICE_RESET Reset
;
105 PBL_DEVICE_FLUSH Flush
;
106 PBL_DEVICE_CREATE Create
;
107 } BL_DEVICE_CALLBACKS
, *PBL_DEVICE_CALLBACKS
;
109 typedef struct _BL_DEVICE_ENTRY
114 ULONG ReferenceCount
;
115 BL_DEVICE_CALLBACKS Callbacks
;
116 PVOID DeviceSpecificData
;
117 PBL_DEVICE_DESCRIPTOR DeviceDescriptor
;
118 } BL_DEVICE_ENTRY
, *PBL_DEVICE_ENTRY
;
120 typedef struct _BL_REGISTERED_DEVICE
122 LIST_ENTRY ListEntry
;
123 BL_DEVICE_CALLBACKS Callbacks
;
124 } BL_REGISTERED_DEVICE
, *PBL_REGISTERED_DEVICE
;
126 PVOID
* BlockIoDeviceTable
;
127 ULONG BlockIoDeviceTableEntries
;
129 ULONG BlockIoFirmwareRemovableDiskCount
;
130 ULONG BlockIoFirmwareRawDiskCount
;
131 ULONG BlockIoFirmwareCdromCount
;
133 PVOID BlockIopAlignedBuffer
;
134 ULONG BlockIopAlignedBufferSize
;
136 PVOID BlockIopPartialBlockBuffer
;
137 ULONG BlockIopPartialBlockBufferSize
;
139 PVOID BlockIopPrefetchBuffer
;
141 PVOID BlockIopReadBlockBuffer
;
142 ULONG BlockIopReadBlockBufferSize
;
146 BOOLEAN BlockIoInitialized
;
150 _In_ PBL_DEVICE_DESCRIPTOR Device
,
151 _In_ PBL_DEVICE_ENTRY DeviceEntry
156 _In_ PBL_DEVICE_DESCRIPTOR Device
,
157 _In_ PBL_DEVICE_ENTRY DeviceEntry
160 EfiPrintf(L
"Not implemented!\r\n");
161 return STATUS_NOT_IMPLEMENTED
;
166 _In_ PBL_DEVICE_DESCRIPTOR Device
,
167 _In_ PBL_DEVICE_ENTRY DeviceEntry
170 EfiPrintf(L
"Not implemented!\r\n");
171 return STATUS_NOT_IMPLEMENTED
;
176 _In_ PBL_DEVICE_DESCRIPTOR Device
,
177 _In_ PBL_DEVICE_ENTRY DeviceEntry
180 EfiPrintf(L
"Not implemented!\r\n");
181 return STATUS_NOT_IMPLEMENTED
;
186 _In_ PBL_DEVICE_DESCRIPTOR Device
,
187 _In_ PBL_DEVICE_ENTRY DeviceEntry
190 EfiPrintf(L
"Not implemented!\r\n");
191 return STATUS_NOT_IMPLEMENTED
;
196 _In_ PBL_DEVICE_DESCRIPTOR Device
,
197 _In_ PBL_DEVICE_ENTRY DeviceEntry
200 EfiPrintf(L
"Not implemented!\r\n");
201 return STATUS_NOT_IMPLEMENTED
;
206 _In_ PBL_DEVICE_DESCRIPTOR Device
,
207 _In_ PBL_DEVICE_ENTRY DeviceEntry
210 EfiPrintf(L
"Not implemented!\r\n");
211 return STATUS_NOT_IMPLEMENTED
;
216 _In_ PBL_DEVICE_DESCRIPTOR Device
,
217 _In_ PBL_DEVICE_ENTRY DeviceEntry
220 EfiPrintf(L
"Not implemented!\r\n");
221 return STATUS_NOT_IMPLEMENTED
;
224 BL_DEVICE_CALLBACKS FileDeviceFunctionTable
=
231 BL_DEVICE_CALLBACKS PartitionDeviceFunctionTable
=
238 BL_DEVICE_CALLBACKS RamDiskDeviceFunctionTable
=
245 BL_DEVICE_CALLBACKS DiskDeviceFunctionTable
=
252 BL_DEVICE_CALLBACKS VirtualDiskDeviceFunctionTable
=
259 BL_DEVICE_CALLBACKS BlockIoDeviceFunctionTable
=
266 BL_DEVICE_CALLBACKS UdpFunctionTable
=
273 BL_DEVICE_CALLBACKS SerialPortFunctionTable
=
281 ULONG BcpBlockAllocatorHandle
;
282 ULONG BcpHashTableId
;
289 //BcpPurgeCacheEntries();
290 //return BlpMmDeleteBlockAllocator(BcpBlockAllocatorHandle);
291 EfiPrintf(L
"Destructor for block cache not yet implemented\r\n");
292 return STATUS_NOT_IMPLEMENTED
;
297 _In_ PBL_HASH_ENTRY Entry1
,
298 _In_ PBL_HASH_ENTRY Entry2
301 PULONG Value1
, Value2
;
303 Value1
= Entry1
->Value
;
304 Value2
= Entry2
->Value
;
305 return Entry1
->Size
== Entry2
->Size
&& Entry1
->Flags
== Entry2
->Flags
&& *Value1
== *Value2
&& Value1
[1] == Value2
[1] && Value1
[2] == Value2
[2];
310 _In_ PBL_HASH_ENTRY Entry
,
314 ULONG i
, j
, ValueHash
;
321 ValueBuffer
= Entry
->Value
;
325 ValueHash
+= ValueBuffer
[i
++];
331 ValueHash
+= ValueBuffer
[j
++ + 8];
335 return ValueHash
% TableSize
;
345 Status
= BlHtCreate(50, BcpHashFunction
, BcpCompareKey
, &BcpHashTableId
);
346 if (!NT_SUCCESS(Status
))
351 BcpBlockAllocatorHandle
= BlpMmCreateBlockAllocator();
352 if (BcpBlockAllocatorHandle
== -1)
354 Status
= STATUS_UNSUCCESSFUL
;
358 Status
= BlpIoRegisterDestroyRoutine(BcpDestroy
);
365 EfiPrintf(L
"Failure path not yet implemented\n");
367 if (BcpHashTableId
!= -1)
369 BlHtDestroy(BcpHashTableId
);
371 if (BcpBlockAllocatorHandle
!= -1)
373 BlpMmDeleteBlockAllocator(BcpBlockAllocatorHandle
);
381 _In_ PBL_DEVICE_DESCRIPTOR Device1
,
382 _In_ PBL_DEVICE_DESCRIPTOR Device2
391 /* Check if the two devices exist and are identical in typ */
392 if ((Device1
) && (Device2
) && (Device1
->DeviceType
== Device2
->DeviceType
))
394 /* Take the bigger of the two sizes */
395 DeviceSize
= max(Device1
->Size
, Device2
->Size
);
396 if (DeviceSize
>= (ULONG
)FIELD_OFFSET(BL_DEVICE_DESCRIPTOR
, Local
))
398 /* Compare the two devices up to their size */
399 if (RtlEqualMemory(&Device1
->Local
,
401 DeviceSize
- FIELD_OFFSET(BL_DEVICE_DESCRIPTOR
, Local
)))
409 /* Return matching state */
416 _In_ PVOID Argument1
,
417 _In_ PVOID Argument2
,
418 _Inout_ PVOID Argument3
,
419 _Inout_ PVOID Argument4
423 PBL_DEVICE_DESCRIPTOR Device
= (PBL_DEVICE_DESCRIPTOR
)Entry
;
424 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Argument1
;
425 ULONG Flags
= *(PULONG
)Argument2
;
426 ULONG Unknown
= *(PULONG
)Argument3
;
431 /* Compare the device descriptor */
432 if (BlpDeviceCompare(DeviceEntry
->DeviceDescriptor
, Device
))
434 /* Compare something */
435 if (DeviceEntry
->Unknown
== Unknown
)
438 if ((!(Flags
& 1) || (DeviceEntry
->Flags
& 2)) &&
439 (!(Flags
& 2) || (DeviceEntry
->Flags
& 4)))
442 if (((Flags
& 8) || !(DeviceEntry
->Flags
& 8)) &&
443 (!(Flags
& 8) || (DeviceEntry
->Flags
& 8)))
452 /* Return matching state */
457 DeviceTableDestroyEntry (
462 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Entry
;
465 /* Call the close routine for this entry */
466 Status
= DeviceEntry
->Callbacks
.Close(DmDeviceTable
[DeviceId
]);
468 /* Free the descriptor, and the device itself */
469 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
470 BlMmFreeHeap(DeviceEntry
);
472 /* Clear out the netry, and return */
473 DmDeviceTable
[DeviceId
] = NULL
;
482 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Entry
;
485 /* Check if the device is opened */
486 if (DeviceEntry
->Flags
& 1)
488 /* It is, so can't purge it */
489 Status
= STATUS_UNSUCCESSFUL
;
493 /* It isn't, so destroy the entry */
494 Status
= DeviceTableDestroyEntry(DeviceEntry
, DeviceEntry
->DeviceId
);
497 /* Return back to caller */
502 BlockIoDeviceTableDestroyEntry (
507 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Entry
;
510 /* Call the close routine for this entry */
511 Status
= DeviceEntry
->Callbacks
.Close(DeviceEntry
);
513 /* Free the descriptor, and the device itself */
514 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
515 BlMmFreeHeap(DeviceEntry
);
517 /* Clear out the netry, and return */
518 BlockIoDeviceTable
[DeviceId
] = NULL
;
523 BlockIoDeviceTableDestroy (
529 /* Call the entry destructor on each entry in the table */
530 Status
= BlTblMap(BlockIoDeviceTable
,
531 BlockIoDeviceTableEntries
,
532 BlockIoDeviceTableDestroyEntry
);
534 /* Free the table and return */
535 BlMmFreeHeap(BlockIoDeviceTable
);
544 /* Free the prefetch buffer */
545 BlMmFreeHeap(BlockIopPrefetchBuffer
);
547 /* Set state to non initialized */
548 BlockIoInitialized
= FALSE
;
551 return STATUS_SUCCESS
;
555 BlockIoEfiHashFunction (
556 _In_ PBL_HASH_ENTRY Entry
,
560 /* Get rid of the alignment bits to have a more unique number */
561 return ((ULONG
)Entry
->Value
>> 3) % TableSize
;
571 /* Allocate the block device table and zero it out */
572 BlockIoDeviceTableEntries
= 8;
573 BlockIoDeviceTable
= BlMmAllocateHeap(sizeof(PVOID
) *
574 BlockIoDeviceTableEntries
);
575 if (!BlockIoDeviceTableEntries
)
577 return STATUS_NO_MEMORY
;
579 RtlZeroMemory(BlockIoDeviceTable
, sizeof(PVOID
) * BlockIoDeviceTableEntries
);
581 /* Register our destructor */
582 Status
= BlpIoRegisterDestroyRoutine(BlockIoDeviceTableDestroy
);
583 if (!NT_SUCCESS(Status
))
588 /* Initialize all counters */
589 BlockIoFirmwareRemovableDiskCount
= 0;
590 BlockIoFirmwareRawDiskCount
= 0;
591 BlockIoFirmwareCdromCount
= 0;
593 /* Initialize the buffers and their sizes */
594 BlockIopAlignedBuffer
= NULL
;
595 BlockIopAlignedBufferSize
= 0;
596 BlockIopPartialBlockBuffer
= NULL
;
597 BlockIopPartialBlockBufferSize
= 0;
598 BlockIopPrefetchBuffer
= NULL
;
599 BlockIopReadBlockBuffer
= NULL
;
600 BlockIopReadBlockBufferSize
= 0;
602 /* Allocate the prefetch buffer */
603 Status
= MmPapAllocatePagesInRange(&BlockIopPrefetchBuffer
,
604 BlLoaderDeviceMemory
,
610 if (NT_SUCCESS(Status
))
612 /* Initialize the block cache */
613 Status
= BcInitialize();
614 if (NT_SUCCESS(Status
))
616 /* Initialize the block device hash table */
617 Status
= BlHtCreate(29, BlockIoEfiHashFunction
, NULL
, &HashTableId
);
618 if (NT_SUCCESS(Status
))
620 /* Register our destructor */
621 Status
= BlpIoRegisterDestroyRoutine(BlockIopDestroy
);
622 if (NT_SUCCESS(Status
))
625 BlockIoInitialized
= TRUE
;
631 /* Check if this is the failure path */
632 if (!NT_SUCCESS(Status
))
634 /* Free the prefetch buffer is one was allocated */
635 if (BlockIopPrefetchBuffer
)
637 EfiPrintf(L
"Failure path not implemented %lx\r\n", Status
);
638 //MmPapFreePages(BlockIopPrefetchBuffer, 1);
642 /* Return back to the caller */
647 BlockIopFreeAllocations (
648 _In_ PBL_BLOCK_DEVICE BlockDevice
651 /* If a block device was passed in, free it */
654 BlMmFreeHeap(BlockDevice
);
657 /* Nothing else to do */
658 return STATUS_SUCCESS
;
662 BlockIoEfiGetBlockIoInformation (
663 _In_ PBL_BLOCK_DEVICE BlockDevice
667 EFI_BLOCK_IO_MEDIA
*Media
;
669 /* Open the Block I/O protocol on this device */
670 Status
= EfiOpenProtocol(BlockDevice
->Handle
,
672 (PVOID
*)&BlockDevice
->Protocol
);
673 if (!NT_SUCCESS(Status
))
678 /* Get information on the block media */
679 Media
= BlockDevice
->Protocol
->Media
;
681 /* Set the appropriate device flags */
682 BlockDevice
->DeviceFlags
= 0;
683 if (Media
->RemovableMedia
)
685 BlockDevice
->DeviceFlags
= 1;
687 if (Media
->MediaPresent
)
689 BlockDevice
->DeviceFlags
|= 2;
693 BlockDevice
->Unknown
= 0;
695 /* Set the block size */
696 BlockDevice
->BlockSize
= Media
->BlockSize
;
698 /* Make sure there's a last block value */
699 if (!Media
->LastBlock
)
701 return STATUS_INVALID_PARAMETER
;
704 /* Don't let it be too high */
705 if (Media
->LastBlock
> 0xFFFFFFFFFFE)
707 BlockDevice
->LastBlock
= 0xFFFFFFFFFFE;
711 BlockDevice
->LastBlock
= Media
->LastBlock
;
714 /* Make the alignment the smaller of the I/O alignment or the block size */
715 if (Media
->IoAlign
>= Media
->BlockSize
)
717 BlockDevice
->Alignment
= Media
->IoAlign
;
721 BlockDevice
->Alignment
= Media
->BlockSize
;
725 return STATUS_SUCCESS
;
729 BlockIoEfiGetChildHandle (
730 _In_ PBL_PROTOCOL_HANDLE ProtocolInterface
,
731 _In_ PBL_PROTOCOL_HANDLE ChildProtocolInterface
)
734 ULONG i
, DeviceCount
;
735 EFI_DEVICE_PATH
*DevicePath
, *ParentDevicePath
;
736 EFI_HANDLE
*DeviceHandles
;
739 /* Find all the Block I/O device handles on the system */
742 Status
= EfiLocateHandleBuffer(ByProtocol
,
746 if (!NT_SUCCESS(Status
))
748 /* Failed to enumerate, bail out */
752 /* Loop all the handles */
753 for (i
= 0; i
< DeviceCount
; i
++)
755 /* Check if this is the device itself */
756 Handle
= DeviceHandles
[i
];
757 if (Handle
== ProtocolInterface
->Handle
)
763 /* Get the device path of this device */
764 Status
= EfiOpenProtocol(Handle
,
765 &EfiDevicePathProtocol
,
766 (PVOID
*)&DevicePath
);
767 if (!NT_SUCCESS(Status
))
769 /* We failed, skip it */
773 /* See if we are its parent */
774 ParentDevicePath
= EfiIsDevicePathParent(ProtocolInterface
->Interface
,
776 if (ParentDevicePath
== ProtocolInterface
->Interface
)
778 /* Yup, return back to caller */
779 ChildProtocolInterface
->Handle
= Handle
;
780 ChildProtocolInterface
->Interface
= DevicePath
;
784 /* Close the device path */
785 EfiCloseProtocol(Handle
, &EfiDevicePathProtocol
);
788 /* If we got here, nothing was found */
789 Status
= STATUS_NO_SUCH_DEVICE
;
791 /* Free the handle array buffer */
792 BlMmFreeHeap(DeviceHandles
);
797 BlockIoGetGPTDiskSignature (
798 _In_ PBL_DEVICE_ENTRY DeviceEntry
,
799 _Out_ PGUID DiskSignature
802 EfiPrintf(L
"GPT not supported\r\n");
803 return STATUS_NOT_IMPLEMENTED
;
807 BlockIoEfiGetDeviceInformation (
808 _In_ PBL_DEVICE_ENTRY DeviceEntry
812 PBL_DEVICE_DESCRIPTOR Device
;
813 PBL_BLOCK_DEVICE BlockDevice
;
814 EFI_DEVICE_PATH
*LeafNode
;
816 BL_PROTOCOL_HANDLE Protocol
[2];
817 ACPI_HID_DEVICE_PATH
*AcpiPath
;
818 HARDDRIVE_DEVICE_PATH
*DiskPath
;
822 Device
= DeviceEntry
->DeviceDescriptor
;
823 BlockDevice
= (PBL_BLOCK_DEVICE
)DeviceEntry
->DeviceSpecificData
;
827 Handle
= BlockDevice
->Handle
;
829 Protocol
[0].Handle
= Handle
;
830 Protocol
[1].Handle
= 0;
832 Status
= EfiOpenProtocol(Handle
,
833 &EfiDevicePathProtocol
,
834 &Protocol
[0].Interface
);
840 for (i
= 0, Found
= FALSE
; Found
== FALSE
&& Protocol
[i
].Handle
; i
++)
842 LeafNode
= EfiGetLeafNode(Protocol
[i
].Interface
);
843 if (LeafNode
->Type
== ACPI_DEVICE_PATH
)
845 /* We only support floppy drives */
846 AcpiPath
= (ACPI_HID_DEVICE_PATH
*)LeafNode
;
847 if ((AcpiPath
->HID
== EISA_PNP_ID(0x604)) &&
848 (AcpiPath
->HID
== EISA_PNP_ID(0x700)))
850 /* Set the boot library specific device types */
851 Device
->DeviceType
= LocalDevice
;
852 Device
->Local
.Type
= FloppyDevice
;
854 /* The ACPI UID is the drive number */
855 Device
->Local
.FloppyDisk
.DriveNumber
= AcpiPath
->UID
;
857 /* We found a match */
861 else if ((LeafNode
->Type
== MEDIA_DEVICE_PATH
) && (i
== 1))
863 /* Extract the disk path and check if it's a physical disk */
864 DiskPath
= (HARDDRIVE_DEVICE_PATH
*)LeafNode
;
865 if (LeafNode
->SubType
== MEDIA_HARDDRIVE_DP
)
867 Device
->Local
.Type
= LocalDevice
;
869 /* Check if this is an MBR partition */
870 if (DiskPath
->SignatureType
== SIGNATURE_TYPE_MBR
)
872 /* Set that this is a local partition */
873 Device
->DeviceType
= LegacyPartitionDevice
;
874 Device
->Partition
.Disk
.Type
= LocalDevice
;
876 BlockDevice
->PartitionType
= MbrPartition
;
877 BlockDevice
->Disk
.Mbr
.Signature
= *(PULONG
)&DiskPath
->Signature
[0];
880 else if (DiskPath
->SignatureType
== SIGNATURE_TYPE_GUID
)
882 BlockDevice
->PartitionType
= 0;
883 Device
->Local
.HardDisk
.PartitionType
= GptPartition
;
885 Status
= BlockIoGetGPTDiskSignature(DeviceEntry
,
886 &Device
->Local
.HardDisk
.Gpt
.PartitionSignature
);
887 if (NT_SUCCESS(Status
))
889 RtlCopyMemory(&BlockDevice
->Disk
.Gpt
.Signature
,
890 &Device
->Local
.HardDisk
.Gpt
.PartitionSignature
,
891 sizeof(&BlockDevice
->Disk
.Gpt
.Signature
));
896 /* Otherwise, raw boot is not supported */
897 BlockDevice
->PartitionType
= RawPartition
;
898 Device
->Local
.HardDisk
.PartitionType
= RawPartition
;
899 Device
->Local
.HardDisk
.Raw
.DiskNumber
= BlockIoFirmwareRawDiskCount
++;;
901 else if (LeafNode
->SubType
== MEDIA_CDROM_DP
)
903 /* Set block device information */
904 BlockDevice
->PartitionType
= RawPartition
;
905 BlockDevice
->Type
= CdRomDevice
;
908 Device
->Local
.Type
= CdRomDevice
;
909 Device
->Local
.FloppyDisk
.DriveNumber
= 0;
913 else if ((LeafNode
->Type
!= MEDIA_DEVICE_PATH
) &&
914 (LeafNode
->Type
== ACPI_DEVICE_PATH
) &&
917 Status
= BlockIoEfiGetChildHandle(Protocol
, &Protocol
[i
]);
918 if (!NT_SUCCESS(Status
))
920 Device
->DeviceType
= LocalDevice
;
922 if (BlockDevice
->DeviceFlags
& 1)
924 BlockDevice
->Type
= FloppyDevice
;
925 Device
->Local
.HardDisk
.PartitionType
= BlockIoFirmwareRemovableDiskCount
++;
926 Device
->Local
.Type
= FloppyDevice
;
930 BlockDevice
->Type
= DiskDevice
;
931 Device
->Local
.Type
= DiskDevice
;
932 Device
->Local
.HardDisk
.PartitionType
= RawPartition
;
933 BlockDevice
->PartitionType
= RawPartition
;
934 Device
->Local
.HardDisk
.Mbr
.PartitionSignature
= BlockIoFirmwareRawDiskCount
++;
942 EfiCloseProtocol(Protocol
[--i
].Handle
, &EfiDevicePathProtocol
);
951 Status
= STATUS_NOT_SUPPORTED
;
961 EfiPrintf(L
"not implemented\r\n");
962 return STATUS_NOT_IMPLEMENTED
;
970 EfiPrintf(L
"not implemented\r\n");
971 return STATUS_NOT_IMPLEMENTED
;
975 BlockIoEfiCreateDeviceEntry (
976 _In_ PBL_DEVICE_ENTRY
*DeviceEntry
,
980 PBL_DEVICE_ENTRY IoDeviceEntry
;
981 PBL_BLOCK_DEVICE BlockDevice
;
983 PBL_DEVICE_DESCRIPTOR Device
;
985 /* Allocate the entry for this device and zero it out */
986 IoDeviceEntry
= BlMmAllocateHeap(sizeof(*IoDeviceEntry
));
989 return STATUS_NO_MEMORY
;
991 RtlZeroMemory(IoDeviceEntry
, sizeof(*IoDeviceEntry
));
993 /* Allocate the device descriptor for this device and zero it out */
994 Device
= BlMmAllocateHeap(sizeof(*Device
));
997 return STATUS_NO_MEMORY
;
999 RtlZeroMemory(Device
, sizeof(*Device
));
1001 /* Allocate the block device specific data, and zero it out */
1002 BlockDevice
= BlMmAllocateHeap(sizeof(*BlockDevice
));
1005 return STATUS_NO_MEMORY
;
1007 RtlZeroMemory(BlockDevice
, sizeof(*BlockDevice
));
1009 /* Save the descriptor and block device specific data */
1010 IoDeviceEntry
->DeviceSpecificData
= BlockDevice
;
1011 IoDeviceEntry
->DeviceDescriptor
= Device
;
1013 /* Set the size of the descriptor */
1014 Device
->Size
= sizeof(*Device
);
1016 /* Copy the standard I/O callbacks */
1017 RtlCopyMemory(&IoDeviceEntry
->Callbacks
,
1018 &BlockIoDeviceFunctionTable
,
1019 sizeof(IoDeviceEntry
->Callbacks
));
1021 /* Add the two that are firmware specific */
1022 IoDeviceEntry
->Callbacks
.Reset
= BlockIoEfiReset
;
1023 IoDeviceEntry
->Callbacks
.Flush
= BlockIoEfiFlush
;
1025 /* Save the EFI handle */
1026 BlockDevice
->Handle
= Handle
;
1028 /* Get information on this device from EFI, caching it in the device */
1029 Status
= BlockIoEfiGetBlockIoInformation(BlockDevice
);
1030 if (NT_SUCCESS(Status
))
1032 /* Build the descriptor structure for this device */
1033 Status
= BlockIoEfiGetDeviceInformation(IoDeviceEntry
);
1034 if (NT_SUCCESS(Status
))
1036 /* We have a fully constructed device, reuturn it */
1037 *DeviceEntry
= IoDeviceEntry
;
1038 return STATUS_SUCCESS
;
1042 /* Failure path, free the descriptor if we allocated one */
1043 if (IoDeviceEntry
->DeviceDescriptor
)
1045 BlMmFreeHeap(IoDeviceEntry
->DeviceDescriptor
);
1048 /* Free any other specific allocations */
1049 BlockIopFreeAllocations(IoDeviceEntry
->DeviceSpecificData
);
1051 /* Free the device entry itself and return the failure code */
1052 BlMmFreeHeap(IoDeviceEntry
);
1057 BlockIoFirmwareOpen (
1058 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1059 _In_ PBL_BLOCK_DEVICE BlockIoDevice
1063 BOOLEAN DeviceMatch
;
1064 BL_HASH_ENTRY HashEntry
;
1065 ULONG i
, Id
, DeviceCount
;
1066 PBL_DEVICE_ENTRY DeviceEntry
;
1067 EFI_HANDLE
* DeviceHandles
;
1069 /* Initialize everything */
1075 /* Ask EFI for handles to all block devices */
1076 Status
= EfiLocateHandleBuffer(ByProtocol
,
1077 &EfiBlockIoProtocol
,
1080 if (!NT_SUCCESS(Status
))
1082 return STATUS_NO_SUCH_DEVICE
;
1085 /* Build a hash entry, with the value inline */
1086 HashEntry
.Flags
= 1;
1087 HashEntry
.Size
= sizeof(EFI_HANDLE
);
1089 /* Loop each device we got */
1090 DeviceMatch
= FALSE
;
1091 Status
= STATUS_NO_SUCH_DEVICE
;
1092 for (i
= 0; i
< DeviceCount
; i
++)
1094 /* Check if we have a match in the device hash table */
1095 HashEntry
.Value
= DeviceHandles
[i
];
1096 Status
= BlHtLookup(HashTableId
, &HashEntry
, 0);
1097 if (NT_SUCCESS(Status
))
1099 /* We already know about this device */
1103 /* New device, store it in the hash table */
1104 Status
= BlHtStore(HashTableId
,
1107 sizeof(DeviceHandles
[i
]));
1108 if (!NT_SUCCESS(Status
))
1110 /* Free the array and fail */
1111 BlMmFreeHeap(DeviceHandles
);
1115 /* Create an entry for this device*/
1116 Status
= BlockIoEfiCreateDeviceEntry(&DeviceEntry
, DeviceHandles
[i
]);
1117 if (!NT_SUCCESS(Status
))
1122 /* Add the device entry to the device table */
1123 Status
= BlTblSetEntry(&BlockIoDeviceTable
,
1124 &BlockIoDeviceTableEntries
,
1127 TblDoNotPurgeEntry
);
1128 if (!NT_SUCCESS(Status
))
1130 EfiPrintf(L
"Failure path not implemented: %lx\r\n", Status
);
1132 BlHtDelete(HashTableId
, &HashKey
);
1134 /* Free the block I/O device data */
1135 BlockIopFreeAllocations(DeviceEntry
->DeviceSpecificData
);
1137 /* Free the descriptor */
1138 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
1140 /* Free the entry */
1141 BlMmFreeHeap(DeviceEntry
);
1145 /* Does this device match what we're looking for? */
1146 DeviceMatch
= BlpDeviceCompare(DeviceEntry
->DeviceDescriptor
, Device
);
1149 /* Yep, return the data back */
1150 RtlCopyMemory(BlockIoDevice
,
1151 DeviceEntry
->DeviceSpecificData
,
1152 sizeof(*BlockIoDevice
));
1153 Status
= STATUS_SUCCESS
;
1158 /* Free the device handle buffer array */
1159 BlMmFreeHeap(DeviceHandles
);
1166 BlockIoDeviceTableCompare (
1168 _In_ PVOID Argument1
,
1169 _In_ PVOID Argument2
,
1170 _In_ PVOID Argument3
,
1171 _In_ PVOID Argument4
1174 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Entry
;
1175 PBL_DEVICE_DESCRIPTOR Device
= (PBL_DEVICE_DESCRIPTOR
)Argument1
;
1177 /* Compare the two devices */
1178 return BlpDeviceCompare(DeviceEntry
->DeviceDescriptor
, Device
);
1183 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1184 _In_ PBL_DEVICE_ENTRY DeviceEntry
1188 PBL_BLOCK_DEVICE BlockDevice
;
1189 PBL_DEVICE_ENTRY FoundDeviceEntry
;
1192 /* Check if the block I/O manager is initialized */
1193 if (!BlockIoInitialized
)
1195 /* First call, initialize it now */
1196 Status
= BlockIopInitialize();
1197 if (!NT_SUCCESS(Status
))
1199 /* Failed to initialize block I/O */
1204 /* Copy a function table for block I/O devices */
1205 RtlCopyMemory(&DeviceEntry
->Callbacks
,
1206 &BlockIoDeviceFunctionTable
,
1207 sizeof(DeviceEntry
->Callbacks
));
1209 /* Allocate a block I/O device */
1210 BlockDevice
= BlMmAllocateHeap(sizeof(*BlockDevice
));
1213 return STATUS_NO_MEMORY
;
1216 /* Set this as the device-specific data for this device entry */
1217 Status
= STATUS_SUCCESS
;
1218 DeviceEntry
->DeviceSpecificData
= BlockDevice
;
1220 /* Check if we already have this device in our device table */
1221 FoundDeviceEntry
= BlTblFindEntry(BlockIoDeviceTable
,
1222 BlockIoDeviceTableEntries
,
1224 BlockIoDeviceTableCompare
,
1229 if (FoundDeviceEntry
)
1231 /* We already found a device, so copy its device data and callbacks */
1232 RtlCopyMemory(BlockDevice
, FoundDeviceEntry
->DeviceSpecificData
, sizeof(*BlockDevice
));
1233 RtlCopyMemory(&DeviceEntry
->Callbacks
,
1234 &FoundDeviceEntry
->Callbacks
,
1235 sizeof(DeviceEntry
->Callbacks
));
1239 /* Zero out the device for now */
1240 RtlZeroMemory(BlockDevice
, sizeof(*BlockDevice
));
1242 /* Is this a disk? */
1243 if (Device
->DeviceType
== DiskDevice
)
1245 /* What type of disk is it? */
1246 switch (Device
->Local
.Type
)
1248 /* Is it a raw physical disk? */
1252 /* Open a disk device */
1253 Status
= DiskDeviceFunctionTable
.Open(Device
, DeviceEntry
);
1256 /* Is it a RAM disk? */
1258 /* Open a RAM disk */
1259 Status
= RamDiskDeviceFunctionTable
.Open(Device
, DeviceEntry
);
1265 Status
= FileDeviceFunctionTable
.Open(Device
, DeviceEntry
);
1269 case VirtualDiskDevice
:
1270 /* Open a virtual disk */
1271 Status
= VirtualDiskDeviceFunctionTable
.Open(Device
, DeviceEntry
);
1274 /* Is it something else? */
1277 Status
= STATUS_INVALID_PARAMETER
;
1281 else if ((Device
->DeviceType
== LegacyPartitionDevice
) ||
1282 (Device
->DeviceType
== PartitionDevice
))
1284 /* This is a partition on a disk, open it as such */
1285 Status
= PartitionDeviceFunctionTable
.Open(Device
, DeviceEntry
);
1289 /* Other devices are not supported */
1290 Status
= STATUS_INVALID_PARAMETER
;
1293 /* Check for failure */
1294 if (!NT_SUCCESS(Status
))
1296 /* Free any allocations for this device */
1297 BlockIopFreeAllocations(BlockDevice
);
1300 /* Return back to the caller */
1305 BlpDeviceResolveLocate (
1306 _In_ PBL_DEVICE_DESCRIPTOR InputDevice
,
1307 _Out_ PBL_DEVICE_DESCRIPTOR
* LocateDevice
1310 EfiPrintf(L
"Not implemented!\r\n");
1311 return STATUS_NOT_IMPLEMENTED
;
1319 PBL_DEVICE_ENTRY DeviceEntry
;
1321 /* Validate the device ID */
1322 if (DmTableEntries
<= DeviceId
)
1324 return STATUS_INVALID_PARAMETER
;
1327 /* Make sure there's a device there */
1328 DeviceEntry
= DmDeviceTable
[DeviceId
];
1329 if (DeviceEntry
== NULL
)
1331 return STATUS_INVALID_PARAMETER
;
1334 /* Make sure the device is active */
1335 if (!(DeviceEntry
->Flags
& 1))
1337 return STATUS_INVALID_PARAMETER
;
1340 /* Drop a reference and check if it's the last one */
1341 DeviceEntry
->ReferenceCount
--;
1342 if (!DeviceEntry
->ReferenceCount
)
1344 /* Mark the device as inactive */
1345 DeviceEntry
->Flags
= ~1;
1349 return STATUS_SUCCESS
;
1354 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1357 _Out_ PULONG DeviceId
1361 PBL_DEVICE_ENTRY DeviceEntry
;
1362 PBL_DEVICE_DESCRIPTOR LocateDeviceDescriptor
;
1363 PBL_REGISTERED_DEVICE RegisteredDevice
;
1364 PLIST_ENTRY NextEntry
, ListHead
;
1368 /* Check for missing parameters */
1369 if (!(Device
) || !(DeviceId
) || !(Device
->Size
))
1372 Status
= STATUS_INVALID_PARAMETER
;
1376 /* Check for unsupported flags */
1380 Status
= STATUS_INVALID_PARAMETER
;
1384 /* Check if the boot device is being opened */
1385 if (Device
->DeviceType
== BootDevice
)
1388 Device
= BlpBootDevice
;
1391 /* Check if the 'locate' device is being opened */
1392 if (Device
->DeviceType
== LocateDevice
)
1395 Status
= BlpDeviceResolveLocate(Device
, &LocateDeviceDescriptor
);
1396 if (!NT_SUCCESS(Status
))
1398 /* Not found, bail out */
1403 Device
= LocateDeviceDescriptor
;
1406 /* Check if the device isn't ready yet */
1407 if (Device
->Flags
& 1)
1409 /* Return a failure */
1410 Status
= STATUS_DEVICE_NOT_READY
;
1414 /* Check if we already have an entry for the device */
1415 DeviceEntry
= BlTblFindEntry(DmDeviceTable
,
1425 /* Return it, taking a reference on it */
1426 *DeviceId
= DeviceEntry
->DeviceId
;
1427 ++DeviceEntry
->ReferenceCount
;
1428 DeviceEntry
->Flags
|= 1;
1429 return STATUS_SUCCESS
;
1432 /* We don't, allocate one */
1433 DeviceEntry
= BlMmAllocateHeap(sizeof(*DeviceEntry
));
1436 Status
= STATUS_NO_MEMORY
;
1441 RtlZeroMemory(DeviceEntry
, sizeof(*DeviceEntry
));
1442 DeviceEntry
->ReferenceCount
= 1;
1443 DeviceEntry
->Flags
|= 7;
1444 DeviceEntry
->Unknown
= Unknown
;
1446 /* Save flag 8 if needed */
1449 DeviceEntry
->Flags
|= 8;
1452 /* Allocate a device descriptor for the device */
1453 DeviceEntry
->DeviceDescriptor
= BlMmAllocateHeap(Device
->Size
);
1454 if (!DeviceEntry
->DeviceDescriptor
)
1456 Status
= STATUS_NO_MEMORY
;
1460 /* Copy the descriptor that was passed in */
1461 RtlCopyMemory(DeviceEntry
->DeviceDescriptor
, Device
, Device
->Size
);
1463 /* Now loop the list of dynamically registered devices */
1464 ListHead
= &DmRegisteredDevices
;
1465 NextEntry
= ListHead
->Flink
;
1466 while (NextEntry
!= ListHead
)
1468 /* Get the device */
1469 RegisteredDevice
= CONTAINING_RECORD(NextEntry
,
1470 BL_REGISTERED_DEVICE
,
1473 /* Open the device */
1474 Status
= RegisteredDevice
->Callbacks
.Open(Device
, DeviceEntry
);
1475 if (NT_SUCCESS(Status
))
1477 /* The device was opened, so we have the right one */
1481 /* Nope, keep trying */
1482 NextEntry
= NextEntry
->Flink
;
1485 /* Well, it wasn't a dynamic device. Is it a block device? */
1486 if ((Device
->DeviceType
== PartitionDevice
) ||
1487 (Device
->DeviceType
== DiskDevice
) ||
1488 (Device
->DeviceType
== LegacyPartitionDevice
))
1490 /* Call the Block I/O handler */
1491 Status
= BlockIoDeviceFunctionTable
.Open(Device
, DeviceEntry
);
1493 else if (Device
->DeviceType
== SerialDevice
)
1495 /* It's a serial device, call the serial device handler */
1496 Status
= SerialPortFunctionTable
.Open(Device
, DeviceEntry
);
1498 else if (Device
->DeviceType
== UdpDevice
)
1500 /* It's a network device, call the UDP device handler */
1501 Status
= UdpFunctionTable
.Open(Device
, DeviceEntry
);
1505 /* Unsupported type of device */
1506 Status
= STATUS_NOT_IMPLEMENTED
;
1509 /* Check if the device was opened successfuly */
1510 if (NT_SUCCESS(Status
))
1513 /* Save the entry in the device table */
1514 Status
= BlTblSetEntry(&DmDeviceTable
,
1519 if (NT_SUCCESS(Status
))
1521 /* It worked -- return the ID in the table to the caller */
1522 DeviceEntry
->DeviceId
= *DeviceId
;
1523 return STATUS_SUCCESS
;
1528 /* Failure path -- did we allocate a device entry? */
1531 /* Yep -- did it have a descriptor? */
1532 if (DeviceEntry
->DeviceDescriptor
)
1535 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
1538 /* Free the entry */
1539 BlMmFreeHeap(DeviceEntry
);
1542 /* Return the failure */
1547 BlpDeviceInitialize (
1553 /* Initialize the table count and list of devices */
1555 InitializeListHead(&DmRegisteredDevices
);
1557 /* Initialize device information */
1558 DmDeviceIoInformation
.Unknown0
= 0;
1559 DmDeviceIoInformation
.Unknown1
= 0;
1560 DmDeviceIoInformation
.Unknown2
= 0;
1561 DmDeviceIoInformation
.Unknown3
= 0;
1563 /* Allocate the device table */
1564 DmDeviceTable
= BlMmAllocateHeap(DmTableEntries
* sizeof(PVOID
));
1568 RtlZeroMemory(DmDeviceTable
, DmTableEntries
* sizeof(PVOID
));
1570 /* Initialize BitLocker support */
1571 Status
= FvebInitialize();
1573 Status
= STATUS_SUCCESS
;
1578 /* No memory, we'll fail */
1579 Status
= STATUS_NO_MEMORY
;
1582 /* Return initialization state */