• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Routines supporting partition discovery and
3   logical device reading
4 
5 Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
6 
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
11 
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.
14 
15 **/
16 
17 #include <IndustryStandard/Mbr.h>
18 #include <IndustryStandard/ElTorito.h>
19 #include "FatLitePeim.h"
20 
21 /**
22   This function finds Eltorito partitions. Main algorithm
23   is ported from DXE partition driver.
24 
25   @param  PrivateData       The global memory map
26   @param  ParentBlockDevNo  The parent block device
27 
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;
31 
32 **/
33 BOOLEAN
34 FatFindEltoritoPartitions (
35   IN  PEI_FAT_PRIVATE_DATA *PrivateData,
36   IN  UINTN                ParentBlockDevNo
37   );
38 
39 /**
40   This function finds Mbr partitions. Main algorithm
41   is ported from DXE partition driver.
42 
43   @param  PrivateData       The global memory map
44   @param  ParentBlockDevNo  The parent block device
45 
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;
49 
50 **/
51 BOOLEAN
52 FatFindMbrPartitions (
53   IN  PEI_FAT_PRIVATE_DATA *PrivateData,
54   IN  UINTN                ParentBlockDevNo
55   );
56 
57 
58 /**
59   This function finds partitions (logical devices) in physical block devices.
60 
61   @param  PrivateData       Global memory map for accessing global variables.
62 
63 **/
64 VOID
FatFindPartitions(IN PEI_FAT_PRIVATE_DATA * PrivateData)65 FatFindPartitions (
66   IN  PEI_FAT_PRIVATE_DATA  *PrivateData
67   )
68 {
69   BOOLEAN Found;
70   UINTN   Index;
71 
72   do {
73     Found = FALSE;
74 
75     for (Index = 0; Index < PrivateData->BlockDeviceCount; Index++) {
76       if (!PrivateData->BlockDevice[Index].PartitionChecked) {
77         Found = FatFindMbrPartitions (PrivateData, Index);
78         if (!Found) {
79           Found = FatFindEltoritoPartitions (PrivateData, Index);
80         }
81       }
82     }
83   } while (Found && PrivateData->BlockDeviceCount <= PEI_FAT_MAX_BLOCK_DEVICE);
84 }
85 
86 
87 /**
88   This function finds Eltorito partitions. Main algorithm
89   is ported from DXE partition driver.
90 
91   @param  PrivateData       The global memory map
92   @param  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
FatFindEltoritoPartitions(IN PEI_FAT_PRIVATE_DATA * PrivateData,IN UINTN ParentBlockDevNo)100 FatFindEltoritoPartitions (
101   IN  PEI_FAT_PRIVATE_DATA *PrivateData,
102   IN  UINTN                ParentBlockDevNo
103   )
104 {
105   EFI_STATUS              Status;
106   BOOLEAN                 Found;
107   PEI_FAT_BLOCK_DEVICE    *BlockDev;
108   PEI_FAT_BLOCK_DEVICE    *ParentBlockDev;
109   UINT32                  VolDescriptorLba;
110   UINT32                  Lba;
111   CDROM_VOLUME_DESCRIPTOR *VolDescriptor;
112   ELTORITO_CATALOG        *Catalog;
113   UINTN                   Check;
114   UINTN                   Index;
115   UINTN                   MaxIndex;
116   UINT16                  *CheckBuffer;
117   UINT32                  SubBlockSize;
118   UINT32                  SectorCount;
119   UINT32                  VolSpaceSize;
120 
121   if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {
122     return FALSE;
123   }
124 
125   Found           = FALSE;
126   ParentBlockDev  = &(PrivateData->BlockDevice[ParentBlockDevNo]);
127   VolSpaceSize    = 0;
128 
129   //
130   // CD_ROM has the fixed block size as 2048 bytes
131   //
132   if (ParentBlockDev->BlockSize != 2048) {
133     return FALSE;
134   }
135 
136   VolDescriptor = (CDROM_VOLUME_DESCRIPTOR *) PrivateData->BlockData;
137   Catalog       = (ELTORITO_CATALOG *) VolDescriptor;
138 
139   //
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...
142   //
143   VolDescriptorLba = 15;
144   //
145   // ((16*2048) / Media->BlockSize) - 1;
146   //
147   // Loop: handle one volume descriptor per time
148   //
149   while (TRUE) {
150 
151     VolDescriptorLba += 1;
152     if (VolDescriptorLba > ParentBlockDev->LastBlock) {
153       //
154       // We are pointing past the end of the device so exit
155       //
156       break;
157     }
158 
159     Status = FatReadBlock (
160               PrivateData,
161               ParentBlockDevNo,
162               VolDescriptorLba,
163               ParentBlockDev->BlockSize,
164               VolDescriptor
165               );
166     if (EFI_ERROR (Status)) {
167       break;
168     }
169     //
170     // Check for valid volume descriptor signature
171     //
172     if (VolDescriptor->Unknown.Type == CDVOL_TYPE_END ||
173         CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0
174         ) {
175       //
176       // end of Volume descriptor list
177       //
178       break;
179     }
180     //
181     // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte
182     //
183     if (VolDescriptor->Unknown.Type == CDVOL_TYPE_CODED) {
184       VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[1];
185     }
186     //
187     // Is it an El Torito volume descriptor?
188     //
189     if (CompareMem (
190           VolDescriptor->BootRecordVolume.SystemId,
191           CDVOL_ELTORITO_ID,
192           sizeof (CDVOL_ELTORITO_ID) - 1
193           ) != 0) {
194       continue;
195     }
196     //
197     // Read in the boot El Torito boot catalog
198     //
199     Lba = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);
200     if (Lba > ParentBlockDev->LastBlock) {
201       continue;
202     }
203 
204     Status = FatReadBlock (
205               PrivateData,
206               ParentBlockDevNo,
207               Lba,
208               ParentBlockDev->BlockSize,
209               Catalog
210               );
211     if (EFI_ERROR (Status)) {
212       continue;
213     }
214     //
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
217     //
218     if (Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG || Catalog->Catalog.Id55AA != 0xAA55) {
219       continue;
220     }
221 
222     Check       = 0;
223     CheckBuffer = (UINT16 *) Catalog;
224     for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) {
225       Check += CheckBuffer[Index];
226     }
227 
228     if ((Check & 0xFFFF) != 0) {
229       continue;
230     }
231 
232     MaxIndex = ParentBlockDev->BlockSize / sizeof (ELTORITO_CATALOG);
233     for (Index = 1; Index < MaxIndex; Index += 1) {
234       //
235       // Next entry
236       //
237       Catalog += 1;
238 
239       //
240       // Check this entry
241       //
242       if (Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE || Catalog->Boot.Lba == 0) {
243         continue;
244       }
245 
246       SubBlockSize  = 512;
247       SectorCount   = Catalog->Boot.SectorCount;
248 
249       switch (Catalog->Boot.MediaType) {
250 
251       case ELTORITO_NO_EMULATION:
252         SubBlockSize  = ParentBlockDev->BlockSize;
253         SectorCount   = Catalog->Boot.SectorCount;
254         break;
255 
256       case ELTORITO_HARD_DISK:
257         break;
258 
259       case ELTORITO_12_DISKETTE:
260         SectorCount = 0x50 * 0x02 * 0x0F;
261         break;
262 
263       case ELTORITO_14_DISKETTE:
264         SectorCount = 0x50 * 0x02 * 0x12;
265         break;
266 
267       case ELTORITO_28_DISKETTE:
268         SectorCount = 0x50 * 0x02 * 0x24;
269         break;
270 
271       default:
272         SectorCount   = 0;
273         SubBlockSize  = ParentBlockDev->BlockSize;
274         break;
275       }
276 
277       if (SectorCount < 2) {
278         SectorCount = (VolSpaceSize > ParentBlockDev->LastBlock + 1) ? (UINT32) (ParentBlockDev->LastBlock - Catalog->Boot.Lba + 1) : (UINT32) (VolSpaceSize - Catalog->Boot.Lba);
279       }
280       //
281       // Register this partition
282       //
283       if (PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE) {
284 
285         Found                       = TRUE;
286 
287         BlockDev                    = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]);
288 
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;
296 
297         PrivateData->BlockDeviceCount++;
298       }
299     }
300   }
301 
302   ParentBlockDev->PartitionChecked = TRUE;
303 
304   return Found;
305 
306 }
307 
308 
309 /**
310   Test to see if the Mbr buffer is a valid MBR
311 
312   @param  Mbr               Parent Handle
313   @param  LastLba           Last Lba address on the device.
314 
315   @retval TRUE              Mbr is a Valid MBR
316   @retval FALSE             Mbr is not a Valid MBR
317 
318 **/
319 BOOLEAN
PartitionValidMbr(IN MASTER_BOOT_RECORD * Mbr,IN EFI_PEI_LBA LastLba)320 PartitionValidMbr (
321   IN  MASTER_BOOT_RECORD      *Mbr,
322   IN  EFI_PEI_LBA             LastLba
323   )
324 {
325   UINT32  StartingLBA;
326   UINT32  EndingLBA;
327   UINT32  NewEndingLBA;
328   INTN    Index1;
329   INTN    Index2;
330   BOOLEAN MbrValid;
331 
332   if (Mbr->Signature != MBR_SIGNATURE) {
333     return FALSE;
334   }
335   //
336   // The BPB also has this signature, so it can not be used alone.
337   //
338   MbrValid = FALSE;
339   for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) {
340     if (Mbr->Partition[Index1].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) == 0) {
341       continue;
342     }
343 
344     MbrValid    = TRUE;
345     StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA);
346     EndingLBA   = StartingLBA + UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) - 1;
347     if (EndingLBA > LastLba) {
348       //
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.
355       //
356       //  return FALSE Because no block devices on a system are implemented
357       //  with INT 13h
358       //
359       return FALSE;
360     }
361 
362     for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) {
363       if (Mbr->Partition[Index2].OSIndicator == 0x00 || UNPACK_INT32 (Mbr->Partition[Index2].SizeInLBA) == 0) {
364         continue;
365       }
366 
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) {
369         //
370         // This region overlaps with the Index1'th region
371         //
372         return FALSE;
373       }
374     }
375   }
376   //
377   // Non of the regions overlapped so MBR is O.K.
378   //
379   return MbrValid;
380 }
381 
382 
383 /**
384   This function finds Mbr partitions. Main algorithm
385   is ported from DXE partition driver.
386 
387   @param  PrivateData       The global memory map
388   @param  ParentBlockDevNo  The parent block device
389 
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;
393 
394 **/
395 BOOLEAN
FatFindMbrPartitions(IN PEI_FAT_PRIVATE_DATA * PrivateData,IN UINTN ParentBlockDevNo)396 FatFindMbrPartitions (
397   IN  PEI_FAT_PRIVATE_DATA *PrivateData,
398   IN  UINTN                ParentBlockDevNo
399   )
400 {
401   EFI_STATUS            Status;
402   MASTER_BOOT_RECORD    *Mbr;
403   UINTN                 Index;
404   BOOLEAN               Found;
405   PEI_FAT_BLOCK_DEVICE  *ParentBlockDev;
406   PEI_FAT_BLOCK_DEVICE  *BlockDev;
407 
408   if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {
409     return FALSE;
410   }
411 
412   ParentBlockDev  = &(PrivateData->BlockDevice[ParentBlockDevNo]);
413 
414   Found           = FALSE;
415   Mbr             = (MASTER_BOOT_RECORD *) PrivateData->BlockData;
416 
417   Status = FatReadBlock (
418             PrivateData,
419             ParentBlockDevNo,
420             0,
421             ParentBlockDev->BlockSize,
422             Mbr
423             );
424 
425   if (EFI_ERROR (Status) || !PartitionValidMbr (Mbr, ParentBlockDev->LastBlock)) {
426     goto Done;
427   }
428   //
429   // We have a valid mbr - add each partition
430   //
431   for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
432     if (Mbr->Partition[Index].OSIndicator == 0x00 || UNPACK_INT32 (Mbr->Partition[Index].SizeInLBA) == 0) {
433       //
434       // Don't use null MBR entries
435       //
436       continue;
437     }
438     //
439     // Register this partition
440     //
441     if (PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE) {
442 
443       Found                       = TRUE;
444 
445       BlockDev                    = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]);
446 
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
455                                 );
456       BlockDev->ParentDevNo = ParentBlockDevNo;
457 
458       PrivateData->BlockDeviceCount++;
459     }
460   }
461 
462 Done:
463 
464   ParentBlockDev->PartitionChecked = TRUE;
465   return Found;
466 }
467