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 BlDeviceSetInformation (
614 _Out_ PBL_DEVICE_INFORMATION DeviceInformation
617 PBL_DEVICE_ENTRY DeviceEntry
;
619 /* This parameter is not optional */
620 if (!DeviceInformation
)
622 return STATUS_INVALID_PARAMETER
;
625 /* Make sure the device ID is valid */
626 if (DmTableEntries
<= DeviceId
)
628 return STATUS_INVALID_PARAMETER
;
631 /* Get the device entry */
632 DeviceEntry
= DmDeviceTable
[DeviceId
];
635 return STATUS_INVALID_PARAMETER
;
638 /* Make sure the device is open */
639 if (!(DeviceEntry
->Flags
& BL_DEVICE_ENTRY_OPENED
))
641 return STATUS_INVALID_PARAMETER
;
644 /* Set the device information */
645 return DeviceEntry
->Callbacks
.SetInformation(DeviceEntry
, DeviceInformation
);
649 BlDeviceGetInformation (
651 _Out_ PBL_DEVICE_INFORMATION DeviceInformation
654 PBL_DEVICE_ENTRY DeviceEntry
;
656 /* This parameter is not optional */
657 if (!DeviceInformation
)
659 return STATUS_INVALID_PARAMETER
;
662 /* Make sure the device ID is valid */
663 if (DmTableEntries
<= DeviceId
)
665 return STATUS_INVALID_PARAMETER
;
668 /* Get the device entry */
669 DeviceEntry
= DmDeviceTable
[DeviceId
];
672 return STATUS_INVALID_PARAMETER
;
675 /* Make sure the device is open */
676 if (!(DeviceEntry
->Flags
& BL_DEVICE_ENTRY_OPENED
))
678 return STATUS_INVALID_PARAMETER
;
681 /* Return the device information */
682 DeviceInformation
->DeviceType
= DeviceEntry
->DeviceDescriptor
->DeviceType
;
683 return DeviceEntry
->Callbacks
.GetInformation(DeviceEntry
, DeviceInformation
);
691 _Out_opt_ PULONG BytesRead
694 PBL_DEVICE_ENTRY DeviceEntry
;
696 ULONG BytesTransferred
;
698 /* Make sure we have a buffer, and the device ID is valid */
699 if (!(Buffer
) || (DmTableEntries
<= DeviceId
))
701 return STATUS_INVALID_PARAMETER
;
704 /* Get the device entry for it */
705 DeviceEntry
= DmDeviceTable
[DeviceId
];
708 return STATUS_INVALID_PARAMETER
;
711 /* Make sure this is a device opened for read access */
712 if (!(DeviceEntry
->Flags
& BL_DEVICE_ENTRY_OPENED
) ||
713 !(DeviceEntry
->Flags
& BL_DEVICE_ENTRY_READ_ACCESS
))
715 return STATUS_INVALID_PARAMETER
;
719 Status
= DeviceEntry
->Callbacks
.Read(DeviceEntry
,
723 if (!DeviceEntry
->Unknown
)
725 /* Update performance counters */
726 DmDeviceIoInformation
.ReadCount
+= BytesTransferred
;
729 /* Return back how many bytes were read, if caller wants to know */
732 *BytesRead
= BytesTransferred
;
735 /* Return read result */
740 BlDeviceReadAtOffset (
743 _In_ ULONGLONG Offset
,
745 _Out_ PULONG BytesRead
749 BL_DEVICE_INFORMATION DeviceInfo
;
751 /* Get the current block and offset */
752 Status
= BlDeviceGetInformation(DeviceId
, &DeviceInfo
);
753 if (!NT_SUCCESS(Status
))
758 /* Get the block and block-offset based on the new raw offset */
759 DeviceInfo
.BlockDeviceInfo
.Block
= Offset
/ DeviceInfo
.BlockDeviceInfo
.BlockSize
;
760 DeviceInfo
.BlockDeviceInfo
.Offset
= Offset
% DeviceInfo
.BlockDeviceInfo
.BlockSize
;
762 /* Update the block and offset */
763 Status
= BlDeviceSetInformation(DeviceId
, &DeviceInfo
);
764 if (NT_SUCCESS(Status
))
766 /* Now issue a read, with this block and offset configured */
767 Status
= BlDeviceRead(DeviceId
, Buffer
, Size
, BytesRead
);
770 /* All good, return the caller */
776 _In_ PBL_DEVICE_DESCRIPTOR Device1
,
777 _In_ PBL_DEVICE_DESCRIPTOR Device2
786 /* Check if the two devices exist and are identical in type */
787 if ((Device1
) && (Device2
) && (Device1
->DeviceType
== Device2
->DeviceType
))
789 /* Take the bigger of the two sizes */
790 DeviceSize
= max(Device1
->Size
, Device2
->Size
);
791 if (DeviceSize
>= (ULONG
)FIELD_OFFSET(BL_DEVICE_DESCRIPTOR
, Local
))
793 /* Compare the two devices up to their size */
794 if (RtlEqualMemory(&Device1
->Local
,
796 DeviceSize
- FIELD_OFFSET(BL_DEVICE_DESCRIPTOR
, Local
)))
804 /* Return matching state */
809 BlockIopFreeAllocations (
810 _In_ PBL_BLOCK_DEVICE BlockDevice
813 /* If a block device was passed in, free it */
816 BlMmFreeHeap(BlockDevice
);
819 /* Nothing else to do */
820 return STATUS_SUCCESS
;
824 BlockIoEfiGetBlockIoInformation (
825 _In_ PBL_BLOCK_DEVICE BlockDevice
829 EFI_BLOCK_IO_MEDIA
*Media
;
831 /* Open the Block I/O protocol on this device */
832 Status
= EfiOpenProtocol(BlockDevice
->Handle
,
834 (PVOID
*)&BlockDevice
->Protocol
);
835 if (!NT_SUCCESS(Status
))
840 /* Get information on the block media */
841 Media
= BlockDevice
->Protocol
->Media
;
843 /* Set the appropriate device flags */
844 BlockDevice
->DeviceFlags
= 0;
845 if (Media
->RemovableMedia
)
847 BlockDevice
->DeviceFlags
= BL_BLOCK_DEVICE_REMOVABLE_FLAG
;
849 if (Media
->MediaPresent
)
851 BlockDevice
->DeviceFlags
|= BL_BLOCK_DEVICE_PRESENT_FLAG
;
855 BlockDevice
->Unknown
= 0;
857 /* Set the block size */
858 BlockDevice
->BlockSize
= Media
->BlockSize
;
860 /* Make sure there's a last block value */
861 if (!Media
->LastBlock
)
863 return STATUS_INVALID_PARAMETER
;
866 /* Don't let it be too high */
867 if (Media
->LastBlock
> 0xFFFFFFFFFFE)
869 BlockDevice
->LastBlock
= 0xFFFFFFFFFFE;
873 BlockDevice
->LastBlock
= Media
->LastBlock
;
876 /* Make the alignment the smaller of the I/O alignment or the block size */
877 if (Media
->IoAlign
>= Media
->BlockSize
)
879 BlockDevice
->Alignment
= Media
->IoAlign
;
883 BlockDevice
->Alignment
= Media
->BlockSize
;
887 return STATUS_SUCCESS
;
891 BlockIoEfiGetChildHandle (
892 _In_ PBL_PROTOCOL_HANDLE ProtocolInterface
,
893 _In_ PBL_PROTOCOL_HANDLE ChildProtocolInterface
)
896 ULONG i
, DeviceCount
;
897 EFI_DEVICE_PATH
*DevicePath
, *ParentDevicePath
;
898 EFI_HANDLE
*DeviceHandles
;
901 /* Find all the Block I/O device handles on the system */
904 Status
= EfiLocateHandleBuffer(ByProtocol
,
908 if (!NT_SUCCESS(Status
))
910 /* Failed to enumerate, bail out */
914 /* Loop all the handles */
915 for (i
= 0; i
< DeviceCount
; i
++)
917 /* Check if this is the device itself */
918 Handle
= DeviceHandles
[i
];
919 if (Handle
== ProtocolInterface
->Handle
)
925 /* Get the device path of this device */
926 Status
= EfiOpenProtocol(Handle
,
927 &EfiDevicePathProtocol
,
928 (PVOID
*)&DevicePath
);
929 if (!NT_SUCCESS(Status
))
931 /* We failed, skip it */
935 /* See if we are its parent */
936 ParentDevicePath
= EfiIsDevicePathParent(ProtocolInterface
->Interface
,
938 if (ParentDevicePath
== ProtocolInterface
->Interface
)
940 /* Yup, return back to caller */
941 ChildProtocolInterface
->Handle
= Handle
;
942 ChildProtocolInterface
->Interface
= DevicePath
;
943 Status
= STATUS_SUCCESS
;
947 /* Close the device path */
948 EfiCloseProtocol(Handle
, &EfiDevicePathProtocol
);
951 /* If we got here, nothing was found */
952 Status
= STATUS_NO_SUCH_DEVICE
;
955 /* Free the handle array buffer */
956 BlMmFreeHeap(DeviceHandles
);
961 BlockIoGetGPTDiskSignature (
962 _In_ PBL_DEVICE_ENTRY DeviceEntry
,
963 _Out_ PGUID DiskSignature
966 EfiPrintf(L
"GPT not supported\r\n");
967 return STATUS_NOT_IMPLEMENTED
;
971 BlockIoEfiGetDeviceInformation (
972 _In_ PBL_DEVICE_ENTRY DeviceEntry
976 PBL_DEVICE_DESCRIPTOR Device
;
977 PBL_BLOCK_DEVICE BlockDevice
;
978 EFI_DEVICE_PATH
*LeafNode
;
979 BL_PROTOCOL_HANDLE Protocol
[2];
980 ACPI_HID_DEVICE_PATH
*AcpiPath
;
981 HARDDRIVE_DEVICE_PATH
*DiskPath
;
985 /* Extract the identifier, and the block device object */
986 Device
= DeviceEntry
->DeviceDescriptor
;
987 BlockDevice
= (PBL_BLOCK_DEVICE
)DeviceEntry
->DeviceSpecificData
;
989 /* Initialize protocol handles */
990 Protocol
[0].Handle
= BlockDevice
->Handle
;
991 Protocol
[1].Handle
= 0;
993 /* Open this device */
994 Status
= EfiOpenProtocol(Protocol
[0].Handle
,
995 &EfiDevicePathProtocol
,
996 &Protocol
[0].Interface
);
997 if (!NT_SUCCESS(Status
))
1003 /* Iterate twice -- once for the top level, once for the bottom */
1004 for (i
= 0, Found
= FALSE
; Found
== FALSE
&& Protocol
[i
].Handle
; i
++)
1006 /* Check what kind of leaf node device this is */
1007 LeafNode
= EfiGetLeafNode(Protocol
[i
].Interface
);
1008 EfiPrintf(L
"Pass %d, Leaf node: %p Type: %d\r\n", i
, LeafNode
, LeafNode
->Type
);
1009 if (LeafNode
->Type
== ACPI_DEVICE_PATH
)
1011 /* We only support floppy drives */
1012 AcpiPath
= (ACPI_HID_DEVICE_PATH
*)LeafNode
;
1013 if ((AcpiPath
->HID
== EISA_PNP_ID(0x604)) ||
1014 (AcpiPath
->HID
== EISA_PNP_ID(0x700)))
1016 /* Set the boot library specific device types */
1017 Device
->DeviceType
= LocalDevice
;
1018 Device
->Local
.Type
= FloppyDevice
;
1020 /* The ACPI UID is the drive number */
1021 Device
->Local
.FloppyDisk
.DriveNumber
= AcpiPath
->UID
;
1023 /* We found a match */
1027 else if ((LeafNode
->Type
== MEDIA_DEVICE_PATH
) && (i
== 1))
1029 /* Extract the disk path and check if it's a physical disk */
1030 DiskPath
= (HARDDRIVE_DEVICE_PATH
*)LeafNode
;
1031 EfiPrintf(L
"Disk path: %p Type: %lx\r\n", DiskPath
, LeafNode
->SubType
);
1032 if (LeafNode
->SubType
== MEDIA_HARDDRIVE_DP
)
1034 /* Set this as a local device */
1035 Device
->Local
.Type
= LocalDevice
;
1037 /* Check if this is an MBR partition */
1038 if (DiskPath
->SignatureType
== SIGNATURE_TYPE_MBR
)
1040 /* Set that this is a local partition */
1041 Device
->DeviceType
= LegacyPartitionDevice
;
1042 Device
->Partition
.Disk
.Type
= LocalDevice
;
1044 /* Write the MBR partition signature */
1045 BlockDevice
->PartitionType
= MbrPartition
;
1046 BlockDevice
->Disk
.Mbr
.Signature
= *(PULONG
)&DiskPath
->Signature
[0];
1049 else if (DiskPath
->SignatureType
== SIGNATURE_TYPE_GUID
)
1051 /* Set this as a GPT partition */
1052 BlockDevice
->PartitionType
= GptPartition
;
1053 Device
->Local
.HardDisk
.PartitionType
= GptPartition
;
1055 /* Get the GPT signature */
1056 Status
= BlockIoGetGPTDiskSignature(DeviceEntry
,
1057 &Device
->Local
.HardDisk
.Gpt
.PartitionSignature
);
1058 if (NT_SUCCESS(Status
))
1061 RtlCopyMemory(&BlockDevice
->Disk
.Gpt
.Signature
,
1062 &Device
->Local
.HardDisk
.Gpt
.PartitionSignature
,
1063 sizeof(BlockDevice
->Disk
.Gpt
.Signature
));
1068 /* Otherwise, this is a raw disk */
1069 BlockDevice
->PartitionType
= RawPartition
;
1070 Device
->Local
.HardDisk
.PartitionType
= RawPartition
;
1071 Device
->Local
.HardDisk
.Raw
.DiskNumber
= BlockIoFirmwareRawDiskCount
++;
1073 else if (LeafNode
->SubType
== MEDIA_CDROM_DP
)
1075 /* Set block device information */
1076 EfiPrintf(L
"Found CD-ROM\r\n");
1077 BlockDevice
->PartitionType
= RawPartition
;
1078 BlockDevice
->Type
= CdRomDevice
;
1080 /* Set CDROM data */
1081 Device
->Local
.Type
= CdRomDevice
;
1082 Device
->Local
.FloppyDisk
.DriveNumber
= 0;
1086 else if ((LeafNode
->Type
!= MEDIA_DEVICE_PATH
) &&
1087 (LeafNode
->Type
!= ACPI_DEVICE_PATH
) &&
1090 /* This is probably a messaging device node. Are we under it? */
1091 Status
= BlockIoEfiGetChildHandle(Protocol
, &Protocol
[1]);
1092 EfiPrintf(L
"Pass 0, non DP/ACPI path. Child handle obtained: %lx\r\n", Protocol
[1].Handle
);
1093 if (!NT_SUCCESS(Status
))
1095 /* We're not. So this must be a raw device */
1096 Device
->DeviceType
= LocalDevice
;
1099 /* Is it a removable raw device? */
1100 if (BlockDevice
->DeviceFlags
& BL_BLOCK_DEVICE_REMOVABLE_FLAG
)
1102 /* This is a removable (CD or Floppy or USB) device */
1103 BlockDevice
->Type
= FloppyDevice
;
1104 Device
->Local
.Type
= FloppyDevice
;
1105 Device
->Local
.FloppyDisk
.DriveNumber
= BlockIoFirmwareRemovableDiskCount
++;
1106 EfiPrintf(L
"Found Floppy\r\n");
1110 /* It's a fixed device */
1111 BlockDevice
->Type
= DiskDevice
;
1112 Device
->Local
.Type
= DiskDevice
;
1114 /* Set it as a raw partition */
1115 Device
->Local
.HardDisk
.PartitionType
= RawPartition
;
1116 Device
->Local
.HardDisk
.Mbr
.PartitionSignature
= BlockIoFirmwareRawDiskCount
++;
1117 EfiPrintf(L
"Found raw disk\r\n");
1123 /* Close any protocols that we opened for each handle */
1126 EfiCloseProtocol(Protocol
[--i
].Handle
, &EfiDevicePathProtocol
);
1129 /* Return appropriate status */
1130 return Found
? STATUS_SUCCESS
: STATUS_NOT_SUPPORTED
;
1138 EfiPrintf(L
"not implemented\r\n");
1139 return STATUS_NOT_IMPLEMENTED
;
1147 EfiPrintf(L
"not implemented\r\n");
1148 return STATUS_NOT_IMPLEMENTED
;
1152 BlockIoEfiCreateDeviceEntry (
1153 _In_ PBL_DEVICE_ENTRY
*DeviceEntry
,
1157 PBL_DEVICE_ENTRY IoDeviceEntry
;
1158 PBL_BLOCK_DEVICE BlockDevice
;
1160 PBL_DEVICE_DESCRIPTOR Device
;
1162 /* Allocate the entry for this device and zero it out */
1163 IoDeviceEntry
= BlMmAllocateHeap(sizeof(*IoDeviceEntry
));
1166 return STATUS_NO_MEMORY
;
1168 RtlZeroMemory(IoDeviceEntry
, sizeof(*IoDeviceEntry
));
1170 /* Allocate the device descriptor for this device and zero it out */
1171 Device
= BlMmAllocateHeap(sizeof(*Device
));
1174 return STATUS_NO_MEMORY
;
1176 RtlZeroMemory(Device
, sizeof(*Device
));
1178 /* Allocate the block device specific data, and zero it out */
1179 BlockDevice
= BlMmAllocateHeap(sizeof(*BlockDevice
));
1182 return STATUS_NO_MEMORY
;
1184 RtlZeroMemory(BlockDevice
, sizeof(*BlockDevice
));
1186 /* Save the descriptor and block device specific data */
1187 IoDeviceEntry
->DeviceSpecificData
= BlockDevice
;
1188 IoDeviceEntry
->DeviceDescriptor
= Device
;
1190 /* Set the size of the descriptor */
1191 Device
->Size
= sizeof(*Device
);
1193 /* Copy the standard I/O callbacks */
1194 RtlCopyMemory(&IoDeviceEntry
->Callbacks
,
1195 &BlockIoDeviceFunctionTable
,
1196 sizeof(IoDeviceEntry
->Callbacks
));
1198 /* Add the two that are firmware specific */
1199 IoDeviceEntry
->Callbacks
.Reset
= BlockIoEfiReset
;
1200 IoDeviceEntry
->Callbacks
.Flush
= BlockIoEfiFlush
;
1202 /* Save the EFI handle */
1203 BlockDevice
->Handle
= Handle
;
1205 /* Get information on this device from EFI, caching it in the device */
1206 Status
= BlockIoEfiGetBlockIoInformation(BlockDevice
);
1207 if (NT_SUCCESS(Status
))
1209 /* Build the descriptor structure for this device */
1210 Status
= BlockIoEfiGetDeviceInformation(IoDeviceEntry
);
1211 if (NT_SUCCESS(Status
))
1213 /* We have a fully constructed device, return it */
1214 *DeviceEntry
= IoDeviceEntry
;
1215 return STATUS_SUCCESS
;
1219 /* Failure path, free the descriptor if we allocated one */
1220 if (IoDeviceEntry
->DeviceDescriptor
)
1222 BlMmFreeHeap(IoDeviceEntry
->DeviceDescriptor
);
1225 /* Free any other specific allocations */
1226 BlockIopFreeAllocations(IoDeviceEntry
->DeviceSpecificData
);
1228 /* Free the device entry itself and return the failure code */
1229 BlMmFreeHeap(IoDeviceEntry
);
1230 EfiPrintf(L
"Failed: %lx\r\n", Status
);
1235 BlockIoEfiCompareDevice (
1236 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1237 _In_ EFI_HANDLE Handle
1240 PBL_LOCAL_DEVICE LocalDeviceInfo
, EfiLocalDeviceInfo
;
1241 PBL_DEVICE_ENTRY DeviceEntry
;
1242 PBL_DEVICE_DESCRIPTOR EfiDevice
;
1247 /* Check if no device was given */
1250 /* Fail the comparison */
1251 Status
= STATUS_INVALID_PARAMETER
;
1255 /* Check if this is a local disk device */
1256 if (Device
->DeviceType
!= DiskDevice
)
1258 /* Nope -- is it a partition device? */
1259 if ((Device
->DeviceType
!= LegacyPartitionDevice
) &&
1260 (Device
->DeviceType
!= PartitionDevice
))
1262 /* Nope, so we can't compare */
1263 Status
= STATUS_INVALID_PARAMETER
;
1267 /* If so, return the device information for the parent disk */
1268 LocalDeviceInfo
= &Device
->Partition
.Disk
;
1272 /* Just return the disk information itself */
1273 LocalDeviceInfo
= &Device
->Local
;
1276 /* Create an EFI device entry for the EFI device handle */
1277 Status
= BlockIoEfiCreateDeviceEntry(&DeviceEntry
, Handle
);
1278 if (!NT_SUCCESS(Status
))
1283 /* Read the descriptor and assume failure for now */
1284 EfiDevice
= DeviceEntry
->DeviceDescriptor
;
1285 Status
= STATUS_UNSUCCESSFUL
;
1287 /* Check if the EFI device is a disk */
1288 if (EfiDevice
->DeviceType
!= DiskDevice
)
1290 /* Nope, is it a partition? */
1291 if ((EfiDevice
->DeviceType
!= LegacyPartitionDevice
) &&
1292 (EfiDevice
->DeviceType
!= PartitionDevice
))
1294 /* Neither, invalid handle so bail out */
1295 Status
= STATUS_INVALID_PARAMETER
;
1299 /* Yes, so get the information of the parent disk */
1300 EfiLocalDeviceInfo
= &EfiDevice
->Partition
.Disk
;
1304 /* It's a disk, so get the disk information itself */
1305 EfiLocalDeviceInfo
= &EfiDevice
->Local
;
1308 /* Are the two devices the same type? */
1309 if (EfiLocalDeviceInfo
->Type
!= LocalDeviceInfo
->Type
)
1311 /* Nope, that was easy */
1315 /* Yes, what kind of device is the EFI side? */
1316 switch (EfiLocalDeviceInfo
->Type
)
1320 /* Local hard drive, compare the signature */
1321 if (RtlCompareMemory(&EfiLocalDeviceInfo
->HardDisk
,
1322 &LocalDeviceInfo
->HardDisk
,
1323 sizeof(LocalDeviceInfo
->HardDisk
)) ==
1324 sizeof(LocalDeviceInfo
->HardDisk
))
1326 Status
= STATUS_SUCCESS
;
1333 /* Removable floppy or CD, compare the disk number */
1334 if (RtlCompareMemory(&EfiLocalDeviceInfo
->FloppyDisk
,
1335 &LocalDeviceInfo
->FloppyDisk
,
1336 sizeof(LocalDeviceInfo
->FloppyDisk
)) ==
1337 sizeof(LocalDeviceInfo
->FloppyDisk
))
1339 Status
= STATUS_SUCCESS
;
1345 /* RAM disk, compare the size and base information */
1346 if (RtlCompareMemory(&EfiLocalDeviceInfo
->RamDisk
,
1347 &LocalDeviceInfo
->RamDisk
,
1348 sizeof(LocalDeviceInfo
->RamDisk
)) ==
1349 sizeof(LocalDeviceInfo
->RamDisk
))
1351 Status
= STATUS_SUCCESS
;
1357 /* File, compare the file identifier */
1358 if (RtlCompareMemory(&EfiLocalDeviceInfo
->File
,
1359 &LocalDeviceInfo
->File
,
1360 sizeof(LocalDeviceInfo
->File
)) ==
1361 sizeof(LocalDeviceInfo
->File
))
1363 Status
= STATUS_SUCCESS
;
1367 /* Something else we don't support */
1373 /* All done, did we have an EFI device entry? */
1376 /* Free it, since we only needed it locally for comparison */
1377 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
1378 BlockIopFreeAllocations(DeviceEntry
->DeviceSpecificData
);
1379 BlMmFreeHeap(DeviceEntry
);
1382 /* Return back to the caller */
1387 BlockIoFirmwareOpen (
1388 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1389 _In_ PBL_BLOCK_DEVICE BlockIoDevice
1393 BOOLEAN DeviceMatch
;
1394 BL_HASH_ENTRY HashEntry
;
1395 ULONG i
, Id
, DeviceCount
;
1396 PBL_DEVICE_ENTRY DeviceEntry
;
1397 EFI_HANDLE
* DeviceHandles
;
1399 /* Initialize everything */
1405 /* Ask EFI for handles to all block devices */
1406 Status
= EfiLocateHandleBuffer(ByProtocol
,
1407 &EfiBlockIoProtocol
,
1410 if (!NT_SUCCESS(Status
))
1412 return STATUS_NO_SUCH_DEVICE
;
1415 /* Build a hash entry, with the value inline */
1416 HashEntry
.Flags
= 1;
1417 HashEntry
.Size
= sizeof(EFI_HANDLE
);
1419 /* Loop each device we got */
1420 DeviceMatch
= FALSE
;
1421 Status
= STATUS_NO_SUCH_DEVICE
;
1422 for (i
= 0; i
< DeviceCount
; i
++)
1424 /* Check if we have a match in the device hash table */
1425 HashEntry
.Value
= DeviceHandles
[i
];
1426 Status
= BlHtLookup(HashTableId
, &HashEntry
, 0);
1427 if (NT_SUCCESS(Status
))
1429 /* We already know about this device */
1430 EfiPrintf(L
"Device is known\r\n");
1434 /* New device, store it in the hash table */
1435 Status
= BlHtStore(HashTableId
,
1438 sizeof(DeviceHandles
[i
]));
1439 if (!NT_SUCCESS(Status
))
1441 /* Free the array and fail */
1442 BlMmFreeHeap(DeviceHandles
);
1446 /* Create an entry for this device*/
1447 Status
= BlockIoEfiCreateDeviceEntry(&DeviceEntry
, DeviceHandles
[i
]);
1448 if (!NT_SUCCESS(Status
))
1450 EfiPrintf(L
"EFI create failed: %lx\r\n", Status
);
1454 /* Add the device entry to the device table */
1455 Status
= BlTblSetEntry(&BlockIoDeviceTable
,
1456 &BlockIoDeviceTableEntries
,
1459 TblDoNotPurgeEntry
);
1460 if (!NT_SUCCESS(Status
))
1462 EfiPrintf(L
"Failure path not implemented: %lx\r\n", Status
);
1464 BlHtDelete(HashTableId
, &HashKey
);
1466 /* Free the block I/O device data */
1467 BlockIopFreeAllocations(DeviceEntry
->DeviceSpecificData
);
1469 /* Free the descriptor */
1470 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
1472 /* Free the entry */
1473 BlMmFreeHeap(DeviceEntry
);
1477 /* Does this device match what we're looking for? */
1478 DeviceMatch
= BlpDeviceCompare(DeviceEntry
->DeviceDescriptor
, Device
);
1481 /* Yep, return the data back */
1482 RtlCopyMemory(BlockIoDevice
,
1483 DeviceEntry
->DeviceSpecificData
,
1484 sizeof(*BlockIoDevice
));
1485 Status
= STATUS_SUCCESS
;
1490 /* Free the device handle buffer array */
1491 BlMmFreeHeap(DeviceHandles
);
1499 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1500 _In_ PBL_DEVICE_ENTRY DeviceEntry
1503 EfiPrintf(L
"Not implemented!\r\n");
1504 return STATUS_NOT_IMPLEMENTED
;
1509 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1510 _In_ PBL_DEVICE_ENTRY DeviceEntry
1513 EfiPrintf(L
"Not implemented!\r\n");
1514 return STATUS_NOT_IMPLEMENTED
;
1519 _In_ PBL_DEVICE_ENTRY DeviceEntry
1522 NTSTATUS Status
, LocalStatus
;
1523 PBL_BLOCK_DEVICE BlockDevice
;
1525 /* Assume success */
1526 Status
= STATUS_SUCCESS
;
1527 BlockDevice
= DeviceEntry
->DeviceSpecificData
;
1529 /* Close the protocol */
1530 LocalStatus
= EfiCloseProtocol(BlockDevice
->Handle
, &EfiBlockIoProtocol
);
1531 if (!NT_SUCCESS(LocalStatus
))
1533 /* Only inherit failures */
1534 Status
= LocalStatus
;
1537 /* Free the block device allocations */
1538 LocalStatus
= BlockIopFreeAllocations(BlockDevice
);
1539 if (!NT_SUCCESS(LocalStatus
))
1541 /* Only inherit failures */
1542 Status
= LocalStatus
;
1545 /* Return back to caller */
1551 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1552 _In_ PBL_DEVICE_ENTRY DeviceEntry
1557 /* Use firmware-specific functions to open the disk */
1558 Status
= BlockIoFirmwareOpen(Device
, DeviceEntry
->DeviceSpecificData
);
1559 if (NT_SUCCESS(Status
))
1561 /* Overwrite with our own close routine */
1562 DeviceEntry
->Callbacks
.Close
= DiskClose
;
1565 /* Return back to caller */
1571 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1572 _In_ PBL_DEVICE_ENTRY DeviceEntry
1575 EfiPrintf(L
"Not implemented!\r\n");
1576 return STATUS_NOT_IMPLEMENTED
;
1581 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1582 _In_ PBL_DEVICE_ENTRY DeviceEntry
1585 EfiPrintf(L
"Not implemented!\r\n");
1586 return STATUS_NOT_IMPLEMENTED
;
1591 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1592 _In_ PBL_DEVICE_ENTRY DeviceEntry
1595 EfiPrintf(L
"Not implemented!\r\n");
1596 return STATUS_NOT_IMPLEMENTED
;
1601 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1602 _In_ PBL_DEVICE_ENTRY DeviceEntry
1605 EfiPrintf(L
"Not implemented!\r\n");
1606 return STATUS_NOT_IMPLEMENTED
;
1609 BL_DEVICE_CALLBACKS FileDeviceFunctionTable
=
1616 BL_DEVICE_CALLBACKS PartitionDeviceFunctionTable
=
1623 BL_DEVICE_CALLBACKS RamDiskDeviceFunctionTable
=
1630 BL_DEVICE_CALLBACKS DiskDeviceFunctionTable
=
1637 BL_DEVICE_CALLBACKS VirtualDiskDeviceFunctionTable
=
1644 BL_DEVICE_CALLBACKS UdpFunctionTable
=
1651 BL_DEVICE_CALLBACKS SerialPortFunctionTable
=
1659 DeviceTableCompare (
1661 _In_ PVOID Argument1
,
1662 _In_ PVOID Argument2
,
1663 _Inout_ PVOID Argument3
,
1664 _Inout_ PVOID Argument4
1668 PBL_DEVICE_DESCRIPTOR Device
= (PBL_DEVICE_DESCRIPTOR
)Argument1
;
1669 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Entry
;
1670 ULONG Flags
= *(PULONG
)Argument2
;
1671 ULONG Unknown
= *(PULONG
)Argument3
;
1673 /* Assume failure */
1676 /* Compare the device descriptor */
1677 if (BlpDeviceCompare(DeviceEntry
->DeviceDescriptor
, Device
))
1679 /* Compare something */
1680 if (DeviceEntry
->Unknown
== Unknown
)
1683 if ((!(Flags
& BL_DEVICE_READ_ACCESS
) || (DeviceEntry
->Flags
& BL_DEVICE_ENTRY_READ_ACCESS
)) &&
1684 (!(Flags
& BL_DEVICE_WRITE_ACCESS
) || (DeviceEntry
->Flags
& BL_DEVICE_ENTRY_WRITE_ACCESS
)))
1686 /* And more flags */
1687 if (((Flags
& 8) || !(DeviceEntry
->Flags
& 8)) &&
1688 (!(Flags
& 8) || (DeviceEntry
->Flags
& 8)))
1690 /* Found a match! */
1697 /* Return matching state */
1702 DeviceTableDestroyEntry (
1707 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Entry
;
1710 /* Call the close routine for this entry */
1711 Status
= DeviceEntry
->Callbacks
.Close(DmDeviceTable
[DeviceId
]);
1713 /* Free the descriptor, and the device itself */
1714 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
1715 BlMmFreeHeap(DeviceEntry
);
1717 /* Clear out the netry, and return */
1718 DmDeviceTable
[DeviceId
] = NULL
;
1727 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Entry
;
1730 /* Check if the device is opened */
1731 if (DeviceEntry
->Flags
& BL_DEVICE_ENTRY_OPENED
)
1733 /* It is, so can't purge it */
1734 Status
= STATUS_UNSUCCESSFUL
;
1738 /* It isn't, so destroy the entry */
1739 Status
= DeviceTableDestroyEntry(DeviceEntry
, DeviceEntry
->DeviceId
);
1742 /* Return back to caller */
1747 BlockIoDeviceTableDestroyEntry (
1752 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Entry
;
1755 /* Call the close routine for this entry */
1756 Status
= DeviceEntry
->Callbacks
.Close(DeviceEntry
);
1758 /* Free the descriptor, and the device itself */
1759 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
1760 BlMmFreeHeap(DeviceEntry
);
1762 /* Clear out the netry, and return */
1763 BlockIoDeviceTable
[DeviceId
] = NULL
;
1768 BlockIoDeviceTableDestroy (
1774 /* Call the entry destructor on each entry in the table */
1775 Status
= BlTblMap(BlockIoDeviceTable
,
1776 BlockIoDeviceTableEntries
,
1777 BlockIoDeviceTableDestroyEntry
);
1779 /* Free the table and return */
1780 BlMmFreeHeap(BlockIoDeviceTable
);
1789 /* Free the prefetch buffer */
1790 BlMmFreeHeap(BlockIopPrefetchBuffer
);
1792 /* Set state to non initialized */
1793 BlockIoInitialized
= FALSE
;
1796 return STATUS_SUCCESS
;
1800 BlockIoEfiHashFunction (
1801 _In_ PBL_HASH_ENTRY Entry
,
1802 _In_ ULONG TableSize
1805 /* Get rid of the alignment bits to have a more unique number */
1806 return ((ULONG
)Entry
->Value
>> 3) % TableSize
;
1810 BlockIopInitialize (
1816 /* Allocate the block device table and zero it out */
1817 BlockIoDeviceTableEntries
= 8;
1818 BlockIoDeviceTable
= BlMmAllocateHeap(sizeof(PVOID
) *
1819 BlockIoDeviceTableEntries
);
1820 if (!BlockIoDeviceTableEntries
)
1822 return STATUS_NO_MEMORY
;
1824 RtlZeroMemory(BlockIoDeviceTable
, sizeof(PVOID
) * BlockIoDeviceTableEntries
);
1826 /* Register our destructor */
1827 Status
= BlpIoRegisterDestroyRoutine(BlockIoDeviceTableDestroy
);
1828 if (!NT_SUCCESS(Status
))
1833 /* Initialize all counters */
1834 BlockIoFirmwareRemovableDiskCount
= 0;
1835 BlockIoFirmwareRawDiskCount
= 0;
1836 BlockIoFirmwareCdromCount
= 0;
1838 /* Initialize the buffers and their sizes */
1839 BlockIopAlignedBuffer
= NULL
;
1840 BlockIopAlignedBufferSize
= 0;
1841 BlockIopPartialBlockBuffer
= NULL
;
1842 BlockIopPartialBlockBufferSize
= 0;
1843 BlockIopPrefetchBuffer
= NULL
;
1844 BlockIopReadBlockBuffer
= NULL
;
1845 BlockIopReadBlockBufferSize
= 0;
1847 /* Allocate the prefetch buffer */
1848 Status
= MmPapAllocatePagesInRange(&BlockIopPrefetchBuffer
,
1849 BlLoaderDeviceMemory
,
1855 if (NT_SUCCESS(Status
))
1857 /* Initialize the block cache */
1858 Status
= BcInitialize();
1859 if (NT_SUCCESS(Status
))
1861 /* Initialize the block device hash table */
1862 Status
= BlHtCreate(29, BlockIoEfiHashFunction
, NULL
, &HashTableId
);
1863 if (NT_SUCCESS(Status
))
1865 /* Register our destructor */
1866 Status
= BlpIoRegisterDestroyRoutine(BlockIopDestroy
);
1867 if (NT_SUCCESS(Status
))
1870 BlockIoInitialized
= TRUE
;
1876 /* Check if this is the failure path */
1877 if (!NT_SUCCESS(Status
))
1879 /* Free the prefetch buffer is one was allocated */
1880 if (BlockIopPrefetchBuffer
)
1882 MmPapFreePages(BlockIopPrefetchBuffer
, BL_MM_INCLUDE_MAPPED_ALLOCATED
);
1886 /* Return back to the caller */
1891 BlockIoDeviceTableCompare (
1893 _In_ PVOID Argument1
,
1894 _In_ PVOID Argument2
,
1895 _In_ PVOID Argument3
,
1896 _In_ PVOID Argument4
1899 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Entry
;
1900 PBL_DEVICE_DESCRIPTOR Device
= (PBL_DEVICE_DESCRIPTOR
)Argument1
;
1902 /* Compare the two devices */
1903 return BlpDeviceCompare(DeviceEntry
->DeviceDescriptor
, Device
);
1908 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1909 _In_ PBL_DEVICE_ENTRY DeviceEntry
1913 PBL_BLOCK_DEVICE BlockDevice
;
1914 PBL_DEVICE_ENTRY FoundDeviceEntry
;
1917 /* Check if the block I/O manager is initialized */
1918 if (!BlockIoInitialized
)
1920 /* First call, initialize it now */
1921 Status
= BlockIopInitialize();
1922 if (!NT_SUCCESS(Status
))
1924 /* Failed to initialize block I/O */
1929 /* Copy a function table for block I/O devices */
1930 RtlCopyMemory(&DeviceEntry
->Callbacks
,
1931 &BlockIoDeviceFunctionTable
,
1932 sizeof(DeviceEntry
->Callbacks
));
1934 /* Allocate a block I/O device */
1935 BlockDevice
= BlMmAllocateHeap(sizeof(*BlockDevice
));
1938 return STATUS_NO_MEMORY
;
1941 /* Set this as the device-specific data for this device entry */
1942 Status
= STATUS_SUCCESS
;
1943 DeviceEntry
->DeviceSpecificData
= BlockDevice
;
1945 /* Check if we already have this device in our device table */
1946 FoundDeviceEntry
= BlTblFindEntry(BlockIoDeviceTable
,
1947 BlockIoDeviceTableEntries
,
1949 BlockIoDeviceTableCompare
,
1954 if (FoundDeviceEntry
)
1956 /* We already found a device, so copy its device data and callbacks */
1957 //EfiPrintf(L"Block I/O Device entry found: %p\r\n", FoundDeviceEntry);
1958 RtlCopyMemory(BlockDevice
, FoundDeviceEntry
->DeviceSpecificData
, sizeof(*BlockDevice
));
1959 RtlCopyMemory(&DeviceEntry
->Callbacks
,
1960 &FoundDeviceEntry
->Callbacks
,
1961 sizeof(DeviceEntry
->Callbacks
));
1965 /* Zero out the device for now */
1966 RtlZeroMemory(BlockDevice
, sizeof(*BlockDevice
));
1968 /* Is this a disk? */
1969 if (Device
->DeviceType
== DiskDevice
)
1971 /* What type of disk is it? */
1972 switch (Device
->Local
.Type
)
1974 /* Is it a raw physical disk? */
1978 /* Open a disk device */
1979 Status
= DiskDeviceFunctionTable
.Open(Device
, DeviceEntry
);
1982 /* Is it a RAM disk? */
1984 /* Open a RAM disk */
1985 Status
= RamDiskDeviceFunctionTable
.Open(Device
, DeviceEntry
);
1991 Status
= FileDeviceFunctionTable
.Open(Device
, DeviceEntry
);
1995 case VirtualDiskDevice
:
1996 /* Open a virtual disk */
1997 Status
= VirtualDiskDeviceFunctionTable
.Open(Device
, DeviceEntry
);
2000 /* Is it something else? */
2003 Status
= STATUS_INVALID_PARAMETER
;
2007 else if ((Device
->DeviceType
== LegacyPartitionDevice
) ||
2008 (Device
->DeviceType
== PartitionDevice
))
2010 /* This is a partition on a disk, open it as such */
2011 Status
= PartitionDeviceFunctionTable
.Open(Device
, DeviceEntry
);
2015 /* Other devices are not supported */
2016 Status
= STATUS_INVALID_PARAMETER
;
2019 /* Check for failure */
2020 if (!NT_SUCCESS(Status
))
2022 /* Free any allocations for this device */
2023 BlockIopFreeAllocations(BlockDevice
);
2026 /* Return back to the caller */
2031 BlpDeviceResolveLocate (
2032 _In_ PBL_DEVICE_DESCRIPTOR InputDevice
,
2033 _Out_ PBL_DEVICE_DESCRIPTOR
* LocateDevice
2036 EfiPrintf(L
"Not implemented!\r\n");
2037 return STATUS_NOT_IMPLEMENTED
;
2045 PBL_DEVICE_ENTRY DeviceEntry
;
2047 /* Validate the device ID */
2048 if (DmTableEntries
<= DeviceId
)
2050 return STATUS_INVALID_PARAMETER
;
2053 /* Make sure there's a device there */
2054 DeviceEntry
= DmDeviceTable
[DeviceId
];
2055 if (DeviceEntry
== NULL
)
2057 return STATUS_INVALID_PARAMETER
;
2060 /* Make sure the device is active */
2061 if (!(DeviceEntry
->Flags
& BL_DEVICE_ENTRY_OPENED
))
2063 return STATUS_INVALID_PARAMETER
;
2066 /* Drop a reference and check if it's the last one */
2067 DeviceEntry
->ReferenceCount
--;
2068 if (!DeviceEntry
->ReferenceCount
)
2070 /* Mark the device as inactive */
2071 DeviceEntry
->Flags
= ~BL_DEVICE_ENTRY_OPENED
;
2075 return STATUS_SUCCESS
;
2080 _In_ PBL_DEVICE_DESCRIPTOR Device
,
2083 _Out_ PULONG DeviceId
2087 PBL_DEVICE_ENTRY DeviceEntry
;
2088 PBL_DEVICE_DESCRIPTOR LocateDeviceDescriptor
;
2089 PBL_REGISTERED_DEVICE RegisteredDevice
;
2090 PLIST_ENTRY NextEntry
, ListHead
;
2094 /* Check for missing parameters */
2095 if (!(Device
) || !(DeviceId
) || !(Device
->Size
))
2098 Status
= STATUS_INVALID_PARAMETER
;
2102 /* Make sure both read and write access are set */
2103 if (!(Flags
& (BL_DEVICE_READ_ACCESS
| BL_DEVICE_WRITE_ACCESS
)))
2106 Status
= STATUS_INVALID_PARAMETER
;
2110 /* Check if the boot device is being opened */
2111 if (Device
->DeviceType
== BootDevice
)
2114 Device
= BlpBootDevice
;
2117 /* Check if the 'locate' device is being opened */
2118 if (Device
->DeviceType
== LocateDevice
)
2121 Status
= BlpDeviceResolveLocate(Device
, &LocateDeviceDescriptor
);
2122 if (!NT_SUCCESS(Status
))
2124 /* Not found, bail out */
2129 Device
= LocateDeviceDescriptor
;
2132 /* Check if the device isn't ready yet */
2133 if (Device
->Flags
& 1)
2135 /* Return a failure */
2136 Status
= STATUS_DEVICE_NOT_READY
;
2140 /* Check if we already have an entry for the device */
2141 DeviceEntry
= BlTblFindEntry(DmDeviceTable
,
2151 /* Return it, taking a reference on it */
2152 *DeviceId
= DeviceEntry
->DeviceId
;
2153 ++DeviceEntry
->ReferenceCount
;
2154 DeviceEntry
->Flags
|= BL_DEVICE_ENTRY_OPENED
;
2155 return STATUS_SUCCESS
;
2158 /* We don't, allocate one */
2159 DeviceEntry
= BlMmAllocateHeap(sizeof(*DeviceEntry
));
2162 Status
= STATUS_NO_MEMORY
;
2167 RtlZeroMemory(DeviceEntry
, sizeof(*DeviceEntry
));
2168 DeviceEntry
->ReferenceCount
= 1;
2169 DeviceEntry
->Flags
|= (BL_DEVICE_ENTRY_OPENED
|
2170 BL_DEVICE_ENTRY_READ_ACCESS
|
2171 BL_DEVICE_ENTRY_WRITE_ACCESS
);
2172 DeviceEntry
->Unknown
= Unknown
;
2174 /* Save flag 8 if needed */
2177 DeviceEntry
->Flags
|= 8;
2180 /* Allocate a device descriptor for the device */
2181 DeviceEntry
->DeviceDescriptor
= BlMmAllocateHeap(Device
->Size
);
2182 if (!DeviceEntry
->DeviceDescriptor
)
2184 Status
= STATUS_NO_MEMORY
;
2188 /* Copy the descriptor that was passed in */
2189 RtlCopyMemory(DeviceEntry
->DeviceDescriptor
, Device
, Device
->Size
);
2191 /* Now loop the list of dynamically registered devices */
2192 ListHead
= &DmRegisteredDevices
;
2193 NextEntry
= ListHead
->Flink
;
2194 while (NextEntry
!= ListHead
)
2196 /* Get the device */
2197 RegisteredDevice
= CONTAINING_RECORD(NextEntry
,
2198 BL_REGISTERED_DEVICE
,
2201 /* Open the device */
2202 Status
= RegisteredDevice
->Callbacks
.Open(Device
, DeviceEntry
);
2203 if (NT_SUCCESS(Status
))
2205 /* The device was opened, so we have the right one */
2209 /* Nope, keep trying */
2210 NextEntry
= NextEntry
->Flink
;
2213 /* Well, it wasn't a dynamic device. Is it a block device? */
2214 if ((Device
->DeviceType
== PartitionDevice
) ||
2215 (Device
->DeviceType
== DiskDevice
) ||
2216 (Device
->DeviceType
== LegacyPartitionDevice
))
2218 /* Call the Block I/O handler */
2219 Status
= BlockIoDeviceFunctionTable
.Open(Device
, DeviceEntry
);
2221 else if (Device
->DeviceType
== SerialDevice
)
2223 /* It's a serial device, call the serial device handler */
2224 Status
= SerialPortFunctionTable
.Open(Device
, DeviceEntry
);
2226 else if (Device
->DeviceType
== UdpDevice
)
2228 /* It's a network device, call the UDP device handler */
2229 Status
= UdpFunctionTable
.Open(Device
, DeviceEntry
);
2233 /* Unsupported type of device */
2234 Status
= STATUS_NOT_IMPLEMENTED
;
2237 /* Check if the device was opened successfully */
2238 if (NT_SUCCESS(Status
))
2241 /* Save the entry in the device table */
2242 Status
= BlTblSetEntry(&DmDeviceTable
,
2247 if (NT_SUCCESS(Status
))
2249 /* It worked -- return the ID in the table to the caller */
2250 EfiPrintf(L
"Device ID: %lx\r\n", *DeviceId
);
2251 DeviceEntry
->DeviceId
= *DeviceId
;
2252 return STATUS_SUCCESS
;
2257 /* Failure path -- did we allocate a device entry? */
2258 EfiPrintf(L
"Block failure: %lx\r\n", Status
);
2261 /* Yep -- did it have a descriptor? */
2262 if (DeviceEntry
->DeviceDescriptor
)
2265 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
2268 /* Free the entry */
2269 BlMmFreeHeap(DeviceEntry
);
2272 /* Return the failure */
2277 BlpDeviceInitialize (
2283 /* Initialize the table count and list of devices */
2285 InitializeListHead(&DmRegisteredDevices
);
2287 /* Initialize device information */
2288 DmDeviceIoInformation
.ReadCount
= 0;
2289 DmDeviceIoInformation
.WriteCount
= 0;
2291 /* Allocate the device table */
2292 DmDeviceTable
= BlMmAllocateHeap(DmTableEntries
* sizeof(PVOID
));
2296 RtlZeroMemory(DmDeviceTable
, DmTableEntries
* sizeof(PVOID
));
2297 #if BL_BITLOCKER_SUPPORT
2298 /* Initialize BitLocker support */
2299 Status
= FvebInitialize();
2301 Status
= STATUS_SUCCESS
;
2306 /* No memory, we'll fail */
2307 Status
= STATUS_NO_MEMORY
;
2310 /* Return initialization state */