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