]> 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 // 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((EFI_D_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 LastBlock;
139 EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
140
141 Found = EFI_NOT_FOUND;
142
143 BlockSize = BlockIo->Media->BlockSize;
144 MediaId = BlockIo->Media->MediaId;
145 LastBlock = BlockIo->Media->LastBlock;
146
147 //
148 // Ensure the block size can hold the MBR
149 //
150 if (BlockSize < sizeof (MASTER_BOOT_RECORD)) {
151 return EFI_NOT_FOUND;
152 }
153
154 Mbr = AllocatePool (BlockSize);
155 if (Mbr == NULL) {
156 return Found;
157 }
158
159 Status = DiskIo->ReadDisk (
160 DiskIo,
161 MediaId,
162 0,
163 BlockSize,
164 Mbr
165 );
166 if (EFI_ERROR (Status)) {
167 Found = Status;
168 goto Done;
169 }
170 if (!PartitionValidMbr (Mbr, LastBlock)) {
171 goto Done;
172 }
173 //
174 // We have a valid mbr - add each partition
175 //
176 //
177 // Get starting and ending LBA of the parent block device.
178 //
179 LastDevicePathNode = NULL;
180 ZeroMem (&ParentHdDev, sizeof (ParentHdDev));
181 DevicePathNode = DevicePath;
182 while (!IsDevicePathEnd (DevicePathNode)) {
183 LastDevicePathNode = DevicePathNode;
184 DevicePathNode = NextDevicePathNode (DevicePathNode);
185 }
186
187 if (LastDevicePathNode != NULL) {
188 if (DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH &&
189 DevicePathSubType (LastDevicePathNode) == MEDIA_HARDDRIVE_DP
190 ) {
191 CopyMem (&ParentHdDev, LastDevicePathNode, sizeof (ParentHdDev));
192 } else {
193 LastDevicePathNode = NULL;
194 }
195 }
196
197 ZeroMem (&HdDev, sizeof (HdDev));
198 HdDev.Header.Type = MEDIA_DEVICE_PATH;
199 HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;
200 SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
201 HdDev.MBRType = MBR_TYPE_PCAT;
202 HdDev.SignatureType = SIGNATURE_TYPE_MBR;
203
204 if (LastDevicePathNode == NULL) {
205 //
206 // This is a MBR, add each partition
207 //
208 for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
209 if (Mbr->Partition[Index].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA) == 0) {
210 //
211 // Don't use null MBR entries
212 //
213 continue;
214 }
215
216 if (Mbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION) {
217 //
218 // This is the guard MBR for the GPT. If you ever see a GPT disk with zero partitions you can get here.
219 // We can not produce an MBR BlockIo for this device as the MBR spans the GPT headers. So formating
220 // this BlockIo would corrupt the GPT structures and require a recovery that would corrupt the format
221 // that corrupted the GPT partition.
222 //
223 continue;
224 }
225
226 HdDev.PartitionNumber = Index + 1;
227 HdDev.PartitionStart = UNPACK_UINT32 (Mbr->Partition[Index].StartingLBA);
228 HdDev.PartitionSize = UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA);
229 CopyMem (HdDev.Signature, &(Mbr->UniqueMbrSignature[0]), sizeof (Mbr->UniqueMbrSignature));
230
231 ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
232 PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
233 PartitionInfo.Type = PARTITION_TYPE_MBR;
234 if (Mbr->Partition[Index].OSIndicator == EFI_PARTITION) {
235 PartitionInfo.System = 1;
236 }
237 CopyMem (&PartitionInfo.Info.Mbr, &Mbr->Partition[Index], sizeof (MBR_PARTITION_RECORD));
238
239 Status = PartitionInstallChildHandle (
240 This,
241 Handle,
242 DiskIo,
243 DiskIo2,
244 BlockIo,
245 BlockIo2,
246 DevicePath,
247 (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
248 &PartitionInfo,
249 HdDev.PartitionStart,
250 HdDev.PartitionStart + HdDev.PartitionSize - 1,
251 MBR_SIZE,
252 ((Mbr->Partition[Index].OSIndicator == EFI_PARTITION) ? &gEfiPartTypeSystemPartGuid: NULL)
253 );
254
255 if (!EFI_ERROR (Status)) {
256 Found = EFI_SUCCESS;
257 }
258 }
259 } else {
260 //
261 // It's an extended partition. Follow the extended partition
262 // chain to get all the logical drives
263 //
264 Index = 0;
265 ExtMbrStartingLba = 0;
266
267 do {
268
269 Status = DiskIo->ReadDisk (
270 DiskIo,
271 MediaId,
272 MultU64x32 (ExtMbrStartingLba, BlockSize),
273 BlockSize,
274 Mbr
275 );
276 if (EFI_ERROR (Status)) {
277 Found = Status;
278 goto Done;
279 }
280
281 if (UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA) == 0) {
282 break;
283 }
284
285 if ((Mbr->Partition[0].OSIndicator == EXTENDED_DOS_PARTITION) ||
286 (Mbr->Partition[0].OSIndicator == EXTENDED_WINDOWS_PARTITION)) {
287 ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA);
288 continue;
289 }
290 HdDev.PartitionNumber = ++Index;
291 HdDev.PartitionStart = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA) + ExtMbrStartingLba + ParentHdDev.PartitionStart;
292 HdDev.PartitionSize = UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA);
293 if ((HdDev.PartitionStart + HdDev.PartitionSize - 1 >= ParentHdDev.PartitionStart + ParentHdDev.PartitionSize) ||
294 (HdDev.PartitionStart <= ParentHdDev.PartitionStart)) {
295 break;
296 }
297
298 //
299 // The signature in EBR(Extended Boot Record) should always be 0.
300 //
301 *((UINT32 *) &HdDev.Signature[0]) = 0;
302
303 ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
304 PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
305 PartitionInfo.Type = PARTITION_TYPE_MBR;
306 if (Mbr->Partition[0].OSIndicator == EFI_PARTITION) {
307 PartitionInfo.System = 1;
308 }
309 CopyMem (&PartitionInfo.Info.Mbr, &Mbr->Partition[0], sizeof (MBR_PARTITION_RECORD));
310
311 Status = PartitionInstallChildHandle (
312 This,
313 Handle,
314 DiskIo,
315 DiskIo2,
316 BlockIo,
317 BlockIo2,
318 DevicePath,
319 (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
320 &PartitionInfo,
321 HdDev.PartitionStart - ParentHdDev.PartitionStart,
322 HdDev.PartitionStart - ParentHdDev.PartitionStart + HdDev.PartitionSize - 1,
323 MBR_SIZE,
324 ((Mbr->Partition[0].OSIndicator == EFI_PARTITION) ? &gEfiPartTypeSystemPartGuid: NULL)
325 );
326 if (!EFI_ERROR (Status)) {
327 Found = EFI_SUCCESS;
328 }
329
330 if ((Mbr->Partition[1].OSIndicator != EXTENDED_DOS_PARTITION) &&
331 (Mbr->Partition[1].OSIndicator != EXTENDED_WINDOWS_PARTITION)
332 ) {
333 break;
334 }
335
336 ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[1].StartingLBA);
337 //
338 // Don't allow partition to be self referencing
339 //
340 if (ExtMbrStartingLba == 0) {
341 break;
342 }
343 } while (ExtMbrStartingLba < ParentHdDev.PartitionSize);
344 }
345
346 Done:
347 FreePool (Mbr);
348
349 return Found;
350 }