OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
DiskMisc.c
Go to the documentation of this file.
1
13#include <Uefi.h>
14
15#include <Guid/Gpt.h>
16
17#include <IndustryStandard/Mbr.h>
18
19#include <Protocol/BlockIo.h>
20#include <Protocol/BlockIo2.h>
21#include <Protocol/DiskIo.h>
22#include <Protocol/DiskIo2.h>
23
24#include <Library/BaseLib.h>
25#include <Library/BaseMemoryLib.h>
26#include <Library/BaseOverflowLib.h>
27#include <Library/DebugLib.h>
28#include <Library/DevicePathLib.h>
29#include <Library/MemoryAllocationLib.h>
32#include <Library/OcFileLib.h>
33#include <Library/UefiBootServicesTableLib.h>
34
36 0x1A81704, 0x3442, 0x4A7D, { 0x87, 0x40, 0xF4, 0xEC, 0x5B, 0xBE, 0x59, 0x77 }
37};
38
40 0x9FC6B19, 0xB8A1, 0x4A01, { 0x8D, 0xB1, 0x87, 0x94, 0xE7, 0x63, 0x4C, 0xA5 }
41};
42
43#define MBR_PARTITION_ACTIVE 0x80
44
45EFI_STATUS
47 OUT OC_DISK_CONTEXT *Context,
48 IN EFI_HANDLE DiskHandle,
49 IN BOOLEAN UseBlockIo2
50 )
51{
52 EFI_STATUS Status;
53
54 ASSERT (Context != NULL);
55 ASSERT (DiskHandle != NULL);
56
57 //
58 // Retrieve the Block I/O protocol.
59 //
60 if (UseBlockIo2) {
61 Status = gBS->HandleProtocol (
62 DiskHandle,
63 &gEfiBlockIo2ProtocolGuid,
64 (VOID **)&Context->BlockIo2
65 );
66 } else {
67 Context->BlockIo2 = NULL;
68 Status = EFI_ABORTED;
69 }
70
71 if (EFI_ERROR (Status)) {
72 Status = gBS->HandleProtocol (
73 DiskHandle,
75 (VOID **)&Context->BlockIo
76 );
77 } else {
78 Context->BlockIo = NULL;
79 }
80
81 if (EFI_ERROR (Status)) {
82 DEBUG ((
83 DEBUG_INFO,
84 "OCPI: Block I/O (%d/%d) protocols (%d) are not present on %p - %r\n",
85 Context->BlockIo != NULL,
86 Context->BlockIo2 != NULL,
87 UseBlockIo2,
88 DiskHandle,
89 Status
90 ));
91 return Status;
92 }
93
94 if ((Context->BlockIo2 != NULL) && (Context->BlockIo2->Media != NULL)) {
95 Context->BlockSize = Context->BlockIo2->Media->BlockSize;
96 Context->MediaId = Context->BlockIo2->Media->MediaId;
97 } else if ((Context->BlockIo != NULL) && (Context->BlockIo->Media != NULL)) {
98 Context->BlockSize = Context->BlockIo->Media->BlockSize;
99 Context->MediaId = Context->BlockIo->Media->MediaId;
100 } else {
101 return EFI_UNSUPPORTED;
102 }
103
104 //
105 // Check that BlockSize is POT.
106 //
107 if ((Context->BlockSize == 0) || ((Context->BlockSize & (Context->BlockSize - 1)) != 0)) {
108 DEBUG ((DEBUG_INFO, "OCPI: Block I/O has invalid block size %u\n", Context->BlockSize));
109 return EFI_UNSUPPORTED;
110 }
111
112 return EFI_SUCCESS;
113}
114
115EFI_STATUS
117 IN OC_DISK_CONTEXT *Context,
118 IN UINT64 Lba,
119 IN UINTN BufferSize,
120 OUT VOID *Buffer
121 )
122{
123 EFI_STATUS Status;
124
125 ASSERT (Context->BlockIo != NULL || Context->BlockIo2 != NULL);
126 ASSERT ((BufferSize & (Context->BlockSize - 1)) == 0);
127
128 if (Context->BlockIo2 != NULL) {
129 Status = Context->BlockIo2->ReadBlocksEx (
130 Context->BlockIo2,
131 Context->MediaId,
132 Lba,
133 NULL,
134 BufferSize,
135 Buffer
136 );
137 } else {
138 Status = Context->BlockIo->ReadBlocks (
139 Context->BlockIo,
140 Context->MediaId,
141 Lba,
142 BufferSize,
143 Buffer
144 );
145 }
146
147 return Status;
148}
149
150EFI_STATUS
152 IN OC_DISK_CONTEXT *Context,
153 IN UINT64 Lba,
154 IN UINTN BufferSize,
155 IN VOID *Buffer
156 )
157{
158 EFI_STATUS Status;
159
160 ASSERT (Context->BlockIo != NULL || Context->BlockIo2 != NULL);
161 ASSERT ((BufferSize & (Context->BlockSize - 1)) == 0);
162
163 if (Context->BlockIo2 != NULL) {
164 Status = Context->BlockIo2->WriteBlocksEx (
165 Context->BlockIo2,
166 Context->MediaId,
167 Lba,
168 NULL,
169 BufferSize,
170 Buffer
171 );
172 } else {
173 Status = Context->BlockIo->WriteBlocks (
174 Context->BlockIo,
175 Context->MediaId,
176 Lba,
177 BufferSize,
178 Buffer
179 );
180 }
181
182 return Status;
183}
184
185STATIC
186VOID
188 IN UINTN ErrorLevel,
189 IN CONST CHAR8 *Message,
190 IN CONST EFI_PARTITION_ENTRY *PartitionEntry
191 )
192{
193 ASSERT (PartitionEntry != NULL);
194
195 DEBUG ((
196 ErrorLevel,
197 "%a:\n"
198 "- PartitionTypeGUID: %g\n"
199 "- UniquePartitionGUID: %g\n"
200 "- StartingLBA: %lx\n"
201 "- EndingLBA: %lx\n"
202 "- Attributes: %lx\n"
203 "- PartitionName: %s\n",
204 Message,
205 PartitionEntry->PartitionTypeGUID,
206 PartitionEntry->UniquePartitionGUID,
207 PartitionEntry->StartingLBA,
208 PartitionEntry->EndingLBA,
209 PartitionEntry->Attributes,
210 PartitionEntry->PartitionName
211 ));
212}
213
214STATIC
215EFI_HANDLE
217 IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath,
218 IN BOOLEAN IsPartitionPath,
219 OUT BOOLEAN *HasBlockIo2
220 )
221{
222 EFI_HANDLE DiskHandle;
223
224 EFI_STATUS Status;
225
226 EFI_DEVICE_PATH_PROTOCOL *DiskPath;
227 EFI_DEVICE_PATH_PROTOCOL *TempPath;
228
229 ASSERT (HdDevicePath != NULL);
230 ASSERT (HasBlockIo2 != NULL);
231
232 if (IsPartitionPath) {
233 DiskPath = OcDiskGetDevicePath (HdDevicePath);
234 } else {
235 DiskPath = HdDevicePath;
236 }
237
238 TempPath = DiskPath;
239 Status = gBS->LocateDevicePath (
240 &gEfiBlockIo2ProtocolGuid,
241 &TempPath,
242 &DiskHandle
243 );
244 *HasBlockIo2 = !EFI_ERROR (Status);
245
246 if (EFI_ERROR (Status)) {
247 TempPath = DiskPath;
248 Status = gBS->LocateDevicePath (
250 &TempPath,
251 &DiskHandle
252 );
253 }
254
255 if (EFI_ERROR (Status)) {
257 DEBUG_INFO,
258 "OCPI: Failed to locate disk",
259 TempPath
260 );
261
262 DiskHandle = NULL;
263 }
264
265 if (IsPartitionPath && (DiskPath != NULL)) {
266 FreePool (DiskPath);
267 }
268
269 return DiskHandle;
270}
271
279EFI_DEVICE_PATH_PROTOCOL *
281 IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath
282 )
283{
284 EFI_DEVICE_PATH_PROTOCOL *PrefixPath;
285 EFI_DEVICE_PATH_PROTOCOL *TempPath;
286 CONST EFI_DEVICE_PATH_PROTOCOL *HdNode;
287
288 ASSERT (HdDevicePath != NULL);
289
291 HdDevicePath,
292 MEDIA_DEVICE_PATH,
293 MEDIA_HARDDRIVE_DP
294 );
295 if (HdNode == NULL) {
297 HdDevicePath,
298 MEDIA_DEVICE_PATH,
299 MEDIA_CDROM_DP
300 );
301 if (HdNode == NULL) {
302 return NULL;
303 }
304 }
305
306 PrefixPath = DuplicateDevicePath (HdDevicePath);
307 if (PrefixPath == NULL) {
308 DEBUG ((DEBUG_INFO, "OCPI: DP allocation error\n"));
309 return NULL;
310 }
311
312 //
313 // Strip the HD node in order to retrieve the last node supporting Block I/O
314 // before it, which is going to be its disk.
315 //
316 TempPath = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)PrefixPath + ((UINTN)HdNode - (UINTN)HdDevicePath));
317 SetDevicePathEndNode (TempPath);
318
319 TempPath = PrefixPath;
320
321 return TempPath;
322}
323
330EFI_HANDLE
332 IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath
333 )
334{
335 BOOLEAN Dummy;
336
337 ASSERT (HdDevicePath != NULL);
338
339 return InternalGetDiskHandle (
340 HdDevicePath,
341 TRUE,
342 &Dummy
343 );
344}
345
352EFI_HANDLE
354 IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath
355 )
356{
357 BOOLEAN Dummy;
358
359 ASSERT (HdDevicePath != NULL);
360
361 return InternalGetDiskHandle (
362 HdDevicePath,
363 FALSE,
364 &Dummy
365 );
366}
367
368BOOLEAN
370 IN EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath
371 )
372{
373 EFI_DEVICE_PATH_PROTOCOL *DevicePathWalker;
374
375 ASSERT (DiskDevicePath != NULL);
376
377 DevicePathWalker = DiskDevicePath;
378 while (!IsDevicePathEnd (DevicePathWalker)) {
379 if ( (DevicePathType (DevicePathWalker) == MEDIA_DEVICE_PATH)
380 && (DevicePathSubType (DevicePathWalker) == MEDIA_CDROM_DP))
381 {
382 return TRUE;
383 }
384
385 DevicePathWalker = NextDevicePathNode (DevicePathWalker);
386 }
387
388 return FALSE;
389}
390
391EFI_STATUS
393 IN EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath,
394 OUT UINT8 **Buffer,
395 OUT UINTN *BufferSize
396 )
397{
398 EFI_STATUS Status;
399 UINT8 *BootBuffer;
400 UINTN BootBufferSize;
401
402 CDROM_DEVICE_PATH *CdNode;
403 EFI_HANDLE DiskHandle;
404 OC_DISK_CONTEXT DiskContext;
405
406 ASSERT (DiskDevicePath != NULL);
407 ASSERT (Buffer != NULL);
408 ASSERT (BufferSize != NULL);
409
410 //
411 // Retrieve the CD-ROM Device Path information.
412 //
413 CdNode = (CDROM_DEVICE_PATH *)(
415 DiskDevicePath,
416 MEDIA_DEVICE_PATH,
417 MEDIA_CDROM_DP
418 )
419 );
420 if (CdNode == NULL) {
421 DEBUG ((DEBUG_INFO, "OCPI: Device Path does not describe a CD-ROM\n"));
422 return EFI_UNSUPPORTED;
423 }
424
425 DiskHandle = OcPartitionGetDiskHandle (DiskDevicePath);
426
427 Status = OcDiskInitializeContext (&DiskContext, DiskHandle, TRUE);
428 if (EFI_ERROR (Status)) {
429 return Status;
430 }
431
432 //
433 // TODO: Unclear whether the sector size here is the native CD size 2048 or 512.
434 //
435 BootBufferSize = (UINTN)(CdNode->PartitionSize * DiskContext.BlockSize);
436 BootBuffer = AllocatePool (BootBufferSize);
437 if (BootBuffer == NULL) {
438 return EFI_OUT_OF_RESOURCES;
439 }
440
441 Status = OcDiskRead (
442 &DiskContext,
443 CdNode->PartitionStart,
444 BootBufferSize,
445 BootBuffer
446 );
447 if (EFI_ERROR (Status)) {
448 FreePool (BootBuffer);
449 return Status;
450 }
451
452 *Buffer = BootBuffer;
453 *BufferSize = BootBufferSize;
454 return EFI_SUCCESS;
455}
456
457EFI_DEVICE_PATH_PROTOCOL *
459 IN CONST EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath,
460 OUT UINTN *EspDevicePathSize,
461 OUT EFI_HANDLE *EspDeviceHandle
462 )
463{
464 EFI_DEVICE_PATH_PROTOCOL *EspDevicePath;
465
466 EFI_STATUS Status;
467 BOOLEAN Result;
468 INTN CmpResult;
469
470 UINTN Index;
471 UINTN NumHandles;
472 EFI_HANDLE *Handles;
473 EFI_HANDLE Handle;
474
475 UINTN DiskDpSize;
476 UINTN DiskDpCmpSize;
477 EFI_DEVICE_PATH_PROTOCOL *HdDevicePath;
478 UINTN HdDpSize;
479
480 CONST EFI_PARTITION_ENTRY *PartEntry;
481
482 ASSERT (DiskDevicePath != NULL);
483 ASSERT (EspDevicePathSize != NULL);
484 ASSERT (EspDeviceHandle != NULL);
485
487 DEBUG_INFO,
488 "OCPI: Locating disk's ESP",
489 (EFI_DEVICE_PATH_PROTOCOL *)DiskDevicePath
490 );
491
492 Status = gBS->LocateHandleBuffer (
493 ByProtocol,
495 NULL,
496 &NumHandles,
497 &Handles
498 );
499 if (EFI_ERROR (Status)) {
500 DEBUG ((DEBUG_INFO, "OCPI: Failed to locate FS handles\n"));
501 return NULL;
502 }
503
504 EspDevicePath = NULL;
505
506 DiskDpSize = GetDevicePathSize (DiskDevicePath);
507 //
508 // The partition's Device Path must be at least as big as the disk's (prefix)
509 // plus an additional HardDrive node.
510 //
511 Result = BaseOverflowAddUN (
512 DiskDpSize,
513 sizeof (HARDDRIVE_DEVICE_PATH),
514 &DiskDpCmpSize
515 );
516 if (Result) {
517 DEBUG ((DEBUG_INFO, "OCPI: HD node would overflow DP\n"));
518 return NULL;
519 }
520
521 for (Index = 0; Index < NumHandles; ++Index) {
522 Handle = Handles[Index];
523
524 HdDevicePath = DevicePathFromHandle (Handle);
525 if (HdDevicePath == NULL) {
526 continue;
527 }
528
529 HdDpSize = GetDevicePathSize (HdDevicePath);
530 if (HdDpSize < DiskDpCmpSize) {
531 continue;
532 }
533
534 //
535 // Verify the partition's Device Path has the disk's prefixed.
536 //
537 CmpResult = CompareMem (
538 HdDevicePath,
539 DiskDevicePath,
540 DiskDpSize - END_DEVICE_PATH_LENGTH
541 );
542 if (CmpResult != 0) {
543 continue;
544 }
545
546 DebugPrintDevicePath (DEBUG_INFO, "OCPI: Discovered HD DP", HdDevicePath);
547
548 PartEntry = OcGetGptPartitionEntry (Handle);
549 if (PartEntry == NULL) {
550 continue;
551 }
552
554 DEBUG_INFO,
555 "OCPI: Discovered PartEntry",
556 PartEntry
557 );
558
559 if (CompareGuid (&PartEntry->PartitionTypeGUID, &gEfiPartTypeSystemPartGuid)) {
560 EspDevicePath = HdDevicePath;
561 *EspDevicePathSize = HdDpSize;
562 *EspDeviceHandle = Handle;
563 break;
564 }
565 }
566
567 FreePool (Handles);
568
569 return EspDevicePath;
570}
571
574 IN EFI_HANDLE DiskHandle,
575 IN BOOLEAN UseBlockIo2
576 )
577{
578 OC_PARTITION_ENTRIES *PartEntries;
579
580 EFI_STATUS Status;
581 BOOLEAN Result;
582
583 OC_DISK_CONTEXT DiskContext;
584
585 EFI_LBA PartEntryLBA;
586 UINT32 NumPartitions;
587 UINT32 PartEntrySize;
588 UINTN PartEntriesSize;
589 UINTN PartEntriesStructSize;
590 UINTN BufferSize;
591 EFI_PARTITION_TABLE_HEADER *GptHeader;
592
593 ASSERT (DiskHandle != NULL);
594
595 Status = gBS->HandleProtocol (
596 DiskHandle,
598 (VOID **)&PartEntries
599 );
600 if (!EFI_ERROR (Status)) {
601 DEBUG ((DEBUG_VERBOSE, "OCPI: Located cached partition entries\n"));
602 return PartEntries;
603 }
604
605 Status = OcDiskInitializeContext (&DiskContext, DiskHandle, UseBlockIo2);
606 if (EFI_ERROR (Status)) {
607 return NULL;
608 }
609
610 //
611 // Retrieve the GPT header.
612 //
613 BufferSize = ALIGN_VALUE (sizeof (*GptHeader), DiskContext.BlockSize);
614 GptHeader = AllocatePool (BufferSize);
615 if (GptHeader == NULL) {
616 DEBUG ((DEBUG_INFO, "OCPI: GPT header allocation error\n"));
617 return NULL;
618 }
619
620 Status = OcDiskRead (
621 &DiskContext,
622 PRIMARY_PART_HEADER_LBA,
623 BufferSize,
624 GptHeader
625 );
626 if (EFI_ERROR (Status)) {
627 FreePool (GptHeader);
628 DEBUG ((
629 DEBUG_INFO,
630 "OCPI: ReadDisk1 (block: %u, io1: %d, io2: %d, size: %u) %r\n",
631 DiskContext.BlockSize,
632 DiskContext.BlockIo != NULL,
633 DiskContext.BlockIo2 != NULL,
634 (UINT32)BufferSize,
635 Status
636 ));
637 return NULL;
638 }
639
640 if (GptHeader->Header.Signature != EFI_PTAB_HEADER_ID) {
641 FreePool (GptHeader);
642 DEBUG ((DEBUG_INFO, "OCPI: Partition table not supported\n"));
643 return NULL;
644 }
645
646 PartEntrySize = GptHeader->SizeOfPartitionEntry;
647 if (PartEntrySize < sizeof (EFI_PARTITION_ENTRY)) {
648 FreePool (GptHeader);
649 DEBUG ((DEBUG_INFO, "OCPI: GPT header is malformed\n"));
650 return NULL;
651 }
652
653 NumPartitions = GptHeader->NumberOfPartitionEntries;
654 PartEntryLBA = GptHeader->PartitionEntryLBA;
655
656 FreePool (GptHeader);
657
658 Result = BaseOverflowMulUN (NumPartitions, PartEntrySize, &PartEntriesSize);
659 if (Result || (MAX_UINTN - DiskContext.BlockSize < PartEntriesSize)) {
660 DEBUG ((DEBUG_INFO, "OCPI: Partition entries size overflows\n"));
661 return NULL;
662 }
663
664 PartEntriesSize = ALIGN_VALUE (PartEntriesSize, DiskContext.BlockSize);
665
666 Result = BaseOverflowAddUN (
667 sizeof (PartEntries),
668 PartEntriesSize,
669 &PartEntriesStructSize
670 );
671 if (Result) {
672 DEBUG ((DEBUG_INFO, "OCPI: Partition entries struct size overflows\n"));
673 return NULL;
674 }
675
676 //
677 // Retrieve the GPT partition entries.
678 //
679 PartEntries = AllocatePool (PartEntriesStructSize);
680 if (PartEntries == NULL) {
681 DEBUG ((DEBUG_INFO, "OCPI: Partition entries allocation error\n"));
682 return NULL;
683 }
684
685 Status = OcDiskRead (
686 &DiskContext,
687 PartEntryLBA,
688 PartEntriesSize,
689 PartEntries->FirstEntry
690 );
691 if (EFI_ERROR (Status)) {
692 FreePool (PartEntries);
693 DEBUG ((
694 DEBUG_INFO,
695 "OCPI: ReadDisk2 (block: %u, io1: %d, io2: %d, size: %u) %r\n",
696 DiskContext.BlockSize,
697 DiskContext.BlockIo != NULL,
698 DiskContext.BlockIo2 != NULL,
699 (UINT32)PartEntriesSize,
700 Status
701 ));
702 return NULL;
703 }
704
705 PartEntries->NumPartitions = NumPartitions;
706 PartEntries->PartitionEntrySize = PartEntrySize;
707 //
708 // FIXME: This causes the handle to be dangling if the device is detached.
709 //
710 Status = gBS->InstallMultipleProtocolInterfaces (
711 &DiskHandle,
713 PartEntries,
714 NULL
715 );
716 if (EFI_ERROR (Status)) {
717 DEBUG ((DEBUG_INFO, "OCPI: Failed to cache partition entries\n"));
718 FreePool (PartEntries);
719 return NULL;
720 }
721
722 return PartEntries;
723}
724
731CONST EFI_PARTITION_ENTRY *
733 IN EFI_HANDLE FsHandle
734 )
735{
736 CONST EFI_PARTITION_ENTRY *PartEntry;
737 CONST OC_PARTITION_ENTRIES *Partitions;
738
739 EFI_STATUS Status;
740 EFI_DEVICE_PATH_PROTOCOL *FsDevicePath;
741 CONST HARDDRIVE_DEVICE_PATH *HdNode;
742 EFI_HANDLE DiskHandle;
743 BOOLEAN HasBlockIo2;
744 UINTN Offset;
745
746 ASSERT (FsHandle != NULL);
747
748 Status = gBS->HandleProtocol (
749 FsHandle,
751 (VOID **)&PartEntry
752 );
753 if (!EFI_ERROR (Status)) {
754 DEBUG ((DEBUG_VERBOSE, "OCPI: Located cached partition entry\n"));
755 return PartEntry;
756 }
757
758 //
759 // Retrieve the partition Device Path information.
760 //
761 FsDevicePath = DevicePathFromHandle (FsHandle);
762 if (FsDevicePath == NULL) {
763 DEBUG ((DEBUG_INFO, "OCPI: Failed to retrieve Device Path\n"));
764 return NULL;
765 }
766
767 HdNode = (HARDDRIVE_DEVICE_PATH *)(
769 FsDevicePath,
770 MEDIA_DEVICE_PATH,
771 MEDIA_HARDDRIVE_DP
772 )
773 );
774 if (HdNode == NULL) {
775 DEBUG ((DEBUG_INFO, "OCPI: Device Path does not describe a partition\n"));
776 return NULL;
777 }
778
779 DiskHandle = InternalGetDiskHandle (
780 FsDevicePath,
781 TRUE,
782 &HasBlockIo2
783 );
784 if (DiskHandle == NULL) {
786 DEBUG_INFO,
787 "OCPI: Could not locate partition's disk",
788 FsDevicePath
789 );
790 return NULL;
791 }
792
793 //
794 // Get the disk's GPT partition entries.
795 //
796 Partitions = OcGetDiskPartitions (DiskHandle, HasBlockIo2);
797 if (Partitions == NULL) {
798 DEBUG ((DEBUG_INFO, "OCPI: Failed to retrieve disk info\n"));
799 return NULL;
800 }
801
802 if (HdNode->PartitionNumber > Partitions->NumPartitions) {
803 DEBUG ((DEBUG_INFO, "OCPI: Partition is OOB\n"));
804 return NULL;
805 }
806
807 ASSERT (HdNode->PartitionNumber > 0);
808 Offset = ((UINTN)(HdNode->PartitionNumber - 1) * Partitions->PartitionEntrySize);
809 PartEntry = (EFI_PARTITION_ENTRY *)((UINTN)Partitions->FirstEntry + Offset);
810 //
811 // FIXME: This causes the handle to be dangling if the device is detached.
812 //
813 Status = gBS->InstallMultipleProtocolInterfaces (
814 &FsHandle,
816 PartEntry,
817 NULL
818 );
819 if (EFI_ERROR (Status)) {
820 DEBUG ((DEBUG_INFO, "OCPI: Failed to cache partition entry\n"));
821 return NULL;
822 }
823
824 return PartEntry;
825}
826
827MASTER_BOOT_RECORD *
829 IN EFI_HANDLE DiskHandle,
830 IN BOOLEAN CheckPartitions
831 )
832{
833 EFI_STATUS Status;
834 MASTER_BOOT_RECORD *Mbr;
835 UINTN MbrSize;
836 OC_DISK_CONTEXT DiskContext;
837 UINTN Index;
838 BOOLEAN IsProtectiveMbr;
839
840 ASSERT (DiskHandle != NULL);
841
842 //
843 // Read first sector containing MBR table.
844 //
845 Status = OcDiskInitializeContext (
846 &DiskContext,
847 DiskHandle,
848 TRUE
849 );
850 if (EFI_ERROR (Status)) {
851 return NULL;
852 }
853
854 MbrSize = ALIGN_VALUE (sizeof (*Mbr), DiskContext.BlockSize);
855 Mbr = (MASTER_BOOT_RECORD *)AllocatePool (MbrSize);
856 if (Mbr == NULL) {
857 return NULL;
858 }
859
860 Status = OcDiskRead (
861 &DiskContext,
862 0,
863 MbrSize,
864 Mbr
865 );
866 if (EFI_ERROR (Status)) {
867 FreePool (Mbr);
868 return NULL;
869 }
870
871 //
872 // Validate MBR signatures.
873 //
874 // If MBR is a protective one (as part of a GPT disk), ignore.
875 // Protective MBR is defined as a single partition of type 0xEE, other three partitions are to be zero.
876 //
877 if (Mbr->Signature != MBR_SIGNATURE) {
878 FreePool (Mbr);
879 return NULL;
880 }
881
882 if (CheckPartitions) {
883 if ( (Mbr->Partition[0].OSIndicator == PMBR_GPT_PARTITION)
884 && (ReadUnaligned32 ((UINT32 *)Mbr->Partition[0].StartingLBA) == 0x01)
885 && (ReadUnaligned32 ((UINT32 *)Mbr->Partition[0].SizeInLBA) != 0))
886 {
887 IsProtectiveMbr = TRUE;
888 for (Index = 1; Index < MAX_MBR_PARTITIONS; Index++) {
889 if ( (ReadUnaligned32 ((UINT32 *)Mbr->Partition[Index].StartingLBA) != 0)
890 || (ReadUnaligned32 ((UINT32 *)Mbr->Partition[Index].SizeInLBA) != 0))
891 {
892 IsProtectiveMbr = FALSE;
893 break;
894 }
895 }
896
897 if (IsProtectiveMbr) {
898 FreePool (Mbr);
899 return NULL;
900 }
901 }
902 }
903
904 return Mbr;
905}
906
907EFI_STATUS
909 IN EFI_HANDLE PartitionHandle,
910 OUT UINT8 *PartitionIndex
911 )
912{
913 EFI_STATUS Status;
914 MASTER_BOOT_RECORD *Mbr;
915 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
916 EFI_HANDLE DiskHandle;
917 CONST HARDDRIVE_DEVICE_PATH *HdNode;
918 UINT8 Index;
919
920 ASSERT (PartitionHandle != NULL);
921 ASSERT (PartitionIndex != NULL);
922
923 //
924 // Retrieve the partition Device Path information.
925 //
926 DevicePath = DevicePathFromHandle (PartitionHandle);
927 if (DevicePath == NULL) {
928 DEBUG ((DEBUG_INFO, "OCPI: Failed to retrieve Device Path\n"));
929 return EFI_UNSUPPORTED;
930 }
931
932 HdNode = (HARDDRIVE_DEVICE_PATH *)(
934 DevicePath,
935 MEDIA_DEVICE_PATH,
936 MEDIA_HARDDRIVE_DP
937 )
938 );
939 if (HdNode == NULL) {
940 DEBUG ((DEBUG_INFO, "OCPI: Device Path does not describe a partition\n"));
941 return EFI_UNSUPPORTED;
942 }
943
944 DiskHandle = OcPartitionGetDiskHandle (DevicePath);
945 if (DiskHandle == NULL) {
946 return EFI_UNSUPPORTED;
947 }
948
949 //
950 // Get MBR from partition's disk.
951 //
952 Mbr = OcGetDiskMbrTable (
953 DiskHandle,
954 TRUE
955 );
956 if (Mbr == NULL) {
957 DEBUG ((DEBUG_INFO, "OCPI: Disk does not have an MBR partition table\n"));
958 return EFI_UNSUPPORTED;
959 }
960
961 Status = EFI_NOT_FOUND;
962 for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
963 if ( (ReadUnaligned32 ((UINT32 *)Mbr->Partition[Index].StartingLBA) == HdNode->PartitionStart)
964 && (ReadUnaligned32 ((UINT32 *)Mbr->Partition[Index].SizeInLBA) == HdNode->PartitionSize))
965 {
966 *PartitionIndex = Index;
967 Status = EFI_SUCCESS;
968 break;
969 }
970 }
971
972 FreePool (Mbr);
973
974 return Status;
975}
976
977EFI_STATUS
979 IN EFI_HANDLE DiskHandle,
980 IN UINT8 PartitionIndex
981 )
982{
983 EFI_STATUS Status;
984 MASTER_BOOT_RECORD *Mbr;
985 UINTN MbrSize;
986 UINTN Index;
987 OC_DISK_CONTEXT DiskContext;
988
989 ASSERT (DiskHandle != NULL);
990 ASSERT (PartitionIndex < MAX_MBR_PARTITIONS);
991
992 //
993 // Read first sector containing MBR table.
994 //
995 Status = OcDiskInitializeContext (
996 &DiskContext,
997 DiskHandle,
998 TRUE
999 );
1000 if (EFI_ERROR (Status)) {
1001 return Status;
1002 }
1003
1004 MbrSize = ALIGN_VALUE (sizeof (*Mbr), DiskContext.BlockSize);
1005 Mbr = (MASTER_BOOT_RECORD *)AllocatePool (MbrSize);
1006 if (Mbr == NULL) {
1007 return EFI_OUT_OF_RESOURCES;
1008 }
1009
1010 Status = OcDiskRead (
1011 &DiskContext,
1012 0,
1013 MbrSize,
1014 Mbr
1015 );
1016 if (EFI_ERROR (Status)) {
1017 FreePool (Mbr);
1018 return Status;
1019 }
1020
1021 //
1022 // Validate MBR signatures.
1023 //
1024 // If MBR is a protective one (as part of a GPT disk), ignore.
1025 // Protective MBR is defined as a single partition of type 0xEE, other three partitions are to be zero.
1026 //
1027 if (Mbr->Signature != MBR_SIGNATURE) {
1028 FreePool (Mbr);
1029 return EFI_UNSUPPORTED;
1030 }
1031
1032 //
1033 // Mark desired partition as active.
1034 //
1035 for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
1036 Mbr->Partition[Index].BootIndicator = 0x00;
1037 }
1038
1039 Mbr->Partition[PartitionIndex].BootIndicator = MBR_PARTITION_ACTIVE;
1040
1041 //
1042 // Write MBR to disk.
1043 //
1044 Status = OcDiskWrite (
1045 &DiskContext,
1046 0,
1047 MbrSize,
1048 Mbr
1049 );
1050
1051 FreePool (Mbr);
1052
1053 return Status;
1054}
1055
1056EFI_DEVICE_PATH_PROTOCOL *
1058 IN EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath,
1059 OUT UINTN *PartitionDevicePathSize,
1060 OUT EFI_HANDLE *PartitionDeviceHandle
1061 )
1062{
1063 EFI_STATUS Status;
1064 EFI_HANDLE DiskHandle;
1065 BOOLEAN HasBlockIo2;
1066 UINTN Index;
1067 INT32 ActivePartition;
1068 BOOLEAN Result;
1069 INTN CmpResult;
1070
1071 UINTN NoHandles;
1072 EFI_HANDLE *Handles;
1073 EFI_DEVICE_PATH_PROTOCOL *PartitionDevicePath;
1074 HARDDRIVE_DEVICE_PATH *HdNode;
1075 MASTER_BOOT_RECORD *Mbr;
1076
1077 UINTN DiskDpSize;
1078 UINTN DiskDpCmpSize;
1079 EFI_DEVICE_PATH_PROTOCOL *HdDevicePath;
1080 UINTN HdDpSize;
1081
1082 ASSERT (DiskDevicePath != NULL);
1083 ASSERT (PartitionDevicePathSize != NULL);
1084 ASSERT (PartitionDeviceHandle != NULL);
1085
1087 DEBUG_INFO,
1088 "OCPI: Locating MBR disk's active partition",
1089 (EFI_DEVICE_PATH_PROTOCOL *)DiskDevicePath
1090 );
1091
1092 Status = gBS->LocateHandleBuffer (
1093 ByProtocol,
1095 NULL,
1096 &NoHandles,
1097 &Handles
1098 );
1099 if (EFI_ERROR (Status)) {
1100 DEBUG ((DEBUG_INFO, "OCPI: Failed to locate Block I/O handles\n"));
1101 return NULL;
1102 }
1103
1104 //
1105 // Get MBR partition table from disk.
1106 //
1107 DiskHandle = InternalGetDiskHandle (
1108 DiskDevicePath,
1109 FALSE,
1110 &HasBlockIo2
1111 );
1112 if (DiskHandle == NULL) {
1113 return NULL;
1114 }
1115
1116 Mbr = OcGetDiskMbrTable (
1117 DiskHandle,
1118 TRUE
1119 );
1120 if (Mbr == NULL) {
1121 return NULL;
1122 }
1123
1124 //
1125 // Determine active partition based on first one with active partition set.
1126 // Multiple active partitions should not occur but possible.
1127 //
1128 ActivePartition = -1;
1129 for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
1130 if (Mbr->Partition[Index].BootIndicator == MBR_PARTITION_ACTIVE) {
1131 ActivePartition = (INT32)Index;
1132 break;
1133 }
1134 }
1135
1136 //
1137 // No active partitions present.
1138 //
1139 if (ActivePartition == -1) {
1140 DEBUG ((DEBUG_INFO, "OCPI: No active partitions found in MBR\n"));
1141 FreePool (Mbr);
1142 return NULL;
1143 }
1144
1145 //
1146 // The partition's Device Path must be at least as big as the disk's (prefix)
1147 // plus an additional HardDrive node.
1148 //
1149 DiskDpSize = GetDevicePathSize (DiskDevicePath);
1150 Result = BaseOverflowAddUN (
1151 DiskDpSize,
1152 sizeof (HARDDRIVE_DEVICE_PATH),
1153 &DiskDpCmpSize
1154 );
1155 if (Result) {
1156 DEBUG ((DEBUG_INFO, "OCPI: HD node would overflow DP\n"));
1157 FreePool (Mbr);
1158 return NULL;
1159 }
1160
1161 PartitionDevicePath = NULL;
1162
1163 for (Index = 0; Index < NoHandles; Index++) {
1164 HdDevicePath = DevicePathFromHandle (Handles[Index]);
1165 if (HdDevicePath == NULL) {
1166 continue;
1167 }
1168
1169 HdDpSize = GetDevicePathSize (HdDevicePath);
1170 if (HdDpSize < DiskDpCmpSize) {
1171 continue;
1172 }
1173
1174 //
1175 // Verify the partition's Device Path has the disk's prefixed.
1176 //
1177 CmpResult = CompareMem (
1178 HdDevicePath,
1179 DiskDevicePath,
1180 DiskDpSize - END_DEVICE_PATH_LENGTH
1181 );
1182 if (CmpResult != 0) {
1183 continue;
1184 }
1185
1186 if (CompareMem (HdDevicePath, DiskDevicePath, GetDevicePathSize (DiskDevicePath) - END_DEVICE_PATH_LENGTH) == 0) {
1187 HdNode = (HARDDRIVE_DEVICE_PATH *)FindDevicePathNodeWithType (
1188 HdDevicePath,
1189 MEDIA_DEVICE_PATH,
1190 MEDIA_HARDDRIVE_DP
1191 );
1192 if (HdNode != NULL) {
1193 if (HdNode->PartitionStart == *((UINT32 *)Mbr->Partition[ActivePartition].StartingLBA)) {
1194 DebugPrintDevicePath (DEBUG_INFO, "OCPI: Got active MBR partition device path", HdDevicePath);
1195
1196 PartitionDevicePath = HdDevicePath;
1197 *PartitionDevicePathSize = HdDpSize;
1198 *PartitionDeviceHandle = Handles[Index];
1199 break;
1200 }
1201 }
1202 }
1203 }
1204
1205 FreePool (Handles);
1206 FreePool (Mbr);
1207
1208 return PartitionDevicePath;
1209}
EFI_HANDLE OcPartitionGetPartitionHandle(IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath)
Definition DiskMisc.c:353
EFI_STATUS OcDiskGetMbrPartitionIndex(IN EFI_HANDLE PartitionHandle, OUT UINT8 *PartitionIndex)
Definition DiskMisc.c:908
EFI_HANDLE OcPartitionGetDiskHandle(IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath)
Definition DiskMisc.c:331
EFI_DEVICE_PATH_PROTOCOL * OcDiskGetDevicePath(IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath)
Definition DiskMisc.c:280
EFI_DEVICE_PATH_PROTOCOL * OcDiskFindSystemPartitionPath(IN CONST EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath, OUT UINTN *EspDevicePathSize, OUT EFI_HANDLE *EspDeviceHandle)
Definition DiskMisc.c:458
EFI_STATUS OcDiskWrite(IN OC_DISK_CONTEXT *Context, IN UINT64 Lba, IN UINTN BufferSize, IN VOID *Buffer)
Definition DiskMisc.c:151
EFI_STATUS OcDiskReadElTorito(IN EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath, OUT UINT8 **Buffer, OUT UINTN *BufferSize)
Definition DiskMisc.c:392
BOOLEAN OcIsDiskCdRom(IN EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath)
Definition DiskMisc.c:369
EFI_STATUS OcDiskRead(IN OC_DISK_CONTEXT *Context, IN UINT64 Lba, IN UINTN BufferSize, OUT VOID *Buffer)
Definition DiskMisc.c:116
STATIC EFI_GUID mInternalDiskPartitionEntriesProtocolGuid
Definition DiskMisc.c:35
STATIC EFI_HANDLE InternalGetDiskHandle(IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath, IN BOOLEAN IsPartitionPath, OUT BOOLEAN *HasBlockIo2)
Definition DiskMisc.c:216
CONST OC_PARTITION_ENTRIES * OcGetDiskPartitions(IN EFI_HANDLE DiskHandle, IN BOOLEAN UseBlockIo2)
Definition DiskMisc.c:573
EFI_STATUS OcDiskInitializeContext(OUT OC_DISK_CONTEXT *Context, IN EFI_HANDLE DiskHandle, IN BOOLEAN UseBlockIo2)
Definition DiskMisc.c:46
STATIC EFI_GUID mInternalPartitionEntryProtocolGuid
Definition DiskMisc.c:39
EFI_DEVICE_PATH_PROTOCOL * OcDiskFindActiveMbrPartitionPath(IN EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath, OUT UINTN *PartitionDevicePathSize, OUT EFI_HANDLE *PartitionDeviceHandle)
Definition DiskMisc.c:1057
#define MBR_PARTITION_ACTIVE
Definition DiskMisc.c:43
MASTER_BOOT_RECORD * OcGetDiskMbrTable(IN EFI_HANDLE DiskHandle, IN BOOLEAN CheckPartitions)
Definition DiskMisc.c:828
STATIC VOID InternalDebugPrintPartitionEntry(IN UINTN ErrorLevel, IN CONST CHAR8 *Message, IN CONST EFI_PARTITION_ENTRY *PartitionEntry)
Definition DiskMisc.c:187
CONST EFI_PARTITION_ENTRY * OcGetGptPartitionEntry(IN EFI_HANDLE FsHandle)
Definition DiskMisc.c:732
EFI_STATUS OcDiskMarkMbrPartitionActive(IN EFI_HANDLE DiskHandle, IN UINT8 PartitionIndex)
Definition DiskMisc.c:978
EFI_BOOT_SERVICES * gBS
VOID DebugPrintDevicePath(IN UINTN ErrorLevel, IN CONST CHAR8 *Message, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL)
EFI_DEVICE_PATH_PROTOCOL * FindDevicePathNodeWithType(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN UINT8 Type, IN UINT8 SubType OPTIONAL)
OC_TYPING_BUFFER_ENTRY Buffer[OC_TYPING_BUFFER_SIZE]
Definition OcTypingLib.h:42
APPLE_EVENT_HANDLE Handle
Definition OcTypingLib.h:45
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
UINT32 EFIAPI ReadUnaligned32(IN CONST UINT32 *Buffer)
EFI_GUID gEfiSimpleFileSystemProtocolGuid
EFI_GUID gEfiBlockIoProtocolGuid
EFI_DEVICE_PATH_PROTOCOL *EFIAPI DevicePathFromHandle(IN EFI_HANDLE Handle)
Definition UserMisc.c:680
#define ASSERT(x)
Definition coder.h:55
EFI_BLOCK_IO_PROTOCOL * BlockIo
Definition OcFileLib.h:570
EFI_BLOCK_IO2_PROTOCOL * BlockIo2
Definition OcFileLib.h:571
EFI_PARTITION_ENTRY FirstEntry[]
Definition OcFileLib.h:634