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