VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/VBoxPkg/PartitionDxe/Mbr.c@ 48730

Last change on this file since 48730 was 48730, checked in by vboxsync, 11 years ago

EFI: Use VBox prefix for our stuff so that it's obvious what's our stuff and what isn't. Also, I do NOT like anyone but iprt/log.h defining LogXXX macros!

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette