328 lines
9.9 KiB
C++
328 lines
9.9 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 1999 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
layout.cxx
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module contains the functions used to determine the disk layout for the EFI filesystem (FAT).
|
||
|
|
||
|
--*/
|
||
|
#include <pch.cxx>
|
||
|
|
||
|
#include "efiwintypes.hxx"
|
||
|
#include "layout.hxx"
|
||
|
|
||
|
BOOLEAN // TRUE if success, FALSE if failure
|
||
|
ChooseLayout(
|
||
|
PPART_DESCRIPTOR PartDes // Pointer to characteristic description of partition
|
||
|
)
|
||
|
{
|
||
|
UINT32 FatType;
|
||
|
UINT32 SectorsPerCluster;
|
||
|
UINT32 FatSectorCount;
|
||
|
|
||
|
//
|
||
|
// Prove that a well formed layout is possible
|
||
|
//
|
||
|
if ( ! ((PartDes->SectorSize == 512) || (PartDes->SectorSize == 1024) ||
|
||
|
(PartDes->SectorSize == 2048) || (PartDes->SectorSize == 4096)) )
|
||
|
{
|
||
|
PartDes->FatType = FAT_TYPE_ILLEGAL;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
FatType = FAT_TYPE_ILLEGAL;
|
||
|
|
||
|
if (PartDes->SectorCount >= MinSectorsFat16(PartDes->SectorSize)) {
|
||
|
FatType = FAT_TYPE_F16;
|
||
|
}
|
||
|
|
||
|
if (PartDes->SectorCount >= MinSectorsFat32(PartDes->SectorSize)) {
|
||
|
FatType = FAT_TYPE_F32;
|
||
|
}
|
||
|
|
||
|
PartDes->FatType = FatType;
|
||
|
|
||
|
switch (FatType) {
|
||
|
|
||
|
case FAT_TYPE_F32:
|
||
|
//
|
||
|
// Fill in PartDes completely...
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// SectorCount is already set
|
||
|
// SectorSize is already set
|
||
|
PartDes->HeaderCount = HEADER_F32;
|
||
|
PartDes->FatEntrySize = 4;
|
||
|
PartDes->MinClusterCount = MIN_CLUSTER_F32;
|
||
|
PartDes->MaxClusterCount = MAX_CLUSTER_F32;
|
||
|
// SectorsPerCluster set below
|
||
|
// FatSectorCount set below
|
||
|
// FatType set above
|
||
|
|
||
|
if (PickClusterSize(PartDes, &SectorsPerCluster, &FatSectorCount)) {
|
||
|
PartDes->SectorsPerCluster = SectorsPerCluster;
|
||
|
PartDes->FatSectorCount = FatSectorCount;
|
||
|
return TRUE;
|
||
|
} else {
|
||
|
DebugPrint("It did not work\n");
|
||
|
return FALSE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case FAT_TYPE_F16:
|
||
|
//
|
||
|
// Fill in PartDes completely...
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// SectorCount is already set
|
||
|
// SectorSize is already set
|
||
|
PartDes->HeaderCount = HEADER_F16 ;
|
||
|
PartDes->FatEntrySize = 2;
|
||
|
PartDes->MinClusterCount = MIN_CLUSTER_F16;
|
||
|
PartDes->MaxClusterCount = MAX_CLUSTER_F16;
|
||
|
// SectorsPerCluster set below
|
||
|
// FatSectorCount set below
|
||
|
// FatType set above
|
||
|
|
||
|
if (PickClusterSize(PartDes, &SectorsPerCluster, &FatSectorCount)) {
|
||
|
PartDes->SectorsPerCluster = SectorsPerCluster;
|
||
|
PartDes->FatSectorCount = FatSectorCount;
|
||
|
return TRUE;
|
||
|
} else {
|
||
|
DebugPrint("It did not work\n");
|
||
|
return FALSE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
DebugAbort("Really Weird Terrible Error...\n");
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
UINT32 // Min. # of sectors for Fat32 part. for given sector size
|
||
|
MinSectorsFat32(
|
||
|
UINT32 SectorSize // The Sector size in question
|
||
|
)
|
||
|
{
|
||
|
UINT32 MinFatSectors32;
|
||
|
UINT32 SectorMin32;
|
||
|
|
||
|
MinFatSectors32 = (SMALLEST_FAT32_BYTES + (SectorSize-1)) / SectorSize;
|
||
|
SectorMin32 =
|
||
|
HEADER_F32 +
|
||
|
(MinFatSectors32*2) + // 2 fats
|
||
|
SAFE_MIN_CLUSTER_F32; // 1 sector for each cluster min
|
||
|
|
||
|
return SectorMin32;
|
||
|
}
|
||
|
|
||
|
UINT32 // Min. # of sectors for Fat16 part. for given sector size
|
||
|
MinSectorsFat16(
|
||
|
UINT32 SectorSize // Sector size to compute for
|
||
|
)
|
||
|
{
|
||
|
UINT32 MinFatSectors16;
|
||
|
UINT32 SectorMin16;
|
||
|
|
||
|
MinFatSectors16 = (SMALLEST_FAT16_BYTES + (SectorSize-1)) / SectorSize;
|
||
|
SectorMin16 =
|
||
|
HEADER_F16 +
|
||
|
(MinFatSectors16*2) + // 2 fats
|
||
|
SAFE_MIN_CLUSTER_F16; // 1 sector for each cluster min
|
||
|
|
||
|
return SectorMin16;
|
||
|
}
|
||
|
|
||
|
BOOLEAN // TRUE for success, FALSE for failure
|
||
|
PickClusterSize(
|
||
|
PPART_DESCRIPTOR PartDes, // characteristics of part. at hand
|
||
|
PUINT32 ReturnedSectorsPerCluster, // RETURNED = number of sectors per cluster
|
||
|
PUINT32 ReturnedFatSectorCount // RETURNED = number of sectors for FAT
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// we need a Cluster size >= SectorSize and <= 32K
|
||
|
// we need MinClusterCount <= ClusterCount <= MaxClusterCount
|
||
|
// we want the FAT size to be reasonable.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// How do we do this? We cheat.
|
||
|
//
|
||
|
// If it's a FAT32 partition (FatEntrySize == 4) we know that we'll
|
||
|
// always have at least approximately 64k clusters, and therefore allow
|
||
|
// at least that many files. So keep upping the cluster size until
|
||
|
// the count falls as low as it can go. This gives a minimum size
|
||
|
// FAT.
|
||
|
//
|
||
|
// If it's a FAT16 partition, we know the FAT table can't take up
|
||
|
// more than 128K of data, so we go for the smallest cluster size we
|
||
|
// can, to make sure there can be as many different files as may be
|
||
|
// needed.
|
||
|
//
|
||
|
// This routine will not work for FAT12 partitions.
|
||
|
//
|
||
|
|
||
|
UINT32 SavedSectorsPerCluster = 0;
|
||
|
UINT32 SavedFatSectorCount = 0;
|
||
|
UINT32 SectorsPerCluster;
|
||
|
UINT32 FatSectorCount;
|
||
|
|
||
|
if (PartDes->FatEntrySize == 4) {
|
||
|
//
|
||
|
// It's a FAT32 partition
|
||
|
//
|
||
|
// Loop along looking for the largest cluster size we can
|
||
|
// get away with
|
||
|
//
|
||
|
|
||
|
SectorsPerCluster = 1;
|
||
|
while ((PartDes->SectorSize * SectorsPerCluster) <= MAX_CLUSTER_BYTES) {
|
||
|
|
||
|
if ( ComputeFatSize(PartDes, SectorsPerCluster, &FatSectorCount) ) {
|
||
|
//
|
||
|
// ComputeFatSize found a FatSectorCount that works with
|
||
|
// this cluster size, so save it, it might be the best one.
|
||
|
//
|
||
|
SavedFatSectorCount = FatSectorCount;
|
||
|
SavedSectorsPerCluster = SectorsPerCluster;
|
||
|
}
|
||
|
//
|
||
|
// If ComputeFatSize returns FALSE, that cluster size didn't work.
|
||
|
// If it returns TRUE, it did work, but the next might work better.
|
||
|
// Keep going until we run out of legal sizes in either case
|
||
|
//
|
||
|
SectorsPerCluster = SectorsPerCluster * 2;
|
||
|
}
|
||
|
|
||
|
} else if (PartDes->FatEntrySize = 2) {
|
||
|
//
|
||
|
// It's a FAT16 partition
|
||
|
//
|
||
|
// Find the *first* (smallest) cluster size that is legal, and use that.
|
||
|
// (Note difference from FAT32 case above)
|
||
|
//
|
||
|
|
||
|
SectorsPerCluster = 1;
|
||
|
while ((PartDes->SectorSize * SectorsPerCluster) <= MAX_CLUSTER_BYTES) {
|
||
|
|
||
|
if ( ComputeFatSize(PartDes, SectorsPerCluster, &FatSectorCount) ) {
|
||
|
//
|
||
|
// ComputeFatSize found a FatSectorCount that works with
|
||
|
// this cluster size, for this loop it's the first one, and
|
||
|
// therefore the smallest cluster size, which is what we
|
||
|
// want for this case. So we are done.
|
||
|
//
|
||
|
SavedFatSectorCount = FatSectorCount;
|
||
|
SavedSectorsPerCluster = SectorsPerCluster;
|
||
|
break;
|
||
|
}
|
||
|
//
|
||
|
// If ComputeFatSize returns FALSE, that cluster size didn't work.
|
||
|
// Keep going until we run out of legal sizes.
|
||
|
//
|
||
|
SectorsPerCluster = SectorsPerCluster * 2;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
//
|
||
|
// TERRIBLE ERROR
|
||
|
//
|
||
|
DebugAbort("TERRIBLE ERROR");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// At this point, if we have found a workable set of cluster size and
|
||
|
// fat size, it is in the Saved vars. If they are 0, we have found
|
||
|
// nothing that will work.
|
||
|
//
|
||
|
if ((SavedSectorsPerCluster) && (SavedFatSectorCount)) {
|
||
|
*ReturnedSectorsPerCluster = SavedSectorsPerCluster;
|
||
|
*ReturnedFatSectorCount = SavedFatSectorCount;
|
||
|
return TRUE;
|
||
|
} else {
|
||
|
*ReturnedSectorsPerCluster = 0;
|
||
|
*ReturnedSectorsPerCluster = 0;
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOLEAN // FALSE if ERROR, TRUE if SUCCESS
|
||
|
ComputeFatSize(
|
||
|
PPART_DESCRIPTOR PartDes, // partition characteristics to compute for
|
||
|
UINT32 SectorsPerCluster, // number of sectors per cluster
|
||
|
PUINT32 ReturnedFatSectorCount // RETURN Number of FAT sectors in each fat
|
||
|
)
|
||
|
{
|
||
|
UINT32 FatSectorCount;
|
||
|
UINT32 EntryCount;
|
||
|
UINT64 SectorsLeft;
|
||
|
UINT64 SpanCount;
|
||
|
UINT64 ClusterCount;
|
||
|
|
||
|
//
|
||
|
// Start with 1 sector of FAT entries, see if it spans. Keep adding
|
||
|
// 1 sector at a time to the FAT size (and reducing data sectors as we go)
|
||
|
// until the remaining data is spanned (or overspanned) by the number
|
||
|
// of cluster entries that fit in the fat.
|
||
|
//
|
||
|
// If entry count runs out of bounds before we find a working answer,
|
||
|
// report an error. (caller must try again with a different cluster size)
|
||
|
//
|
||
|
|
||
|
FatSectorCount = 1;
|
||
|
|
||
|
while (TRUE) {
|
||
|
|
||
|
EntryCount = ((FatSectorCount * PartDes->SectorSize) / PartDes->FatEntrySize) - 2;
|
||
|
|
||
|
if (EntryCount > PartDes->MaxClusterCount) {
|
||
|
return FALSE; // this cluster size is too small
|
||
|
}
|
||
|
|
||
|
SectorsLeft = PartDes->SectorCount - (PartDes->HeaderCount + (FatSectorCount * 2));
|
||
|
|
||
|
SpanCount = (UINT64)EntryCount * (UINT64)SectorsPerCluster;
|
||
|
if (SpanCount >= (UINT64)SectorsLeft) {
|
||
|
//
|
||
|
// This might work, check it out for sure.
|
||
|
//
|
||
|
ClusterCount = (SectorsLeft / SectorsPerCluster);
|
||
|
if ((ClusterCount >= PartDes->MinClusterCount) &&
|
||
|
(ClusterCount <= PartDes->MaxClusterCount))
|
||
|
{
|
||
|
//
|
||
|
// yup, we found it.
|
||
|
//
|
||
|
*ReturnedFatSectorCount = FatSectorCount;
|
||
|
return TRUE;
|
||
|
|
||
|
} else {
|
||
|
//
|
||
|
// something weird has happened, but the basic result
|
||
|
// is that this cluster size won't work, so fail
|
||
|
//
|
||
|
*ReturnedFatSectorCount = 0;
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FatSectorCount = FatSectorCount + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|