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