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