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