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