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
21 } BL_DEVICE_IO_INFORMATION
, *PBL_DEVICE_IO_INFORMATION
;
23 LIST_ENTRY DmRegisteredDevices
;
25 LIST_ENTRY DmRegisteredDevices
;
28 BL_DEVICE_IO_INFORMATION DmDeviceIoInformation
;
30 /* FUNCTIONS *****************************************************************/
32 typedef struct _BL_REGISTERED_DEVICE
35 BL_DEVICE_CALLBACKS Callbacks
;
36 } BL_REGISTERED_DEVICE
, *PBL_REGISTERED_DEVICE
;
38 PVOID
* BlockIoDeviceTable
;
39 ULONG BlockIoDeviceTableEntries
;
41 ULONG BlockIoFirmwareRemovableDiskCount
;
42 ULONG BlockIoFirmwareRawDiskCount
;
43 ULONG BlockIoFirmwareCdromCount
;
45 PVOID BlockIopAlignedBuffer
;
46 ULONG BlockIopAlignedBufferSize
;
48 PVOID BlockIopPartialBlockBuffer
;
49 ULONG BlockIopPartialBlockBufferSize
;
51 PVOID BlockIopPrefetchBuffer
;
53 PVOID BlockIopReadBlockBuffer
;
54 ULONG BlockIopReadBlockBufferSize
;
58 BOOLEAN BlockIoInitialized
;
62 _In_ PBL_DEVICE_DESCRIPTOR Device
,
63 _In_ PBL_DEVICE_ENTRY DeviceEntry
67 BlockIoGetInformation (
68 _In_ PBL_DEVICE_ENTRY DeviceEntry
,
69 _Out_ PBL_DEVICE_INFORMATION DeviceInformation
72 BL_DEVICE_CALLBACKS BlockIoDeviceFunctionTable
=
83 BlockIoGetInformation (
84 _In_ PBL_DEVICE_ENTRY DeviceEntry
,
85 _Out_ PBL_DEVICE_INFORMATION DeviceInformation
88 PBL_BLOCK_DEVICE BlockDevice
;
90 BlockDevice
= DeviceEntry
->DeviceSpecificData
;
92 RtlCopyMemory(&DeviceInformation
->BlockDeviceInfo
,
94 sizeof(DeviceInformation
->BlockDeviceInfo
));
95 DeviceInformation
->DeviceType
= DiskDevice
;
96 return STATUS_SUCCESS
;
100 BlDeviceGetInformation (
102 _Out_ PBL_DEVICE_INFORMATION DeviceInformation
105 PBL_DEVICE_ENTRY DeviceEntry
;
107 if (!(DeviceInformation
))
109 return STATUS_INVALID_PARAMETER
;
112 if (DmTableEntries
<= DeviceId
)
114 return STATUS_INVALID_PARAMETER
;
117 DeviceEntry
= DmDeviceTable
[DeviceId
];
120 return STATUS_INVALID_PARAMETER
;
123 if (!(DeviceEntry
->Flags
& 1))
125 return STATUS_INVALID_PARAMETER
;
128 DeviceInformation
->DeviceType
= DeviceEntry
->DeviceDescriptor
->DeviceType
;
129 return DeviceEntry
->Callbacks
.GetInformation(DeviceEntry
, DeviceInformation
);
134 _In_ PBL_DEVICE_DESCRIPTOR Device1
,
135 _In_ PBL_DEVICE_DESCRIPTOR Device2
144 /* Check if the two devices exist and are identical in typ */
145 if ((Device1
) && (Device2
) && (Device1
->DeviceType
== Device2
->DeviceType
))
147 /* Take the bigger of the two sizes */
148 DeviceSize
= max(Device1
->Size
, Device2
->Size
);
149 if (DeviceSize
>= (ULONG
)FIELD_OFFSET(BL_DEVICE_DESCRIPTOR
, Local
))
151 /* Compare the two devices up to their size */
152 if (RtlEqualMemory(&Device1
->Local
,
154 DeviceSize
- FIELD_OFFSET(BL_DEVICE_DESCRIPTOR
, Local
)))
162 /* Return matching state */
167 BlockIopFreeAllocations (
168 _In_ PBL_BLOCK_DEVICE BlockDevice
171 /* If a block device was passed in, free it */
174 BlMmFreeHeap(BlockDevice
);
177 /* Nothing else to do */
178 return STATUS_SUCCESS
;
182 BlockIoEfiGetBlockIoInformation (
183 _In_ PBL_BLOCK_DEVICE BlockDevice
187 EFI_BLOCK_IO_MEDIA
*Media
;
189 /* Open the Block I/O protocol on this device */
190 Status
= EfiOpenProtocol(BlockDevice
->Handle
,
192 (PVOID
*)&BlockDevice
->Protocol
);
193 if (!NT_SUCCESS(Status
))
198 /* Get information on the block media */
199 Media
= BlockDevice
->Protocol
->Media
;
201 EfiPrintf(L
"Block I/O Info for Device 0x%p, 0x%lX\r\n", BlockDevice
, BlockDevice
->Handle
);
202 EfiPrintf(L
"Removable: %d Present: %d Last Block: %I64d BlockSize: %d IoAlign: %d MediaId: %d ReadOnly: %d\r\n",
203 Media
->RemovableMedia
, Media
->MediaPresent
, Media
->LastBlock
, Media
->BlockSize
, Media
->IoAlign
,
204 Media
->MediaId
, Media
->ReadOnly
);
206 /* Set the appropriate device flags */
207 BlockDevice
->DeviceFlags
= 0;
208 if (Media
->RemovableMedia
)
210 BlockDevice
->DeviceFlags
= BL_BLOCK_DEVICE_REMOVABLE_FLAG
;
212 if (Media
->MediaPresent
)
214 BlockDevice
->DeviceFlags
|= 2;
218 BlockDevice
->Unknown
= 0;
220 /* Set the block size */
221 BlockDevice
->BlockSize
= Media
->BlockSize
;
223 /* Make sure there's a last block value */
224 if (!Media
->LastBlock
)
226 return STATUS_INVALID_PARAMETER
;
229 /* Don't let it be too high */
230 if (Media
->LastBlock
> 0xFFFFFFFFFFE)
232 BlockDevice
->LastBlock
= 0xFFFFFFFFFFE;
236 BlockDevice
->LastBlock
= Media
->LastBlock
;
239 /* Make the alignment the smaller of the I/O alignment or the block size */
240 if (Media
->IoAlign
>= Media
->BlockSize
)
242 BlockDevice
->Alignment
= Media
->IoAlign
;
246 BlockDevice
->Alignment
= Media
->BlockSize
;
250 return STATUS_SUCCESS
;
254 BlockIoEfiGetChildHandle (
255 _In_ PBL_PROTOCOL_HANDLE ProtocolInterface
,
256 _In_ PBL_PROTOCOL_HANDLE ChildProtocolInterface
)
259 ULONG i
, DeviceCount
;
260 EFI_DEVICE_PATH
*DevicePath
, *ParentDevicePath
;
261 EFI_HANDLE
*DeviceHandles
;
264 /* Find all the Block I/O device handles on the system */
267 Status
= EfiLocateHandleBuffer(ByProtocol
,
271 if (!NT_SUCCESS(Status
))
273 /* Failed to enumerate, bail out */
277 /* Loop all the handles */
278 for (i
= 0; i
< DeviceCount
; i
++)
280 /* Check if this is the device itself */
281 Handle
= DeviceHandles
[i
];
282 if (Handle
== ProtocolInterface
->Handle
)
288 /* Get the device path of this device */
289 Status
= EfiOpenProtocol(Handle
,
290 &EfiDevicePathProtocol
,
291 (PVOID
*)&DevicePath
);
292 if (!NT_SUCCESS(Status
))
294 /* We failed, skip it */
298 /* See if we are its parent */
299 ParentDevicePath
= EfiIsDevicePathParent(ProtocolInterface
->Interface
,
301 if (ParentDevicePath
== ProtocolInterface
->Interface
)
303 /* Yup, return back to caller */
304 ChildProtocolInterface
->Handle
= Handle
;
305 ChildProtocolInterface
->Interface
= DevicePath
;
309 /* Close the device path */
310 EfiCloseProtocol(Handle
, &EfiDevicePathProtocol
);
313 /* If we got here, nothing was found */
314 Status
= STATUS_NO_SUCH_DEVICE
;
316 /* Free the handle array buffer */
317 BlMmFreeHeap(DeviceHandles
);
322 BlockIoGetGPTDiskSignature (
323 _In_ PBL_DEVICE_ENTRY DeviceEntry
,
324 _Out_ PGUID DiskSignature
327 EfiPrintf(L
"GPT not supported\r\n");
328 return STATUS_NOT_IMPLEMENTED
;
332 BlockIoEfiGetDeviceInformation (
333 _In_ PBL_DEVICE_ENTRY DeviceEntry
337 PBL_DEVICE_DESCRIPTOR Device
;
338 PBL_BLOCK_DEVICE BlockDevice
;
339 EFI_DEVICE_PATH
*LeafNode
;
340 BL_PROTOCOL_HANDLE Protocol
[2];
341 ACPI_HID_DEVICE_PATH
*AcpiPath
;
342 HARDDRIVE_DEVICE_PATH
*DiskPath
;
346 /* Extract the identifier, and the block device object */
347 Device
= DeviceEntry
->DeviceDescriptor
;
348 BlockDevice
= (PBL_BLOCK_DEVICE
)DeviceEntry
->DeviceSpecificData
;
350 /* Initialize protocol handles */
351 Protocol
[0].Handle
= BlockDevice
->Handle
;
352 Protocol
[1].Handle
= 0;
354 /* Open this device */
355 Status
= EfiOpenProtocol(Protocol
[0].Handle
,
356 &EfiDevicePathProtocol
,
357 &Protocol
[0].Interface
);
358 if (!NT_SUCCESS(Status
))
364 /* Iteratate twice -- once for the top level, once for the bottom */
365 for (i
= 0, Found
= FALSE
; Found
== FALSE
&& Protocol
[i
].Handle
; i
++)
367 LeafNode
= EfiGetLeafNode(Protocol
[i
].Interface
);
368 EfiPrintf(L
"Pass %d, Leaf node: %p Type: %d\r\n", i
, LeafNode
, LeafNode
->Type
);
369 if (LeafNode
->Type
== ACPI_DEVICE_PATH
)
371 /* We only support floppy drives */
372 AcpiPath
= (ACPI_HID_DEVICE_PATH
*)LeafNode
;
373 if ((AcpiPath
->HID
== EISA_PNP_ID(0x604)) &&
374 (AcpiPath
->HID
== EISA_PNP_ID(0x700)))
376 /* Set the boot library specific device types */
377 Device
->DeviceType
= LocalDevice
;
378 Device
->Local
.Type
= FloppyDevice
;
380 /* The ACPI UID is the drive number */
381 Device
->Local
.FloppyDisk
.DriveNumber
= AcpiPath
->UID
;
383 /* We found a match */
387 else if ((LeafNode
->Type
== MEDIA_DEVICE_PATH
) && (i
== 1))
389 /* Extract the disk path and check if it's a physical disk */
390 DiskPath
= (HARDDRIVE_DEVICE_PATH
*)LeafNode
;
391 EfiPrintf(L
"Disk path: %p Type: %lx\r\n", DiskPath
, LeafNode
->SubType
);
392 if (LeafNode
->SubType
== MEDIA_HARDDRIVE_DP
)
394 /* Set this as a local device */
395 Device
->Local
.Type
= LocalDevice
;
397 /* Check if this is an MBR partition */
398 if (DiskPath
->SignatureType
== SIGNATURE_TYPE_MBR
)
400 /* Set that this is a local partition */
401 Device
->DeviceType
= LegacyPartitionDevice
;
402 Device
->Partition
.Disk
.Type
= LocalDevice
;
404 /* Write the MBR partition signature */
405 BlockDevice
->PartitionType
= MbrPartition
;
406 BlockDevice
->Disk
.Mbr
.Signature
= *(PULONG
)&DiskPath
->Signature
[0];
409 else if (DiskPath
->SignatureType
== SIGNATURE_TYPE_GUID
)
411 /* Set this as a GPT partition */
412 BlockDevice
->PartitionType
= GptPartition
;
413 Device
->Local
.HardDisk
.PartitionType
= GptPartition
;
415 /* Get the GPT signature */
416 Status
= BlockIoGetGPTDiskSignature(DeviceEntry
,
417 &Device
->Local
.HardDisk
.Gpt
.PartitionSignature
);
418 if (NT_SUCCESS(Status
))
421 RtlCopyMemory(&BlockDevice
->Disk
.Gpt
.Signature
,
422 &Device
->Local
.HardDisk
.Gpt
.PartitionSignature
,
423 sizeof(&BlockDevice
->Disk
.Gpt
.Signature
));
428 /* Otherwise, this is a raw disk */
429 BlockDevice
->PartitionType
= RawPartition
;
430 Device
->Local
.HardDisk
.PartitionType
= RawPartition
;
431 Device
->Local
.HardDisk
.Raw
.DiskNumber
= BlockIoFirmwareRawDiskCount
++;;
433 else if (LeafNode
->SubType
== MEDIA_CDROM_DP
)
435 /* Set block device information */
436 EfiPrintf(L
"Found CD-ROM\r\n");
437 BlockDevice
->PartitionType
= RawPartition
;
438 BlockDevice
->Type
= CdRomDevice
;
441 Device
->Local
.Type
= CdRomDevice
;
442 Device
->Local
.FloppyDisk
.DriveNumber
= 0;
446 else if ((LeafNode
->Type
!= MEDIA_DEVICE_PATH
) &&
447 (LeafNode
->Type
!= ACPI_DEVICE_PATH
) &&
450 /* This is probably a messaging device node. Are we under it? */
451 Status
= BlockIoEfiGetChildHandle(Protocol
, &Protocol
[1]);
452 EfiPrintf(L
"Pass 0, non DP/ACPI path. Child handle obtained: %lx\r\n", Protocol
[1].Handle
);
453 if (!NT_SUCCESS(Status
))
455 /* We're not. So this must be a raw device */
456 Device
->DeviceType
= LocalDevice
;
459 /* Is it a removable raw device? */
460 if (BlockDevice
->DeviceFlags
& BL_BLOCK_DEVICE_REMOVABLE_FLAG
)
462 /* This is a removable (CD or Floppy or USB) device */
463 BlockDevice
->Type
= FloppyDevice
;
464 Device
->Local
.Type
= FloppyDevice
;
465 Device
->Local
.FloppyDisk
.DriveNumber
= BlockIoFirmwareRemovableDiskCount
++;
466 EfiPrintf(L
"Found Floppy\r\n");
470 /* It's a fixed device */
471 BlockDevice
->Type
= DiskDevice
;
472 Device
->Local
.Type
= DiskDevice
;
474 /* Set it as a raw partition */
475 Device
->Local
.HardDisk
.PartitionType
= RawPartition
;
476 Device
->Local
.HardDisk
.Mbr
.PartitionSignature
= BlockIoFirmwareRawDiskCount
++;
477 EfiPrintf(L
"Found raw disk\r\n");
483 /* Close any protocols that we opened for each handle */
486 EfiCloseProtocol(Protocol
[--i
].Handle
, &EfiDevicePathProtocol
);
489 /* Return appropriate status */
490 return Found
? STATUS_SUCCESS
: STATUS_NOT_SUPPORTED
;
498 EfiPrintf(L
"not implemented\r\n");
499 return STATUS_NOT_IMPLEMENTED
;
507 EfiPrintf(L
"not implemented\r\n");
508 return STATUS_NOT_IMPLEMENTED
;
512 BlockIoEfiCreateDeviceEntry (
513 _In_ PBL_DEVICE_ENTRY
*DeviceEntry
,
517 PBL_DEVICE_ENTRY IoDeviceEntry
;
518 PBL_BLOCK_DEVICE BlockDevice
;
520 PBL_DEVICE_DESCRIPTOR Device
;
522 /* Allocate the entry for this device and zero it out */
523 IoDeviceEntry
= BlMmAllocateHeap(sizeof(*IoDeviceEntry
));
526 return STATUS_NO_MEMORY
;
528 RtlZeroMemory(IoDeviceEntry
, sizeof(*IoDeviceEntry
));
530 /* Allocate the device descriptor for this device and zero it out */
531 Device
= BlMmAllocateHeap(sizeof(*Device
));
534 return STATUS_NO_MEMORY
;
536 RtlZeroMemory(Device
, sizeof(*Device
));
538 /* Allocate the block device specific data, and zero it out */
539 BlockDevice
= BlMmAllocateHeap(sizeof(*BlockDevice
));
542 return STATUS_NO_MEMORY
;
544 RtlZeroMemory(BlockDevice
, sizeof(*BlockDevice
));
546 /* Save the descriptor and block device specific data */
547 IoDeviceEntry
->DeviceSpecificData
= BlockDevice
;
548 IoDeviceEntry
->DeviceDescriptor
= Device
;
550 /* Set the size of the descriptor */
551 Device
->Size
= sizeof(*Device
);
553 /* Copy the standard I/O callbacks */
554 RtlCopyMemory(&IoDeviceEntry
->Callbacks
,
555 &BlockIoDeviceFunctionTable
,
556 sizeof(IoDeviceEntry
->Callbacks
));
558 /* Add the two that are firmware specific */
559 IoDeviceEntry
->Callbacks
.Reset
= BlockIoEfiReset
;
560 IoDeviceEntry
->Callbacks
.Flush
= BlockIoEfiFlush
;
562 /* Save the EFI handle */
563 BlockDevice
->Handle
= Handle
;
565 /* Get information on this device from EFI, caching it in the device */
566 Status
= BlockIoEfiGetBlockIoInformation(BlockDevice
);
567 if (NT_SUCCESS(Status
))
569 /* Build the descriptor structure for this device */
570 Status
= BlockIoEfiGetDeviceInformation(IoDeviceEntry
);
571 if (NT_SUCCESS(Status
))
573 /* We have a fully constructed device, reuturn it */
574 *DeviceEntry
= IoDeviceEntry
;
575 return STATUS_SUCCESS
;
579 /* Failure path, free the descriptor if we allocated one */
580 if (IoDeviceEntry
->DeviceDescriptor
)
582 BlMmFreeHeap(IoDeviceEntry
->DeviceDescriptor
);
585 /* Free any other specific allocations */
586 BlockIopFreeAllocations(IoDeviceEntry
->DeviceSpecificData
);
588 /* Free the device entry itself and return the failure code */
589 BlMmFreeHeap(IoDeviceEntry
);
590 EfiPrintf(L
"Failed: %lx\r\n", Status
);
595 BlockIoFirmwareOpen (
596 _In_ PBL_DEVICE_DESCRIPTOR Device
,
597 _In_ PBL_BLOCK_DEVICE BlockIoDevice
602 BL_HASH_ENTRY HashEntry
;
603 ULONG i
, Id
, DeviceCount
;
604 PBL_DEVICE_ENTRY DeviceEntry
;
605 EFI_HANDLE
* DeviceHandles
;
607 /* Initialize everything */
613 /* Ask EFI for handles to all block devices */
614 Status
= EfiLocateHandleBuffer(ByProtocol
,
618 if (!NT_SUCCESS(Status
))
620 return STATUS_NO_SUCH_DEVICE
;
623 /* Build a hash entry, with the value inline */
625 HashEntry
.Size
= sizeof(EFI_HANDLE
);
627 /* Loop each device we got */
629 Status
= STATUS_NO_SUCH_DEVICE
;
630 for (i
= 0; i
< DeviceCount
; i
++)
632 /* Check if we have a match in the device hash table */
633 HashEntry
.Value
= DeviceHandles
[i
];
634 Status
= BlHtLookup(HashTableId
, &HashEntry
, 0);
635 if (NT_SUCCESS(Status
))
637 /* We already know about this device */
638 EfiPrintf(L
"Device is known\r\n");
642 /* New device, store it in the hash table */
643 Status
= BlHtStore(HashTableId
,
646 sizeof(DeviceHandles
[i
]));
647 if (!NT_SUCCESS(Status
))
649 /* Free the array and fail */
650 BlMmFreeHeap(DeviceHandles
);
654 /* Create an entry for this device*/
655 Status
= BlockIoEfiCreateDeviceEntry(&DeviceEntry
, DeviceHandles
[i
]);
656 if (!NT_SUCCESS(Status
))
658 EfiPrintf(L
"EFI create failed: %lx\n", Status
);
662 /* Add the device entry to the device table */
663 Status
= BlTblSetEntry(&BlockIoDeviceTable
,
664 &BlockIoDeviceTableEntries
,
668 if (!NT_SUCCESS(Status
))
670 EfiPrintf(L
"Failure path not implemented: %lx\r\n", Status
);
672 BlHtDelete(HashTableId
, &HashKey
);
674 /* Free the block I/O device data */
675 BlockIopFreeAllocations(DeviceEntry
->DeviceSpecificData
);
677 /* Free the descriptor */
678 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
681 BlMmFreeHeap(DeviceEntry
);
685 /* Does this device match what we're looking for? */
686 DeviceMatch
= BlpDeviceCompare(DeviceEntry
->DeviceDescriptor
, Device
);
687 EfiPrintf(L
"Device match: %d\r\n", DeviceMatch
);
690 /* Yep, return the data back */
691 RtlCopyMemory(BlockIoDevice
,
692 DeviceEntry
->DeviceSpecificData
,
693 sizeof(*BlockIoDevice
));
694 Status
= STATUS_SUCCESS
;
699 /* Free the device handle buffer array */
700 BlMmFreeHeap(DeviceHandles
);
708 _In_ PBL_DEVICE_DESCRIPTOR Device
,
709 _In_ PBL_DEVICE_ENTRY DeviceEntry
712 EfiPrintf(L
"Not implemented!\r\n");
713 return STATUS_NOT_IMPLEMENTED
;
718 _In_ PBL_DEVICE_DESCRIPTOR Device
,
719 _In_ PBL_DEVICE_ENTRY DeviceEntry
722 EfiPrintf(L
"Not implemented!\r\n");
723 return STATUS_NOT_IMPLEMENTED
;
728 _In_ PBL_DEVICE_ENTRY DeviceEntry
731 NTSTATUS Status
, LocalStatus
;
732 PBL_BLOCK_DEVICE BlockDevice
;
735 Status
= STATUS_SUCCESS
;
736 BlockDevice
= DeviceEntry
->DeviceSpecificData
;
738 /* Close the protocol */
739 LocalStatus
= EfiCloseProtocol(BlockDevice
->Handle
, &EfiBlockIoProtocol
);
740 if (!NT_SUCCESS(LocalStatus
))
742 /* Only inherit failures */
743 Status
= LocalStatus
;
746 /* Free the block device allocations */
747 LocalStatus
= BlockIopFreeAllocations(BlockDevice
);
748 if (!NT_SUCCESS(LocalStatus
))
750 /* Only inherit failures */
751 Status
= LocalStatus
;
754 /* Return back to caller */
760 _In_ PBL_DEVICE_DESCRIPTOR Device
,
761 _In_ PBL_DEVICE_ENTRY DeviceEntry
766 /* Use firmware-specific functions to open the disk */
767 Status
= BlockIoFirmwareOpen(Device
, DeviceEntry
->DeviceSpecificData
);
768 if (NT_SUCCESS(Status
))
770 /* Overwrite with our own close routine */
771 DeviceEntry
->Callbacks
.Close
= DiskClose
;
774 /* Return back to caller */
780 _In_ PBL_DEVICE_DESCRIPTOR Device
,
781 _In_ PBL_DEVICE_ENTRY DeviceEntry
784 EfiPrintf(L
"Not implemented!\r\n");
785 return STATUS_NOT_IMPLEMENTED
;
790 _In_ PBL_DEVICE_DESCRIPTOR Device
,
791 _In_ PBL_DEVICE_ENTRY DeviceEntry
794 EfiPrintf(L
"Not implemented!\r\n");
795 return STATUS_NOT_IMPLEMENTED
;
800 _In_ PBL_DEVICE_DESCRIPTOR Device
,
801 _In_ PBL_DEVICE_ENTRY DeviceEntry
804 EfiPrintf(L
"Not implemented!\r\n");
805 return STATUS_NOT_IMPLEMENTED
;
810 _In_ PBL_DEVICE_DESCRIPTOR Device
,
811 _In_ PBL_DEVICE_ENTRY DeviceEntry
814 EfiPrintf(L
"Not implemented!\r\n");
815 return STATUS_NOT_IMPLEMENTED
;
818 BL_DEVICE_CALLBACKS FileDeviceFunctionTable
=
825 BL_DEVICE_CALLBACKS PartitionDeviceFunctionTable
=
832 BL_DEVICE_CALLBACKS RamDiskDeviceFunctionTable
=
839 BL_DEVICE_CALLBACKS DiskDeviceFunctionTable
=
846 BL_DEVICE_CALLBACKS VirtualDiskDeviceFunctionTable
=
853 BL_DEVICE_CALLBACKS UdpFunctionTable
=
860 BL_DEVICE_CALLBACKS SerialPortFunctionTable
=
870 _In_ PVOID Argument1
,
871 _In_ PVOID Argument2
,
872 _Inout_ PVOID Argument3
,
873 _Inout_ PVOID Argument4
877 PBL_DEVICE_DESCRIPTOR Device
= (PBL_DEVICE_DESCRIPTOR
)Entry
;
878 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Argument1
;
879 ULONG Flags
= *(PULONG
)Argument2
;
880 ULONG Unknown
= *(PULONG
)Argument3
;
885 /* Compare the device descriptor */
886 if (BlpDeviceCompare(DeviceEntry
->DeviceDescriptor
, Device
))
888 /* Compare something */
889 if (DeviceEntry
->Unknown
== Unknown
)
892 if ((!(Flags
& 1) || (DeviceEntry
->Flags
& 2)) &&
893 (!(Flags
& 2) || (DeviceEntry
->Flags
& 4)))
896 if (((Flags
& 8) || !(DeviceEntry
->Flags
& 8)) &&
897 (!(Flags
& 8) || (DeviceEntry
->Flags
& 8)))
906 /* Return matching state */
911 DeviceTableDestroyEntry (
916 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Entry
;
919 /* Call the close routine for this entry */
920 Status
= DeviceEntry
->Callbacks
.Close(DmDeviceTable
[DeviceId
]);
922 /* Free the descriptor, and the device itself */
923 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
924 BlMmFreeHeap(DeviceEntry
);
926 /* Clear out the netry, and return */
927 DmDeviceTable
[DeviceId
] = NULL
;
936 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Entry
;
939 /* Check if the device is opened */
940 if (DeviceEntry
->Flags
& 1)
942 /* It is, so can't purge it */
943 Status
= STATUS_UNSUCCESSFUL
;
947 /* It isn't, so destroy the entry */
948 Status
= DeviceTableDestroyEntry(DeviceEntry
, DeviceEntry
->DeviceId
);
951 /* Return back to caller */
956 BlockIoDeviceTableDestroyEntry (
961 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Entry
;
964 /* Call the close routine for this entry */
965 Status
= DeviceEntry
->Callbacks
.Close(DeviceEntry
);
967 /* Free the descriptor, and the device itself */
968 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
969 BlMmFreeHeap(DeviceEntry
);
971 /* Clear out the netry, and return */
972 BlockIoDeviceTable
[DeviceId
] = NULL
;
977 BlockIoDeviceTableDestroy (
983 /* Call the entry destructor on each entry in the table */
984 Status
= BlTblMap(BlockIoDeviceTable
,
985 BlockIoDeviceTableEntries
,
986 BlockIoDeviceTableDestroyEntry
);
988 /* Free the table and return */
989 BlMmFreeHeap(BlockIoDeviceTable
);
998 /* Free the prefetch buffer */
999 BlMmFreeHeap(BlockIopPrefetchBuffer
);
1001 /* Set state to non initialized */
1002 BlockIoInitialized
= FALSE
;
1005 return STATUS_SUCCESS
;
1009 BlockIoEfiHashFunction (
1010 _In_ PBL_HASH_ENTRY Entry
,
1011 _In_ ULONG TableSize
1014 /* Get rid of the alignment bits to have a more unique number */
1015 return ((ULONG
)Entry
->Value
>> 3) % TableSize
;
1019 BlockIopInitialize (
1025 /* Allocate the block device table and zero it out */
1026 BlockIoDeviceTableEntries
= 8;
1027 BlockIoDeviceTable
= BlMmAllocateHeap(sizeof(PVOID
) *
1028 BlockIoDeviceTableEntries
);
1029 if (!BlockIoDeviceTableEntries
)
1031 return STATUS_NO_MEMORY
;
1033 RtlZeroMemory(BlockIoDeviceTable
, sizeof(PVOID
) * BlockIoDeviceTableEntries
);
1035 /* Register our destructor */
1036 Status
= BlpIoRegisterDestroyRoutine(BlockIoDeviceTableDestroy
);
1037 if (!NT_SUCCESS(Status
))
1042 /* Initialize all counters */
1043 BlockIoFirmwareRemovableDiskCount
= 0;
1044 BlockIoFirmwareRawDiskCount
= 0;
1045 BlockIoFirmwareCdromCount
= 0;
1047 /* Initialize the buffers and their sizes */
1048 BlockIopAlignedBuffer
= NULL
;
1049 BlockIopAlignedBufferSize
= 0;
1050 BlockIopPartialBlockBuffer
= NULL
;
1051 BlockIopPartialBlockBufferSize
= 0;
1052 BlockIopPrefetchBuffer
= NULL
;
1053 BlockIopReadBlockBuffer
= NULL
;
1054 BlockIopReadBlockBufferSize
= 0;
1056 /* Allocate the prefetch buffer */
1057 Status
= MmPapAllocatePagesInRange(&BlockIopPrefetchBuffer
,
1058 BlLoaderDeviceMemory
,
1064 if (NT_SUCCESS(Status
))
1066 /* Initialize the block cache */
1067 Status
= BcInitialize();
1068 if (NT_SUCCESS(Status
))
1070 /* Initialize the block device hash table */
1071 Status
= BlHtCreate(29, BlockIoEfiHashFunction
, NULL
, &HashTableId
);
1072 if (NT_SUCCESS(Status
))
1074 /* Register our destructor */
1075 Status
= BlpIoRegisterDestroyRoutine(BlockIopDestroy
);
1076 if (NT_SUCCESS(Status
))
1079 BlockIoInitialized
= TRUE
;
1085 /* Check if this is the failure path */
1086 if (!NT_SUCCESS(Status
))
1088 /* Free the prefetch buffer is one was allocated */
1089 if (BlockIopPrefetchBuffer
)
1091 EfiPrintf(L
"Failure path not implemented %lx\r\n", Status
);
1092 //MmPapFreePages(BlockIopPrefetchBuffer, 1);
1096 /* Return back to the caller */
1102 BlockIoDeviceTableCompare (
1104 _In_ PVOID Argument1
,
1105 _In_ PVOID Argument2
,
1106 _In_ PVOID Argument3
,
1107 _In_ PVOID Argument4
1110 PBL_DEVICE_ENTRY DeviceEntry
= (PBL_DEVICE_ENTRY
)Entry
;
1111 PBL_DEVICE_DESCRIPTOR Device
= (PBL_DEVICE_DESCRIPTOR
)Argument1
;
1113 /* Compare the two devices */
1114 return BlpDeviceCompare(DeviceEntry
->DeviceDescriptor
, Device
);
1119 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1120 _In_ PBL_DEVICE_ENTRY DeviceEntry
1124 PBL_BLOCK_DEVICE BlockDevice
;
1125 PBL_DEVICE_ENTRY FoundDeviceEntry
;
1128 /* Check if the block I/O manager is initialized */
1129 if (!BlockIoInitialized
)
1131 /* First call, initialize it now */
1132 Status
= BlockIopInitialize();
1133 if (!NT_SUCCESS(Status
))
1135 /* Failed to initialize block I/O */
1136 EfiPrintf(L
"Block I/O Init failed\r\n");
1141 /* Copy a function table for block I/O devices */
1142 RtlCopyMemory(&DeviceEntry
->Callbacks
,
1143 &BlockIoDeviceFunctionTable
,
1144 sizeof(DeviceEntry
->Callbacks
));
1146 /* Allocate a block I/O device */
1147 BlockDevice
= BlMmAllocateHeap(sizeof(*BlockDevice
));
1150 return STATUS_NO_MEMORY
;
1153 /* Set this as the device-specific data for this device entry */
1154 Status
= STATUS_SUCCESS
;
1155 DeviceEntry
->DeviceSpecificData
= BlockDevice
;
1157 /* Check if we already have this device in our device table */
1158 FoundDeviceEntry
= BlTblFindEntry(BlockIoDeviceTable
,
1159 BlockIoDeviceTableEntries
,
1161 BlockIoDeviceTableCompare
,
1166 if (FoundDeviceEntry
)
1168 /* We already found a device, so copy its device data and callbacks */
1169 EfiPrintf(L
"Device entry found: %p\r\n", FoundDeviceEntry
);
1170 RtlCopyMemory(BlockDevice
, FoundDeviceEntry
->DeviceSpecificData
, sizeof(*BlockDevice
));
1171 RtlCopyMemory(&DeviceEntry
->Callbacks
,
1172 &FoundDeviceEntry
->Callbacks
,
1173 sizeof(DeviceEntry
->Callbacks
));
1177 /* Zero out the device for now */
1178 RtlZeroMemory(BlockDevice
, sizeof(*BlockDevice
));
1180 /* Is this a disk? */
1181 if (Device
->DeviceType
== DiskDevice
)
1183 /* What type of disk is it? */
1184 switch (Device
->Local
.Type
)
1186 /* Is it a raw physical disk? */
1190 /* Open a disk device */
1191 Status
= DiskDeviceFunctionTable
.Open(Device
, DeviceEntry
);
1194 /* Is it a RAM disk? */
1196 /* Open a RAM disk */
1197 Status
= RamDiskDeviceFunctionTable
.Open(Device
, DeviceEntry
);
1203 Status
= FileDeviceFunctionTable
.Open(Device
, DeviceEntry
);
1207 case VirtualDiskDevice
:
1208 /* Open a virtual disk */
1209 Status
= VirtualDiskDeviceFunctionTable
.Open(Device
, DeviceEntry
);
1212 /* Is it something else? */
1215 Status
= STATUS_INVALID_PARAMETER
;
1219 else if ((Device
->DeviceType
== LegacyPartitionDevice
) ||
1220 (Device
->DeviceType
== PartitionDevice
))
1222 /* This is a partition on a disk, open it as such */
1223 Status
= PartitionDeviceFunctionTable
.Open(Device
, DeviceEntry
);
1227 /* Other devices are not supported */
1228 Status
= STATUS_INVALID_PARAMETER
;
1231 /* Check for failure */
1232 if (!NT_SUCCESS(Status
))
1234 /* Free any allocations for this device */
1235 BlockIopFreeAllocations(BlockDevice
);
1238 /* Return back to the caller */
1243 BlpDeviceResolveLocate (
1244 _In_ PBL_DEVICE_DESCRIPTOR InputDevice
,
1245 _Out_ PBL_DEVICE_DESCRIPTOR
* LocateDevice
1248 EfiPrintf(L
"Not implemented!\r\n");
1249 return STATUS_NOT_IMPLEMENTED
;
1257 PBL_DEVICE_ENTRY DeviceEntry
;
1259 /* Validate the device ID */
1260 if (DmTableEntries
<= DeviceId
)
1262 return STATUS_INVALID_PARAMETER
;
1265 /* Make sure there's a device there */
1266 DeviceEntry
= DmDeviceTable
[DeviceId
];
1267 if (DeviceEntry
== NULL
)
1269 return STATUS_INVALID_PARAMETER
;
1272 /* Make sure the device is active */
1273 if (!(DeviceEntry
->Flags
& 1))
1275 return STATUS_INVALID_PARAMETER
;
1278 /* Drop a reference and check if it's the last one */
1279 DeviceEntry
->ReferenceCount
--;
1280 if (!DeviceEntry
->ReferenceCount
)
1282 /* Mark the device as inactive */
1283 DeviceEntry
->Flags
= ~1;
1287 return STATUS_SUCCESS
;
1292 _In_ PBL_DEVICE_DESCRIPTOR Device
,
1295 _Out_ PULONG DeviceId
1299 PBL_DEVICE_ENTRY DeviceEntry
;
1300 PBL_DEVICE_DESCRIPTOR LocateDeviceDescriptor
;
1301 PBL_REGISTERED_DEVICE RegisteredDevice
;
1302 PLIST_ENTRY NextEntry
, ListHead
;
1306 /* Check for missing parameters */
1307 if (!(Device
) || !(DeviceId
) || !(Device
->Size
))
1310 Status
= STATUS_INVALID_PARAMETER
;
1314 /* Check for unsupported flags */
1318 Status
= STATUS_INVALID_PARAMETER
;
1322 /* Check if the boot device is being opened */
1323 if (Device
->DeviceType
== BootDevice
)
1326 Device
= BlpBootDevice
;
1329 /* Check if the 'locate' device is being opened */
1330 if (Device
->DeviceType
== LocateDevice
)
1333 Status
= BlpDeviceResolveLocate(Device
, &LocateDeviceDescriptor
);
1334 if (!NT_SUCCESS(Status
))
1336 /* Not found, bail out */
1341 Device
= LocateDeviceDescriptor
;
1344 /* Check if the device isn't ready yet */
1345 if (Device
->Flags
& 1)
1347 /* Return a failure */
1348 Status
= STATUS_DEVICE_NOT_READY
;
1352 /* Check if we already have an entry for the device */
1353 DeviceEntry
= BlTblFindEntry(DmDeviceTable
,
1363 /* Return it, taking a reference on it */
1364 EfiPrintf(L
"Device found: %p\r\n", DeviceEntry
);
1365 *DeviceId
= DeviceEntry
->DeviceId
;
1366 ++DeviceEntry
->ReferenceCount
;
1367 DeviceEntry
->Flags
|= 1;
1368 return STATUS_SUCCESS
;
1371 /* We don't, allocate one */
1372 DeviceEntry
= BlMmAllocateHeap(sizeof(*DeviceEntry
));
1375 Status
= STATUS_NO_MEMORY
;
1380 RtlZeroMemory(DeviceEntry
, sizeof(*DeviceEntry
));
1381 DeviceEntry
->ReferenceCount
= 1;
1382 DeviceEntry
->Flags
|= 7;
1383 DeviceEntry
->Unknown
= Unknown
;
1385 /* Save flag 8 if needed */
1388 DeviceEntry
->Flags
|= 8;
1391 /* Allocate a device descriptor for the device */
1392 DeviceEntry
->DeviceDescriptor
= BlMmAllocateHeap(Device
->Size
);
1393 if (!DeviceEntry
->DeviceDescriptor
)
1395 Status
= STATUS_NO_MEMORY
;
1399 /* Copy the descriptor that was passed in */
1400 RtlCopyMemory(DeviceEntry
->DeviceDescriptor
, Device
, Device
->Size
);
1402 /* Now loop the list of dynamically registered devices */
1403 ListHead
= &DmRegisteredDevices
;
1404 NextEntry
= ListHead
->Flink
;
1405 while (NextEntry
!= ListHead
)
1407 /* Get the device */
1408 RegisteredDevice
= CONTAINING_RECORD(NextEntry
,
1409 BL_REGISTERED_DEVICE
,
1412 /* Open the device */
1413 Status
= RegisteredDevice
->Callbacks
.Open(Device
, DeviceEntry
);
1414 if (NT_SUCCESS(Status
))
1416 /* The device was opened, so we have the right one */
1420 /* Nope, keep trying */
1421 NextEntry
= NextEntry
->Flink
;
1424 /* Well, it wasn't a dynamic device. Is it a block device? */
1425 if ((Device
->DeviceType
== PartitionDevice
) ||
1426 (Device
->DeviceType
== DiskDevice
) ||
1427 (Device
->DeviceType
== LegacyPartitionDevice
))
1429 /* Call the Block I/O handler */
1430 Status
= BlockIoDeviceFunctionTable
.Open(Device
, DeviceEntry
);
1432 else if (Device
->DeviceType
== SerialDevice
)
1434 /* It's a serial device, call the serial device handler */
1435 Status
= SerialPortFunctionTable
.Open(Device
, DeviceEntry
);
1437 else if (Device
->DeviceType
== UdpDevice
)
1439 /* It's a network device, call the UDP device handler */
1440 Status
= UdpFunctionTable
.Open(Device
, DeviceEntry
);
1444 /* Unsupported type of device */
1445 Status
= STATUS_NOT_IMPLEMENTED
;
1448 /* Check if the device was opened successfuly */
1449 if (NT_SUCCESS(Status
))
1452 /* Save the entry in the device table */
1453 Status
= BlTblSetEntry(&DmDeviceTable
,
1458 if (NT_SUCCESS(Status
))
1460 /* It worked -- return the ID in the table to the caller */
1461 EfiPrintf(L
"Device ID: %lx\r\n", *DeviceId
);
1462 DeviceEntry
->DeviceId
= *DeviceId
;
1463 return STATUS_SUCCESS
;
1468 /* Failure path -- did we allocate a device entry? */
1469 EfiPrintf(L
"Block failure: %lx\r\n", Status
);
1472 /* Yep -- did it have a descriptor? */
1473 if (DeviceEntry
->DeviceDescriptor
)
1476 BlMmFreeHeap(DeviceEntry
->DeviceDescriptor
);
1479 /* Free the entry */
1480 BlMmFreeHeap(DeviceEntry
);
1483 /* Return the failure */
1488 BlpDeviceInitialize (
1494 /* Initialize the table count and list of devices */
1496 InitializeListHead(&DmRegisteredDevices
);
1498 /* Initialize device information */
1499 DmDeviceIoInformation
.Unknown0
= 0;
1500 DmDeviceIoInformation
.Unknown1
= 0;
1501 DmDeviceIoInformation
.Unknown2
= 0;
1502 DmDeviceIoInformation
.Unknown3
= 0;
1504 /* Allocate the device table */
1505 DmDeviceTable
= BlMmAllocateHeap(DmTableEntries
* sizeof(PVOID
));
1509 RtlZeroMemory(DmDeviceTable
, DmTableEntries
* sizeof(PVOID
));
1511 /* Initialize BitLocker support */
1512 Status
= FvebInitialize();
1514 Status
= STATUS_SUCCESS
;
1519 /* No memory, we'll fail */
1520 Status
= STATUS_NO_MEMORY
;
1523 /* Return initialization state */