]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c
df25a93f8587bf134a61238cfc6a5c3c49caa822
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / PartitionDxe / Mbr.c
1 /** @file
2 Decode a hard disk partitioned with the legacy MBR found on most PC's
3
4 MBR - Master Boot Record is in the first sector of a partitioned hard disk.
5 The MBR supports four partitions per disk. The MBR also contains legacy
6 code that is not run on an EFI system. The legacy code reads the
7 first sector of the active partition into memory and
8
9 BPB - BIOS Parameter Block is in the first sector of a FAT file system.
10 The BPB contains information about the FAT file system. The BPB is
11 always on the first sector of a media. The first sector also contains
12 the legacy boot strap code.
13
14 Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
15 Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
16 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
17 SPDX-License-Identifier: BSD-2-Clause-Patent
18
19 **/
20
21 #include "Partition.h"
22
23 /**
24 Test to see if the Mbr buffer is a valid MBR.
25
26 @param Mbr Parent Handle.
27 @param LastLba Last Lba address on the device.
28
29 @retval TRUE Mbr is a Valid MBR.
30 @retval FALSE Mbr is not a Valid MBR.
31
32 **/
33 BOOLEAN
34 PartitionValidMbr (
35 IN MASTER_BOOT_RECORD *Mbr,
36 IN EFI_LBA LastLba
37 )
38 {
39 UINT32 StartingLBA;
40 UINT32 EndingLBA;
41 UINT32 NewEndingLBA;
42 INTN Index1;
43 INTN Index2;
44 BOOLEAN MbrValid;
45
46 if (Mbr->Signature != MBR_SIGNATURE) {
47 return FALSE;
48 }
49 //
50 // The BPB also has this signature, so it can not be used alone.
51 //
52 MbrValid = FALSE;
53 for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) {
54 if (Mbr->Partition[Index1].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) == 0) {
55 continue;
56 }
57
58 MbrValid = TRUE;
59 StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA);
60 EndingLBA = StartingLBA + UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) - 1;
61 if (EndingLBA > LastLba) {
62 //
63 // Compatibility Errata:
64 // Some systems try to hide drive space with their INT 13h driver
65 // This does not hide space from the OS driver. This means the MBR
66 // that gets created from DOS is smaller than the MBR created from
67 // a real OS (NT & Win98). This leads to BlockIo->LastBlock being
68 // wrong on some systems FDISKed by the OS.
69 //
70 // return FALSE since no block devices on a system are implemented
71 // with INT 13h
72 //
73
74 DEBUG((DEBUG_INFO, "PartitionValidMbr: Bad MBR partition size EndingLBA(%1x) > LastLBA(%1x)\n", EndingLBA, LastLba));
75
76 return FALSE;
77 }
78
79 for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) {
80 if (Mbr->Partition[Index2].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) == 0) {
81 continue;
82 }
83
84 NewEndingLBA = UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) + UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) - 1;
85 if (NewEndingLBA >= StartingLBA && UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) <= EndingLBA) {
86 //
87 // This region overlaps with the Index1'th region
88 //
89 return FALSE;
90 }
91 }
92 }
93 //
94 // None of the regions overlapped so MBR is O.K.
95 //
96 return MbrValid;
97 }
98
99
100 /**
101 Install child handles if the Handle supports MBR format.
102
103 @param[in] This Calling context.
104 @param[in] Handle Parent Handle.
105 @param[in] DiskIo Parent DiskIo interface.
106 @param[in] DiskIo2 Parent DiskIo2 interface.
107 @param[in] BlockIo Parent BlockIo interface.
108 @param[in] BlockIo2 Parent BlockIo2 interface.
109 @param[in] DevicePath Parent Device Path.
110
111 @retval EFI_SUCCESS A child handle was added.
112 @retval EFI_MEDIA_CHANGED Media change was detected.
113 @retval Others MBR partition was not found.
114
115 **/
116 EFI_STATUS
117 PartitionInstallMbrChildHandles (
118 IN EFI_DRIVER_BINDING_PROTOCOL *This,
119 IN EFI_HANDLE Handle,
120 IN EFI_DISK_IO_PROTOCOL *DiskIo,
121 IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
122 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
123 IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
124 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
125 )
126 {
127 EFI_STATUS Status;
128 MASTER_BOOT_RECORD *Mbr;
129 UINT32 ExtMbrStartingLba;
130 UINT32 Index;
131 HARDDRIVE_DEVICE_PATH HdDev;
132 HARDDRIVE_DEVICE_PATH ParentHdDev;
133 EFI_STATUS Found;
134 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
135 EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode;
136 UINT32 BlockSize;
137 UINT32 MediaId;
138 EFI_LBA LastSector;
139 EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
140
141 Found = EFI_NOT_FOUND;
142
143 BlockSize = BlockIo->Media->BlockSize;
144 MediaId = BlockIo->Media->MediaId;
145 LastSector = DivU64x32 (
146 MultU64x32 (BlockIo->Media->LastBlock + 1, BlockSize),
147 MBR_SIZE
148 ) - 1;
149
150 //
151 // Ensure the block size can hold the MBR
152 //
153 if (BlockSize < sizeof (MASTER_BOOT_RECORD)) {
154 return EFI_NOT_FOUND;
155 }
156
157 Mbr = AllocatePool (BlockSize);
158 if (Mbr == NULL) {
159 return Found;
160 }
161
162 Status = DiskIo->ReadDisk (
163 DiskIo,
164 MediaId,
165 0,
166 BlockSize,
167 Mbr
168 );
169 if (EFI_ERROR (Status)) {
170 Found = Status;
171 goto Done;
172 }
173 if (!PartitionValidMbr (Mbr, LastSector)) {
174 goto Done;
175 }
176 //
177 // We have a valid mbr - add each partition
178 //
179 //
180 // Get starting and ending LBA of the parent block device.
181 //
182 LastDevicePathNode = NULL;
183 ZeroMem (&ParentHdDev, sizeof (ParentHdDev));
184 DevicePathNode = DevicePath;
185 while (!IsDevicePathEnd (DevicePathNode)) {
186 LastDevicePathNode = DevicePathNode;
187 DevicePathNode = NextDevicePathNode (DevicePathNode);
188 }
189
190 if (LastDevicePathNode != NULL) {
191 if (DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH &&
192 DevicePathSubType (LastDevicePathNode) == MEDIA_HARDDRIVE_DP
193 ) {
194 CopyMem (&ParentHdDev, LastDevicePathNode, sizeof (ParentHdDev));
195 } else {
196 LastDevicePathNode = NULL;
197 }
198 }
199
200 ZeroMem (&HdDev, sizeof (HdDev));
201 HdDev.Header.Type = MEDIA_DEVICE_PATH;
202 HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;
203 SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
204 HdDev.MBRType = MBR_TYPE_PCAT;
205 HdDev.SignatureType = SIGNATURE_TYPE_MBR;
206
207 if (LastDevicePathNode == NULL) {
208 //
209 // This is a MBR, add each partition
210 //
211 for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
212 if (Mbr->Partition[Index].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA) == 0) {
213 //
214 // Don't use null MBR entries
215 //
216 continue;
217 }
218
219 if (Mbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION) {
220 //
221 // This is the guard MBR for the GPT. If you ever see a GPT disk with zero partitions you can get here.
222 // We can not produce an MBR BlockIo for this device as the MBR spans the GPT headers. So formating
223 // this BlockIo would corrupt the GPT structures and require a recovery that would corrupt the format
224 // that corrupted the GPT partition.
225 //
226 continue;
227 }
228
229 HdDev.PartitionNumber = Index + 1;
230 HdDev.PartitionStart = UNPACK_UINT32 (Mbr->Partition[Index].StartingLBA);
231 HdDev.PartitionSize = UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA);
232 CopyMem (HdDev.Signature, &(Mbr->UniqueMbrSignature[0]), sizeof (Mbr->UniqueMbrSignature));
233
234 ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
235 PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
236 PartitionInfo.Type = PARTITION_TYPE_MBR;
237 if (Mbr->Partition[Index].OSIndicator == EFI_PARTITION) {
238 PartitionInfo.System = 1;
239 }
240 CopyMem (&PartitionInfo.Info.Mbr, &Mbr->Partition[Index], sizeof (MBR_PARTITION_RECORD));
241
242 Status = PartitionInstallChildHandle (
243 This,
244 Handle,
245 DiskIo,
246 DiskIo2,
247 BlockIo,
248 BlockIo2,
249 DevicePath,
250 (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
251 &PartitionInfo,
252 HdDev.PartitionStart,
253 HdDev.PartitionStart + HdDev.PartitionSize - 1,
254 MBR_SIZE,
255 ((Mbr->Partition[Index].OSIndicator == EFI_PARTITION) ? &gEfiPartTypeSystemPartGuid: NULL)
256 );
257
258 if (!EFI_ERROR (Status)) {
259 Found = EFI_SUCCESS;
260 }
261 }
262 } else {
263 //
264 // It's an extended partition. Follow the extended partition
265 // chain to get all the logical drives
266 //
267 Index = 0;
268 ExtMbrStartingLba = 0;
269
270 do {
271
272 Status = DiskIo->ReadDisk (
273 DiskIo,
274 MediaId,
275 MultU64x32 (ExtMbrStartingLba, BlockSize),
276 BlockSize,
277 Mbr
278 );
279 if (EFI_ERROR (Status)) {
280 Found = Status;
281 goto Done;
282 }
283
284 if (UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA) == 0) {
285 break;
286 }
287
288 if ((Mbr->Partition[0].OSIndicator == EXTENDED_DOS_PARTITION) ||
289 (Mbr->Partition[0].OSIndicator == EXTENDED_WINDOWS_PARTITION)) {
290 ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA);
291 continue;
292 }
293 HdDev.PartitionNumber = ++Index;
294 HdDev.PartitionStart = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA) + ExtMbrStartingLba + ParentHdDev.PartitionStart;
295 HdDev.PartitionSize = UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA);
296 if ((HdDev.PartitionStart + HdDev.PartitionSize - 1 >= ParentHdDev.PartitionStart + ParentHdDev.PartitionSize) ||
297 (HdDev.PartitionStart <= ParentHdDev.PartitionStart)) {
298 break;
299 }
300
301 //
302 // The signature in EBR(Extended Boot Record) should always be 0.
303 //
304 *((UINT32 *) &HdDev.Signature[0]) = 0;
305
306 ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
307 PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
308 PartitionInfo.Type = PARTITION_TYPE_MBR;
309 if (Mbr->Partition[0].OSIndicator == EFI_PARTITION) {
310 PartitionInfo.System = 1;
311 }
312 CopyMem (&PartitionInfo.Info.Mbr, &Mbr->Partition[0], sizeof (MBR_PARTITION_RECORD));
313
314 Status = PartitionInstallChildHandle (
315 This,
316 Handle,
317 DiskIo,
318 DiskIo2,
319 BlockIo,
320 BlockIo2,
321 DevicePath,
322 (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
323 &PartitionInfo,
324 HdDev.PartitionStart - ParentHdDev.PartitionStart,
325 HdDev.PartitionStart - ParentHdDev.PartitionStart + HdDev.PartitionSize - 1,
326 MBR_SIZE,
327 ((Mbr->Partition[0].OSIndicator == EFI_PARTITION) ? &gEfiPartTypeSystemPartGuid: NULL)
328 );
329 if (!EFI_ERROR (Status)) {
330 Found = EFI_SUCCESS;
331 }
332
333 if ((Mbr->Partition[1].OSIndicator != EXTENDED_DOS_PARTITION) &&
334 (Mbr->Partition[1].OSIndicator != EXTENDED_WINDOWS_PARTITION)
335 ) {
336 break;
337 }
338
339 ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[1].StartingLBA);
340 //
341 // Don't allow partition to be self referencing
342 //
343 if (ExtMbrStartingLba == 0) {
344 break;
345 }
346 } while (ExtMbrStartingLba < ParentHdDev.PartitionSize);
347 }
348
349 Done:
350 FreePool (Mbr);
351
352 return Found;
353 }