1 /** @file
2 Routines supporting partition discovery and
3 logical device reading
4
5 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include <IndustryStandard/Mbr.h>
12 #include "FatLitePeim.h"
13
14 /**
15 Test to see if the Mbr buffer is a valid MBR
16
17 @param[in] Mbr Parent Handle
18 @param[in] LastLba Last Lba address on the device.
19
20 @retval TRUE Mbr is a Valid MBR
21 @retval FALSE Mbr is not a Valid MBR
22
23 **/
24 BOOLEAN
PartitionValidMbr(IN MASTER_BOOT_RECORD * Mbr,IN EFI_PEI_LBA LastLba)25 PartitionValidMbr (
26 IN MASTER_BOOT_RECORD *Mbr,
27 IN EFI_PEI_LBA LastLba
28 )
29 {
30 UINT32 StartingLBA;
31 UINT32 EndingLBA;
32 UINT32 NewEndingLBA;
33 INTN Index1;
34 INTN Index2;
35 BOOLEAN MbrValid;
36
37 if (Mbr->Signature != MBR_SIGNATURE) {
38 return FALSE;
39 }
40 //
41 // The BPB also has this signature, so it can not be used alone.
42 //
43 MbrValid = FALSE;
44 for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) {
45 if (Mbr->Partition[Index1].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) == 0) {
46 continue;
47 }
48
49 MbrValid = TRUE;
50 StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA);
51 EndingLBA = StartingLBA + UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) - 1;
52 if (EndingLBA > LastLba) {
53 //
54 // Compatability Errata:
55 // Some systems try to hide drive space with thier INT 13h driver
56 // This does not hide space from the OS driver. This means the MBR
57 // that gets created from DOS is smaller than the MBR created from
58 // a real OS (NT & Win98). This leads to BlockIo->LastBlock being
59 // wrong on some systems FDISKed by the OS.
60 //
61 // return FALSE Because no block devices on a system are implemented
62 // with INT 13h
63 //
64 return FALSE;
65 }
66
67 for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) {
68 if (Mbr->Partition[Index2].OSIndicator == 0x00 || UNPACK_INT32 (Mbr->Partition[Index2].SizeInLBA) == 0) {
69 continue;
70 }
71
72 NewEndingLBA = UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) + UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) - 1;
73 if (NewEndingLBA >= StartingLBA && UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) <= EndingLBA) {
74 //
75 // This region overlaps with the Index1'th region
76 //
77 return FALSE;
78 }
79 }
80 }
81 //
82 // Non of the regions overlapped so MBR is O.K.
83 //
84 return MbrValid;
85 }
86
87 /**
88 This function finds Mbr partitions. Main algorithm
89 is ported from DXE partition driver.
90
91 @param[in] PrivateData The global memory map
92 @param[in] ParentBlockDevNo The parent block device
93
94 @retval TRUE New partitions are detected and logical block devices
95 are added to block device array
96 @retval FALSE No new partitions are added
97
98 **/
99 BOOLEAN
FatFindMbrPartitions(IN PEI_FAT_PRIVATE_DATA * PrivateData,IN UINTN ParentBlockDevNo)100 FatFindMbrPartitions (
101 IN PEI_FAT_PRIVATE_DATA *PrivateData,
102 IN UINTN ParentBlockDevNo
103 )
104 {
105 EFI_STATUS Status;
106 MASTER_BOOT_RECORD *Mbr;
107 UINTN Index;
108 BOOLEAN Found;
109 PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
110 PEI_FAT_BLOCK_DEVICE *BlockDev;
111
112 if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {
113 return FALSE;
114 }
115
116 ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
117
118 if (ParentBlockDev->BlockSize > PEI_FAT_MAX_BLOCK_SIZE) {
119 DEBUG((DEBUG_ERROR, "Device BlockSize %x exceeds FAT_MAX_BLOCK_SIZE\n", ParentBlockDev->BlockSize));
120 return FALSE;
121 }
122
123 Found = FALSE;
124 Mbr = (MASTER_BOOT_RECORD *) PrivateData->BlockData;
125
126 Status = FatReadBlock (
127 PrivateData,
128 ParentBlockDevNo,
129 0,
130 ParentBlockDev->BlockSize,
131 Mbr
132 );
133
134 if (EFI_ERROR (Status) || !PartitionValidMbr (Mbr, ParentBlockDev->LastBlock)) {
135 goto Done;
136 }
137 //
138 // We have a valid mbr - add each partition
139 //
140 for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
141 if (Mbr->Partition[Index].OSIndicator == 0x00 || UNPACK_INT32 (Mbr->Partition[Index].SizeInLBA) == 0) {
142 //
143 // Don't use null MBR entries
144 //
145 continue;
146 }
147 //
148 // Register this partition
149 //
150 if (PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE) {
151
152 Found = TRUE;
153
154 BlockDev = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]);
155
156 BlockDev->BlockSize = MBR_SIZE;
157 BlockDev->LastBlock = UNPACK_INT32 (Mbr->Partition[Index].SizeInLBA) - 1;
158 BlockDev->IoAlign = ParentBlockDev->IoAlign;
159 BlockDev->Logical = TRUE;
160 BlockDev->PartitionChecked = FALSE;
161 BlockDev->StartingPos = MultU64x32 (
162 UNPACK_INT32 (Mbr->Partition[Index].StartingLBA),
163 ParentBlockDev->BlockSize
164 );
165 BlockDev->ParentDevNo = ParentBlockDevNo;
166
167 PrivateData->BlockDeviceCount++;
168 }
169 }
170
171 Done:
172
173 ParentBlockDev->PartitionChecked = TRUE;
174 return Found;
175 }
176