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