[BOOTMGFW]
[reactos.git] / reactos / boot / environ / lib / io / device.c
1 /*
2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Library
4 * FILE: boot/environ/lib/io/device.c
5 * PURPOSE: Boot Library Device Management Routines
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "bl.h"
12
13 /* DATA VARIABLES ************************************************************/
14
15 typedef struct _BL_DEVICE_INFORMATION
16 {
17 ULONG Unknown0;
18 ULONG Unknown1;
19 ULONG Unknown2;
20 ULONG Unknown3;
21 } BL_DEVICE_INFORMATION, *PBL_DEVICE_INFORMATION;
22
23 LIST_ENTRY DmRegisteredDevices;
24 ULONG DmTableEntries;
25 LIST_ENTRY DmRegisteredDevices;
26 PVOID* DmDeviceTable;
27
28 BL_DEVICE_INFORMATION DmDeviceIoInformation;
29
30 /* FUNCTIONS *****************************************************************/
31
32 struct _BL_DEVICE_ENTRY;
33
34 typedef
35 NTSTATUS
36 (*PBL_DEVICE_ENUMERATE_DEVICE_CLASS) (
37 VOID
38 );
39
40 typedef
41 NTSTATUS
42 (*PBL_DEVICE_OPEN) (
43 _In_ PBL_DEVICE_DESCRIPTOR Device,
44 _In_ struct _BL_DEVICE_ENTRY* DeviceEntry
45 );
46
47 typedef
48 NTSTATUS
49 (*PBL_DEVICE_CLOSE) (
50 _In_ struct _BL_DEVICE_ENTRY* DeviceEntry
51 );
52
53 typedef
54 NTSTATUS
55 (*PBL_DEVICE_READ) (
56 VOID
57 );
58
59 typedef
60 NTSTATUS
61 (*PBL_DEVICE_WRITE) (
62 VOID
63 );
64
65 typedef
66 NTSTATUS
67 (*PBL_DEVICE_GET_INFORMATION) (
68 VOID
69 );
70
71 typedef
72 NTSTATUS
73 (*PBL_DEVICE_SET_INFORMATION) (
74 VOID
75 );
76
77 typedef
78 NTSTATUS
79 (*PBL_DEVICE_RESET) (
80 VOID
81 );
82
83 typedef
84 NTSTATUS
85 (*PBL_DEVICE_FLUSH) (
86 VOID
87 );
88
89 typedef
90 NTSTATUS
91 (*PBL_DEVICE_CREATE) (
92 VOID
93 );
94
95 typedef struct _BL_DEVICE_CALLBACKS
96 {
97 PBL_DEVICE_ENUMERATE_DEVICE_CLASS EnumerateDeviceClass;
98 PBL_DEVICE_OPEN Open;
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;
108
109 typedef struct _BL_DEVICE_ENTRY
110 {
111 ULONG DeviceId;
112 ULONG Flags;
113 ULONG Unknown;
114 ULONG ReferenceCount;
115 BL_DEVICE_CALLBACKS Callbacks;
116 PVOID DeviceSpecificData;
117 PBL_DEVICE_DESCRIPTOR DeviceDescriptor;
118 } BL_DEVICE_ENTRY, *PBL_DEVICE_ENTRY;
119
120 typedef struct _BL_REGISTERED_DEVICE
121 {
122 LIST_ENTRY ListEntry;
123 BL_DEVICE_CALLBACKS Callbacks;
124 } BL_REGISTERED_DEVICE, *PBL_REGISTERED_DEVICE;
125
126 PVOID* BlockIoDeviceTable;
127 ULONG BlockIoDeviceTableEntries;
128
129 ULONG BlockIoFirmwareRemovableDiskCount;
130 ULONG BlockIoFirmwareRawDiskCount;
131 ULONG BlockIoFirmwareCdromCount;
132
133 PVOID BlockIopAlignedBuffer;
134 ULONG BlockIopAlignedBufferSize;
135
136 PVOID BlockIopPartialBlockBuffer;
137 ULONG BlockIopPartialBlockBufferSize;
138
139 PVOID BlockIopPrefetchBuffer;
140
141 PVOID BlockIopReadBlockBuffer;
142 ULONG BlockIopReadBlockBufferSize;
143
144 ULONG HashTableId;
145
146 BOOLEAN BlockIoInitialized;
147
148 NTSTATUS
149 BlockIoOpen (
150 _In_ PBL_DEVICE_DESCRIPTOR Device,
151 _In_ PBL_DEVICE_ENTRY DeviceEntry
152 );
153
154 NTSTATUS
155 PartitionOpen (
156 _In_ PBL_DEVICE_DESCRIPTOR Device,
157 _In_ PBL_DEVICE_ENTRY DeviceEntry
158 )
159 {
160 EfiPrintf(L"Not implemented!\r\n");
161 return STATUS_NOT_IMPLEMENTED;
162 }
163
164 NTSTATUS
165 VhdFileDeviceOpen (
166 _In_ PBL_DEVICE_DESCRIPTOR Device,
167 _In_ PBL_DEVICE_ENTRY DeviceEntry
168 )
169 {
170 EfiPrintf(L"Not implemented!\r\n");
171 return STATUS_NOT_IMPLEMENTED;
172 }
173
174 NTSTATUS
175 DiskOpen (
176 _In_ PBL_DEVICE_DESCRIPTOR Device,
177 _In_ PBL_DEVICE_ENTRY DeviceEntry
178 )
179 {
180 EfiPrintf(L"Not implemented!\r\n");
181 return STATUS_NOT_IMPLEMENTED;
182 }
183
184 NTSTATUS
185 RdDeviceOpen (
186 _In_ PBL_DEVICE_DESCRIPTOR Device,
187 _In_ PBL_DEVICE_ENTRY DeviceEntry
188 )
189 {
190 EfiPrintf(L"Not implemented!\r\n");
191 return STATUS_NOT_IMPLEMENTED;
192 }
193
194 NTSTATUS
195 FileDeviceOpen (
196 _In_ PBL_DEVICE_DESCRIPTOR Device,
197 _In_ PBL_DEVICE_ENTRY DeviceEntry
198 )
199 {
200 EfiPrintf(L"Not implemented!\r\n");
201 return STATUS_NOT_IMPLEMENTED;
202 }
203
204 NTSTATUS
205 SpOpen (
206 _In_ PBL_DEVICE_DESCRIPTOR Device,
207 _In_ PBL_DEVICE_ENTRY DeviceEntry
208 )
209 {
210 EfiPrintf(L"Not implemented!\r\n");
211 return STATUS_NOT_IMPLEMENTED;
212 }
213
214 NTSTATUS
215 UdpOpen (
216 _In_ PBL_DEVICE_DESCRIPTOR Device,
217 _In_ PBL_DEVICE_ENTRY DeviceEntry
218 )
219 {
220 EfiPrintf(L"Not implemented!\r\n");
221 return STATUS_NOT_IMPLEMENTED;
222 }
223
224 BL_DEVICE_CALLBACKS FileDeviceFunctionTable =
225 {
226 NULL,
227 FileDeviceOpen,
228 NULL,
229 };
230
231 BL_DEVICE_CALLBACKS PartitionDeviceFunctionTable =
232 {
233 NULL,
234 PartitionOpen,
235 NULL,
236 };
237
238 BL_DEVICE_CALLBACKS RamDiskDeviceFunctionTable =
239 {
240 NULL,
241 RdDeviceOpen,
242 NULL,
243 };
244
245 BL_DEVICE_CALLBACKS DiskDeviceFunctionTable =
246 {
247 NULL,
248 DiskOpen,
249 NULL,
250 };
251
252 BL_DEVICE_CALLBACKS VirtualDiskDeviceFunctionTable =
253 {
254 NULL,
255 VhdFileDeviceOpen,
256 NULL,
257 };
258
259 BL_DEVICE_CALLBACKS BlockIoDeviceFunctionTable =
260 {
261 NULL,
262 BlockIoOpen,
263 NULL,
264 };
265
266 BL_DEVICE_CALLBACKS UdpFunctionTable =
267 {
268 NULL,
269 UdpOpen,
270 NULL,
271 };
272
273 BL_DEVICE_CALLBACKS SerialPortFunctionTable =
274 {
275 NULL,
276 SpOpen,
277 NULL,
278 };
279
280
281 ULONG BcpBlockAllocatorHandle;
282 ULONG BcpHashTableId;
283
284 NTSTATUS
285 BcpDestroy (
286 VOID
287 )
288 {
289 //BcpPurgeCacheEntries();
290 //return BlpMmDeleteBlockAllocator(BcpBlockAllocatorHandle);
291 EfiPrintf(L"Destructor for block cache not yet implemented\r\n");
292 return STATUS_NOT_IMPLEMENTED;
293 }
294
295 BOOLEAN
296 BcpCompareKey (
297 _In_ PBL_HASH_ENTRY Entry1,
298 _In_ PBL_HASH_ENTRY Entry2
299 )
300 {
301 PULONG Value1, Value2;
302
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];
306 }
307
308 ULONG
309 BcpHashFunction (
310 _In_ PBL_HASH_ENTRY Entry,
311 _In_ ULONG TableSize
312 )
313 {
314 ULONG i, j, ValueHash;
315 PUCHAR ValueBuffer;
316
317 j = 0;
318 ValueHash = 0;
319 i = 0;
320
321 ValueBuffer = Entry->Value;
322
323 do
324 {
325 ValueHash += ValueBuffer[i++];
326 }
327 while (i < 8);
328
329 do
330 {
331 ValueHash += ValueBuffer[j++ + 8];
332 }
333 while (j < 4);
334
335 return ValueHash % TableSize;
336 }
337
338 NTSTATUS
339 BcInitialize (
340 VOID
341 )
342 {
343 NTSTATUS Status;
344
345 Status = BlHtCreate(50, BcpHashFunction, BcpCompareKey, &BcpHashTableId);
346 if (!NT_SUCCESS(Status))
347 {
348 goto Quickie;
349 }
350
351 BcpBlockAllocatorHandle = BlpMmCreateBlockAllocator();
352 if (BcpBlockAllocatorHandle == -1)
353 {
354 Status = STATUS_UNSUCCESSFUL;
355 goto Quickie;
356 }
357
358 Status = BlpIoRegisterDestroyRoutine(BcpDestroy);
359 if (Status >= 0)
360 {
361 return Status;
362 }
363
364 Quickie:
365 EfiPrintf(L"Failure path not yet implemented\n");
366 #if 0
367 if (BcpHashTableId != -1)
368 {
369 BlHtDestroy(BcpHashTableId);
370 }
371 if (BcpBlockAllocatorHandle != -1)
372 {
373 BlpMmDeleteBlockAllocator(BcpBlockAllocatorHandle);
374 }
375 #endif
376 return Status;
377 }
378
379 BOOLEAN
380 BlpDeviceCompare (
381 _In_ PBL_DEVICE_DESCRIPTOR Device1,
382 _In_ PBL_DEVICE_DESCRIPTOR Device2
383 )
384 {
385 BOOLEAN DeviceMatch;
386 ULONG DeviceSize;
387
388 /* Assume failure */
389 DeviceMatch = FALSE;
390
391 /* Check if the two devices exist and are identical in typ */
392 if ((Device1) && (Device2) && (Device1->DeviceType == Device2->DeviceType))
393 {
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))
397 {
398 /* Compare the two devices up to their size */
399 if (RtlEqualMemory(&Device1->Local,
400 &Device2->Local,
401 DeviceSize - FIELD_OFFSET(BL_DEVICE_DESCRIPTOR, Local)))
402 {
403 /* They match! */
404 DeviceMatch = TRUE;
405 }
406 }
407 }
408
409 /* Return matching state */
410 return DeviceMatch;
411 }
412
413 BOOLEAN
414 DeviceTableCompare (
415 _In_ PVOID Entry,
416 _In_ PVOID Argument1,
417 _In_ PVOID Argument2,
418 _Inout_ PVOID Argument3,
419 _Inout_ PVOID Argument4
420 )
421 {
422 BOOLEAN Found;
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;
427
428 /* Assume failure */
429 Found = FALSE;
430
431 /* Compare the device descriptor */
432 if (BlpDeviceCompare(DeviceEntry->DeviceDescriptor, Device))
433 {
434 /* Compare something */
435 if (DeviceEntry->Unknown == Unknown)
436 {
437 /* Compare flags */
438 if ((!(Flags & 1) || (DeviceEntry->Flags & 2)) &&
439 (!(Flags & 2) || (DeviceEntry->Flags & 4)))
440 {
441 /* And more flags */
442 if (((Flags & 8) || !(DeviceEntry->Flags & 8)) &&
443 (!(Flags & 8) || (DeviceEntry->Flags & 8)))
444 {
445 /* Found a match! */
446 Found = TRUE;
447 }
448 }
449 }
450 }
451
452 /* Return matching state */
453 return Found;
454 }
455
456 NTSTATUS
457 DeviceTableDestroyEntry (
458 _In_ PVOID Entry,
459 _In_ ULONG DeviceId
460 )
461 {
462 PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry;
463 NTSTATUS Status;
464
465 /* Call the close routine for this entry */
466 Status = DeviceEntry->Callbacks.Close(DmDeviceTable[DeviceId]);
467
468 /* Free the descriptor, and the device itself */
469 BlMmFreeHeap(DeviceEntry->DeviceDescriptor);
470 BlMmFreeHeap(DeviceEntry);
471
472 /* Clear out the netry, and return */
473 DmDeviceTable[DeviceId] = NULL;
474 return Status;
475 }
476
477 NTSTATUS
478 DeviceTablePurge (
479 _In_ PVOID Entry
480 )
481 {
482 PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry;
483 NTSTATUS Status;
484
485 /* Check if the device is opened */
486 if (DeviceEntry->Flags & 1)
487 {
488 /* It is, so can't purge it */
489 Status = STATUS_UNSUCCESSFUL;
490 }
491 else
492 {
493 /* It isn't, so destroy the entry */
494 Status = DeviceTableDestroyEntry(DeviceEntry, DeviceEntry->DeviceId);
495 }
496
497 /* Return back to caller */
498 return Status;
499 }
500
501 NTSTATUS
502 BlockIoDeviceTableDestroyEntry (
503 _In_ PVOID Entry,
504 _In_ ULONG DeviceId
505 )
506 {
507 PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry;
508 NTSTATUS Status;
509
510 /* Call the close routine for this entry */
511 Status = DeviceEntry->Callbacks.Close(DeviceEntry);
512
513 /* Free the descriptor, and the device itself */
514 BlMmFreeHeap(DeviceEntry->DeviceDescriptor);
515 BlMmFreeHeap(DeviceEntry);
516
517 /* Clear out the netry, and return */
518 BlockIoDeviceTable[DeviceId] = NULL;
519 return Status;
520 }
521
522 NTSTATUS
523 BlockIoDeviceTableDestroy (
524 VOID
525 )
526 {
527 NTSTATUS Status;
528
529 /* Call the entry destructor on each entry in the table */
530 Status = BlTblMap(BlockIoDeviceTable,
531 BlockIoDeviceTableEntries,
532 BlockIoDeviceTableDestroyEntry);
533
534 /* Free the table and return */
535 BlMmFreeHeap(BlockIoDeviceTable);
536 return Status;
537 }
538
539 NTSTATUS
540 BlockIopDestroy (
541 VOID
542 )
543 {
544 /* Free the prefetch buffer */
545 BlMmFreeHeap(BlockIopPrefetchBuffer);
546
547 /* Set state to non initialized */
548 BlockIoInitialized = FALSE;
549
550 /* Return back */
551 return STATUS_SUCCESS;
552 }
553
554 ULONG
555 BlockIoEfiHashFunction (
556 _In_ PBL_HASH_ENTRY Entry,
557 _In_ ULONG TableSize
558 )
559 {
560 /* Get rid of the alignment bits to have a more unique number */
561 return ((ULONG)Entry->Value >> 3) % TableSize;
562 }
563
564 NTSTATUS
565 BlockIopInitialize (
566 VOID
567 )
568 {
569 NTSTATUS Status;
570
571 /* Allocate the block device table and zero it out */
572 BlockIoDeviceTableEntries = 8;
573 BlockIoDeviceTable = BlMmAllocateHeap(sizeof(PVOID) *
574 BlockIoDeviceTableEntries);
575 if (!BlockIoDeviceTableEntries)
576 {
577 return STATUS_NO_MEMORY;
578 }
579 RtlZeroMemory(BlockIoDeviceTable, sizeof(PVOID) * BlockIoDeviceTableEntries);
580
581 /* Register our destructor */
582 Status = BlpIoRegisterDestroyRoutine(BlockIoDeviceTableDestroy);
583 if (!NT_SUCCESS(Status))
584 {
585 return Status;
586 }
587
588 /* Initialize all counters */
589 BlockIoFirmwareRemovableDiskCount = 0;
590 BlockIoFirmwareRawDiskCount = 0;
591 BlockIoFirmwareCdromCount = 0;
592
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;
601
602 /* Allocate the prefetch buffer */
603 Status = MmPapAllocatePagesInRange(&BlockIopPrefetchBuffer,
604 BlLoaderDeviceMemory,
605 0x100,
606 0,
607 0,
608 NULL,
609 0);
610 if (NT_SUCCESS(Status))
611 {
612 /* Initialize the block cache */
613 Status = BcInitialize();
614 if (NT_SUCCESS(Status))
615 {
616 /* Initialize the block device hash table */
617 Status = BlHtCreate(29, BlockIoEfiHashFunction, NULL, &HashTableId);
618 if (NT_SUCCESS(Status))
619 {
620 /* Register our destructor */
621 Status = BlpIoRegisterDestroyRoutine(BlockIopDestroy);
622 if (NT_SUCCESS(Status))
623 {
624 /* We're good */
625 BlockIoInitialized = TRUE;
626 }
627 }
628 }
629 }
630
631 /* Check if this is the failure path */
632 if (!NT_SUCCESS(Status))
633 {
634 /* Free the prefetch buffer is one was allocated */
635 if (BlockIopPrefetchBuffer)
636 {
637 EfiPrintf(L"Failure path not implemented %lx\r\n", Status);
638 //MmPapFreePages(BlockIopPrefetchBuffer, 1);
639 }
640 }
641
642 /* Return back to the caller */
643 return Status;
644 }
645
646 NTSTATUS
647 BlockIopFreeAllocations (
648 _In_ PBL_BLOCK_DEVICE BlockDevice
649 )
650 {
651 /* If a block device was passed in, free it */
652 if (BlockDevice)
653 {
654 BlMmFreeHeap(BlockDevice);
655 }
656
657 /* Nothing else to do */
658 return STATUS_SUCCESS;
659 }
660
661 NTSTATUS
662 BlockIoEfiGetBlockIoInformation (
663 _In_ PBL_BLOCK_DEVICE BlockDevice
664 )
665 {
666 NTSTATUS Status;
667 EFI_BLOCK_IO_MEDIA *Media;
668
669 /* Open the Block I/O protocol on this device */
670 Status = EfiOpenProtocol(BlockDevice->Handle,
671 &EfiBlockIoProtocol,
672 (PVOID*)&BlockDevice->Protocol);
673 if (!NT_SUCCESS(Status))
674 {
675 return Status;
676 }
677
678 /* Get information on the block media */
679 Media = BlockDevice->Protocol->Media;
680
681 /* Set the appropriate device flags */
682 BlockDevice->DeviceFlags = 0;
683 if (Media->RemovableMedia)
684 {
685 BlockDevice->DeviceFlags = 1;
686 }
687 if (Media->MediaPresent)
688 {
689 BlockDevice->DeviceFlags |= 2;
690 }
691
692 /* No clue */
693 BlockDevice->Unknown = 0;
694
695 /* Set the block size */
696 BlockDevice->BlockSize = Media->BlockSize;
697
698 /* Make sure there's a last block value */
699 if (!Media->LastBlock)
700 {
701 return STATUS_INVALID_PARAMETER;
702 }
703
704 /* Don't let it be too high */
705 if (Media->LastBlock > 0xFFFFFFFFFFE)
706 {
707 BlockDevice->LastBlock = 0xFFFFFFFFFFE;
708 }
709 else
710 {
711 BlockDevice->LastBlock = Media->LastBlock;
712 }
713
714 /* Make the alignment the smaller of the I/O alignment or the block size */
715 if (Media->IoAlign >= Media->BlockSize)
716 {
717 BlockDevice->Alignment = Media->IoAlign;
718 }
719 else
720 {
721 BlockDevice->Alignment = Media->BlockSize;
722 }
723
724 /* All good */
725 return STATUS_SUCCESS;
726 }
727
728 NTSTATUS
729 BlockIoEfiGetChildHandle (
730 _In_ PBL_PROTOCOL_HANDLE ProtocolInterface,
731 _In_ PBL_PROTOCOL_HANDLE ChildProtocolInterface)
732 {
733 NTSTATUS Status;
734 ULONG i, DeviceCount;
735 EFI_DEVICE_PATH *DevicePath, *ParentDevicePath;
736 EFI_HANDLE *DeviceHandles;
737 EFI_HANDLE Handle;
738
739 /* Find all the Block I/O device handles on the system */
740 DeviceCount = 0;
741 DeviceHandles = 0;
742 Status = EfiLocateHandleBuffer(ByProtocol,
743 &EfiBlockIoProtocol,
744 &DeviceCount,
745 &DeviceHandles);
746 if (!NT_SUCCESS(Status))
747 {
748 /* Failed to enumerate, bail out */
749 return Status;
750 }
751
752 /* Loop all the handles */
753 for (i = 0; i < DeviceCount; i++)
754 {
755 /* Check if this is the device itself */
756 Handle = DeviceHandles[i];
757 if (Handle == ProtocolInterface->Handle)
758 {
759 /* Skip it */
760 continue;
761 }
762
763 /* Get the device path of this device */
764 Status = EfiOpenProtocol(Handle,
765 &EfiDevicePathProtocol,
766 (PVOID*)&DevicePath);
767 if (!NT_SUCCESS(Status))
768 {
769 /* We failed, skip it */
770 continue;
771 }
772
773 /* See if we are its parent */
774 ParentDevicePath = EfiIsDevicePathParent(ProtocolInterface->Interface,
775 DevicePath);
776 if (ParentDevicePath == ProtocolInterface->Interface)
777 {
778 /* Yup, return back to caller */
779 ChildProtocolInterface->Handle = Handle;
780 ChildProtocolInterface->Interface = DevicePath;
781 break;
782 }
783
784 /* Close the device path */
785 EfiCloseProtocol(Handle, &EfiDevicePathProtocol);
786 }
787
788 /* If we got here, nothing was found */
789 Status = STATUS_NO_SUCH_DEVICE;
790
791 /* Free the handle array buffer */
792 BlMmFreeHeap(DeviceHandles);
793 return Status;
794 }
795
796 NTSTATUS
797 BlockIoGetGPTDiskSignature (
798 _In_ PBL_DEVICE_ENTRY DeviceEntry,
799 _Out_ PGUID DiskSignature
800 )
801 {
802 EfiPrintf(L"GPT not supported\r\n");
803 return STATUS_NOT_IMPLEMENTED;
804 }
805
806 NTSTATUS
807 BlockIoEfiGetDeviceInformation (
808 _In_ PBL_DEVICE_ENTRY DeviceEntry
809 )
810 {
811 NTSTATUS Status;
812 PBL_DEVICE_DESCRIPTOR Device;
813 PBL_BLOCK_DEVICE BlockDevice;
814 EFI_DEVICE_PATH *LeafNode;
815 EFI_HANDLE Handle;
816 BL_PROTOCOL_HANDLE Protocol[2];
817 ACPI_HID_DEVICE_PATH *AcpiPath;
818 HARDDRIVE_DEVICE_PATH *DiskPath;
819 BOOLEAN Found;
820 ULONG i;
821
822 Device = DeviceEntry->DeviceDescriptor;
823 BlockDevice = (PBL_BLOCK_DEVICE)DeviceEntry->DeviceSpecificData;
824
825 Found = FALSE;
826
827 Handle = BlockDevice->Handle;
828
829 Protocol[0].Handle = Handle;
830 Protocol[1].Handle = 0;
831
832 Status = EfiOpenProtocol(Handle,
833 &EfiDevicePathProtocol,
834 &Protocol[0].Interface);
835 if (Status < 0)
836 {
837 return Status;
838 }
839
840 for (i = 0, Found = FALSE; Found == FALSE && Protocol[i].Handle; i++)
841 {
842 LeafNode = EfiGetLeafNode(Protocol[i].Interface);
843 if (LeafNode->Type == ACPI_DEVICE_PATH)
844 {
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)))
849 {
850 /* Set the boot library specific device types */
851 Device->DeviceType = LocalDevice;
852 Device->Local.Type = FloppyDevice;
853
854 /* The ACPI UID is the drive number */
855 Device->Local.FloppyDisk.DriveNumber = AcpiPath->UID;
856
857 /* We found a match */
858 Found = TRUE;
859 }
860 }
861 else if ((LeafNode->Type == MEDIA_DEVICE_PATH) && (i == 1))
862 {
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)
866 {
867 Device->Local.Type = LocalDevice;
868
869 /* Check if this is an MBR partition */
870 if (DiskPath->SignatureType == SIGNATURE_TYPE_MBR)
871 {
872 /* Set that this is a local partition */
873 Device->DeviceType = LegacyPartitionDevice;
874 Device->Partition.Disk.Type = LocalDevice;
875
876 BlockDevice->PartitionType = MbrPartition;
877 BlockDevice->Disk.Mbr.Signature = *(PULONG)&DiskPath->Signature[0];
878 Found = TRUE;
879 }
880 else if (DiskPath->SignatureType == SIGNATURE_TYPE_GUID)
881 {
882 BlockDevice->PartitionType = 0;
883 Device->Local.HardDisk.PartitionType = GptPartition;
884
885 Status = BlockIoGetGPTDiskSignature(DeviceEntry,
886 &Device->Local.HardDisk.Gpt.PartitionSignature);
887 if (NT_SUCCESS(Status))
888 {
889 RtlCopyMemory(&BlockDevice->Disk.Gpt.Signature,
890 &Device->Local.HardDisk.Gpt.PartitionSignature,
891 sizeof(&BlockDevice->Disk.Gpt.Signature));
892 Found = TRUE;
893 }
894 }
895
896 /* Otherwise, raw boot is not supported */
897 BlockDevice->PartitionType = RawPartition;
898 Device->Local.HardDisk.PartitionType = RawPartition;
899 Device->Local.HardDisk.Raw.DiskNumber = BlockIoFirmwareRawDiskCount++;;
900 }
901 else if (LeafNode->SubType == MEDIA_CDROM_DP)
902 {
903 /* Set block device information */
904 BlockDevice->PartitionType = RawPartition;
905 BlockDevice->Type = CdRomDevice;
906
907 /* Set CDROM data */
908 Device->Local.Type = CdRomDevice;
909 Device->Local.FloppyDisk.DriveNumber = 0;
910 Found = TRUE;
911 }
912 }
913 else if ((LeafNode->Type != MEDIA_DEVICE_PATH) &&
914 (LeafNode->Type == ACPI_DEVICE_PATH) &&
915 (i == 0))
916 {
917 Status = BlockIoEfiGetChildHandle(Protocol, &Protocol[i]);
918 if (!NT_SUCCESS(Status))
919 {
920 Device->DeviceType = LocalDevice;
921 Found = 1;
922 if (BlockDevice->DeviceFlags & 1)
923 {
924 BlockDevice->Type = FloppyDevice;
925 Device->Local.HardDisk.PartitionType = BlockIoFirmwareRemovableDiskCount++;
926 Device->Local.Type = FloppyDevice;
927 }
928 else
929 {
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++;
935 }
936 }
937 }
938 }
939
940 while (i)
941 {
942 EfiCloseProtocol(Protocol[--i].Handle, &EfiDevicePathProtocol);
943 }
944
945 if (Found)
946 {
947 Status = 0;
948 }
949 else
950 {
951 Status = STATUS_NOT_SUPPORTED;
952 }
953 return Status;
954 }
955
956 NTSTATUS
957 BlockIoEfiReset (
958 VOID
959 )
960 {
961 EfiPrintf(L"not implemented\r\n");
962 return STATUS_NOT_IMPLEMENTED;
963 }
964
965 NTSTATUS
966 BlockIoEfiFlush (
967 VOID
968 )
969 {
970 EfiPrintf(L"not implemented\r\n");
971 return STATUS_NOT_IMPLEMENTED;
972 }
973
974 NTSTATUS
975 BlockIoEfiCreateDeviceEntry (
976 _In_ PBL_DEVICE_ENTRY *DeviceEntry,
977 _Out_ PVOID Handle
978 )
979 {
980 PBL_DEVICE_ENTRY IoDeviceEntry;
981 PBL_BLOCK_DEVICE BlockDevice;
982 NTSTATUS Status;
983 PBL_DEVICE_DESCRIPTOR Device;
984
985 /* Allocate the entry for this device and zero it out */
986 IoDeviceEntry = BlMmAllocateHeap(sizeof(*IoDeviceEntry));
987 if (!IoDeviceEntry)
988 {
989 return STATUS_NO_MEMORY;
990 }
991 RtlZeroMemory(IoDeviceEntry, sizeof(*IoDeviceEntry));
992
993 /* Allocate the device descriptor for this device and zero it out */
994 Device = BlMmAllocateHeap(sizeof(*Device));
995 if (!Device)
996 {
997 return STATUS_NO_MEMORY;
998 }
999 RtlZeroMemory(Device, sizeof(*Device));
1000
1001 /* Allocate the block device specific data, and zero it out */
1002 BlockDevice = BlMmAllocateHeap(sizeof(*BlockDevice));
1003 if (!BlockDevice)
1004 {
1005 return STATUS_NO_MEMORY;
1006 }
1007 RtlZeroMemory(BlockDevice, sizeof(*BlockDevice));
1008
1009 /* Save the descriptor and block device specific data */
1010 IoDeviceEntry->DeviceSpecificData = BlockDevice;
1011 IoDeviceEntry->DeviceDescriptor = Device;
1012
1013 /* Set the size of the descriptor */
1014 Device->Size = sizeof(*Device);
1015
1016 /* Copy the standard I/O callbacks */
1017 RtlCopyMemory(&IoDeviceEntry->Callbacks,
1018 &BlockIoDeviceFunctionTable,
1019 sizeof(IoDeviceEntry->Callbacks));
1020
1021 /* Add the two that are firmware specific */
1022 IoDeviceEntry->Callbacks.Reset = BlockIoEfiReset;
1023 IoDeviceEntry->Callbacks.Flush = BlockIoEfiFlush;
1024
1025 /* Save the EFI handle */
1026 BlockDevice->Handle = Handle;
1027
1028 /* Get information on this device from EFI, caching it in the device */
1029 Status = BlockIoEfiGetBlockIoInformation(BlockDevice);
1030 if (NT_SUCCESS(Status))
1031 {
1032 /* Build the descriptor structure for this device */
1033 Status = BlockIoEfiGetDeviceInformation(IoDeviceEntry);
1034 if (NT_SUCCESS(Status))
1035 {
1036 /* We have a fully constructed device, reuturn it */
1037 *DeviceEntry = IoDeviceEntry;
1038 return STATUS_SUCCESS;
1039 }
1040 }
1041
1042 /* Failure path, free the descriptor if we allocated one */
1043 if (IoDeviceEntry->DeviceDescriptor)
1044 {
1045 BlMmFreeHeap(IoDeviceEntry->DeviceDescriptor);
1046 }
1047
1048 /* Free any other specific allocations */
1049 BlockIopFreeAllocations(IoDeviceEntry->DeviceSpecificData);
1050
1051 /* Free the device entry itself and return the failure code */
1052 BlMmFreeHeap(IoDeviceEntry);
1053 return Status;
1054 }
1055
1056 NTSTATUS
1057 BlockIoFirmwareOpen (
1058 _In_ PBL_DEVICE_DESCRIPTOR Device,
1059 _In_ PBL_BLOCK_DEVICE BlockIoDevice
1060 )
1061 {
1062 NTSTATUS Status;
1063 BOOLEAN DeviceMatch;
1064 BL_HASH_ENTRY HashEntry;
1065 ULONG i, Id, DeviceCount;
1066 PBL_DEVICE_ENTRY DeviceEntry;
1067 EFI_HANDLE* DeviceHandles;
1068
1069 /* Initialize everything */
1070 DeviceEntry = NULL;
1071 DeviceCount = 0;
1072 DeviceHandles = 0;
1073 DeviceEntry = NULL;
1074
1075 /* Ask EFI for handles to all block devices */
1076 Status = EfiLocateHandleBuffer(ByProtocol,
1077 &EfiBlockIoProtocol,
1078 &DeviceCount,
1079 &DeviceHandles);
1080 if (!NT_SUCCESS(Status))
1081 {
1082 return STATUS_NO_SUCH_DEVICE;
1083 }
1084
1085 /* Build a hash entry, with the value inline */
1086 HashEntry.Flags = 1;
1087 HashEntry.Size = sizeof(EFI_HANDLE);
1088
1089 /* Loop each device we got */
1090 DeviceMatch = FALSE;
1091 Status = STATUS_NO_SUCH_DEVICE;
1092 for (i = 0; i < DeviceCount; i++)
1093 {
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))
1098 {
1099 /* We already know about this device */
1100 continue;
1101 }
1102
1103 /* New device, store it in the hash table */
1104 Status = BlHtStore(HashTableId,
1105 &HashEntry,
1106 DeviceHandles[i],
1107 sizeof(DeviceHandles[i]));
1108 if (!NT_SUCCESS(Status))
1109 {
1110 /* Free the array and fail */
1111 BlMmFreeHeap(DeviceHandles);
1112 break;
1113 }
1114
1115 /* Create an entry for this device*/
1116 Status = BlockIoEfiCreateDeviceEntry(&DeviceEntry, DeviceHandles[i]);
1117 if (!NT_SUCCESS(Status))
1118 {
1119 break;
1120 }
1121
1122 /* Add the device entry to the device table */
1123 Status = BlTblSetEntry(&BlockIoDeviceTable,
1124 &BlockIoDeviceTableEntries,
1125 DeviceEntry,
1126 &Id,
1127 TblDoNotPurgeEntry);
1128 if (!NT_SUCCESS(Status))
1129 {
1130 EfiPrintf(L"Failure path not implemented: %lx\r\n", Status);
1131 #if 0
1132 BlHtDelete(HashTableId, &HashKey);
1133 #endif
1134 /* Free the block I/O device data */
1135 BlockIopFreeAllocations(DeviceEntry->DeviceSpecificData);
1136
1137 /* Free the descriptor */
1138 BlMmFreeHeap(DeviceEntry->DeviceDescriptor);
1139
1140 /* Free the entry */
1141 BlMmFreeHeap(DeviceEntry);
1142 break;
1143 }
1144
1145 /* Does this device match what we're looking for? */
1146 DeviceMatch = BlpDeviceCompare(DeviceEntry->DeviceDescriptor, Device);
1147 if (DeviceMatch)
1148 {
1149 /* Yep, return the data back */
1150 RtlCopyMemory(BlockIoDevice,
1151 DeviceEntry->DeviceSpecificData,
1152 sizeof(*BlockIoDevice));
1153 Status = STATUS_SUCCESS;
1154 break;
1155 }
1156 }
1157
1158 /* Free the device handle buffer array */
1159 BlMmFreeHeap(DeviceHandles);
1160
1161 /* Return status */
1162 return Status;
1163 }
1164
1165 BOOLEAN
1166 BlockIoDeviceTableCompare (
1167 _In_ PVOID Entry,
1168 _In_ PVOID Argument1,
1169 _In_ PVOID Argument2,
1170 _In_ PVOID Argument3,
1171 _In_ PVOID Argument4
1172 )
1173 {
1174 PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry;
1175 PBL_DEVICE_DESCRIPTOR Device = (PBL_DEVICE_DESCRIPTOR)Argument1;
1176
1177 /* Compare the two devices */
1178 return BlpDeviceCompare(DeviceEntry->DeviceDescriptor, Device);
1179 }
1180
1181 NTSTATUS
1182 BlockIoOpen (
1183 _In_ PBL_DEVICE_DESCRIPTOR Device,
1184 _In_ PBL_DEVICE_ENTRY DeviceEntry
1185 )
1186 {
1187 NTSTATUS Status;
1188 PBL_BLOCK_DEVICE BlockDevice;
1189 PBL_DEVICE_ENTRY FoundDeviceEntry;
1190 ULONG Dummy;
1191
1192 /* Check if the block I/O manager is initialized */
1193 if (!BlockIoInitialized)
1194 {
1195 /* First call, initialize it now */
1196 Status = BlockIopInitialize();
1197 if (!NT_SUCCESS(Status))
1198 {
1199 /* Failed to initialize block I/O */
1200 return Status;
1201 }
1202 }
1203
1204 /* Copy a function table for block I/O devices */
1205 RtlCopyMemory(&DeviceEntry->Callbacks,
1206 &BlockIoDeviceFunctionTable,
1207 sizeof(DeviceEntry->Callbacks));
1208
1209 /* Allocate a block I/O device */
1210 BlockDevice = BlMmAllocateHeap(sizeof(*BlockDevice));
1211 if (!BlockDevice)
1212 {
1213 return STATUS_NO_MEMORY;
1214 }
1215
1216 /* Set this as the device-specific data for this device entry */
1217 Status = STATUS_SUCCESS;
1218 DeviceEntry->DeviceSpecificData = BlockDevice;
1219
1220 /* Check if we already have this device in our device table */
1221 FoundDeviceEntry = BlTblFindEntry(BlockIoDeviceTable,
1222 BlockIoDeviceTableEntries,
1223 &Dummy,
1224 BlockIoDeviceTableCompare,
1225 Device,
1226 NULL,
1227 NULL,
1228 NULL);
1229 if (FoundDeviceEntry)
1230 {
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));
1236 return Status;
1237 }
1238
1239 /* Zero out the device for now */
1240 RtlZeroMemory(BlockDevice, sizeof(*BlockDevice));
1241
1242 /* Is this a disk? */
1243 if (Device->DeviceType == DiskDevice)
1244 {
1245 /* What type of disk is it? */
1246 switch (Device->Local.Type)
1247 {
1248 /* Is it a raw physical disk? */
1249 case LocalDevice:
1250 case FloppyDevice:
1251 case CdRomDevice:
1252 /* Open a disk device */
1253 Status = DiskDeviceFunctionTable.Open(Device, DeviceEntry);
1254 break;
1255
1256 /* Is it a RAM disk? */
1257 case RamDiskDevice:
1258 /* Open a RAM disk */
1259 Status = RamDiskDeviceFunctionTable.Open(Device, DeviceEntry);
1260 break;
1261
1262 /* Is it a file? */
1263 case FileDevice:
1264 /* Open a file */
1265 Status = FileDeviceFunctionTable.Open(Device, DeviceEntry);
1266 break;
1267
1268 /* Is it a VHD? */
1269 case VirtualDiskDevice:
1270 /* Open a virtual disk */
1271 Status = VirtualDiskDeviceFunctionTable.Open(Device, DeviceEntry);
1272 break;
1273
1274 /* Is it something else? */
1275 default:
1276 /* Not supported */
1277 Status = STATUS_INVALID_PARAMETER;
1278 break;
1279 }
1280 }
1281 else if ((Device->DeviceType == LegacyPartitionDevice) ||
1282 (Device->DeviceType == PartitionDevice))
1283 {
1284 /* This is a partition on a disk, open it as such */
1285 Status = PartitionDeviceFunctionTable.Open(Device, DeviceEntry);
1286 }
1287 else
1288 {
1289 /* Other devices are not supported */
1290 Status = STATUS_INVALID_PARAMETER;
1291 }
1292
1293 /* Check for failure */
1294 if (!NT_SUCCESS(Status))
1295 {
1296 /* Free any allocations for this device */
1297 BlockIopFreeAllocations(BlockDevice);
1298 }
1299
1300 /* Return back to the caller */
1301 return Status;
1302 }
1303
1304 NTSTATUS
1305 BlpDeviceResolveLocate (
1306 _In_ PBL_DEVICE_DESCRIPTOR InputDevice,
1307 _Out_ PBL_DEVICE_DESCRIPTOR* LocateDevice
1308 )
1309 {
1310 EfiPrintf(L"Not implemented!\r\n");
1311 return STATUS_NOT_IMPLEMENTED;
1312 }
1313
1314 NTSTATUS
1315 BlDeviceClose (
1316 _In_ ULONG DeviceId
1317 )
1318 {
1319 PBL_DEVICE_ENTRY DeviceEntry;
1320
1321 /* Validate the device ID */
1322 if (DmTableEntries <= DeviceId)
1323 {
1324 return STATUS_INVALID_PARAMETER;
1325 }
1326
1327 /* Make sure there's a device there */
1328 DeviceEntry = DmDeviceTable[DeviceId];
1329 if (DeviceEntry == NULL)
1330 {
1331 return STATUS_INVALID_PARAMETER;
1332 }
1333
1334 /* Make sure the device is active */
1335 if (!(DeviceEntry->Flags & 1))
1336 {
1337 return STATUS_INVALID_PARAMETER;
1338 }
1339
1340 /* Drop a reference and check if it's the last one */
1341 DeviceEntry->ReferenceCount--;
1342 if (!DeviceEntry->ReferenceCount)
1343 {
1344 /* Mark the device as inactive */
1345 DeviceEntry->Flags = ~1;
1346 }
1347
1348 /* We're good */
1349 return STATUS_SUCCESS;
1350 }
1351
1352 NTSTATUS
1353 BlpDeviceOpen (
1354 _In_ PBL_DEVICE_DESCRIPTOR Device,
1355 _In_ ULONG Flags,
1356 _In_ ULONG Unknown,
1357 _Out_ PULONG DeviceId
1358 )
1359 {
1360 NTSTATUS Status;
1361 PBL_DEVICE_ENTRY DeviceEntry;
1362 PBL_DEVICE_DESCRIPTOR LocateDeviceDescriptor;
1363 PBL_REGISTERED_DEVICE RegisteredDevice;
1364 PLIST_ENTRY NextEntry, ListHead;
1365
1366 DeviceEntry = NULL;
1367
1368 /* Check for missing parameters */
1369 if (!(Device) || !(DeviceId) || !(Device->Size))
1370 {
1371 /* Bail out */
1372 Status = STATUS_INVALID_PARAMETER;
1373 goto Quickie;
1374 }
1375
1376 /* Check for unsupported flags */
1377 if (!(Flags & 3))
1378 {
1379 /* Bail out */
1380 Status = STATUS_INVALID_PARAMETER;
1381 goto Quickie;
1382 }
1383
1384 /* Check if the boot device is being opened */
1385 if (Device->DeviceType == BootDevice)
1386 {
1387 /* Select it */
1388 Device = BlpBootDevice;
1389 }
1390
1391 /* Check if the 'locate' device is being opened */
1392 if (Device->DeviceType == LocateDevice)
1393 {
1394 /* Go find it */
1395 Status = BlpDeviceResolveLocate(Device, &LocateDeviceDescriptor);
1396 if (!NT_SUCCESS(Status))
1397 {
1398 /* Not found, bail out */
1399 goto Quickie;
1400 }
1401
1402 /* Select it */
1403 Device = LocateDeviceDescriptor;
1404 }
1405
1406 /* Check if the device isn't ready yet */
1407 if (Device->Flags & 1)
1408 {
1409 /* Return a failure */
1410 Status = STATUS_DEVICE_NOT_READY;
1411 goto Quickie;
1412 }
1413
1414 /* Check if we already have an entry for the device */
1415 DeviceEntry = BlTblFindEntry(DmDeviceTable,
1416 DmTableEntries,
1417 DeviceId,
1418 DeviceTableCompare,
1419 Device,
1420 &Flags,
1421 &Unknown,
1422 NULL);
1423 if (DeviceEntry)
1424 {
1425 /* Return it, taking a reference on it */
1426 *DeviceId = DeviceEntry->DeviceId;
1427 ++DeviceEntry->ReferenceCount;
1428 DeviceEntry->Flags |= 1;
1429 return STATUS_SUCCESS;
1430 }
1431
1432 /* We don't, allocate one */
1433 DeviceEntry = BlMmAllocateHeap(sizeof(*DeviceEntry));
1434 if (!DeviceEntry)
1435 {
1436 Status = STATUS_NO_MEMORY;
1437 goto Quickie;
1438 }
1439
1440 /* Fill it out */
1441 RtlZeroMemory(DeviceEntry, sizeof(*DeviceEntry));
1442 DeviceEntry->ReferenceCount = 1;
1443 DeviceEntry->Flags |= 7;
1444 DeviceEntry->Unknown = Unknown;
1445
1446 /* Save flag 8 if needed */
1447 if (Flags & 8)
1448 {
1449 DeviceEntry->Flags |= 8;
1450 }
1451
1452 /* Allocate a device descriptor for the device */
1453 DeviceEntry->DeviceDescriptor = BlMmAllocateHeap(Device->Size);
1454 if (!DeviceEntry->DeviceDescriptor)
1455 {
1456 Status = STATUS_NO_MEMORY;
1457 goto Quickie;
1458 }
1459
1460 /* Copy the descriptor that was passed in */
1461 RtlCopyMemory(DeviceEntry->DeviceDescriptor, Device, Device->Size);
1462
1463 /* Now loop the list of dynamically registered devices */
1464 ListHead = &DmRegisteredDevices;
1465 NextEntry = ListHead->Flink;
1466 while (NextEntry != ListHead)
1467 {
1468 /* Get the device */
1469 RegisteredDevice = CONTAINING_RECORD(NextEntry,
1470 BL_REGISTERED_DEVICE,
1471 ListEntry);
1472
1473 /* Open the device */
1474 Status = RegisteredDevice->Callbacks.Open(Device, DeviceEntry);
1475 if (NT_SUCCESS(Status))
1476 {
1477 /* The device was opened, so we have the right one */
1478 goto DeviceOpened;
1479 }
1480
1481 /* Nope, keep trying */
1482 NextEntry = NextEntry->Flink;
1483 }
1484
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))
1489 {
1490 /* Call the Block I/O handler */
1491 Status = BlockIoDeviceFunctionTable.Open(Device, DeviceEntry);
1492 }
1493 else if (Device->DeviceType == SerialDevice)
1494 {
1495 /* It's a serial device, call the serial device handler */
1496 Status = SerialPortFunctionTable.Open(Device, DeviceEntry);
1497 }
1498 else if (Device->DeviceType == UdpDevice)
1499 {
1500 /* It's a network device, call the UDP device handler */
1501 Status = UdpFunctionTable.Open(Device, DeviceEntry);
1502 }
1503 else
1504 {
1505 /* Unsupported type of device */
1506 Status = STATUS_NOT_IMPLEMENTED;
1507 }
1508
1509 /* Check if the device was opened successfuly */
1510 if (NT_SUCCESS(Status))
1511 {
1512 DeviceOpened:
1513 /* Save the entry in the device table */
1514 Status = BlTblSetEntry(&DmDeviceTable,
1515 &DmTableEntries,
1516 DeviceEntry,
1517 DeviceId,
1518 DeviceTablePurge);
1519 if (NT_SUCCESS(Status))
1520 {
1521 /* It worked -- return the ID in the table to the caller */
1522 DeviceEntry->DeviceId = *DeviceId;
1523 return STATUS_SUCCESS;
1524 }
1525 }
1526
1527 Quickie:
1528 /* Failure path -- did we allocate a device entry? */
1529 if (DeviceEntry)
1530 {
1531 /* Yep -- did it have a descriptor? */
1532 if (DeviceEntry->DeviceDescriptor)
1533 {
1534 /* Free it */
1535 BlMmFreeHeap(DeviceEntry->DeviceDescriptor);
1536 }
1537
1538 /* Free the entry */
1539 BlMmFreeHeap(DeviceEntry);
1540 }
1541
1542 /* Return the failure */
1543 return Status;
1544 }
1545
1546 NTSTATUS
1547 BlpDeviceInitialize (
1548 VOID
1549 )
1550 {
1551 NTSTATUS Status;
1552
1553 /* Initialize the table count and list of devices */
1554 DmTableEntries = 8;
1555 InitializeListHead(&DmRegisteredDevices);
1556
1557 /* Initialize device information */
1558 DmDeviceIoInformation.Unknown0 = 0;
1559 DmDeviceIoInformation.Unknown1 = 0;
1560 DmDeviceIoInformation.Unknown2 = 0;
1561 DmDeviceIoInformation.Unknown3 = 0;
1562
1563 /* Allocate the device table */
1564 DmDeviceTable = BlMmAllocateHeap(DmTableEntries * sizeof(PVOID));
1565 if (DmDeviceTable)
1566 {
1567 /* Clear it */
1568 RtlZeroMemory(DmDeviceTable, DmTableEntries * sizeof(PVOID));
1569 #if 0
1570 /* Initialize BitLocker support */
1571 Status = FvebInitialize();
1572 #else
1573 Status = STATUS_SUCCESS;
1574 #endif
1575 }
1576 else
1577 {
1578 /* No memory, we'll fail */
1579 Status = STATUS_NO_MEMORY;
1580 }
1581
1582 /* Return initialization state */
1583 return Status;
1584 }
1585