76dbed0674656a5db29a15c0ed2492a297e14011
[reactos.git] / 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 ULONGLONG ReadCount;
18 ULONGLONG WriteCount;
19 } BL_DEVICE_IO_INFORMATION, *PBL_DEVICE_IO_INFORMATION;
20
21 LIST_ENTRY DmRegisteredDevices;
22 ULONG DmTableEntries;
23 LIST_ENTRY DmRegisteredDevices;
24 PVOID* DmDeviceTable;
25
26 BL_DEVICE_IO_INFORMATION DmDeviceIoInformation;
27
28 /* FUNCTIONS *****************************************************************/
29
30 typedef struct _BL_REGISTERED_DEVICE
31 {
32 LIST_ENTRY ListEntry;
33 BL_DEVICE_CALLBACKS Callbacks;
34 } BL_REGISTERED_DEVICE, *PBL_REGISTERED_DEVICE;
35
36 PVOID* BlockIoDeviceTable;
37 ULONG BlockIoDeviceTableEntries;
38
39 ULONG BlockIoFirmwareRemovableDiskCount;
40 ULONG BlockIoFirmwareRawDiskCount;
41 ULONG BlockIoFirmwareCdromCount;
42
43 PVOID BlockIopAlignedBuffer;
44 ULONG BlockIopAlignedBufferSize;
45
46 PVOID BlockIopPartialBlockBuffer;
47 ULONG BlockIopPartialBlockBufferSize;
48
49 PVOID BlockIopPrefetchBuffer;
50
51 PVOID BlockIopReadBlockBuffer;
52 ULONG BlockIopReadBlockBufferSize;
53
54 ULONG HashTableId;
55
56 BOOLEAN BlockIoInitialized;
57
58 NTSTATUS
59 BlockIoOpen (
60 _In_ PBL_DEVICE_DESCRIPTOR Device,
61 _In_ PBL_DEVICE_ENTRY DeviceEntry
62 );
63
64 NTSTATUS
65 BlockIoGetInformation (
66 _In_ PBL_DEVICE_ENTRY DeviceEntry,
67 _Out_ PBL_DEVICE_INFORMATION DeviceInformation
68 );
69
70 NTSTATUS
71 BlockIoSetInformation (
72 _In_ PBL_DEVICE_ENTRY DeviceEntry,
73 _Out_ PBL_DEVICE_INFORMATION DeviceInformation
74 );
75
76 NTSTATUS
77 BlockIoRead (
78 _In_ PBL_DEVICE_ENTRY DeviceEntry,
79 _In_ PVOID Buffer,
80 _In_ ULONG Size,
81 _Out_ PULONG BytesRead
82 );
83
84 BL_DEVICE_CALLBACKS BlockIoDeviceFunctionTable =
85 {
86 NULL,
87 BlockIoOpen,
88 NULL,
89 BlockIoRead,
90 NULL,
91 BlockIoGetInformation,
92 BlockIoSetInformation
93 };
94
95 NTSTATUS
96 BlockIoFirmwareWrite (
97 _In_ PBL_BLOCK_DEVICE BlockDevice,
98 _In_ PVOID Buffer,
99 _In_ ULONGLONG Block,
100 _In_ ULONGLONG BlockCount
101 )
102 {
103 return STATUS_NOT_IMPLEMENTED;
104 }
105
106 NTSTATUS
107 BlockIoFirmwareRead (
108 _In_ PBL_BLOCK_DEVICE BlockDevice,
109 _In_ PVOID Buffer,
110 _In_ ULONGLONG Block,
111 _In_ ULONGLONG BlockCount
112 )
113 {
114 NTSTATUS Status;
115 EFI_BLOCK_IO *BlockProtocol;
116 BL_ARCH_MODE OldMode;
117 EFI_STATUS EfiStatus;
118 ULONG FailureCount;
119
120 for (FailureCount = 0, Status = STATUS_SUCCESS;
121 FailureCount < 2 && NT_SUCCESS(Status);
122 FailureCount++)
123 {
124 BlockProtocol = BlockDevice->Protocol;
125
126 OldMode = CurrentExecutionContext->Mode;
127 if (CurrentExecutionContext->Mode != 1)
128 {
129 Status = STATUS_NOT_IMPLEMENTED;
130 break;
131 }
132
133 //EfiPrintf(L"EFI Reading BLOCK %d off media %lx (%d blocks)\r\n",
134 //Block, BlockProtocol->Media->MediaId, BlockCount);
135 EfiStatus = BlockProtocol->ReadBlocks(BlockProtocol,
136 BlockProtocol->Media->MediaId,
137 Block,
138 BlockProtocol->Media->BlockSize * BlockCount,
139 Buffer);
140 if (EfiStatus == EFI_SUCCESS)
141 {
142 //EfiPrintf(L"EFI Read complete into buffer\r\n");
143 //EfiPrintf(L"Buffer data: %lx %lx %lx %lx\r\n", *(PULONG)Buffer, *((PULONG)Buffer + 1), *((PULONG)Buffer + 2), *((PULONG)Buffer + 3));
144 }
145
146 if (OldMode != 1)
147 {
148 BlpArchSwitchContext(OldMode);
149 }
150
151 Status = EfiGetNtStatusCode(EfiStatus);
152 if (Status != STATUS_MEDIA_CHANGED)
153 {
154 break;
155 }
156
157 EfiCloseProtocol(BlockDevice->Handle, &EfiBlockIoProtocol);
158
159 Status = EfiOpenProtocol(BlockDevice->Handle,
160 &EfiBlockIoProtocol,
161 (PVOID*)BlockDevice->Protocol);
162 }
163
164 return Status;
165 }
166
167 NTSTATUS
168 BlockIopFirmwareOperation (
169 PBL_DEVICE_ENTRY DeviceEntry,
170 _In_ PVOID Buffer,
171 _In_ ULONGLONG Block,
172 _In_ ULONGLONG BlockCount,
173 _In_ ULONG OperationType
174 )
175 {
176 ULONG FailureCount;
177 PBL_BLOCK_DEVICE BlockDevice;
178 NTSTATUS Status;
179
180 BlockDevice = DeviceEntry->DeviceSpecificData;
181
182 if (OperationType == 1)
183 {
184 for (FailureCount = 0; FailureCount < 3; FailureCount++)
185 {
186 Status = BlockIoFirmwareWrite(BlockDevice, Buffer, Block, BlockCount);
187 if (Status >= 0)
188 {
189 break;
190 }
191 }
192 }
193 else
194 {
195 for (FailureCount = 0; FailureCount < 3; FailureCount++)
196 {
197 Status = BlockIoFirmwareRead(BlockDevice, Buffer, Block, BlockCount);
198 if (Status >= 0)
199 {
200 break;
201 }
202 }
203 }
204 return Status;
205 }
206
207 NTSTATUS
208 BlockIopFreeAlignedBuffer (
209 _Inout_ PVOID* Buffer,
210 _Inout_ PULONG BufferSize
211 )
212 {
213 NTSTATUS Status;
214
215 if (*BufferSize)
216 {
217 Status = MmPapFreePages(*Buffer, BL_MM_INCLUDE_MAPPED_ALLOCATED);
218
219 *Buffer = NULL;
220 *BufferSize = 0;
221 }
222 else
223 {
224 Status = STATUS_SUCCESS;
225 }
226
227 return Status;
228 }
229
230 NTSTATUS
231 BlockIopAllocateAlignedBuffer (
232 _Inout_ PVOID* Buffer,
233 _Inout_ PULONG BufferSize,
234 _In_ ULONG Size,
235 _In_ ULONG Alignment
236 )
237 {
238 NTSTATUS Status;
239
240 if (!Alignment)
241 {
242 ++Alignment;
243 }
244
245 Status = STATUS_SUCCESS;
246 if ((Size > *BufferSize) || ((Alignment - 1) & (ULONG_PTR)*Buffer))
247 {
248 BlockIopFreeAlignedBuffer(Buffer, BufferSize);
249
250 *BufferSize = ROUND_TO_PAGES(Size);
251
252 Status = MmPapAllocatePagesInRange(Buffer,
253 BlLoaderDeviceMemory,
254 *BufferSize >> PAGE_SHIFT,
255 0,
256 Alignment >> PAGE_SHIFT,
257 NULL,
258 0);
259 if (!NT_SUCCESS(Status))
260 {
261 *BufferSize = 0;
262 }
263 }
264
265 return Status;
266 }
267
268 NTSTATUS
269 BlockIopReadUsingPrefetch (
270 _In_ PBL_DEVICE_ENTRY DeviceEntry,
271 _In_ PVOID Buffer,
272 _In_ ULONG BlockCount
273 )
274 {
275 EfiPrintf(L"No prefetch support\r\n");
276 return STATUS_NOT_IMPLEMENTED;
277 }
278
279 NTSTATUS
280 BlockIopOperation (
281 _In_ PBL_DEVICE_ENTRY DeviceEntry,
282 _In_ PVOID Buffer,
283 _In_ ULONG BlockCount,
284 _In_ ULONG OperationType
285 )
286 {
287 PBL_BLOCK_DEVICE BlockDevice;
288 ULONG BufferSize, Alignment;
289 ULONGLONG Offset;
290 NTSTATUS Status;
291
292 BlockDevice = DeviceEntry->DeviceSpecificData;
293 BufferSize = BlockDevice->BlockSize * BlockCount;
294 Offset = BlockDevice->Block + BlockDevice->StartOffset;
295 if ((BlockDevice->LastBlock + 1) < (BlockDevice->Block + BlockCount))
296 {
297 EfiPrintf(L"Read past end of device\r\n");
298 return STATUS_INVALID_PARAMETER;
299 }
300
301 Alignment = BlockDevice->Alignment;
302 if (!(Alignment) || !((Alignment - 1) & (ULONG_PTR)Buffer))
303 {
304 Status = BlockIopFirmwareOperation(DeviceEntry,
305 Buffer,
306 Offset,
307 BlockCount,
308 OperationType);
309 if (!NT_SUCCESS(Status))
310 {
311 EfiPrintf(L"EFI op failed: %lx\r\n", Status);
312 return Status;
313 }
314
315 return STATUS_SUCCESS;
316 }
317
318 Status = BlockIopAllocateAlignedBuffer(&BlockIopAlignedBuffer,
319 &BlockIopAlignedBufferSize,
320 BufferSize,
321 BlockDevice->Alignment);
322 if (!NT_SUCCESS(Status))
323 {
324 EfiPrintf(L"No memory for align\r\n");
325 return STATUS_NO_MEMORY;
326 }
327
328 if (OperationType == 1)
329 {
330 RtlCopyMemory(BlockIopAlignedBuffer, Buffer, BufferSize);
331 }
332
333 Status = BlockIopFirmwareOperation(DeviceEntry,
334 BlockIopAlignedBuffer,
335 Offset,
336 BlockCount,
337 OperationType);
338 if (!NT_SUCCESS(Status))
339 {
340 return Status;
341 }
342
343 if (!OperationType)
344 {
345 RtlCopyMemory(Buffer, BlockIopAlignedBuffer, BufferSize);
346 }
347
348 return STATUS_SUCCESS;
349 }
350
351 NTSTATUS
352 BlockIopReadWriteVirtualDevice (
353 _In_ PBL_DEVICE_ENTRY DeviceEntry,
354 _In_ PVOID Buffer,
355 _In_ ULONG Size,
356 _In_ ULONG Operation,
357 _Out_ PULONG BytesRead
358 )
359 {
360 return STATUS_NOT_IMPLEMENTED;
361 }
362
363 NTSTATUS
364 BlockIopReadPhysicalDevice (
365 _In_ PBL_DEVICE_ENTRY DeviceEntry,
366 _In_ PVOID Buffer,
367 _In_ ULONG Size,
368 _Out_ PULONG BytesRead
369 )
370 {
371 PBL_BLOCK_DEVICE BlockDevice;
372 PVOID ReadBuffer;
373 ULONGLONG OffsetEnd, AlignedOffsetEnd, Offset;
374 NTSTATUS Status;
375
376 BlockDevice = DeviceEntry->DeviceSpecificData;
377 ReadBuffer = Buffer;
378 OffsetEnd = Size + BlockDevice->Offset;
379 if (OffsetEnd < Size)
380 {
381 OffsetEnd = -1;
382 return STATUS_INTEGER_OVERFLOW;
383 }
384
385 AlignedOffsetEnd = ~(BlockDevice->BlockSize - 1) & (OffsetEnd + BlockDevice->BlockSize - 1);
386 if (AlignedOffsetEnd < OffsetEnd)
387 {
388 return STATUS_INTEGER_OVERFLOW;
389 }
390
391 if ((BlockDevice->Offset) || (Size != AlignedOffsetEnd))
392 {
393 Status = BlockIopAllocateAlignedBuffer(&BlockIopReadBlockBuffer,
394 &BlockIopReadBlockBufferSize,
395 AlignedOffsetEnd,
396 BlockDevice->Alignment);
397 if (!NT_SUCCESS(Status))
398 {
399 EfiPrintf(L"Failed to allocate buffer: %lx\r\n", Status);
400 return Status;
401 }
402
403 ReadBuffer = BlockIopReadBlockBuffer;
404 }
405
406 Offset = AlignedOffsetEnd / BlockDevice->BlockSize;
407
408 if (BlockDevice->Unknown & 2)
409 {
410 Status = BlockIopReadUsingPrefetch(DeviceEntry,
411 ReadBuffer,
412 AlignedOffsetEnd / BlockDevice->BlockSize);
413 if (NT_SUCCESS(Status))
414 {
415 goto ReadComplete;
416 }
417 }
418
419 Status = BlockIopOperation(DeviceEntry, ReadBuffer, Offset, 0);
420 if (!NT_SUCCESS(Status))
421 {
422 EfiPrintf(L"Block I/O failed: %lx\r\n", Status);
423 return Status;
424 }
425
426 BlockDevice->Block += Offset;
427
428 ReadComplete:
429 if (ReadBuffer != Buffer)
430 {
431 RtlCopyMemory(Buffer,
432 (PVOID)((ULONG_PTR)ReadBuffer +
433 (ULONG_PTR)BlockDevice->Offset),
434 Size);
435 }
436
437 if (BytesRead)
438 {
439 *BytesRead = Size;
440 }
441
442 return STATUS_SUCCESS;
443 }
444
445 NTSTATUS
446 BlockIopBlockInformationCheck (
447 _In_ PBL_BLOCK_DEVICE BlockDevice,
448 _In_opt_ PULONG DesiredSize,
449 _Out_opt_ PULONG Size,
450 _Out_opt_ PULONG OutputAdjustedSize
451 )
452 {
453 ULONG RealSize;
454 ULONGLONG Offset, LastOffset, RemainingOffset, MaxOffset;
455 NTSTATUS Status;
456
457 RealSize = 0;
458
459 Offset = (BlockDevice->Offset * BlockDevice->BlockSize) + BlockDevice->Block;
460
461 if (Offset > ((BlockDevice->LastBlock + 1) * BlockDevice->BlockSize))
462 {
463 Status = STATUS_INVALID_PARAMETER;
464 goto Quickie;
465 }
466
467 LastOffset = (BlockDevice->LastBlock * BlockDevice->BlockSize) + BlockDevice->BlockSize - 1;
468
469 MaxOffset = BlockDevice->LastBlock;
470 if (MaxOffset < BlockDevice->BlockSize)
471 {
472 MaxOffset = BlockDevice->BlockSize;
473 }
474
475 if (LastOffset < MaxOffset)
476 {
477
478 Status = STATUS_INVALID_PARAMETER;
479 goto Quickie;
480 }
481
482 if (Offset > LastOffset)
483 {
484 Status = STATUS_INVALID_PARAMETER;
485 goto Quickie;
486 }
487
488 RemainingOffset = LastOffset - Offset + 1;
489
490 if (DesiredSize != FALSE)
491 {
492 RealSize = *DesiredSize;
493 }
494 else
495 {
496 RealSize = ULONG_MAX;
497 }
498
499 if (RemainingOffset < RealSize)
500 {
501 if (Size == FALSE)
502 {
503 RealSize = 0;
504 Status = STATUS_INVALID_PARAMETER;
505 goto Quickie;
506 }
507
508 RealSize = RemainingOffset;
509 }
510
511 Status = STATUS_SUCCESS;
512
513 Quickie:
514 if (Size)
515 {
516 *Size = RealSize;
517 }
518
519 return Status;
520 }
521
522 NTSTATUS
523 BlockIoRead (
524 _In_ PBL_DEVICE_ENTRY DeviceEntry,
525 _In_ PVOID Buffer,
526 _In_ ULONG Size,
527 _Out_ PULONG BytesRead
528 )
529 {
530 PBL_BLOCK_DEVICE BlockDevice;
531 NTSTATUS Status;
532
533 /* Get the device-specific data, which is our block device descriptor */
534 BlockDevice = DeviceEntry->DeviceSpecificData;
535
536 /* Make sure that the buffer and size is valid */
537 Status = BlockIopBlockInformationCheck(BlockDevice, &Size, BytesRead, &Size);
538 if (NT_SUCCESS(Status))
539 {
540 /* Check if this is a virtual device or a physical device */
541 if (BlockDevice->DeviceFlags & BL_BLOCK_DEVICE_VIRTUAL_FLAG)
542 {
543 /* Do a virtual read or write */
544 Status = BlockIopReadWriteVirtualDevice(DeviceEntry, Buffer, Size, 0, BytesRead);
545 }
546 else
547 {
548 /* Do a physical read or write */
549 Status = BlockIopReadPhysicalDevice(DeviceEntry, Buffer, Size, BytesRead);
550 }
551 }
552 else if (BytesRead)
553 {
554 /* We failed, if the caller wanted bytes read, return 0 */
555 *BytesRead = 0;
556 }
557
558 /* Return back to the caller */
559 return Status;
560 }
561
562 NTSTATUS
563 BlockIoSetInformation (
564 _In_ PBL_DEVICE_ENTRY DeviceEntry,
565 _Out_ PBL_DEVICE_INFORMATION DeviceInformation
566 )
567 {
568 PBL_BLOCK_DEVICE BlockDevice;
569 ULONGLONG Offset;
570
571 BlockDevice = DeviceEntry->DeviceSpecificData;
572
573 /* Take the current block number and block-offset and conver to full offset */
574 Offset = DeviceInformation->BlockDeviceInfo.Block * BlockDevice->BlockSize +
575 DeviceInformation->BlockDeviceInfo.Offset;
576
577 /* Make sure that the full offset is still within the bounds of the device */
578 if (Offset > ((BlockDevice->LastBlock + 1) * BlockDevice->BlockSize - 1))
579 {
580 EfiPrintf(L"Offset out of bounds\r\n");
581 return STATUS_INVALID_PARAMETER;
582 }
583
584 /* Convery the full raw offset into a block number and block-offset */
585 BlockDevice->Block = Offset / BlockDevice->BlockSize;
586 BlockDevice->Offset = Offset % BlockDevice->BlockSize;
587
588 /* Return the unknown */
589 BlockDevice->Unknown = DeviceInformation->BlockDeviceInfo.Unknown;
590
591 /* All done */
592 return STATUS_SUCCESS;
593 }
594
595 NTSTATUS
596 BlockIoGetInformation (
597 _In_ PBL_DEVICE_ENTRY DeviceEntry,
598 _Out_ PBL_DEVICE_INFORMATION DeviceInformation
599 )
600 {
601 /* Copy the device specific data into the block device information */
602 RtlCopyMemory(&DeviceInformation->BlockDeviceInfo,
603 DeviceEntry->DeviceSpecificData,
604 sizeof(DeviceInformation->BlockDeviceInfo));
605
606 /* Hardcode the device type */
607 DeviceInformation->DeviceType = DiskDevice;
608 return STATUS_SUCCESS;
609 }
610
611 NTSTATUS
612 BlDeviceSetInformation (
613 _In_ ULONG DeviceId,
614 _Out_ PBL_DEVICE_INFORMATION DeviceInformation
615 )
616 {
617 PBL_DEVICE_ENTRY DeviceEntry;
618
619 /* This parameter is not optional */
620 if (!DeviceInformation)
621 {
622 return STATUS_INVALID_PARAMETER;
623 }
624
625 /* Make sure the device ID is valid */
626 if (DmTableEntries <= DeviceId)
627 {
628 return STATUS_INVALID_PARAMETER;
629 }
630
631 /* Get the device entry */
632 DeviceEntry = DmDeviceTable[DeviceId];
633 if (!DeviceEntry)
634 {
635 return STATUS_INVALID_PARAMETER;
636 }
637
638 /* Make sure the device is open */
639 if (!(DeviceEntry->Flags & BL_DEVICE_ENTRY_OPENED))
640 {
641 return STATUS_INVALID_PARAMETER;
642 }
643
644 /* Set the device information */
645 return DeviceEntry->Callbacks.SetInformation(DeviceEntry, DeviceInformation);
646 }
647
648 NTSTATUS
649 BlDeviceGetInformation (
650 _In_ ULONG DeviceId,
651 _Out_ PBL_DEVICE_INFORMATION DeviceInformation
652 )
653 {
654 PBL_DEVICE_ENTRY DeviceEntry;
655
656 /* This parameter is not optional */
657 if (!DeviceInformation)
658 {
659 return STATUS_INVALID_PARAMETER;
660 }
661
662 /* Make sure the device ID is valid */
663 if (DmTableEntries <= DeviceId)
664 {
665 return STATUS_INVALID_PARAMETER;
666 }
667
668 /* Get the device entry */
669 DeviceEntry = DmDeviceTable[DeviceId];
670 if (!DeviceEntry)
671 {
672 return STATUS_INVALID_PARAMETER;
673 }
674
675 /* Make sure the device is open */
676 if (!(DeviceEntry->Flags & BL_DEVICE_ENTRY_OPENED))
677 {
678 return STATUS_INVALID_PARAMETER;
679 }
680
681 /* Return the device information */
682 DeviceInformation->DeviceType = DeviceEntry->DeviceDescriptor->DeviceType;
683 return DeviceEntry->Callbacks.GetInformation(DeviceEntry, DeviceInformation);
684 }
685
686 NTSTATUS
687 BlDeviceRead (
688 _In_ ULONG DeviceId,
689 _In_ PVOID Buffer,
690 _In_ ULONG Size,
691 _Out_opt_ PULONG BytesRead
692 )
693 {
694 PBL_DEVICE_ENTRY DeviceEntry;
695 NTSTATUS Status;
696 ULONG BytesTransferred;
697
698 /* Make sure we have a buffer, and the device ID is valid */
699 if (!(Buffer) || (DmTableEntries <= DeviceId))
700 {
701 return STATUS_INVALID_PARAMETER;
702 }
703
704 /* Get the device entry for it */
705 DeviceEntry = DmDeviceTable[DeviceId];
706 if (!DeviceEntry)
707 {
708 return STATUS_INVALID_PARAMETER;
709 }
710
711 /* Make sure this is a device opened for read access */
712 if (!(DeviceEntry->Flags & BL_DEVICE_ENTRY_OPENED) ||
713 !(DeviceEntry->Flags & BL_DEVICE_ENTRY_READ_ACCESS))
714 {
715 return STATUS_INVALID_PARAMETER;
716 }
717
718 /* Issue the read */
719 Status = DeviceEntry->Callbacks.Read(DeviceEntry,
720 Buffer,
721 Size,
722 &BytesTransferred);
723 if (!DeviceEntry->Unknown)
724 {
725 /* Update performance counters */
726 DmDeviceIoInformation.ReadCount += BytesTransferred;
727 }
728
729 /* Return back how many bytes were read, if caller wants to know */
730 if (BytesRead)
731 {
732 *BytesRead = BytesTransferred;
733 }
734
735 /* Return read result */
736 return Status;
737 }
738
739 NTSTATUS
740 BlDeviceReadAtOffset (
741 _In_ ULONG DeviceId,
742 _In_ ULONG Size,
743 _In_ ULONGLONG Offset,
744 _In_ PVOID Buffer,
745 _Out_ PULONG BytesRead
746 )
747 {
748 NTSTATUS Status;
749 BL_DEVICE_INFORMATION DeviceInfo;
750
751 /* Get the current block and offset */
752 Status = BlDeviceGetInformation(DeviceId, &DeviceInfo);
753 if (!NT_SUCCESS(Status))
754 {
755 return Status;
756 }
757
758 /* Get the block and block-offset based on the new raw offset */
759 DeviceInfo.BlockDeviceInfo.Block = Offset / DeviceInfo.BlockDeviceInfo.BlockSize;
760 DeviceInfo.BlockDeviceInfo.Offset = Offset % DeviceInfo.BlockDeviceInfo.BlockSize;
761
762 /* Update the block and offset */
763 Status = BlDeviceSetInformation(DeviceId, &DeviceInfo);
764 if (NT_SUCCESS(Status))
765 {
766 /* Now issue a read, with this block and offset configured */
767 Status = BlDeviceRead(DeviceId, Buffer, Size, BytesRead);
768 }
769
770 /* All good, return the caller */
771 return Status;
772 }
773
774 BOOLEAN
775 BlpDeviceCompare (
776 _In_ PBL_DEVICE_DESCRIPTOR Device1,
777 _In_ PBL_DEVICE_DESCRIPTOR Device2
778 )
779 {
780 BOOLEAN DeviceMatch;
781 ULONG DeviceSize;
782
783 /* Assume failure */
784 DeviceMatch = FALSE;
785
786 /* Check if the two devices exist and are identical in type */
787 if ((Device1) && (Device2) && (Device1->DeviceType == Device2->DeviceType))
788 {
789 /* Take the bigger of the two sizes */
790 DeviceSize = max(Device1->Size, Device2->Size);
791 if (DeviceSize >= (ULONG)FIELD_OFFSET(BL_DEVICE_DESCRIPTOR, Local))
792 {
793 /* Compare the two devices up to their size */
794 if (RtlEqualMemory(&Device1->Local,
795 &Device2->Local,
796 DeviceSize - FIELD_OFFSET(BL_DEVICE_DESCRIPTOR, Local)))
797 {
798 /* They match! */
799 DeviceMatch = TRUE;
800 }
801 }
802 }
803
804 /* Return matching state */
805 return DeviceMatch;
806 }
807
808 NTSTATUS
809 BlockIopFreeAllocations (
810 _In_ PBL_BLOCK_DEVICE BlockDevice
811 )
812 {
813 /* If a block device was passed in, free it */
814 if (BlockDevice)
815 {
816 BlMmFreeHeap(BlockDevice);
817 }
818
819 /* Nothing else to do */
820 return STATUS_SUCCESS;
821 }
822
823 NTSTATUS
824 BlockIoEfiGetBlockIoInformation (
825 _In_ PBL_BLOCK_DEVICE BlockDevice
826 )
827 {
828 NTSTATUS Status;
829 EFI_BLOCK_IO_MEDIA *Media;
830
831 /* Open the Block I/O protocol on this device */
832 Status = EfiOpenProtocol(BlockDevice->Handle,
833 &EfiBlockIoProtocol,
834 (PVOID*)&BlockDevice->Protocol);
835 if (!NT_SUCCESS(Status))
836 {
837 return Status;
838 }
839
840 /* Get information on the block media */
841 Media = BlockDevice->Protocol->Media;
842
843 /* Set the appropriate device flags */
844 BlockDevice->DeviceFlags = 0;
845 if (Media->RemovableMedia)
846 {
847 BlockDevice->DeviceFlags = BL_BLOCK_DEVICE_REMOVABLE_FLAG;
848 }
849 if (Media->MediaPresent)
850 {
851 BlockDevice->DeviceFlags |= BL_BLOCK_DEVICE_PRESENT_FLAG;
852 }
853
854 /* No clue */
855 BlockDevice->Unknown = 0;
856
857 /* Set the block size */
858 BlockDevice->BlockSize = Media->BlockSize;
859
860 /* Make sure there's a last block value */
861 if (!Media->LastBlock)
862 {
863 return STATUS_INVALID_PARAMETER;
864 }
865
866 /* Don't let it be too high */
867 if (Media->LastBlock > 0xFFFFFFFFFFE)
868 {
869 BlockDevice->LastBlock = 0xFFFFFFFFFFE;
870 }
871 else
872 {
873 BlockDevice->LastBlock = Media->LastBlock;
874 }
875
876 /* Make the alignment the smaller of the I/O alignment or the block size */
877 if (Media->IoAlign >= Media->BlockSize)
878 {
879 BlockDevice->Alignment = Media->IoAlign;
880 }
881 else
882 {
883 BlockDevice->Alignment = Media->BlockSize;
884 }
885
886 /* All good */
887 return STATUS_SUCCESS;
888 }
889
890 NTSTATUS
891 BlockIoEfiGetChildHandle (
892 _In_ PBL_PROTOCOL_HANDLE ProtocolInterface,
893 _In_ PBL_PROTOCOL_HANDLE ChildProtocolInterface)
894 {
895 NTSTATUS Status;
896 ULONG i, DeviceCount;
897 EFI_DEVICE_PATH *DevicePath, *ParentDevicePath;
898 EFI_HANDLE *DeviceHandles;
899 EFI_HANDLE Handle;
900
901 /* Find all the Block I/O device handles on the system */
902 DeviceCount = 0;
903 DeviceHandles = 0;
904 Status = EfiLocateHandleBuffer(ByProtocol,
905 &EfiBlockIoProtocol,
906 &DeviceCount,
907 &DeviceHandles);
908 if (!NT_SUCCESS(Status))
909 {
910 /* Failed to enumerate, bail out */
911 return Status;
912 }
913
914 /* Loop all the handles */
915 for (i = 0; i < DeviceCount; i++)
916 {
917 /* Check if this is the device itself */
918 Handle = DeviceHandles[i];
919 if (Handle == ProtocolInterface->Handle)
920 {
921 /* Skip it */
922 continue;
923 }
924
925 /* Get the device path of this device */
926 Status = EfiOpenProtocol(Handle,
927 &EfiDevicePathProtocol,
928 (PVOID*)&DevicePath);
929 if (!NT_SUCCESS(Status))
930 {
931 /* We failed, skip it */
932 continue;
933 }
934
935 /* See if we are its parent */
936 ParentDevicePath = EfiIsDevicePathParent(ProtocolInterface->Interface,
937 DevicePath);
938 if (ParentDevicePath == ProtocolInterface->Interface)
939 {
940 /* Yup, return back to caller */
941 ChildProtocolInterface->Handle = Handle;
942 ChildProtocolInterface->Interface = DevicePath;
943 Status = STATUS_SUCCESS;
944 goto Quickie;
945 }
946
947 /* Close the device path */
948 EfiCloseProtocol(Handle, &EfiDevicePathProtocol);
949 }
950
951 /* If we got here, nothing was found */
952 Status = STATUS_NO_SUCH_DEVICE;
953
954 Quickie:
955 /* Free the handle array buffer */
956 BlMmFreeHeap(DeviceHandles);
957 return Status;
958 }
959
960 NTSTATUS
961 BlockIoGetGPTDiskSignature (
962 _In_ PBL_DEVICE_ENTRY DeviceEntry,
963 _Out_ PGUID DiskSignature
964 )
965 {
966 EfiPrintf(L"GPT not supported\r\n");
967 return STATUS_NOT_IMPLEMENTED;
968 }
969
970 NTSTATUS
971 BlockIoEfiGetDeviceInformation (
972 _In_ PBL_DEVICE_ENTRY DeviceEntry
973 )
974 {
975 NTSTATUS Status;
976 PBL_DEVICE_DESCRIPTOR Device;
977 PBL_BLOCK_DEVICE BlockDevice;
978 EFI_DEVICE_PATH *LeafNode;
979 BL_PROTOCOL_HANDLE Protocol[2];
980 ACPI_HID_DEVICE_PATH *AcpiPath;
981 HARDDRIVE_DEVICE_PATH *DiskPath;
982 BOOLEAN Found;
983 ULONG i;
984
985 /* Extract the identifier, and the block device object */
986 Device = DeviceEntry->DeviceDescriptor;
987 BlockDevice = (PBL_BLOCK_DEVICE)DeviceEntry->DeviceSpecificData;
988
989 /* Initialize protocol handles */
990 Protocol[0].Handle = BlockDevice->Handle;
991 Protocol[1].Handle = 0;
992
993 /* Open this device */
994 Status = EfiOpenProtocol(Protocol[0].Handle,
995 &EfiDevicePathProtocol,
996 &Protocol[0].Interface);
997 if (!NT_SUCCESS(Status))
998 {
999 /* Fail */
1000 return Status;
1001 }
1002
1003 /* Iterate twice -- once for the top level, once for the bottom */
1004 for (i = 0, Found = FALSE; Found == FALSE && Protocol[i].Handle; i++)
1005 {
1006 /* Check what kind of leaf node device this is */
1007 LeafNode = EfiGetLeafNode(Protocol[i].Interface);
1008 EfiPrintf(L"Pass %d, Leaf node: %p Type: %d\r\n", i, LeafNode, LeafNode->Type);
1009 if (LeafNode->Type == ACPI_DEVICE_PATH)
1010 {
1011 /* We only support floppy drives */
1012 AcpiPath = (ACPI_HID_DEVICE_PATH*)LeafNode;
1013 if ((AcpiPath->HID == EISA_PNP_ID(0x604)) ||
1014 (AcpiPath->HID == EISA_PNP_ID(0x700)))
1015 {
1016 /* Set the boot library specific device types */
1017 Device->DeviceType = LocalDevice;
1018 Device->Local.Type = FloppyDevice;
1019
1020 /* The ACPI UID is the drive number */
1021 Device->Local.FloppyDisk.DriveNumber = AcpiPath->UID;
1022
1023 /* We found a match */
1024 Found = TRUE;
1025 }
1026 }
1027 else if ((LeafNode->Type == MEDIA_DEVICE_PATH) && (i == 1))
1028 {
1029 /* Extract the disk path and check if it's a physical disk */
1030 DiskPath = (HARDDRIVE_DEVICE_PATH*)LeafNode;
1031 EfiPrintf(L"Disk path: %p Type: %lx\r\n", DiskPath, LeafNode->SubType);
1032 if (LeafNode->SubType == MEDIA_HARDDRIVE_DP)
1033 {
1034 /* Set this as a local device */
1035 Device->Local.Type = LocalDevice;
1036
1037 /* Check if this is an MBR partition */
1038 if (DiskPath->SignatureType == SIGNATURE_TYPE_MBR)
1039 {
1040 /* Set that this is a local partition */
1041 Device->DeviceType = LegacyPartitionDevice;
1042 Device->Partition.Disk.Type = LocalDevice;
1043
1044 /* Write the MBR partition signature */
1045 BlockDevice->PartitionType = MbrPartition;
1046 BlockDevice->Disk.Mbr.Signature = *(PULONG)&DiskPath->Signature[0];
1047 Found = TRUE;
1048 }
1049 else if (DiskPath->SignatureType == SIGNATURE_TYPE_GUID)
1050 {
1051 /* Set this as a GPT partition */
1052 BlockDevice->PartitionType = GptPartition;
1053 Device->Local.HardDisk.PartitionType = GptPartition;
1054
1055 /* Get the GPT signature */
1056 Status = BlockIoGetGPTDiskSignature(DeviceEntry,
1057 &Device->Local.HardDisk.Gpt.PartitionSignature);
1058 if (NT_SUCCESS(Status))
1059 {
1060 /* Copy it */
1061 RtlCopyMemory(&BlockDevice->Disk.Gpt.Signature,
1062 &Device->Local.HardDisk.Gpt.PartitionSignature,
1063 sizeof(BlockDevice->Disk.Gpt.Signature));
1064 Found = TRUE;
1065 }
1066 }
1067
1068 /* Otherwise, this is a raw disk */
1069 BlockDevice->PartitionType = RawPartition;
1070 Device->Local.HardDisk.PartitionType = RawPartition;
1071 Device->Local.HardDisk.Raw.DiskNumber = BlockIoFirmwareRawDiskCount++;
1072 }
1073 else if (LeafNode->SubType == MEDIA_CDROM_DP)
1074 {
1075 /* Set block device information */
1076 EfiPrintf(L"Found CD-ROM\r\n");
1077 BlockDevice->PartitionType = RawPartition;
1078 BlockDevice->Type = CdRomDevice;
1079
1080 /* Set CDROM data */
1081 Device->Local.Type = CdRomDevice;
1082 Device->Local.FloppyDisk.DriveNumber = 0;
1083 Found = TRUE;
1084 }
1085 }
1086 else if ((LeafNode->Type != MEDIA_DEVICE_PATH) &&
1087 (LeafNode->Type != ACPI_DEVICE_PATH) &&
1088 (i == 0))
1089 {
1090 /* This is probably a messaging device node. Are we under it? */
1091 Status = BlockIoEfiGetChildHandle(Protocol, &Protocol[1]);
1092 EfiPrintf(L"Pass 0, non DP/ACPI path. Child handle obtained: %lx\r\n", Protocol[1].Handle);
1093 if (!NT_SUCCESS(Status))
1094 {
1095 /* We're not. So this must be a raw device */
1096 Device->DeviceType = LocalDevice;
1097 Found = TRUE;
1098
1099 /* Is it a removable raw device? */
1100 if (BlockDevice->DeviceFlags & BL_BLOCK_DEVICE_REMOVABLE_FLAG)
1101 {
1102 /* This is a removable (CD or Floppy or USB) device */
1103 BlockDevice->Type = FloppyDevice;
1104 Device->Local.Type = FloppyDevice;
1105 Device->Local.FloppyDisk.DriveNumber = BlockIoFirmwareRemovableDiskCount++;
1106 EfiPrintf(L"Found Floppy\r\n");
1107 }
1108 else
1109 {
1110 /* It's a fixed device */
1111 BlockDevice->Type = DiskDevice;
1112 Device->Local.Type = DiskDevice;
1113
1114 /* Set it as a raw partition */
1115 Device->Local.HardDisk.PartitionType = RawPartition;
1116 Device->Local.HardDisk.Mbr.PartitionSignature = BlockIoFirmwareRawDiskCount++;
1117 EfiPrintf(L"Found raw disk\r\n");
1118 }
1119 }
1120 }
1121 }
1122
1123 /* Close any protocols that we opened for each handle */
1124 while (i)
1125 {
1126 EfiCloseProtocol(Protocol[--i].Handle, &EfiDevicePathProtocol);
1127 }
1128
1129 /* Return appropriate status */
1130 return Found ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED;
1131 }
1132
1133 NTSTATUS
1134 BlockIoEfiReset (
1135 VOID
1136 )
1137 {
1138 EfiPrintf(L"not implemented\r\n");
1139 return STATUS_NOT_IMPLEMENTED;
1140 }
1141
1142 NTSTATUS
1143 BlockIoEfiFlush (
1144 VOID
1145 )
1146 {
1147 EfiPrintf(L"not implemented\r\n");
1148 return STATUS_NOT_IMPLEMENTED;
1149 }
1150
1151 NTSTATUS
1152 BlockIoEfiCreateDeviceEntry (
1153 _In_ PBL_DEVICE_ENTRY *DeviceEntry,
1154 _Out_ PVOID Handle
1155 )
1156 {
1157 PBL_DEVICE_ENTRY IoDeviceEntry;
1158 PBL_BLOCK_DEVICE BlockDevice;
1159 NTSTATUS Status;
1160 PBL_DEVICE_DESCRIPTOR Device;
1161
1162 /* Allocate the entry for this device and zero it out */
1163 IoDeviceEntry = BlMmAllocateHeap(sizeof(*IoDeviceEntry));
1164 if (!IoDeviceEntry)
1165 {
1166 return STATUS_NO_MEMORY;
1167 }
1168 RtlZeroMemory(IoDeviceEntry, sizeof(*IoDeviceEntry));
1169
1170 /* Allocate the device descriptor for this device and zero it out */
1171 Device = BlMmAllocateHeap(sizeof(*Device));
1172 if (!Device)
1173 {
1174 return STATUS_NO_MEMORY;
1175 }
1176 RtlZeroMemory(Device, sizeof(*Device));
1177
1178 /* Allocate the block device specific data, and zero it out */
1179 BlockDevice = BlMmAllocateHeap(sizeof(*BlockDevice));
1180 if (!BlockDevice)
1181 {
1182 return STATUS_NO_MEMORY;
1183 }
1184 RtlZeroMemory(BlockDevice, sizeof(*BlockDevice));
1185
1186 /* Save the descriptor and block device specific data */
1187 IoDeviceEntry->DeviceSpecificData = BlockDevice;
1188 IoDeviceEntry->DeviceDescriptor = Device;
1189
1190 /* Set the size of the descriptor */
1191 Device->Size = sizeof(*Device);
1192
1193 /* Copy the standard I/O callbacks */
1194 RtlCopyMemory(&IoDeviceEntry->Callbacks,
1195 &BlockIoDeviceFunctionTable,
1196 sizeof(IoDeviceEntry->Callbacks));
1197
1198 /* Add the two that are firmware specific */
1199 IoDeviceEntry->Callbacks.Reset = BlockIoEfiReset;
1200 IoDeviceEntry->Callbacks.Flush = BlockIoEfiFlush;
1201
1202 /* Save the EFI handle */
1203 BlockDevice->Handle = Handle;
1204
1205 /* Get information on this device from EFI, caching it in the device */
1206 Status = BlockIoEfiGetBlockIoInformation(BlockDevice);
1207 if (NT_SUCCESS(Status))
1208 {
1209 /* Build the descriptor structure for this device */
1210 Status = BlockIoEfiGetDeviceInformation(IoDeviceEntry);
1211 if (NT_SUCCESS(Status))
1212 {
1213 /* We have a fully constructed device, return it */
1214 *DeviceEntry = IoDeviceEntry;
1215 return STATUS_SUCCESS;
1216 }
1217 }
1218
1219 /* Failure path, free the descriptor if we allocated one */
1220 if (IoDeviceEntry->DeviceDescriptor)
1221 {
1222 BlMmFreeHeap(IoDeviceEntry->DeviceDescriptor);
1223 }
1224
1225 /* Free any other specific allocations */
1226 BlockIopFreeAllocations(IoDeviceEntry->DeviceSpecificData);
1227
1228 /* Free the device entry itself and return the failure code */
1229 BlMmFreeHeap(IoDeviceEntry);
1230 EfiPrintf(L"Failed: %lx\r\n", Status);
1231 return Status;
1232 }
1233
1234 NTSTATUS
1235 BlockIoEfiCompareDevice (
1236 _In_ PBL_DEVICE_DESCRIPTOR Device,
1237 _In_ EFI_HANDLE Handle
1238 )
1239 {
1240 PBL_LOCAL_DEVICE LocalDeviceInfo, EfiLocalDeviceInfo;
1241 PBL_DEVICE_ENTRY DeviceEntry;
1242 PBL_DEVICE_DESCRIPTOR EfiDevice;
1243 NTSTATUS Status;
1244
1245 DeviceEntry = NULL;
1246
1247 /* Check if no device was given */
1248 if (!Device)
1249 {
1250 /* Fail the comparison */
1251 Status = STATUS_INVALID_PARAMETER;
1252 goto Quickie;
1253 }
1254
1255 /* Check if this is a local disk device */
1256 if (Device->DeviceType != DiskDevice)
1257 {
1258 /* Nope -- is it a partition device? */
1259 if ((Device->DeviceType != LegacyPartitionDevice) &&
1260 (Device->DeviceType != PartitionDevice))
1261 {
1262 /* Nope, so we can't compare */
1263 Status = STATUS_INVALID_PARAMETER;
1264 goto Quickie;
1265 }
1266
1267 /* If so, return the device information for the parent disk */
1268 LocalDeviceInfo = &Device->Partition.Disk;
1269 }
1270 else
1271 {
1272 /* Just return the disk information itself */
1273 LocalDeviceInfo = &Device->Local;
1274 }
1275
1276 /* Create an EFI device entry for the EFI device handle */
1277 Status = BlockIoEfiCreateDeviceEntry(&DeviceEntry, Handle);
1278 if (!NT_SUCCESS(Status))
1279 {
1280 goto Quickie;
1281 }
1282
1283 /* Read the descriptor and assume failure for now */
1284 EfiDevice = DeviceEntry->DeviceDescriptor;
1285 Status = STATUS_UNSUCCESSFUL;
1286
1287 /* Check if the EFI device is a disk */
1288 if (EfiDevice->DeviceType != DiskDevice)
1289 {
1290 /* Nope, is it a partition? */
1291 if ((EfiDevice->DeviceType != LegacyPartitionDevice) &&
1292 (EfiDevice->DeviceType != PartitionDevice))
1293 {
1294 /* Neither, invalid handle so bail out */
1295 Status = STATUS_INVALID_PARAMETER;
1296 goto Quickie;
1297 }
1298
1299 /* Yes, so get the information of the parent disk */
1300 EfiLocalDeviceInfo = &EfiDevice->Partition.Disk;
1301 }
1302 else
1303 {
1304 /* It's a disk, so get the disk information itself */
1305 EfiLocalDeviceInfo = &EfiDevice->Local;
1306 }
1307
1308 /* Are the two devices the same type? */
1309 if (EfiLocalDeviceInfo->Type != LocalDeviceInfo->Type)
1310 {
1311 /* Nope, that was easy */
1312 goto Quickie;
1313 }
1314
1315 /* Yes, what kind of device is the EFI side? */
1316 switch (EfiLocalDeviceInfo->Type)
1317 {
1318 case LocalDevice:
1319
1320 /* Local hard drive, compare the signature */
1321 if (RtlCompareMemory(&EfiLocalDeviceInfo->HardDisk,
1322 &LocalDeviceInfo->HardDisk,
1323 sizeof(LocalDeviceInfo->HardDisk)) ==
1324 sizeof(LocalDeviceInfo->HardDisk))
1325 {
1326 Status = STATUS_SUCCESS;
1327 }
1328 break;
1329
1330 case FloppyDevice:
1331 case CdRomDevice:
1332
1333 /* Removable floppy or CD, compare the disk number */
1334 if (RtlCompareMemory(&EfiLocalDeviceInfo->FloppyDisk,
1335 &LocalDeviceInfo->FloppyDisk,
1336 sizeof(LocalDeviceInfo->FloppyDisk)) ==
1337 sizeof(LocalDeviceInfo->FloppyDisk))
1338 {
1339 Status = STATUS_SUCCESS;
1340 }
1341 break;
1342
1343 case RamDiskDevice:
1344
1345 /* RAM disk, compare the size and base information */
1346 if (RtlCompareMemory(&EfiLocalDeviceInfo->RamDisk,
1347 &LocalDeviceInfo->RamDisk,
1348 sizeof(LocalDeviceInfo->RamDisk)) ==
1349 sizeof(LocalDeviceInfo->RamDisk))
1350 {
1351 Status = STATUS_SUCCESS;
1352 }
1353 break;
1354
1355 case FileDevice:
1356
1357 /* File, compare the file identifier */
1358 if (RtlCompareMemory(&EfiLocalDeviceInfo->File,
1359 &LocalDeviceInfo->File,
1360 sizeof(LocalDeviceInfo->File)) ==
1361 sizeof(LocalDeviceInfo->File))
1362 {
1363 Status = STATUS_SUCCESS;
1364 }
1365 break;
1366
1367 /* Something else we don't support */
1368 default:
1369 break;
1370 }
1371
1372 Quickie:
1373 /* All done, did we have an EFI device entry? */
1374 if (DeviceEntry)
1375 {
1376 /* Free it, since we only needed it locally for comparison */
1377 BlMmFreeHeap(DeviceEntry->DeviceDescriptor);
1378 BlockIopFreeAllocations(DeviceEntry->DeviceSpecificData);
1379 BlMmFreeHeap(DeviceEntry);
1380 }
1381
1382 /* Return back to the caller */
1383 return Status;
1384 }
1385
1386 NTSTATUS
1387 BlockIoFirmwareOpen (
1388 _In_ PBL_DEVICE_DESCRIPTOR Device,
1389 _In_ PBL_BLOCK_DEVICE BlockIoDevice
1390 )
1391 {
1392 NTSTATUS Status;
1393 BOOLEAN DeviceMatch;
1394 BL_HASH_ENTRY HashEntry;
1395 ULONG i, Id, DeviceCount;
1396 PBL_DEVICE_ENTRY DeviceEntry;
1397 EFI_HANDLE* DeviceHandles;
1398
1399 /* Initialize everything */
1400 DeviceEntry = NULL;
1401 DeviceCount = 0;
1402 DeviceHandles = 0;
1403 DeviceEntry = NULL;
1404
1405 /* Ask EFI for handles to all block devices */
1406 Status = EfiLocateHandleBuffer(ByProtocol,
1407 &EfiBlockIoProtocol,
1408 &DeviceCount,
1409 &DeviceHandles);
1410 if (!NT_SUCCESS(Status))
1411 {
1412 return STATUS_NO_SUCH_DEVICE;
1413 }
1414
1415 /* Build a hash entry, with the value inline */
1416 HashEntry.Flags = BL_HT_VALUE_IS_INLINE;
1417 HashEntry.Size = sizeof(EFI_HANDLE);
1418
1419 /* Loop each device we got */
1420 DeviceMatch = FALSE;
1421 Status = STATUS_NO_SUCH_DEVICE;
1422 for (i = 0; i < DeviceCount; i++)
1423 {
1424 /* Check if we have a match in the device hash table */
1425 HashEntry.Value = DeviceHandles[i];
1426 Status = BlHtLookup(HashTableId, &HashEntry, 0);
1427 if (NT_SUCCESS(Status))
1428 {
1429 /* We already know about this device */
1430 EfiPrintf(L"Device is known\r\n");
1431 continue;
1432 }
1433
1434 /* New device, store it in the hash table */
1435 Status = BlHtStore(HashTableId,
1436 &HashEntry,
1437 DeviceHandles[i],
1438 sizeof(DeviceHandles[i]));
1439 if (!NT_SUCCESS(Status))
1440 {
1441 /* Free the array and fail */
1442 BlMmFreeHeap(DeviceHandles);
1443 break;
1444 }
1445
1446 /* Create an entry for this device*/
1447 Status = BlockIoEfiCreateDeviceEntry(&DeviceEntry, DeviceHandles[i]);
1448 if (!NT_SUCCESS(Status))
1449 {
1450 EfiPrintf(L"EFI create failed: %lx\r\n", Status);
1451 continue;
1452 }
1453
1454 /* Add the device entry to the device table */
1455 Status = BlTblSetEntry(&BlockIoDeviceTable,
1456 &BlockIoDeviceTableEntries,
1457 DeviceEntry,
1458 &Id,
1459 TblDoNotPurgeEntry);
1460 if (!NT_SUCCESS(Status))
1461 {
1462 /* Remove it from teh hash table */
1463 BlHtDelete(HashTableId, &HashEntry);
1464
1465 /* Free the block I/O device data */
1466 BlockIopFreeAllocations(DeviceEntry->DeviceSpecificData);
1467
1468 /* Free the descriptor */
1469 BlMmFreeHeap(DeviceEntry->DeviceDescriptor);
1470
1471 /* Free the entry */
1472 BlMmFreeHeap(DeviceEntry);
1473 break;
1474 }
1475
1476 /* Does this device match what we're looking for? */
1477 DeviceMatch = BlpDeviceCompare(DeviceEntry->DeviceDescriptor, Device);
1478 if (DeviceMatch)
1479 {
1480 /* Yep, return the data back */
1481 RtlCopyMemory(BlockIoDevice,
1482 DeviceEntry->DeviceSpecificData,
1483 sizeof(*BlockIoDevice));
1484 Status = STATUS_SUCCESS;
1485 break;
1486 }
1487 }
1488
1489 /* Free the device handle buffer array */
1490 BlMmFreeHeap(DeviceHandles);
1491
1492 /* Return status */
1493 return Status;
1494 }
1495
1496 NTSTATUS
1497 PartitionOpen (
1498 _In_ PBL_DEVICE_DESCRIPTOR Device,
1499 _In_ PBL_DEVICE_ENTRY DeviceEntry
1500 )
1501 {
1502 EfiPrintf(L"Not implemented!\r\n");
1503 return STATUS_NOT_IMPLEMENTED;
1504 }
1505
1506 NTSTATUS
1507 VhdFileDeviceOpen (
1508 _In_ PBL_DEVICE_DESCRIPTOR Device,
1509 _In_ PBL_DEVICE_ENTRY DeviceEntry
1510 )
1511 {
1512 EfiPrintf(L"Not implemented!\r\n");
1513 return STATUS_NOT_IMPLEMENTED;
1514 }
1515
1516 NTSTATUS
1517 DiskClose (
1518 _In_ PBL_DEVICE_ENTRY DeviceEntry
1519 )
1520 {
1521 NTSTATUS Status, LocalStatus;
1522 PBL_BLOCK_DEVICE BlockDevice;
1523
1524 /* Assume success */
1525 Status = STATUS_SUCCESS;
1526 BlockDevice = DeviceEntry->DeviceSpecificData;
1527
1528 /* Close the protocol */
1529 LocalStatus = EfiCloseProtocol(BlockDevice->Handle, &EfiBlockIoProtocol);
1530 if (!NT_SUCCESS(LocalStatus))
1531 {
1532 /* Only inherit failures */
1533 Status = LocalStatus;
1534 }
1535
1536 /* Free the block device allocations */
1537 LocalStatus = BlockIopFreeAllocations(BlockDevice);
1538 if (!NT_SUCCESS(LocalStatus))
1539 {
1540 /* Only inherit failures */
1541 Status = LocalStatus;
1542 }
1543
1544 /* Return back to caller */
1545 return Status;
1546 }
1547
1548 NTSTATUS
1549 DiskOpen (
1550 _In_ PBL_DEVICE_DESCRIPTOR Device,
1551 _In_ PBL_DEVICE_ENTRY DeviceEntry
1552 )
1553 {
1554 NTSTATUS Status;
1555
1556 /* Use firmware-specific functions to open the disk */
1557 Status = BlockIoFirmwareOpen(Device, DeviceEntry->DeviceSpecificData);
1558 if (NT_SUCCESS(Status))
1559 {
1560 /* Overwrite with our own close routine */
1561 DeviceEntry->Callbacks.Close = DiskClose;
1562 }
1563
1564 /* Return back to caller */
1565 return Status;
1566 }
1567
1568 NTSTATUS
1569 RdDeviceOpen (
1570 _In_ PBL_DEVICE_DESCRIPTOR Device,
1571 _In_ PBL_DEVICE_ENTRY DeviceEntry
1572 )
1573 {
1574 EfiPrintf(L"Not implemented!\r\n");
1575 return STATUS_NOT_IMPLEMENTED;
1576 }
1577
1578 NTSTATUS
1579 FileDeviceOpen (
1580 _In_ PBL_DEVICE_DESCRIPTOR Device,
1581 _In_ PBL_DEVICE_ENTRY DeviceEntry
1582 )
1583 {
1584 EfiPrintf(L"Not implemented!\r\n");
1585 return STATUS_NOT_IMPLEMENTED;
1586 }
1587
1588 NTSTATUS
1589 SpOpen (
1590 _In_ PBL_DEVICE_DESCRIPTOR Device,
1591 _In_ PBL_DEVICE_ENTRY DeviceEntry
1592 )
1593 {
1594 EfiPrintf(L"Not implemented!\r\n");
1595 return STATUS_NOT_IMPLEMENTED;
1596 }
1597
1598 NTSTATUS
1599 UdpOpen (
1600 _In_ PBL_DEVICE_DESCRIPTOR Device,
1601 _In_ PBL_DEVICE_ENTRY DeviceEntry
1602 )
1603 {
1604 EfiPrintf(L"Not implemented!\r\n");
1605 return STATUS_NOT_IMPLEMENTED;
1606 }
1607
1608 BL_DEVICE_CALLBACKS FileDeviceFunctionTable =
1609 {
1610 NULL,
1611 FileDeviceOpen,
1612 NULL,
1613 };
1614
1615 BL_DEVICE_CALLBACKS PartitionDeviceFunctionTable =
1616 {
1617 NULL,
1618 PartitionOpen,
1619 NULL,
1620 };
1621
1622 BL_DEVICE_CALLBACKS RamDiskDeviceFunctionTable =
1623 {
1624 NULL,
1625 RdDeviceOpen,
1626 NULL,
1627 };
1628
1629 BL_DEVICE_CALLBACKS DiskDeviceFunctionTable =
1630 {
1631 NULL,
1632 DiskOpen,
1633 NULL,
1634 };
1635
1636 BL_DEVICE_CALLBACKS VirtualDiskDeviceFunctionTable =
1637 {
1638 NULL,
1639 VhdFileDeviceOpen,
1640 NULL,
1641 };
1642
1643 BL_DEVICE_CALLBACKS UdpFunctionTable =
1644 {
1645 NULL,
1646 UdpOpen,
1647 NULL,
1648 };
1649
1650 BL_DEVICE_CALLBACKS SerialPortFunctionTable =
1651 {
1652 NULL,
1653 SpOpen,
1654 NULL,
1655 };
1656
1657 BOOLEAN
1658 DeviceTableCompare (
1659 _In_ PVOID Entry,
1660 _In_ PVOID Argument1,
1661 _In_ PVOID Argument2,
1662 _Inout_ PVOID Argument3,
1663 _Inout_ PVOID Argument4
1664 )
1665 {
1666 BOOLEAN Found;
1667 PBL_DEVICE_DESCRIPTOR Device = (PBL_DEVICE_DESCRIPTOR)Argument1;
1668 PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry;
1669 ULONG Flags = *(PULONG)Argument2;
1670 ULONG Unknown = *(PULONG)Argument3;
1671
1672 /* Assume failure */
1673 Found = FALSE;
1674
1675 /* Compare the device descriptor */
1676 if (BlpDeviceCompare(DeviceEntry->DeviceDescriptor, Device))
1677 {
1678 /* Compare something */
1679 if (DeviceEntry->Unknown == Unknown)
1680 {
1681 /* Compare flags */
1682 if ((!(Flags & BL_DEVICE_READ_ACCESS) || (DeviceEntry->Flags & BL_DEVICE_ENTRY_READ_ACCESS)) &&
1683 (!(Flags & BL_DEVICE_WRITE_ACCESS) || (DeviceEntry->Flags & BL_DEVICE_ENTRY_WRITE_ACCESS)))
1684 {
1685 /* And more flags */
1686 if (((Flags & 8) || !(DeviceEntry->Flags & 8)) &&
1687 (!(Flags & 8) || (DeviceEntry->Flags & 8)))
1688 {
1689 /* Found a match! */
1690 Found = TRUE;
1691 }
1692 }
1693 }
1694 }
1695
1696 /* Return matching state */
1697 return Found;
1698 }
1699
1700 NTSTATUS
1701 DeviceTableDestroyEntry (
1702 _In_ PVOID Entry,
1703 _In_ ULONG DeviceId
1704 )
1705 {
1706 PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry;
1707 NTSTATUS Status;
1708
1709 /* Call the close routine for this entry */
1710 Status = DeviceEntry->Callbacks.Close(DmDeviceTable[DeviceId]);
1711
1712 /* Free the descriptor, and the device itself */
1713 BlMmFreeHeap(DeviceEntry->DeviceDescriptor);
1714 BlMmFreeHeap(DeviceEntry);
1715
1716 /* Clear out the netry, and return */
1717 DmDeviceTable[DeviceId] = NULL;
1718 return Status;
1719 }
1720
1721 NTSTATUS
1722 DeviceTablePurge (
1723 _In_ PVOID Entry
1724 )
1725 {
1726 PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry;
1727 NTSTATUS Status;
1728
1729 /* Check if the device is opened */
1730 if (DeviceEntry->Flags & BL_DEVICE_ENTRY_OPENED)
1731 {
1732 /* It is, so can't purge it */
1733 Status = STATUS_UNSUCCESSFUL;
1734 }
1735 else
1736 {
1737 /* It isn't, so destroy the entry */
1738 Status = DeviceTableDestroyEntry(DeviceEntry, DeviceEntry->DeviceId);
1739 }
1740
1741 /* Return back to caller */
1742 return Status;
1743 }
1744
1745 NTSTATUS
1746 BlockIoDeviceTableDestroyEntry (
1747 _In_ PVOID Entry,
1748 _In_ ULONG DeviceId
1749 )
1750 {
1751 PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry;
1752 NTSTATUS Status;
1753
1754 /* Call the close routine for this entry */
1755 Status = DeviceEntry->Callbacks.Close(DeviceEntry);
1756
1757 /* Free the descriptor, and the device itself */
1758 BlMmFreeHeap(DeviceEntry->DeviceDescriptor);
1759 BlMmFreeHeap(DeviceEntry);
1760
1761 /* Clear out the netry, and return */
1762 BlockIoDeviceTable[DeviceId] = NULL;
1763 return Status;
1764 }
1765
1766 NTSTATUS
1767 BlockIoDeviceTableDestroy (
1768 VOID
1769 )
1770 {
1771 NTSTATUS Status;
1772
1773 /* Call the entry destructor on each entry in the table */
1774 Status = BlTblMap(BlockIoDeviceTable,
1775 BlockIoDeviceTableEntries,
1776 BlockIoDeviceTableDestroyEntry);
1777
1778 /* Free the table and return */
1779 BlMmFreeHeap(BlockIoDeviceTable);
1780 return Status;
1781 }
1782
1783 NTSTATUS
1784 BlockIopDestroy (
1785 VOID
1786 )
1787 {
1788 /* Free the prefetch buffer */
1789 BlMmFreeHeap(BlockIopPrefetchBuffer);
1790
1791 /* Set state to non initialized */
1792 BlockIoInitialized = FALSE;
1793
1794 /* Return back */
1795 return STATUS_SUCCESS;
1796 }
1797
1798 ULONG
1799 BlockIoEfiHashFunction (
1800 _In_ PBL_HASH_ENTRY Entry,
1801 _In_ ULONG TableSize
1802 )
1803 {
1804 /* Get rid of the alignment bits to have a more unique number */
1805 return ((ULONG)Entry->Value >> 3) % TableSize;
1806 }
1807
1808 NTSTATUS
1809 BlockIopInitialize (
1810 VOID
1811 )
1812 {
1813 NTSTATUS Status;
1814
1815 /* Allocate the block device table and zero it out */
1816 BlockIoDeviceTableEntries = 8;
1817 BlockIoDeviceTable = BlMmAllocateHeap(sizeof(PVOID) *
1818 BlockIoDeviceTableEntries);
1819 if (!BlockIoDeviceTableEntries)
1820 {
1821 return STATUS_NO_MEMORY;
1822 }
1823 RtlZeroMemory(BlockIoDeviceTable, sizeof(PVOID) * BlockIoDeviceTableEntries);
1824
1825 /* Register our destructor */
1826 Status = BlpIoRegisterDestroyRoutine(BlockIoDeviceTableDestroy);
1827 if (!NT_SUCCESS(Status))
1828 {
1829 return Status;
1830 }
1831
1832 /* Initialize all counters */
1833 BlockIoFirmwareRemovableDiskCount = 0;
1834 BlockIoFirmwareRawDiskCount = 0;
1835 BlockIoFirmwareCdromCount = 0;
1836
1837 /* Initialize the buffers and their sizes */
1838 BlockIopAlignedBuffer = NULL;
1839 BlockIopAlignedBufferSize = 0;
1840 BlockIopPartialBlockBuffer = NULL;
1841 BlockIopPartialBlockBufferSize = 0;
1842 BlockIopPrefetchBuffer = NULL;
1843 BlockIopReadBlockBuffer = NULL;
1844 BlockIopReadBlockBufferSize = 0;
1845
1846 /* Allocate the prefetch buffer */
1847 Status = MmPapAllocatePagesInRange(&BlockIopPrefetchBuffer,
1848 BlLoaderDeviceMemory,
1849 0x100,
1850 0,
1851 0,
1852 NULL,
1853 0);
1854 if (NT_SUCCESS(Status))
1855 {
1856 /* Initialize the block cache */
1857 Status = BcInitialize();
1858 if (NT_SUCCESS(Status))
1859 {
1860 /* Initialize the block device hash table */
1861 Status = BlHtCreate(29, BlockIoEfiHashFunction, NULL, &HashTableId);
1862 if (NT_SUCCESS(Status))
1863 {
1864 /* Register our destructor */
1865 Status = BlpIoRegisterDestroyRoutine(BlockIopDestroy);
1866 if (NT_SUCCESS(Status))
1867 {
1868 /* We're good */
1869 BlockIoInitialized = TRUE;
1870 }
1871 }
1872 }
1873 }
1874
1875 /* Check if this is the failure path */
1876 if (!NT_SUCCESS(Status))
1877 {
1878 /* Free the prefetch buffer is one was allocated */
1879 if (BlockIopPrefetchBuffer)
1880 {
1881 MmPapFreePages(BlockIopPrefetchBuffer, BL_MM_INCLUDE_MAPPED_ALLOCATED);
1882 }
1883 }
1884
1885 /* Return back to the caller */
1886 return Status;
1887 }
1888
1889 BOOLEAN
1890 BlockIoDeviceTableCompare (
1891 _In_ PVOID Entry,
1892 _In_ PVOID Argument1,
1893 _In_ PVOID Argument2,
1894 _In_ PVOID Argument3,
1895 _In_ PVOID Argument4
1896 )
1897 {
1898 PBL_DEVICE_ENTRY DeviceEntry = (PBL_DEVICE_ENTRY)Entry;
1899 PBL_DEVICE_DESCRIPTOR Device = (PBL_DEVICE_DESCRIPTOR)Argument1;
1900
1901 /* Compare the two devices */
1902 return BlpDeviceCompare(DeviceEntry->DeviceDescriptor, Device);
1903 }
1904
1905 NTSTATUS
1906 BlockIoOpen (
1907 _In_ PBL_DEVICE_DESCRIPTOR Device,
1908 _In_ PBL_DEVICE_ENTRY DeviceEntry
1909 )
1910 {
1911 NTSTATUS Status;
1912 PBL_BLOCK_DEVICE BlockDevice;
1913 PBL_DEVICE_ENTRY FoundDeviceEntry;
1914 ULONG Dummy;
1915
1916 /* Check if the block I/O manager is initialized */
1917 if (!BlockIoInitialized)
1918 {
1919 /* First call, initialize it now */
1920 Status = BlockIopInitialize();
1921 if (!NT_SUCCESS(Status))
1922 {
1923 /* Failed to initialize block I/O */
1924 return Status;
1925 }
1926 }
1927
1928 /* Copy a function table for block I/O devices */
1929 RtlCopyMemory(&DeviceEntry->Callbacks,
1930 &BlockIoDeviceFunctionTable,
1931 sizeof(DeviceEntry->Callbacks));
1932
1933 /* Allocate a block I/O device */
1934 BlockDevice = BlMmAllocateHeap(sizeof(*BlockDevice));
1935 if (!BlockDevice)
1936 {
1937 return STATUS_NO_MEMORY;
1938 }
1939
1940 /* Set this as the device-specific data for this device entry */
1941 Status = STATUS_SUCCESS;
1942 DeviceEntry->DeviceSpecificData = BlockDevice;
1943
1944 /* Check if we already have this device in our device table */
1945 FoundDeviceEntry = BlTblFindEntry(BlockIoDeviceTable,
1946 BlockIoDeviceTableEntries,
1947 &Dummy,
1948 BlockIoDeviceTableCompare,
1949 Device,
1950 NULL,
1951 NULL,
1952 NULL);
1953 if (FoundDeviceEntry)
1954 {
1955 /* We already found a device, so copy its device data and callbacks */
1956 //EfiPrintf(L"Block I/O Device entry found: %p\r\n", FoundDeviceEntry);
1957 RtlCopyMemory(BlockDevice, FoundDeviceEntry->DeviceSpecificData, sizeof(*BlockDevice));
1958 RtlCopyMemory(&DeviceEntry->Callbacks,
1959 &FoundDeviceEntry->Callbacks,
1960 sizeof(DeviceEntry->Callbacks));
1961 return Status;
1962 }
1963
1964 /* Zero out the device for now */
1965 RtlZeroMemory(BlockDevice, sizeof(*BlockDevice));
1966
1967 /* Is this a disk? */
1968 if (Device->DeviceType == DiskDevice)
1969 {
1970 /* What type of disk is it? */
1971 switch (Device->Local.Type)
1972 {
1973 /* Is it a raw physical disk? */
1974 case LocalDevice:
1975 case FloppyDevice:
1976 case CdRomDevice:
1977 /* Open a disk device */
1978 Status = DiskDeviceFunctionTable.Open(Device, DeviceEntry);
1979 break;
1980
1981 /* Is it a RAM disk? */
1982 case RamDiskDevice:
1983 /* Open a RAM disk */
1984 Status = RamDiskDeviceFunctionTable.Open(Device, DeviceEntry);
1985 break;
1986
1987 /* Is it a file? */
1988 case FileDevice:
1989 /* Open a file */
1990 Status = FileDeviceFunctionTable.Open(Device, DeviceEntry);
1991 break;
1992
1993 /* Is it a VHD? */
1994 case VirtualDiskDevice:
1995 /* Open a virtual disk */
1996 Status = VirtualDiskDeviceFunctionTable.Open(Device, DeviceEntry);
1997 break;
1998
1999 /* Is it something else? */
2000 default:
2001 /* Not supported */
2002 Status = STATUS_INVALID_PARAMETER;
2003 break;
2004 }
2005 }
2006 else if ((Device->DeviceType == LegacyPartitionDevice) ||
2007 (Device->DeviceType == PartitionDevice))
2008 {
2009 /* This is a partition on a disk, open it as such */
2010 Status = PartitionDeviceFunctionTable.Open(Device, DeviceEntry);
2011 }
2012 else
2013 {
2014 /* Other devices are not supported */
2015 Status = STATUS_INVALID_PARAMETER;
2016 }
2017
2018 /* Check for failure */
2019 if (!NT_SUCCESS(Status))
2020 {
2021 /* Free any allocations for this device */
2022 BlockIopFreeAllocations(BlockDevice);
2023 }
2024
2025 /* Return back to the caller */
2026 return Status;
2027 }
2028
2029 NTSTATUS
2030 BlpDeviceResolveLocate (
2031 _In_ PBL_DEVICE_DESCRIPTOR InputDevice,
2032 _Out_ PBL_DEVICE_DESCRIPTOR* LocateDevice
2033 )
2034 {
2035 EfiPrintf(L"Not implemented!\r\n");
2036 return STATUS_NOT_IMPLEMENTED;
2037 }
2038
2039 NTSTATUS
2040 BlDeviceClose (
2041 _In_ ULONG DeviceId
2042 )
2043 {
2044 PBL_DEVICE_ENTRY DeviceEntry;
2045
2046 /* Validate the device ID */
2047 if (DmTableEntries <= DeviceId)
2048 {
2049 return STATUS_INVALID_PARAMETER;
2050 }
2051
2052 /* Make sure there's a device there */
2053 DeviceEntry = DmDeviceTable[DeviceId];
2054 if (DeviceEntry == NULL)
2055 {
2056 return STATUS_INVALID_PARAMETER;
2057 }
2058
2059 /* Make sure the device is active */
2060 if (!(DeviceEntry->Flags & BL_DEVICE_ENTRY_OPENED))
2061 {
2062 return STATUS_INVALID_PARAMETER;
2063 }
2064
2065 /* Drop a reference and check if it's the last one */
2066 DeviceEntry->ReferenceCount--;
2067 if (!DeviceEntry->ReferenceCount)
2068 {
2069 /* Mark the device as inactive */
2070 DeviceEntry->Flags = ~BL_DEVICE_ENTRY_OPENED;
2071 }
2072
2073 /* We're good */
2074 return STATUS_SUCCESS;
2075 }
2076
2077 NTSTATUS
2078 BlpDeviceOpen (
2079 _In_ PBL_DEVICE_DESCRIPTOR Device,
2080 _In_ ULONG Flags,
2081 _In_ ULONG Unknown,
2082 _Out_ PULONG DeviceId
2083 )
2084 {
2085 NTSTATUS Status;
2086 PBL_DEVICE_ENTRY DeviceEntry;
2087 PBL_DEVICE_DESCRIPTOR LocateDeviceDescriptor;
2088 PBL_REGISTERED_DEVICE RegisteredDevice;
2089 PLIST_ENTRY NextEntry, ListHead;
2090
2091 DeviceEntry = NULL;
2092
2093 /* Check for missing parameters */
2094 if (!(Device) || !(DeviceId) || !(Device->Size))
2095 {
2096 /* Bail out */
2097 Status = STATUS_INVALID_PARAMETER;
2098 goto Quickie;
2099 }
2100
2101 /* Make sure both read and write access are set */
2102 if (!(Flags & (BL_DEVICE_READ_ACCESS | BL_DEVICE_WRITE_ACCESS)))
2103 {
2104 /* Bail out */
2105 Status = STATUS_INVALID_PARAMETER;
2106 goto Quickie;
2107 }
2108
2109 /* Check if the boot device is being opened */
2110 if (Device->DeviceType == BootDevice)
2111 {
2112 /* Select it */
2113 Device = BlpBootDevice;
2114 }
2115
2116 /* Check if the 'locate' device is being opened */
2117 if (Device->DeviceType == LocateDevice)
2118 {
2119 /* Go find it */
2120 Status = BlpDeviceResolveLocate(Device, &LocateDeviceDescriptor);
2121 if (!NT_SUCCESS(Status))
2122 {
2123 /* Not found, bail out */
2124 goto Quickie;
2125 }
2126
2127 /* Select it */
2128 Device = LocateDeviceDescriptor;
2129 }
2130
2131 /* Check if the device isn't ready yet */
2132 if (Device->Flags & 1)
2133 {
2134 /* Return a failure */
2135 Status = STATUS_DEVICE_NOT_READY;
2136 goto Quickie;
2137 }
2138
2139 /* Check if we already have an entry for the device */
2140 DeviceEntry = BlTblFindEntry(DmDeviceTable,
2141 DmTableEntries,
2142 DeviceId,
2143 DeviceTableCompare,
2144 Device,
2145 &Flags,
2146 &Unknown,
2147 NULL);
2148 if (DeviceEntry)
2149 {
2150 /* Return it, taking a reference on it */
2151 *DeviceId = DeviceEntry->DeviceId;
2152 ++DeviceEntry->ReferenceCount;
2153 DeviceEntry->Flags |= BL_DEVICE_ENTRY_OPENED;
2154 return STATUS_SUCCESS;
2155 }
2156
2157 /* We don't, allocate one */
2158 DeviceEntry = BlMmAllocateHeap(sizeof(*DeviceEntry));
2159 if (!DeviceEntry)
2160 {
2161 Status = STATUS_NO_MEMORY;
2162 goto Quickie;
2163 }
2164
2165 /* Fill it out */
2166 RtlZeroMemory(DeviceEntry, sizeof(*DeviceEntry));
2167 DeviceEntry->ReferenceCount = 1;
2168 DeviceEntry->Flags |= (BL_DEVICE_ENTRY_OPENED |
2169 BL_DEVICE_ENTRY_READ_ACCESS |
2170 BL_DEVICE_ENTRY_WRITE_ACCESS);
2171 DeviceEntry->Unknown = Unknown;
2172
2173 /* Save flag 8 if needed */
2174 if (Flags & 8)
2175 {
2176 DeviceEntry->Flags |= 8;
2177 }
2178
2179 /* Allocate a device descriptor for the device */
2180 DeviceEntry->DeviceDescriptor = BlMmAllocateHeap(Device->Size);
2181 if (!DeviceEntry->DeviceDescriptor)
2182 {
2183 Status = STATUS_NO_MEMORY;
2184 goto Quickie;
2185 }
2186
2187 /* Copy the descriptor that was passed in */
2188 RtlCopyMemory(DeviceEntry->DeviceDescriptor, Device, Device->Size);
2189
2190 /* Now loop the list of dynamically registered devices */
2191 ListHead = &DmRegisteredDevices;
2192 NextEntry = ListHead->Flink;
2193 while (NextEntry != ListHead)
2194 {
2195 /* Get the device */
2196 RegisteredDevice = CONTAINING_RECORD(NextEntry,
2197 BL_REGISTERED_DEVICE,
2198 ListEntry);
2199
2200 /* Open the device */
2201 Status = RegisteredDevice->Callbacks.Open(Device, DeviceEntry);
2202 if (NT_SUCCESS(Status))
2203 {
2204 /* The device was opened, so we have the right one */
2205 goto DeviceOpened;
2206 }
2207
2208 /* Nope, keep trying */
2209 NextEntry = NextEntry->Flink;
2210 }
2211
2212 /* Well, it wasn't a dynamic device. Is it a block device? */
2213 if ((Device->DeviceType == PartitionDevice) ||
2214 (Device->DeviceType == DiskDevice) ||
2215 (Device->DeviceType == LegacyPartitionDevice))
2216 {
2217 /* Call the Block I/O handler */
2218 Status = BlockIoDeviceFunctionTable.Open(Device, DeviceEntry);
2219 }
2220 else if (Device->DeviceType == SerialDevice)
2221 {
2222 /* It's a serial device, call the serial device handler */
2223 Status = SerialPortFunctionTable.Open(Device, DeviceEntry);
2224 }
2225 else if (Device->DeviceType == UdpDevice)
2226 {
2227 /* It's a network device, call the UDP device handler */
2228 Status = UdpFunctionTable.Open(Device, DeviceEntry);
2229 }
2230 else
2231 {
2232 /* Unsupported type of device */
2233 Status = STATUS_NOT_IMPLEMENTED;
2234 }
2235
2236 /* Check if the device was opened successfully */
2237 if (NT_SUCCESS(Status))
2238 {
2239 DeviceOpened:
2240 /* Save the entry in the device table */
2241 Status = BlTblSetEntry(&DmDeviceTable,
2242 &DmTableEntries,
2243 DeviceEntry,
2244 DeviceId,
2245 DeviceTablePurge);
2246 if (NT_SUCCESS(Status))
2247 {
2248 /* It worked -- return the ID in the table to the caller */
2249 EfiPrintf(L"Device ID: %lx\r\n", *DeviceId);
2250 DeviceEntry->DeviceId = *DeviceId;
2251 return STATUS_SUCCESS;
2252 }
2253 }
2254
2255 Quickie:
2256 /* Failure path -- did we allocate a device entry? */
2257 EfiPrintf(L"Block failure: %lx\r\n", Status);
2258 if (DeviceEntry)
2259 {
2260 /* Yep -- did it have a descriptor? */
2261 if (DeviceEntry->DeviceDescriptor)
2262 {
2263 /* Free it */
2264 BlMmFreeHeap(DeviceEntry->DeviceDescriptor);
2265 }
2266
2267 /* Free the entry */
2268 BlMmFreeHeap(DeviceEntry);
2269 }
2270
2271 /* Return the failure */
2272 return Status;
2273 }
2274
2275 NTSTATUS
2276 BlpDeviceInitialize (
2277 VOID
2278 )
2279 {
2280 NTSTATUS Status;
2281
2282 /* Initialize the table count and list of devices */
2283 DmTableEntries = 8;
2284 InitializeListHead(&DmRegisteredDevices);
2285
2286 /* Initialize device information */
2287 DmDeviceIoInformation.ReadCount = 0;
2288 DmDeviceIoInformation.WriteCount = 0;
2289
2290 /* Allocate the device table */
2291 DmDeviceTable = BlMmAllocateHeap(DmTableEntries * sizeof(PVOID));
2292 if (DmDeviceTable)
2293 {
2294 /* Clear it */
2295 RtlZeroMemory(DmDeviceTable, DmTableEntries * sizeof(PVOID));
2296 #if BL_BITLOCKER_SUPPORT
2297 /* Initialize BitLocker support */
2298 Status = FvebInitialize();
2299 #else
2300 Status = STATUS_SUCCESS;
2301 #endif
2302 }
2303 else
2304 {
2305 /* No memory, we'll fail */
2306 Status = STATUS_NO_MEMORY;
2307 }
2308
2309 /* Return initialization state */
2310 return Status;
2311 }
2312