Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

327 lines
9.9 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. layout.cxx
  5. Abstract:
  6. This module contains the functions used to determine the disk layout for the EFI filesystem (FAT).
  7. --*/
  8. #include <pch.cxx>
  9. #include "efiwintypes.hxx"
  10. #include "layout.hxx"
  11. BOOLEAN // TRUE if success, FALSE if failure
  12. ChooseLayout(
  13. PPART_DESCRIPTOR PartDes // Pointer to characteristic description of partition
  14. )
  15. {
  16. UINT32 FatType;
  17. UINT32 SectorsPerCluster;
  18. UINT32 FatSectorCount;
  19. //
  20. // Prove that a well formed layout is possible
  21. //
  22. if ( ! ((PartDes->SectorSize == 512) || (PartDes->SectorSize == 1024) ||
  23. (PartDes->SectorSize == 2048) || (PartDes->SectorSize == 4096)) )
  24. {
  25. PartDes->FatType = FAT_TYPE_ILLEGAL;
  26. return FALSE;
  27. }
  28. FatType = FAT_TYPE_ILLEGAL;
  29. if (PartDes->SectorCount >= MinSectorsFat16(PartDes->SectorSize)) {
  30. FatType = FAT_TYPE_F16;
  31. }
  32. if (PartDes->SectorCount >= MinSectorsFat32(PartDes->SectorSize)) {
  33. FatType = FAT_TYPE_F32;
  34. }
  35. PartDes->FatType = FatType;
  36. switch (FatType) {
  37. case FAT_TYPE_F32:
  38. //
  39. // Fill in PartDes completely...
  40. //
  41. //
  42. // SectorCount is already set
  43. // SectorSize is already set
  44. PartDes->HeaderCount = HEADER_F32;
  45. PartDes->FatEntrySize = 4;
  46. PartDes->MinClusterCount = MIN_CLUSTER_F32;
  47. PartDes->MaxClusterCount = MAX_CLUSTER_F32;
  48. // SectorsPerCluster set below
  49. // FatSectorCount set below
  50. // FatType set above
  51. if (PickClusterSize(PartDes, &SectorsPerCluster, &FatSectorCount)) {
  52. PartDes->SectorsPerCluster = SectorsPerCluster;
  53. PartDes->FatSectorCount = FatSectorCount;
  54. return TRUE;
  55. } else {
  56. DebugPrint("It did not work\n");
  57. return FALSE;
  58. }
  59. break;
  60. case FAT_TYPE_F16:
  61. //
  62. // Fill in PartDes completely...
  63. //
  64. //
  65. // SectorCount is already set
  66. // SectorSize is already set
  67. PartDes->HeaderCount = HEADER_F16 ;
  68. PartDes->FatEntrySize = 2;
  69. PartDes->MinClusterCount = MIN_CLUSTER_F16;
  70. PartDes->MaxClusterCount = MAX_CLUSTER_F16;
  71. // SectorsPerCluster set below
  72. // FatSectorCount set below
  73. // FatType set above
  74. if (PickClusterSize(PartDes, &SectorsPerCluster, &FatSectorCount)) {
  75. PartDes->SectorsPerCluster = SectorsPerCluster;
  76. PartDes->FatSectorCount = FatSectorCount;
  77. return TRUE;
  78. } else {
  79. DebugPrint("It did not work\n");
  80. return FALSE;
  81. }
  82. break;
  83. default:
  84. DebugAbort("Really Weird Terrible Error...\n");
  85. break;
  86. }
  87. return FALSE;
  88. }
  89. UINT32 // Min. # of sectors for Fat32 part. for given sector size
  90. MinSectorsFat32(
  91. UINT32 SectorSize // The Sector size in question
  92. )
  93. {
  94. UINT32 MinFatSectors32;
  95. UINT32 SectorMin32;
  96. MinFatSectors32 = (SMALLEST_FAT32_BYTES + (SectorSize-1)) / SectorSize;
  97. SectorMin32 =
  98. HEADER_F32 +
  99. (MinFatSectors32*2) + // 2 fats
  100. SAFE_MIN_CLUSTER_F32; // 1 sector for each cluster min
  101. return SectorMin32;
  102. }
  103. UINT32 // Min. # of sectors for Fat16 part. for given sector size
  104. MinSectorsFat16(
  105. UINT32 SectorSize // Sector size to compute for
  106. )
  107. {
  108. UINT32 MinFatSectors16;
  109. UINT32 SectorMin16;
  110. MinFatSectors16 = (SMALLEST_FAT16_BYTES + (SectorSize-1)) / SectorSize;
  111. SectorMin16 =
  112. HEADER_F16 +
  113. (MinFatSectors16*2) + // 2 fats
  114. SAFE_MIN_CLUSTER_F16; // 1 sector for each cluster min
  115. return SectorMin16;
  116. }
  117. BOOLEAN // TRUE for success, FALSE for failure
  118. PickClusterSize(
  119. PPART_DESCRIPTOR PartDes, // characteristics of part. at hand
  120. PUINT32 ReturnedSectorsPerCluster, // RETURNED = number of sectors per cluster
  121. PUINT32 ReturnedFatSectorCount // RETURNED = number of sectors for FAT
  122. )
  123. {
  124. //
  125. // we need a Cluster size >= SectorSize and <= 32K
  126. // we need MinClusterCount <= ClusterCount <= MaxClusterCount
  127. // we want the FAT size to be reasonable.
  128. //
  129. //
  130. // How do we do this? We cheat.
  131. //
  132. // If it's a FAT32 partition (FatEntrySize == 4) we know that we'll
  133. // always have at least approximately 64k clusters, and therefore allow
  134. // at least that many files. So keep upping the cluster size until
  135. // the count falls as low as it can go. This gives a minimum size
  136. // FAT.
  137. //
  138. // If it's a FAT16 partition, we know the FAT table can't take up
  139. // more than 128K of data, so we go for the smallest cluster size we
  140. // can, to make sure there can be as many different files as may be
  141. // needed.
  142. //
  143. // This routine will not work for FAT12 partitions.
  144. //
  145. UINT32 SavedSectorsPerCluster = 0;
  146. UINT32 SavedFatSectorCount = 0;
  147. UINT32 SectorsPerCluster;
  148. UINT32 FatSectorCount;
  149. if (PartDes->FatEntrySize == 4) {
  150. //
  151. // It's a FAT32 partition
  152. //
  153. // Loop along looking for the largest cluster size we can
  154. // get away with
  155. //
  156. SectorsPerCluster = 1;
  157. while ((PartDes->SectorSize * SectorsPerCluster) <= MAX_CLUSTER_BYTES) {
  158. if ( ComputeFatSize(PartDes, SectorsPerCluster, &FatSectorCount) ) {
  159. //
  160. // ComputeFatSize found a FatSectorCount that works with
  161. // this cluster size, so save it, it might be the best one.
  162. //
  163. SavedFatSectorCount = FatSectorCount;
  164. SavedSectorsPerCluster = SectorsPerCluster;
  165. }
  166. //
  167. // If ComputeFatSize returns FALSE, that cluster size didn't work.
  168. // If it returns TRUE, it did work, but the next might work better.
  169. // Keep going until we run out of legal sizes in either case
  170. //
  171. SectorsPerCluster = SectorsPerCluster * 2;
  172. }
  173. } else if (PartDes->FatEntrySize = 2) {
  174. //
  175. // It's a FAT16 partition
  176. //
  177. // Find the *first* (smallest) cluster size that is legal, and use that.
  178. // (Note difference from FAT32 case above)
  179. //
  180. SectorsPerCluster = 1;
  181. while ((PartDes->SectorSize * SectorsPerCluster) <= MAX_CLUSTER_BYTES) {
  182. if ( ComputeFatSize(PartDes, SectorsPerCluster, &FatSectorCount) ) {
  183. //
  184. // ComputeFatSize found a FatSectorCount that works with
  185. // this cluster size, for this loop it's the first one, and
  186. // therefore the smallest cluster size, which is what we
  187. // want for this case. So we are done.
  188. //
  189. SavedFatSectorCount = FatSectorCount;
  190. SavedSectorsPerCluster = SectorsPerCluster;
  191. break;
  192. }
  193. //
  194. // If ComputeFatSize returns FALSE, that cluster size didn't work.
  195. // Keep going until we run out of legal sizes.
  196. //
  197. SectorsPerCluster = SectorsPerCluster * 2;
  198. }
  199. } else {
  200. //
  201. // TERRIBLE ERROR
  202. //
  203. DebugAbort("TERRIBLE ERROR");
  204. return FALSE;
  205. }
  206. //
  207. // At this point, if we have found a workable set of cluster size and
  208. // fat size, it is in the Saved vars. If they are 0, we have found
  209. // nothing that will work.
  210. //
  211. if ((SavedSectorsPerCluster) && (SavedFatSectorCount)) {
  212. *ReturnedSectorsPerCluster = SavedSectorsPerCluster;
  213. *ReturnedFatSectorCount = SavedFatSectorCount;
  214. return TRUE;
  215. } else {
  216. *ReturnedSectorsPerCluster = 0;
  217. *ReturnedSectorsPerCluster = 0;
  218. return FALSE;
  219. }
  220. }
  221. BOOLEAN // FALSE if ERROR, TRUE if SUCCESS
  222. ComputeFatSize(
  223. PPART_DESCRIPTOR PartDes, // partition characteristics to compute for
  224. UINT32 SectorsPerCluster, // number of sectors per cluster
  225. PUINT32 ReturnedFatSectorCount // RETURN Number of FAT sectors in each fat
  226. )
  227. {
  228. UINT32 FatSectorCount;
  229. UINT32 EntryCount;
  230. UINT64 SectorsLeft;
  231. UINT64 SpanCount;
  232. UINT64 ClusterCount;
  233. //
  234. // Start with 1 sector of FAT entries, see if it spans. Keep adding
  235. // 1 sector at a time to the FAT size (and reducing data sectors as we go)
  236. // until the remaining data is spanned (or overspanned) by the number
  237. // of cluster entries that fit in the fat.
  238. //
  239. // If entry count runs out of bounds before we find a working answer,
  240. // report an error. (caller must try again with a different cluster size)
  241. //
  242. FatSectorCount = 1;
  243. while (TRUE) {
  244. EntryCount = ((FatSectorCount * PartDes->SectorSize) / PartDes->FatEntrySize) - 2;
  245. if (EntryCount > PartDes->MaxClusterCount) {
  246. return FALSE; // this cluster size is too small
  247. }
  248. SectorsLeft = PartDes->SectorCount - (PartDes->HeaderCount + (FatSectorCount * 2));
  249. SpanCount = (UINT64)EntryCount * (UINT64)SectorsPerCluster;
  250. if (SpanCount >= (UINT64)SectorsLeft) {
  251. //
  252. // This might work, check it out for sure.
  253. //
  254. ClusterCount = (SectorsLeft / SectorsPerCluster);
  255. if ((ClusterCount >= PartDes->MinClusterCount) &&
  256. (ClusterCount <= PartDes->MaxClusterCount))
  257. {
  258. //
  259. // yup, we found it.
  260. //
  261. *ReturnedFatSectorCount = FatSectorCount;
  262. return TRUE;
  263. } else {
  264. //
  265. // something weird has happened, but the basic result
  266. // is that this cluster size won't work, so fail
  267. //
  268. *ReturnedFatSectorCount = 0;
  269. return FALSE;
  270. }
  271. }
  272. FatSectorCount = FatSectorCount + 1;
  273. }
  274. }