1 /** @file
2   Routines supporting partition discovery and
3   logical device reading
4 
5 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
6 
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8 
9 **/
10 
11 #include <IndustryStandard/Mbr.h>
12 #include "FatLitePeim.h"
13 
14 /**
15   Test to see if the Mbr buffer is a valid MBR
16 
17   @param[in]  Mbr               Parent Handle
18   @param[in]  LastLba           Last Lba address on the device.
19 
20   @retval     TRUE              Mbr is a Valid MBR
21   @retval     FALSE             Mbr is not a Valid MBR
22 
23 **/
24 BOOLEAN
PartitionValidMbr(IN MASTER_BOOT_RECORD * Mbr,IN EFI_PEI_LBA LastLba)25 PartitionValidMbr (
26   IN  MASTER_BOOT_RECORD      *Mbr,
27   IN  EFI_PEI_LBA             LastLba
28   )
29 {
30   UINT32  StartingLBA;
31   UINT32  EndingLBA;
32   UINT32  NewEndingLBA;
33   INTN    Index1;
34   INTN    Index2;
35   BOOLEAN MbrValid;
36 
37   if (Mbr->Signature != MBR_SIGNATURE) {
38     return FALSE;
39   }
40   //
41   // The BPB also has this signature, so it can not be used alone.
42   //
43   MbrValid = FALSE;
44   for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) {
45     if (Mbr->Partition[Index1].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) == 0) {
46       continue;
47     }
48 
49     MbrValid    = TRUE;
50     StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA);
51     EndingLBA   = StartingLBA + UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) - 1;
52     if (EndingLBA > LastLba) {
53       //
54       // Compatibility Errata:
55       //  Some systems try to hide drive space with their INT 13h driver
56       //  This does not hide space from the OS driver. This means the MBR
57       //  that gets created from DOS is smaller than the MBR created from
58       //  a real OS (NT & Win98). This leads to BlockIo->LastBlock being
59       //  wrong on some systems FDISKed by the OS.
60       //
61       //  return FALSE Because no block devices on a system are implemented
62       //  with INT 13h
63       //
64       return FALSE;
65     }
66 
67     for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) {
68       if (Mbr->Partition[Index2].OSIndicator == 0x00 || UNPACK_INT32 (Mbr->Partition[Index2].SizeInLBA) == 0) {
69         continue;
70       }
71 
72       NewEndingLBA = UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) + UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) - 1;
73       if (NewEndingLBA >= StartingLBA && UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) <= EndingLBA) {
74         //
75         // This region overlaps with the Index1'th region
76         //
77         return FALSE;
78       }
79     }
80   }
81   //
82   // Non of the regions overlapped so MBR is O.K.
83   //
84   return MbrValid;
85 }
86 
87 /**
88   This function finds Mbr partitions. Main algorithm
89   is ported from DXE partition driver.
90 
91   @param[in]  PrivateData       The global memory map
92   @param[in]  ParentBlockDevNo  The parent block device
93 
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
97 
98 **/
99 BOOLEAN
FatFindMbrPartitions(IN PEI_FAT_PRIVATE_DATA * PrivateData,IN UINTN ParentBlockDevNo)100 FatFindMbrPartitions (
101   IN  PEI_FAT_PRIVATE_DATA *PrivateData,
102   IN  UINTN                ParentBlockDevNo
103   )
104 {
105   EFI_STATUS            Status;
106   MASTER_BOOT_RECORD    *Mbr;
107   UINTN                 Index;
108   BOOLEAN               Found;
109   PEI_FAT_BLOCK_DEVICE  *ParentBlockDev;
110   PEI_FAT_BLOCK_DEVICE  *BlockDev;
111 
112   if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {
113     return FALSE;
114   }
115 
116   ParentBlockDev  = &(PrivateData->BlockDevice[ParentBlockDevNo]);
117 
118   if (ParentBlockDev->BlockSize > PEI_FAT_MAX_BLOCK_SIZE) {
119     DEBUG((DEBUG_ERROR, "Device BlockSize %x exceeds FAT_MAX_BLOCK_SIZE\n", ParentBlockDev->BlockSize));
120     return FALSE;
121   }
122 
123   Found           = FALSE;
124   Mbr             = (MASTER_BOOT_RECORD *) PrivateData->BlockData;
125 
126   Status = FatReadBlock (
127             PrivateData,
128             ParentBlockDevNo,
129             0,
130             ParentBlockDev->BlockSize,
131             Mbr
132             );
133 
134   if (EFI_ERROR (Status) || !PartitionValidMbr (Mbr, ParentBlockDev->LastBlock)) {
135     goto Done;
136   }
137   //
138   // We have a valid mbr - add each partition
139   //
140   for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
141     if (Mbr->Partition[Index].OSIndicator == 0x00 || UNPACK_INT32 (Mbr->Partition[Index].SizeInLBA) == 0) {
142       //
143       // Don't use null MBR entries
144       //
145       continue;
146     }
147     //
148     // Register this partition
149     //
150     if (PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE) {
151 
152       Found                       = TRUE;
153 
154       BlockDev                    = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]);
155 
156       BlockDev->BlockSize         = MBR_SIZE;
157       BlockDev->LastBlock         = UNPACK_INT32 (Mbr->Partition[Index].SizeInLBA) - 1;
158       BlockDev->IoAlign           = ParentBlockDev->IoAlign;
159       BlockDev->Logical           = TRUE;
160       BlockDev->PartitionChecked  = FALSE;
161       BlockDev->StartingPos = MultU64x32 (
162                                 UNPACK_INT32 (Mbr->Partition[Index].StartingLBA),
163                                 ParentBlockDev->BlockSize
164                                 );
165       BlockDev->ParentDevNo = ParentBlockDevNo;
166 
167       PrivateData->BlockDeviceCount++;
168     }
169   }
170 
171 Done:
172 
173   ParentBlockDev->PartitionChecked = TRUE;
174   return Found;
175 }
176