2 Routines supporting partition discovery and
5 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials are licensed and made available
8 under the terms and conditions of the BSD License which accompanies this
9 distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include <IndustryStandard/Mbr.h>
18 #include <IndustryStandard/ElTorito.h>
19 #include "FatLitePeim.h"
22 This function finds Eltorito partitions. Main algorithm
23 is ported from DXE partition driver.
25 @param PrivateData The global memory map
26 @param ParentBlockDevNo The parent block device
28 @retval TRUE New partitions are detected and logical block devices
29 are added to block device array
30 @retval FALSE No New partitions are added;
34 FatFindEltoritoPartitions (
35 IN PEI_FAT_PRIVATE_DATA
*PrivateData
,
36 IN UINTN ParentBlockDevNo
40 This function finds Mbr partitions. Main algorithm
41 is ported from DXE partition driver.
43 @param PrivateData The global memory map
44 @param ParentBlockDevNo The parent block device
46 @retval TRUE New partitions are detected and logical block devices
47 are added to block device array
48 @retval FALSE No New partitions are added;
52 FatFindMbrPartitions (
53 IN PEI_FAT_PRIVATE_DATA
*PrivateData
,
54 IN UINTN ParentBlockDevNo
59 This function finds partitions (logical devices) in physical block devices.
61 @param PrivateData Global memory map for accessing global variables.
66 IN PEI_FAT_PRIVATE_DATA
*PrivateData
75 for (Index
= 0; Index
< PrivateData
->BlockDeviceCount
; Index
++) {
76 if (!PrivateData
->BlockDevice
[Index
].PartitionChecked
) {
77 Found
= FatFindMbrPartitions (PrivateData
, Index
);
79 Found
= FatFindEltoritoPartitions (PrivateData
, Index
);
83 } while (Found
&& PrivateData
->BlockDeviceCount
<= PEI_FAT_MAX_BLOCK_DEVICE
);
88 This function finds Eltorito partitions. Main algorithm
89 is ported from DXE partition driver.
91 @param PrivateData The global memory map
92 @param ParentBlockDevNo The parent block device
94 @retval TRUE New partitions are detected and logical block devices
95 are added to block device array
96 @retval FALSE No New partitions are added;
100 FatFindEltoritoPartitions (
101 IN PEI_FAT_PRIVATE_DATA
*PrivateData
,
102 IN UINTN ParentBlockDevNo
107 PEI_FAT_BLOCK_DEVICE
*BlockDev
;
108 PEI_FAT_BLOCK_DEVICE
*ParentBlockDev
;
109 UINT32 VolDescriptorLba
;
111 CDROM_VOLUME_DESCRIPTOR
*VolDescriptor
;
112 ELTORITO_CATALOG
*Catalog
;
121 if (ParentBlockDevNo
> PEI_FAT_MAX_BLOCK_DEVICE
- 1) {
126 ParentBlockDev
= &(PrivateData
->BlockDevice
[ParentBlockDevNo
]);
130 // CD_ROM has the fixed block size as 2048 bytes
132 if (ParentBlockDev
->BlockSize
!= 2048) {
136 VolDescriptor
= (CDROM_VOLUME_DESCRIPTOR
*) PrivateData
->BlockData
;
137 Catalog
= (ELTORITO_CATALOG
*) VolDescriptor
;
140 // the ISO-9660 volume descriptor starts at 32k on the media
141 // and CD_ROM has the fixed block size as 2048 bytes, so...
143 VolDescriptorLba
= 15;
145 // ((16*2048) / Media->BlockSize) - 1;
147 // Loop: handle one volume descriptor per time
151 VolDescriptorLba
+= 1;
152 if (VolDescriptorLba
> ParentBlockDev
->LastBlock
) {
154 // We are pointing past the end of the device so exit
159 Status
= FatReadBlock (
163 ParentBlockDev
->BlockSize
,
166 if (EFI_ERROR (Status
)) {
170 // Check for valid volume descriptor signature
172 if (VolDescriptor
->Unknown
.Type
== CDVOL_TYPE_END
||
173 CompareMem (VolDescriptor
->Unknown
.Id
, CDVOL_ID
, sizeof (VolDescriptor
->Unknown
.Id
)) != 0
176 // end of Volume descriptor list
181 // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte
183 if (VolDescriptor
->Unknown
.Type
== CDVOL_TYPE_CODED
) {
184 VolSpaceSize
= VolDescriptor
->PrimaryVolume
.VolSpaceSize
[1];
187 // Is it an El Torito volume descriptor?
190 VolDescriptor
->BootRecordVolume
.SystemId
,
192 sizeof (CDVOL_ELTORITO_ID
) - 1
197 // Read in the boot El Torito boot catalog
199 Lba
= UNPACK_INT32 (VolDescriptor
->BootRecordVolume
.EltCatalog
);
200 if (Lba
> ParentBlockDev
->LastBlock
) {
204 Status
= FatReadBlock (
208 ParentBlockDev
->BlockSize
,
211 if (EFI_ERROR (Status
)) {
215 // We don't care too much about the Catalog header's contents, but we do want
216 // to make sure it looks like a Catalog header
218 if (Catalog
->Catalog
.Indicator
!= ELTORITO_ID_CATALOG
|| Catalog
->Catalog
.Id55AA
!= 0xAA55) {
223 CheckBuffer
= (UINT16
*) Catalog
;
224 for (Index
= 0; Index
< sizeof (ELTORITO_CATALOG
) / sizeof (UINT16
); Index
+= 1) {
225 Check
+= CheckBuffer
[Index
];
228 if ((Check
& 0xFFFF) != 0) {
232 MaxIndex
= ParentBlockDev
->BlockSize
/ sizeof (ELTORITO_CATALOG
);
233 for (Index
= 1; Index
< MaxIndex
; Index
+= 1) {
242 if (Catalog
->Boot
.Indicator
!= ELTORITO_ID_SECTION_BOOTABLE
|| Catalog
->Boot
.Lba
== 0) {
247 SectorCount
= Catalog
->Boot
.SectorCount
;
249 switch (Catalog
->Boot
.MediaType
) {
251 case ELTORITO_NO_EMULATION
:
252 SubBlockSize
= ParentBlockDev
->BlockSize
;
253 SectorCount
= Catalog
->Boot
.SectorCount
;
256 case ELTORITO_HARD_DISK
:
259 case ELTORITO_12_DISKETTE
:
260 SectorCount
= 0x50 * 0x02 * 0x0F;
263 case ELTORITO_14_DISKETTE
:
264 SectorCount
= 0x50 * 0x02 * 0x12;
267 case ELTORITO_28_DISKETTE
:
268 SectorCount
= 0x50 * 0x02 * 0x24;
273 SubBlockSize
= ParentBlockDev
->BlockSize
;
277 if (SectorCount
< 2) {
278 SectorCount
= (VolSpaceSize
> ParentBlockDev
->LastBlock
+ 1) ? (UINT32
) (ParentBlockDev
->LastBlock
- Catalog
->Boot
.Lba
+ 1) : (UINT32
) (VolSpaceSize
- Catalog
->Boot
.Lba
);
281 // Register this partition
283 if (PrivateData
->BlockDeviceCount
< PEI_FAT_MAX_BLOCK_DEVICE
) {
287 BlockDev
= &(PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
]);
289 BlockDev
->BlockSize
= SubBlockSize
;
290 BlockDev
->LastBlock
= SectorCount
- 1;
291 BlockDev
->IoAlign
= ParentBlockDev
->IoAlign
;
292 BlockDev
->Logical
= TRUE
;
293 BlockDev
->PartitionChecked
= FALSE
;
294 BlockDev
->StartingPos
= MultU64x32 (Catalog
->Boot
.Lba
, ParentBlockDev
->BlockSize
);
295 BlockDev
->ParentDevNo
= ParentBlockDevNo
;
297 PrivateData
->BlockDeviceCount
++;
302 ParentBlockDev
->PartitionChecked
= TRUE
;
310 Test to see if the Mbr buffer is a valid MBR
312 @param Mbr Parent Handle
313 @param LastLba Last Lba address on the device.
315 @retval TRUE Mbr is a Valid MBR
316 @retval FALSE Mbr is not a Valid MBR
321 IN MASTER_BOOT_RECORD
*Mbr
,
322 IN EFI_PEI_LBA LastLba
332 if (Mbr
->Signature
!= MBR_SIGNATURE
) {
336 // The BPB also has this signature, so it can not be used alone.
339 for (Index1
= 0; Index1
< MAX_MBR_PARTITIONS
; Index1
++) {
340 if (Mbr
->Partition
[Index1
].OSIndicator
== 0x00 || UNPACK_UINT32 (Mbr
->Partition
[Index1
].SizeInLBA
) == 0) {
345 StartingLBA
= UNPACK_UINT32 (Mbr
->Partition
[Index1
].StartingLBA
);
346 EndingLBA
= StartingLBA
+ UNPACK_UINT32 (Mbr
->Partition
[Index1
].SizeInLBA
) - 1;
347 if (EndingLBA
> LastLba
) {
349 // Compatability Errata:
350 // Some systems try to hide drive space with thier INT 13h driver
351 // This does not hide space from the OS driver. This means the MBR
352 // that gets created from DOS is smaller than the MBR created from
353 // a real OS (NT & Win98). This leads to BlockIo->LastBlock being
354 // wrong on some systems FDISKed by the OS.
356 // return FALSE Because no block devices on a system are implemented
362 for (Index2
= Index1
+ 1; Index2
< MAX_MBR_PARTITIONS
; Index2
++) {
363 if (Mbr
->Partition
[Index2
].OSIndicator
== 0x00 || UNPACK_INT32 (Mbr
->Partition
[Index2
].SizeInLBA
) == 0) {
367 NewEndingLBA
= UNPACK_UINT32 (Mbr
->Partition
[Index2
].StartingLBA
) + UNPACK_UINT32 (Mbr
->Partition
[Index2
].SizeInLBA
) - 1;
368 if (NewEndingLBA
>= StartingLBA
&& UNPACK_UINT32 (Mbr
->Partition
[Index2
].StartingLBA
) <= EndingLBA
) {
370 // This region overlaps with the Index1'th region
377 // Non of the regions overlapped so MBR is O.K.
384 This function finds Mbr partitions. Main algorithm
385 is ported from DXE partition driver.
387 @param PrivateData The global memory map
388 @param ParentBlockDevNo The parent block device
390 @retval TRUE New partitions are detected and logical block devices
391 are added to block device array
392 @retval FALSE No New partitions are added;
396 FatFindMbrPartitions (
397 IN PEI_FAT_PRIVATE_DATA
*PrivateData
,
398 IN UINTN ParentBlockDevNo
402 MASTER_BOOT_RECORD
*Mbr
;
405 PEI_FAT_BLOCK_DEVICE
*ParentBlockDev
;
406 PEI_FAT_BLOCK_DEVICE
*BlockDev
;
408 if (ParentBlockDevNo
> PEI_FAT_MAX_BLOCK_DEVICE
- 1) {
412 ParentBlockDev
= &(PrivateData
->BlockDevice
[ParentBlockDevNo
]);
415 Mbr
= (MASTER_BOOT_RECORD
*) PrivateData
->BlockData
;
417 Status
= FatReadBlock (
421 ParentBlockDev
->BlockSize
,
425 if (EFI_ERROR (Status
) || !PartitionValidMbr (Mbr
, ParentBlockDev
->LastBlock
)) {
429 // We have a valid mbr - add each partition
431 for (Index
= 0; Index
< MAX_MBR_PARTITIONS
; Index
++) {
432 if (Mbr
->Partition
[Index
].OSIndicator
== 0x00 || UNPACK_INT32 (Mbr
->Partition
[Index
].SizeInLBA
) == 0) {
434 // Don't use null MBR entries
439 // Register this partition
441 if (PrivateData
->BlockDeviceCount
< PEI_FAT_MAX_BLOCK_DEVICE
) {
445 BlockDev
= &(PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
]);
447 BlockDev
->BlockSize
= MBR_SIZE
;
448 BlockDev
->LastBlock
= UNPACK_INT32 (Mbr
->Partition
[Index
].SizeInLBA
) - 1;
449 BlockDev
->IoAlign
= ParentBlockDev
->IoAlign
;
450 BlockDev
->Logical
= TRUE
;
451 BlockDev
->PartitionChecked
= FALSE
;
452 BlockDev
->StartingPos
= MultU64x32 (
453 UNPACK_INT32 (Mbr
->Partition
[Index
].StartingLBA
),
454 ParentBlockDev
->BlockSize
456 BlockDev
->ParentDevNo
= ParentBlockDevNo
;
458 PrivateData
->BlockDeviceCount
++;
464 ParentBlockDev
->PartitionChecked
= TRUE
;