ff_format.c 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075
  1. /*
  2. * FreeRTOS+FAT V2.3.3
  3. * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. * this software and associated documentation files (the "Software"), to deal in
  7. * the Software without restriction, including without limitation the rights to
  8. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  9. * the Software, and to permit persons to whom the Software is furnished to do so,
  10. * subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in all
  13. * copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  17. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  18. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  19. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * https://www.FreeRTOS.org
  23. * https://github.com/FreeRTOS
  24. *
  25. */
  26. /**
  27. * @file ff_format.c
  28. * @ingroup FORMAT
  29. *
  30. * @defgroup FAT Fat File-System
  31. * @brief Format a drive, given the number of sectors.
  32. *
  33. **/
  34. #include "ff_headers.h"
  35. #include <time.h>
  36. #include <string.h>
  37. #if defined( __BORLANDC__ )
  38. #include "ff_windows.h"
  39. #else
  40. #include "FreeRTOS.h"
  41. #include "task.h" /* For FreeRTOS date/time function */
  42. #endif
  43. /*=========================================================================================== */
  44. #define OFS_PART_ACTIVE_8 0x000 /* 0x01BE 0x80 if active */
  45. #define OFS_PART_START_HEAD_8 0x001 /* 0x01BF */
  46. #define OFS_PART_START_SEC_TRACK_16 0x002 /* 0x01C0 */
  47. #define OFS_PART_ID_NUMBER_8 0x004 /* 0x01C2 */
  48. #define OFS_PART_ENDING_HEAD_8 0x005 /* 0x01C3 */
  49. #define OFS_PART_ENDING_SEC_TRACK_16 0x006 /* 0x01C4 = SectorCount - 1 - ulHiddenSectors */
  50. #define OFS_PART_STARTING_LBA_32 0x008 /* 0x01C6 = ulHiddenSectors (This is important) */
  51. #define OFS_PART_LENGTH_32 0x00C /* 0x01CA = SectorCount - 1 - ulHiddenSectors */
  52. #define OFS_PTABLE_MACH_CODE 0x000 /* 0x0000 */
  53. #define OFS_PTABLE_PART_0 0x1BE /* 446 */
  54. #define OFS_PTABLE_PART_1 0x1CE /* 462 */
  55. #define OFS_PTABLE_PART_2 0x1DE /* 478 */
  56. #define OFS_PTABLE_PART_3 0x1FE /* 494 */
  57. #define OFS_PTABLE_PART_LEN 16
  58. /*=========================================================================================== */
  59. #define OFS_BPB_jmpBoot_24 0x000 /* uchar jmpBoot[3] "0xEB 0x00 0x90" */
  60. #define OFS_BPB_OEMName_64 0x003 /* uchar BS_OEMName[8] "MSWIN4.1" */
  61. #define OFS_BPB_BytsPerSec_16 0x00B /* Only 512, 1024, 2048 or 4096 */
  62. #define OFS_BPB_SecPerClus_8 0x00D /* Only 1, 2, 4, 8, 16, 32, 64, 128 */
  63. #define OFS_BPB_ResvdSecCnt_16 0x00E /* ulFATReservedSectors, e.g. 1 (FAT12/16) or 32 (FAT32) */
  64. #define OFS_BPB_NumFATs_8 0x010 /* 2 recommended */
  65. #define OFS_BPB_RootEntCnt_16 0x011 /* ((iFAT16RootSectors * 512) / 32) 512 (FAT12/16) or 0 (FAT32) */
  66. #define OFS_BPB_TotSec16_16 0x013 /* xxx (FAT12/16) or 0 (FAT32) */
  67. #define OFS_BPB_Media_8 0x015 /* 0xF0 (rem media) also in FAT[0] low byte */
  68. #define OFS_BPB_FATSz16_16 0x016
  69. #define OFS_BPB_SecPerTrk_16 0x018 /* n.a. CF has no tracks */
  70. #define OFS_BPB_NumHeads_16 0x01A /* n.a. 1 ? */
  71. #define OFS_BPB_HiddSec_32 0x01C /* n.a. 0 for nonparitioned volume */
  72. #define OFS_BPB_TotSec32_32 0x020 /* >= 0x10000 */
  73. #define OFS_BPB_16_DrvNum_8 0x024 /* n.a. */
  74. #define OFS_BPB_16_Reserved1_8 0x025 /* n.a. */
  75. #define OFS_BPB_16_BootSig_8 0x026 /* n.a. */
  76. #define OFS_BPB_16_BS_VolID_32 0x027 /* "unique" number */
  77. #define OFS_BPB_16_BS_VolLab_88 0x02B /* "NO NAME " */
  78. #define OFS_BPB_16_FilSysType_64 0x036 /* "FAT12 " */
  79. #define OFS_BPB_32_FATSz32_32 0x024 /* Only when BPB_FATSz16 = 0 */
  80. #define OFS_BPB_32_ExtFlags_16 0x028 /* FAT32 only */
  81. #define OFS_BPB_32_FSVer_16 0x02A /* 0:0 */
  82. #define OFS_BPB_32_RootClus_32 0x02C /* See 'iFAT32RootClusters' Normally 2 */
  83. #define OFS_BPB_32_FSInfo_16 0x030 /* Normally 1 */
  84. #define OFS_BPB_32_BkBootSec_16 0x032 /* Normally 6 */
  85. #define OFS_BPB_32_Reserved_96 0x034 /* Zeros */
  86. #define OFS_BPB_32_DrvNum_8 0x040 /* n.a. */
  87. #define OFS_BPB_32_Reserved1_8 0x041 /* n.a. */
  88. #define OFS_BPB_32_BootSig_8 0x042 /* n.a. */
  89. #define OFS_BPB_32_VolID_32 0x043 /* "unique" number */
  90. #define OFS_BPB_32_VolLab_88 0x047 /* "NO NAME " */
  91. #define OFS_BPB_32_FilSysType_64 0x052 /* "FAT12 " */
  92. #define OFS_FSI_32_LeadSig 0x000 /* With contents 0x41615252 */
  93. #define OFS_FSI_32_Reserved1 0x004 /* 480 times 0 */
  94. #define OFS_FSI_32_StrucSig 0x1E4 /* With contents 0x61417272 */
  95. #define OFS_FSI_32_Free_Count 0x1E8 /* last known free cluster count on the volume, ~0 for unknown */
  96. #define OFS_FSI_32_Nxt_Free 0x1EC /* cluster number at which the driver should start looking for free clusters */
  97. #define OFS_FSI_32_Reserved2 0x1F0 /* zero's */
  98. #define OFS_FSI_32_TrailSig 0x1FC /* 0xAA550000 (little endian) */
  99. #define RESV_COUNT 32
  100. #define MX_LBA_TO_MOVE_FAT 8192uL
  101. #define SIZE_512_MB 0x100000uL
  102. #ifdef ffconfigMIN_CLUSTERS_FAT32
  103. #define MIN_CLUSTER_COUNT_FAT32 ffconfigMIN_CLUSTERS_FAT32
  104. #else
  105. #define MIN_CLUSTER_COUNT_FAT32 ( 65525 )
  106. #endif
  107. #ifdef ffconfigMIN_CLUSTERS_FAT16
  108. #define MIN_CLUSTERS_FAT16 ffconfigMIN_CLUSTERS_FAT16
  109. #else
  110. #define MIN_CLUSTERS_FAT16 ( 4085 + 1 )
  111. #endif
  112. #ifndef ffconfigFAT16_ROOT_SECTORS
  113. #define ffconfigFAT16_ROOT_SECTORS 32
  114. #endif
  115. /*-----------------------------------------------------------*/
  116. /** A set of variables needed while formatting a disk, it is passed to the helper functions. */
  117. struct xFormatSet
  118. {
  119. uint32_t ulHiddenSectors; /**< Space from MBR ( Master Boot Record ) and partition table. */
  120. uint32_t ulFSInfo; /**< Sector number of FSINFO structure within the reserved area. */
  121. uint32_t ulBackupBootSector; /**< Sector number of "copy of the boot record" within the reserved area. */
  122. BaseType_t xFATCount; /**< Number of FAT's, which is fixed as 2. */
  123. uint32_t ulFATReservedSectors; /**< Space between the partition table and FAT table. */
  124. int32_t iFAT16RootSectors; /**< Number of sectors reserved for root directory ( FAT16 only ). */
  125. int32_t iFAT32RootClusters; /**< Initial amount of clusters claimed for root directory ( FAT32 only ). */
  126. uint8_t ucFATType; /**< Either 'FF_T_FAT16' or 'FF_T_FAT32'. */
  127. uint32_t ulVolumeID; /**< A pseudo Volume ID. */
  128. uint32_t ulSectorsPerFAT; /**< Number of sectors used by a single FAT table. */
  129. uint32_t ulClustersPerFATSector; /**< # of clusters which can be described within a sector ( either 256 or 128 ). */
  130. uint32_t ulSectorsPerCluster; /**< Size of a cluster ( # of sectors ). */
  131. uint32_t ulUsableDataSectors; /**< Usable data sectors ( = SectorCount - ( ulHiddenSectors + ulFATReservedSectors ) ). */
  132. uint32_t ulUsableDataClusters; /**< equals "ulUsableDataSectors / ulSectorsPerCluster". */
  133. uint32_t ulNonDataSectors; /**< ulFATReservedSectors + ulHiddenSectors + iFAT16RootSectors. */
  134. uint32_t ulClusterBeginLBA; /**< Sector address of the first data cluster. */
  135. uint32_t ulSectorCount; /**< The total number of sectors in the partition. */
  136. uint8_t * pucSectorBuffer; /**< A buffer big enough to contain the contents of one sector ( see pxIOManager->usSectorSize ). */
  137. FF_SPartFound_t xPartitionsFound; /**< An array of descriptors of partitions. */
  138. FF_Part_t * pxMyPartition; /**< A pointer to the partition descriptor for the disk to be formatted. */
  139. FF_IOManager_t * pxIOManager; /**< The IO-manager. */
  140. };
  141. /** A set of variables needed while partitioning a disk, it is passed to the helper functions. */
  142. struct xPartitionSet
  143. {
  144. uint32_t ulInterSpace; /**< Hidden space between 2 extended partitions. */
  145. FF_Part_t pxPartitions[ ffconfigMAX_PARTITIONS ]; /**< A short description of all partitions. */
  146. BaseType_t xPartitionCount; /**< The number of partitions wanted by the caller. */
  147. FF_IOManager_t * pxIOManager; /**< The +FAT IO-manager. */
  148. };
  149. /*-----------------------------------------------------------*/
  150. /* Five helper functions for FF_FormatDisk(). */
  151. static FF_Error_t prvFormatGetClusterSize( struct xFormatSet * pxSet,
  152. BaseType_t xPreferFAT16,
  153. BaseType_t xSmallClusters );
  154. static void prvFormatOptimiseFATLocation( struct xFormatSet * pxSet );
  155. static FF_Error_t prvFormatWriteBPB( struct xFormatSet * pxSet,
  156. const char * pcVolumeName );
  157. static FF_Error_t prvFormatInitialiseFAT( struct xFormatSet * pxSet,
  158. int32_t lFatBeginLBA );
  159. static FF_Error_t prvFormatInitialiseRootDir( struct xFormatSet * pxSet,
  160. int32_t lDirectoryBegin,
  161. const char * pcVolumeName );
  162. /* And two helper functions for FF_Partition(). */
  163. static FF_Error_t prvPartitionPrimary( struct xPartitionSet * pxSet );
  164. static FF_Error_t prvPartitionExtended( struct xPartitionSet * pxSet,
  165. FF_PartitionParameters_t * pParams );
  166. /*-----------------------------------------------------------*/
  167. static portINLINE uint32_t ulMin32( uint32_t a,
  168. uint32_t b )
  169. {
  170. uint32_t ulReturn;
  171. if( a <= b )
  172. {
  173. ulReturn = a;
  174. }
  175. else
  176. {
  177. ulReturn = b;
  178. }
  179. return ulReturn;
  180. }
  181. /*-----------------------------------------------------------*/
  182. /**
  183. * @brief: Decide whether FAT32 or FAT16 shall be used and try to find an optimum cluster size.
  184. * @param[in] pxSet: A set of parameters describing this format session.
  185. * @param[in] xPreferFAT16: When pdTRUE, it will use FAT16 in stead of FAT32.
  186. * @param[in] xSmallClusters: When pdTRUE, it will make the cluster size as small as possible.
  187. * @return A standard +FAT error code ( not an errno ).
  188. * @note In order to get the best speed, use pdFALSE, pdFALSE: to get FAT32 with large clusters.
  189. */
  190. static FF_Error_t prvFormatGetClusterSize( struct xFormatSet * pxSet,
  191. BaseType_t xPreferFAT16,
  192. BaseType_t xSmallClusters )
  193. {
  194. FF_Error_t xReturn = FF_ERR_NONE;
  195. /* Either search from small to large or v.v. */
  196. if( xSmallClusters != 0 )
  197. {
  198. /* The caller prefers to have small clusters.
  199. * Less waste but it can be slower. */
  200. pxSet->ulSectorsPerCluster = 1U;
  201. }
  202. else
  203. {
  204. if( pxSet->ucFATType == FF_T_FAT32 )
  205. {
  206. pxSet->ulSectorsPerCluster = 64U;
  207. }
  208. else
  209. {
  210. pxSet->ulSectorsPerCluster = 32U;
  211. }
  212. }
  213. for( ; ; )
  214. {
  215. int32_t groupSize;
  216. /* Usable sectors */
  217. pxSet->ulUsableDataSectors = pxSet->ulSectorCount - pxSet->ulNonDataSectors;
  218. /* Each group consists of 'xFATCount' sectors + 'ulClustersPerFATSector' clusters */
  219. groupSize = pxSet->xFATCount + pxSet->ulClustersPerFATSector * pxSet->ulSectorsPerCluster;
  220. /* This amount of groups will fit: */
  221. pxSet->ulSectorsPerFAT = ( pxSet->ulUsableDataSectors + groupSize - pxSet->ulSectorsPerCluster - pxSet->xFATCount ) / groupSize;
  222. pxSet->ulUsableDataClusters = ulMin32(
  223. ( uint32_t ) ( pxSet->ulUsableDataSectors - pxSet->xFATCount * pxSet->ulSectorsPerFAT ) / pxSet->ulSectorsPerCluster,
  224. ( uint32_t ) ( pxSet->ulClustersPerFATSector * pxSet->ulSectorsPerFAT ) );
  225. pxSet->ulUsableDataSectors = pxSet->ulUsableDataClusters * pxSet->ulSectorsPerCluster;
  226. if( ( pxSet->ucFATType == FF_T_FAT16 ) && ( pxSet->ulUsableDataClusters >= MIN_CLUSTERS_FAT16 ) && ( pxSet->ulUsableDataClusters < 65536U ) )
  227. {
  228. break;
  229. }
  230. if( ( pxSet->ucFATType == FF_T_FAT32 ) && ( pxSet->ulUsableDataClusters >= 65536U ) && ( pxSet->ulUsableDataClusters < 0x0FFFFFEFU ) )
  231. {
  232. break;
  233. }
  234. /* Was this the last test? */
  235. if( ( ( xSmallClusters != pdFALSE ) && ( pxSet->ulSectorsPerCluster == 32U ) ) ||
  236. ( ( xSmallClusters == pdFALSE ) && ( pxSet->ulSectorsPerCluster == 1U ) ) )
  237. {
  238. FF_PRINTF( "FF_Format: Can not make a FAT%d (tried %d) with %u sectors\n",
  239. pxSet->ucFATType == FF_T_FAT32 ? 32 : 16,
  240. xPreferFAT16 ? 16 : 32,
  241. ( unsigned ) pxSet->ulSectorCount );
  242. xReturn = FF_ERR_IOMAN_BAD_MEMSIZE | FF_MODULE_FORMAT;
  243. break;
  244. }
  245. /* No it wasn't, try next clustersize */
  246. if( xSmallClusters != pdFALSE )
  247. {
  248. pxSet->ulSectorsPerCluster <<= 1;
  249. }
  250. else
  251. {
  252. pxSet->ulSectorsPerCluster >>= 1;
  253. }
  254. } /* for( ;; ) */
  255. return xReturn;
  256. }
  257. /*-----------------------------------------------------------*/
  258. /**
  259. * @brief: Optimise FAT location: for bigger disks, let the FAT start at 4MB.
  260. * @param[in] pxSet: A set of parameters describing this format session.
  261. */
  262. static void prvFormatOptimiseFATLocation( struct xFormatSet * pxSet )
  263. {
  264. if( ( pxSet->ucFATType == FF_T_FAT32 ) &&
  265. ( pxSet->ulSectorCount >= SIZE_512_MB ) &&
  266. ( pxSet->pxMyPartition->ulStartLBA < MX_LBA_TO_MOVE_FAT ) )
  267. {
  268. uint32_t ulRemaining;
  269. /*
  270. * Putting the FAT-table into the second 4MB erase block gives
  271. * a higher performance and a longer life-time.
  272. * See e.g. here:
  273. * http://3gfp.com/wp/2014/07/formatting-sd-cards-for-speed-and-lifetime/
  274. */
  275. pxSet->ulFATReservedSectors = MX_LBA_TO_MOVE_FAT - pxSet->ulHiddenSectors;
  276. pxSet->ulNonDataSectors = pxSet->ulFATReservedSectors + pxSet->iFAT16RootSectors;
  277. ulRemaining = ( pxSet->ulNonDataSectors + 2U * pxSet->ulSectorsPerFAT ) % 128U;
  278. if( ulRemaining != 0U )
  279. {
  280. /* In order to get ClusterBeginLBA well aligned (on a 128 sector boundary) */
  281. pxSet->ulFATReservedSectors += ( 128U - ulRemaining );
  282. pxSet->ulNonDataSectors = pxSet->ulFATReservedSectors + pxSet->iFAT16RootSectors;
  283. }
  284. pxSet->ulUsableDataSectors = pxSet->ulSectorCount - pxSet->ulNonDataSectors - 2 * pxSet->ulSectorsPerFAT;
  285. pxSet->ulUsableDataClusters = pxSet->ulUsableDataSectors / pxSet->ulSectorsPerCluster;
  286. }
  287. }
  288. /*-----------------------------------------------------------*/
  289. /**
  290. * @brief: Write the so-called BIOS Parameter Block ( BPB ). It describes the FAT partition.
  291. * @param[in] pxSet: A set of parameters describing this format session.
  292. * @return A standard +FAT error code.
  293. */
  294. static FF_Error_t prvFormatWriteBPB( struct xFormatSet * pxSet,
  295. const char * pcVolumeName )
  296. {
  297. FF_Error_t xReturn;
  298. char pcName[ 12 ];
  299. ( void ) strncpy( pcName, pcVolumeName, sizeof( pcName ) - 1 );
  300. pcName[ sizeof( pcName ) - 1 ] = 0;
  301. /* Clear all fields that aren't set explicitely. */
  302. ( void ) memset( pxSet->pucSectorBuffer, 0, pxSet->pxIOManager->usSectorSize );
  303. ( void ) memcpy( pxSet->pucSectorBuffer + OFS_BPB_jmpBoot_24, "\xEB\x00\x90" "FreeRTOS", 11 ); /* Includes OFS_BPB_OEMName_64 */
  304. FF_putShort( pxSet->pucSectorBuffer, OFS_BPB_BytsPerSec_16, pxSet->pxIOManager->usSectorSize ); /* 0x00B / Only 512, 1024, 2048 or 4096 */
  305. FF_putShort( pxSet->pucSectorBuffer, OFS_BPB_ResvdSecCnt_16, ( uint32_t ) pxSet->ulFATReservedSectors ); /* 0x00E / 1 (FAT12/16) or 32 (FAT32) */
  306. FF_putChar( pxSet->pucSectorBuffer, OFS_BPB_NumFATs_8, 2 ); /* 0x010 / 2 recommended */
  307. FF_putShort( pxSet->pucSectorBuffer, OFS_BPB_RootEntCnt_16, ( uint32_t ) ( pxSet->iFAT16RootSectors * 512 ) / 32 ); /* 0x011 / 512 (FAT12/16) or 0 (FAT32) */
  308. /* For FAT12 and FAT16 volumes, this field contains the count of 32- */
  309. /* byte directory entries in the root directory */
  310. FF_putChar( pxSet->pucSectorBuffer, OFS_BPB_Media_8, 0xF8 ); /* 0x015 / 0xF0 (rem media) also in FAT[0] low byte */
  311. FF_putShort( pxSet->pucSectorBuffer, OFS_BPB_SecPerTrk_16, 0x3F ); /* 0x18 n.a. CF has no tracks */
  312. FF_putShort( pxSet->pucSectorBuffer, OFS_BPB_NumHeads_16, 255 ); /* 0x01A / n.a. 1 ? */
  313. FF_putLong( pxSet->pucSectorBuffer, OFS_BPB_HiddSec_32, ( uint32_t ) pxSet->ulHiddenSectors ); /* 0x01C / n.a. 0 for nonparitioned volume */
  314. FF_putChar( pxSet->pucSectorBuffer, OFS_BPB_SecPerClus_8, ( uint32_t ) pxSet->ulSectorsPerCluster ); /* 0x00D / Only 1, 2, 4, 8, 16, 32, 64, 128 */
  315. FF_PRINTF( "FF_Format: SecCluster %lu DatSec %lu DataClus %lu pxSet->ulClusterBeginLBA %lu\n",
  316. pxSet->ulSectorsPerCluster, pxSet->ulUsableDataSectors, pxSet->ulUsableDataClusters, pxSet->ulClusterBeginLBA );
  317. /* This field is the new 32-bit total count of sectors on the volume. */
  318. /* This count includes the count of all sectors in all four regions of the volume */
  319. FF_putShort( pxSet->pucSectorBuffer, OFS_BPB_TotSec16_16, 0 ); /* 0x013 / xxx (FAT12/16) or 0 (FAT32) */
  320. FF_putLong( pxSet->pucSectorBuffer, OFS_BPB_TotSec32_32, pxSet->ulSectorCount ); /* 0x020 / >= 0x10000 */
  321. if( pxSet->ucFATType == FF_T_FAT32 )
  322. {
  323. FF_putLong( pxSet->pucSectorBuffer, OFS_BPB_32_FATSz32_32, pxSet->ulSectorsPerFAT ); /* 0x24 / Only when BPB_FATSz16 = 0 */
  324. FF_putShort( pxSet->pucSectorBuffer, OFS_BPB_32_ExtFlags_16, 0 ); /* 0x28 / FAT32 only */
  325. FF_putShort( pxSet->pucSectorBuffer, OFS_BPB_32_FSVer_16, 0 ); /* 0x2A / 0:0 */
  326. FF_putLong( pxSet->pucSectorBuffer, OFS_BPB_32_RootClus_32, ( uint32_t ) pxSet->iFAT32RootClusters ); /* 0x2C / Normally 2 */
  327. FF_putShort( pxSet->pucSectorBuffer, OFS_BPB_32_FSInfo_16, pxSet->ulFSInfo ); /* 0x30 / Normally 1 */
  328. FF_putShort( pxSet->pucSectorBuffer, OFS_BPB_32_BkBootSec_16, pxSet->ulBackupBootSector ); /* 0x32 / Normally 6 */
  329. FF_putChar( pxSet->pucSectorBuffer, OFS_BPB_32_DrvNum_8, 0 ); /* 0x40 / n.a. */
  330. FF_putChar( pxSet->pucSectorBuffer, OFS_BPB_32_BootSig_8, 0x29 ); /* 0x42 / n.a. */
  331. FF_putLong( pxSet->pucSectorBuffer, OFS_BPB_32_VolID_32, ( uint32_t ) pxSet->ulVolumeID ); /* 0x43 / "unique" number */
  332. ( void ) memcpy( pxSet->pucSectorBuffer + OFS_BPB_32_VolLab_88, pcName, 11 ); /* 0x47 / "NO NAME " */
  333. ( void ) memcpy( pxSet->pucSectorBuffer + OFS_BPB_32_FilSysType_64, "FAT32 ", 8 ); /* 0x52 / "FAT12 " */
  334. }
  335. else
  336. {
  337. FF_putChar( pxSet->pucSectorBuffer, OFS_BPB_16_DrvNum_8, 0u ); /* 0x024 / n.a. */
  338. FF_putChar( pxSet->pucSectorBuffer, OFS_BPB_16_Reserved1_8, 0 ); /* 0x025 / n.a. */
  339. FF_putChar( pxSet->pucSectorBuffer, OFS_BPB_16_BootSig_8, 0x29 ); /* 0x026 / n.a. */
  340. FF_putLong( pxSet->pucSectorBuffer, OFS_BPB_16_BS_VolID_32, ( uint32_t ) pxSet->ulVolumeID ); /* 0x027 / "unique" number */
  341. FF_putShort( pxSet->pucSectorBuffer, OFS_BPB_FATSz16_16, pxSet->ulSectorsPerFAT ); /* 0x16 */
  342. ( void ) memcpy( pxSet->pucSectorBuffer + OFS_BPB_16_BS_VolLab_88, "MY NAME ", 11 ); /* 0x02B / "NO NAME " */
  343. ( void ) memcpy( pxSet->pucSectorBuffer + OFS_BPB_16_FilSysType_64, "FAT16 ", 8 ); /* 0x036 / "FAT12 " */
  344. }
  345. pxSet->pucSectorBuffer[ FF_FAT_MBR_SIGNATURE + 0 ] = 0x55;
  346. pxSet->pucSectorBuffer[ FF_FAT_MBR_SIGNATURE + 1 ] = 0xAA;
  347. xReturn = FF_BlockWrite( pxSet->pxIOManager, pxSet->ulHiddenSectors, 1, pxSet->pucSectorBuffer, 0u );
  348. if( ( pxSet->ucFATType == FF_T_FAT32 ) &&
  349. ( FF_isERR( xReturn ) == pdFALSE ) )
  350. {
  351. /* Store a backup copy of the boot sector. */
  352. xReturn = FF_BlockWrite( pxSet->pxIOManager, pxSet->ulHiddenSectors + pxSet->ulBackupBootSector, 1, pxSet->pucSectorBuffer, pdFALSE );
  353. }
  354. return xReturn;
  355. }
  356. /*-----------------------------------------------------------*/
  357. /**
  358. * @brief: Initialise and clear the File Allocation Table ( FAT ).
  359. * @param[in] pxSet: A set of parameters describing this format session.
  360. * @param[in] lFatBeginLBA: The number of first sector of the FAT.
  361. * @return A standard +FAT error code.
  362. */
  363. static FF_Error_t prvFormatInitialiseFAT( struct xFormatSet * pxSet,
  364. int32_t lFatBeginLBA )
  365. {
  366. FF_Error_t xReturn;
  367. ( void ) memset( pxSet->pucSectorBuffer, 0, pxSet->pxIOManager->usSectorSize );
  368. switch( pxSet->ucFATType )
  369. {
  370. case FF_T_FAT16:
  371. FF_putShort( pxSet->pucSectorBuffer, 0, 0xFFF8U ); /* First FAT entry. */
  372. FF_putShort( pxSet->pucSectorBuffer, 2, 0xFFFFU ); /* RESERVED alloc. */
  373. break;
  374. case FF_T_FAT32:
  375. FF_putLong( pxSet->pucSectorBuffer, 0, 0x0FFFFFF8U ); /* FAT32 FAT sig. */
  376. FF_putLong( pxSet->pucSectorBuffer, 4, 0xFFFFFFFFU ); /* RESERVED alloc. */
  377. FF_putLong( pxSet->pucSectorBuffer, 8, 0x0FFFFFFFU ); /* Root dir allocation. */
  378. break;
  379. default:
  380. break;
  381. }
  382. xReturn = FF_BlockWrite( pxSet->pxIOManager, ( uint32_t ) lFatBeginLBA, 1, pxSet->pucSectorBuffer, pdFALSE );
  383. if( FF_isERR( xReturn ) == pdFALSE )
  384. {
  385. xReturn = FF_BlockWrite( pxSet->pxIOManager, ( uint32_t ) lFatBeginLBA + pxSet->ulSectorsPerFAT, 1, pxSet->pucSectorBuffer, pdFALSE );
  386. }
  387. FF_PRINTF( "FF_Format: Clearing entire FAT (2 x %lu sectors):\n", pxSet->ulSectorsPerFAT );
  388. {
  389. int32_t addr;
  390. ( void ) memset( pxSet->pucSectorBuffer, 0, pxSet->pxIOManager->usSectorSize );
  391. for( addr = lFatBeginLBA + 1;
  392. ( addr < ( lFatBeginLBA + ( int32_t ) pxSet->ulSectorsPerFAT ) ) &&
  393. ( FF_isERR( xReturn ) == pdFALSE );
  394. addr++ )
  395. {
  396. xReturn = FF_BlockWrite( pxSet->pxIOManager, ( uint32_t ) addr, 1, pxSet->pucSectorBuffer, pdFALSE );
  397. if( FF_isERR( xReturn ) == pdFALSE )
  398. {
  399. xReturn = FF_BlockWrite( pxSet->pxIOManager, ( uint32_t ) addr + pxSet->ulSectorsPerFAT, 1, pxSet->pucSectorBuffer, pdFALSE );
  400. }
  401. }
  402. }
  403. FF_PRINTF( "FF_Format: Clearing done\n" );
  404. return xReturn;
  405. }
  406. /*-----------------------------------------------------------*/
  407. /**
  408. * @brief: Initialise and clear the root directory.
  409. * @param[in] pxSet: A set of parameters describing this format session.
  410. * @return A standard +FAT error code.
  411. */
  412. static FF_Error_t prvFormatInitialiseRootDir( struct xFormatSet * pxSet,
  413. int32_t lDirectoryBegin,
  414. const char * pcVolumeName )
  415. {
  416. FF_Error_t xReturn = FF_ERR_NONE;
  417. int32_t lAddress;
  418. int32_t lLastAddress;
  419. BaseType_t xHasCleared = pdFALSE;
  420. ( void ) memset( pxSet->pucSectorBuffer, 0, pxSet->pxIOManager->usSectorSize );
  421. ( void ) memcpy( pxSet->pucSectorBuffer, pcVolumeName, 11 );
  422. pxSet->pucSectorBuffer[ 11 ] = FF_FAT_ATTR_VOLID;
  423. if( pxSet->iFAT16RootSectors != 0 )
  424. {
  425. lLastAddress = lDirectoryBegin + pxSet->iFAT16RootSectors;
  426. }
  427. else
  428. {
  429. lLastAddress = lDirectoryBegin + pxSet->ulSectorsPerCluster;
  430. }
  431. FF_PRINTF( "FF_Format: Clearing root directory at %08lX: %lu sectors\n", lDirectoryBegin, lLastAddress - lDirectoryBegin );
  432. for( lAddress = lDirectoryBegin;
  433. ( lAddress < lLastAddress ) && ( FF_isERR( xReturn ) == pdFALSE );
  434. lAddress++ )
  435. {
  436. xReturn = FF_BlockWrite( pxSet->pxIOManager, ( uint32_t ) lAddress, 1, pxSet->pucSectorBuffer, 0u );
  437. if( xHasCleared == pdFALSE )
  438. {
  439. xHasCleared = pdTRUE;
  440. ( void ) memset( pxSet->pucSectorBuffer, 0, pxSet->pxIOManager->usSectorSize );
  441. }
  442. }
  443. return xReturn;
  444. }
  445. /*-----------------------------------------------------------*/
  446. /**
  447. * @brief Now deprecated, please use the new function 'FF_FormatDisk()'.
  448. * @param[in] pxDisk: The disk object.
  449. * @param[in] xPartitionNumber: the numer of the partitioned that must be FAT-formatted.
  450. * @param[in] xPreferFAT16: When pdTRUE, it will use FAT16 in stead of FAT32.
  451. * @param[in] xSmallClusters: When pdTRUE, it will make the cluster size as small as possible.
  452. * @return A standard +FAT error code ( not an errno ).
  453. */
  454. FF_Error_t FF_Format( FF_Disk_t * pxDisk,
  455. BaseType_t xPartitionNumber,
  456. BaseType_t xPreferFAT16,
  457. BaseType_t xSmallClusters )
  458. {
  459. return FF_FormatDisk( pxDisk, xPartitionNumber, xPreferFAT16, xSmallClusters, "MY_DISK " );
  460. }
  461. /*-----------------------------------------------------------*/
  462. /*_RB_ Candidate for splitting into multiple functions? */
  463. /**
  464. * @brief Format a partition of a disk, either as FAT16 or FAT32. It assumes that
  465. * is has already been partitioned.
  466. * @param[in] pxDisk: The disk object.
  467. * @param[in] xPartitionNumber: the numer of the partitioned that must be FAT-formatted.
  468. * @param[in] xPreferFAT16: When pdTRUE, it will use FAT16 in stead of FAT32.
  469. * @param[in] xSmallClusters: When pdTRUE, it will make the cluster size as small as possible.
  470. * @param[in] pcVolumeName: A string of 11 characters representing the name of the disk.
  471. * @return A standard +FAT error code ( not an errno ).
  472. */
  473. FF_Error_t FF_FormatDisk( FF_Disk_t * pxDisk,
  474. BaseType_t xPartitionNumber,
  475. BaseType_t xPreferFAT16,
  476. BaseType_t xSmallClusters,
  477. const char * pcVolumeName )
  478. {
  479. struct xFormatSet xSet;
  480. int32_t lFatBeginLBA;
  481. int32_t lDirectoryBegin;
  482. FF_Error_t xReturn = FF_ERR_NONE;
  483. memset( &( xSet ), 0, sizeof xSet );
  484. xSet.ulFSInfo = 1; /* Sector number of FSINFO structure within the reserved area */
  485. xSet.ulBackupBootSector = 6; /* Sector number of "copy of the boot record" within the reserved area */
  486. xSet.xFATCount = 2; /* Number of FAT's */
  487. xSet.pxIOManager = pxDisk->pxIOManager;
  488. FF_PartitionSearch( xSet.pxIOManager, &xSet.xPartitionsFound );
  489. /* Introducing a do {} while(false) loop for easy exit without return. */
  490. do
  491. {
  492. if( xPartitionNumber >= xSet.xPartitionsFound.iCount )
  493. {
  494. xReturn = FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_MODULE_FORMAT;
  495. break;
  496. }
  497. xSet.pxMyPartition = xSet.xPartitionsFound.pxPartitions + xPartitionNumber;
  498. xSet.ulSectorCount = xSet.pxMyPartition->ulSectorCount;
  499. xSet.ulHiddenSectors = xSet.pxMyPartition->ulStartLBA;
  500. if( ( ( xPreferFAT16 == pdFALSE ) && ( ( xSet.ulSectorCount - RESV_COUNT ) >= 65536 ) ) ||
  501. ( ( xSet.ulSectorCount - RESV_COUNT ) >= ( 64 * MIN_CLUSTER_COUNT_FAT32 ) ) )
  502. {
  503. xSet.ucFATType = FF_T_FAT32;
  504. xSet.iFAT32RootClusters = 2;
  505. xSet.ulFATReservedSectors = RESV_COUNT;
  506. xSet.iFAT16RootSectors = 0;
  507. }
  508. else
  509. {
  510. xSet.ucFATType = FF_T_FAT16;
  511. xSet.iFAT32RootClusters = 0;
  512. xSet.ulFATReservedSectors = 1u;
  513. xSet.iFAT16RootSectors = ffconfigFAT16_ROOT_SECTORS; /* 32 sectors to get 512 dir entries */
  514. }
  515. /* Set start sector and length to allow FF_BlockRead/Write */
  516. xSet.pxIOManager->xPartition.ulTotalSectors = xSet.pxMyPartition->ulSectorCount;
  517. xSet.pxIOManager->xPartition.ulBeginLBA = xSet.pxMyPartition->ulStartLBA;
  518. /* TODO: Find some solution here to get a unique disk ID */
  519. xSet.ulVolumeID = ( rand() << 16 ) | rand(); /*_RB_ rand() has proven problematic in some environments. */
  520. /* Sectors within partition which can not be used */
  521. xSet.ulNonDataSectors = xSet.ulFATReservedSectors + xSet.iFAT16RootSectors;
  522. /* A fs dependent constant: */
  523. if( xSet.ucFATType == FF_T_FAT32 )
  524. {
  525. /* In FAT32, 4 bytes are needed to store the address (LBA) of a cluster.
  526. * A FAT sector of 512 bytes can contain 512 / 4 = 128 entries. */
  527. xSet.ulClustersPerFATSector = xSet.pxIOManager->usSectorSize / sizeof( uint32_t );
  528. }
  529. else
  530. {
  531. /* In FAT16, 2 bytes are needed to store the address (LBA) of a cluster.
  532. * A FAT sector of 512 bytes can contain 512 / 2 = 256 entries. */
  533. xSet.ulClustersPerFATSector = xSet.pxIOManager->usSectorSize / sizeof( uint16_t );
  534. }
  535. FF_PRINTF( "FF_Format: Secs %lu Rsvd %lu Hidden %lu Root %lu Data %lu\n",
  536. xSet.ulSectorCount, xSet.ulFATReservedSectors, xSet.ulHiddenSectors, xSet.iFAT16RootSectors, xSet.ulSectorCount - xSet.ulNonDataSectors );
  537. /*****************************/
  538. /* Try to find the optimum sector size, and choose betwee FAT16 and FAT32.
  539. */
  540. xReturn = prvFormatGetClusterSize( &( xSet ), xPreferFAT16, xSmallClusters );
  541. if( FF_isERR( xReturn ) != pdFALSE )
  542. {
  543. break;
  544. }
  545. /*****************************/
  546. /* Optimise FAT location: for bigger disks, let the FAT start at an offset of 4MB,
  547. * because that memory is optimised for FAT purposes ( i.e. frequent changes ).
  548. */
  549. prvFormatOptimiseFATLocation( &( xSet ) );
  550. xSet.ulClusterBeginLBA = xSet.ulHiddenSectors + xSet.ulFATReservedSectors + 2 * xSet.ulSectorsPerFAT;
  551. /* Allocate a buffer space to hold a full sector. */
  552. xSet.pucSectorBuffer = ( uint8_t * ) ffconfigMALLOC( xSet.pxIOManager->usSectorSize );
  553. if( xSet.pucSectorBuffer == NULL )
  554. {
  555. xReturn = FF_ERR_NOT_ENOUGH_MEMORY | FF_MODULE_FORMAT;
  556. break;
  557. }
  558. /*****************************/
  559. /* Write the so-called BIOS parameter block (BPB). It describes the FAT partition. */
  560. xReturn = prvFormatWriteBPB( &( xSet ), pcVolumeName );
  561. if( FF_isERR( xReturn ) != pdFALSE )
  562. {
  563. break;
  564. }
  565. /*****************************/
  566. if( xSet.ucFATType == FF_T_FAT32 )
  567. {
  568. /* FAT32 stores extra information in the FSInfo sector, usually sector 1. */
  569. ( void ) memset( xSet.pucSectorBuffer, 0, xSet.pxIOManager->usSectorSize );
  570. FF_putLong( xSet.pucSectorBuffer, OFS_FSI_32_LeadSig, 0x41615252 ); /* to validate that this is in fact an FSInfo sector. */
  571. /* OFS_FSI_32_Reserved1 0x004 / 480 times 0 */
  572. FF_putLong( xSet.pucSectorBuffer, OFS_FSI_32_StrucSig, 0x61417272 ); /* Another signature that is more localized in the */
  573. /* sector to the location of the fields that are used. */
  574. FF_putLong( xSet.pucSectorBuffer, OFS_FSI_32_Free_Count, xSet.ulUsableDataClusters ); /* last known free cluster count on the volume, ~0 for unknown */
  575. FF_putLong( xSet.pucSectorBuffer, OFS_FSI_32_Nxt_Free, 2 ); /* cluster number at which the driver should start looking for free clusters */
  576. /* OFS_FSI_32_Reserved2 0x1F0 / zero's */
  577. FF_putLong( xSet.pucSectorBuffer, OFS_FSI_32_TrailSig, 0xAA550000 ); /* Will correct for endianness */
  578. FF_BlockWrite( xSet.pxIOManager, xSet.ulHiddenSectors + xSet.ulFSInfo, 1, xSet.pucSectorBuffer, pdFALSE );
  579. FF_BlockWrite( xSet.pxIOManager, xSet.ulHiddenSectors + xSet.ulFSInfo + xSet.ulBackupBootSector, 1, xSet.pucSectorBuffer, pdFALSE );
  580. }
  581. /*****************************/
  582. lFatBeginLBA = xSet.ulHiddenSectors + xSet.ulFATReservedSectors;
  583. /* Initialise the FAT. */
  584. xReturn = prvFormatInitialiseFAT( &( xSet ), lFatBeginLBA );
  585. if( FF_isERR( xReturn ) != pdFALSE )
  586. {
  587. break;
  588. }
  589. /*****************************/
  590. lDirectoryBegin = lFatBeginLBA + ( 2 * xSet.ulSectorsPerFAT );
  591. #if ( ffconfigTIME_SUPPORT != 0 )
  592. {
  593. FF_SystemTime_t str_t;
  594. int16_t myShort;
  595. FF_GetSystemTime( &str_t );
  596. myShort = ( ( str_t.Hour << 11 ) & 0xF800 ) |
  597. ( ( str_t.Minute << 5 ) & 0x07E0 ) |
  598. ( ( str_t.Second / 2 ) & 0x001F );
  599. FF_putShort( xSet.pucSectorBuffer, 22, ( uint32_t ) myShort );
  600. myShort = ( ( ( str_t.Year - 1980 ) << 9 ) & 0xFE00 ) |
  601. ( ( str_t.Month << 5 ) & 0x01E0 ) |
  602. ( str_t.Day & 0x001F );
  603. FF_putShort( xSet.pucSectorBuffer, 24, ( uint32_t ) myShort );
  604. }
  605. #endif /* ffconfigTIME_SUPPORT */
  606. /* Initialise and clear the root directory. */
  607. xReturn = prvFormatInitialiseRootDir( &( xSet ), lDirectoryBegin, pcVolumeName );
  608. }
  609. while( pdFALSE );
  610. /* Free the sector buffer. */
  611. ffconfigFREE( xSet.pucSectorBuffer );
  612. return xReturn;
  613. }
  614. /*-----------------------------------------------------------*/
  615. /**
  616. * @brief Create primary and extended partitions.
  617. * @param[in] pxSet: A set of parameters describing this format session.
  618. * @return A standard +FAT error code.
  619. */
  620. static FF_Error_t prvPartitionPrimary( struct xPartitionSet * pxSet )
  621. {
  622. FF_Error_t xReturn = FF_ERR_NONE;
  623. FF_Buffer_t * pxSectorBuffer;
  624. uint8_t * pucBuffer;
  625. uint32_t ulPartitionOffset; /* Pointer within partition table */
  626. BaseType_t xPartitionNumber;
  627. pxSectorBuffer = FF_GetBuffer( pxSet->pxIOManager, 0, ( uint8_t ) FF_MODE_WRITE );
  628. {
  629. if( pxSectorBuffer == NULL )
  630. {
  631. return FF_ERR_DEVICE_DRIVER_FAILED;
  632. }
  633. }
  634. pucBuffer = pxSectorBuffer->pucBuffer;
  635. ( void ) memset( pucBuffer, 0, pxSet->pxIOManager->usSectorSize );
  636. ( void ) memcpy( pucBuffer + OFS_BPB_jmpBoot_24, "\xEB\x00\x90" "FreeRTOS", 11 ); /* Includes OFS_BPB_OEMName_64 */
  637. ulPartitionOffset = OFS_PTABLE_PART_0;
  638. for( xPartitionNumber = 0; xPartitionNumber < ffconfigMAX_PARTITIONS; xPartitionNumber++ )
  639. {
  640. FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_ACTIVE_8, pxSet->pxPartitions[ xPartitionNumber ].ucActive ); /* 0x01BE 0x80 if active */
  641. FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_START_HEAD_8, 1 ); /* 0x001 / 0x01BF */
  642. FF_putShort( pucBuffer, ulPartitionOffset + OFS_PART_START_SEC_TRACK_16, 1 ); /* 0x002 / 0x01C0 */
  643. FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_ID_NUMBER_8, pxSet->pxPartitions[ xPartitionNumber ].ucPartitionID ); /* 0x004 / 0x01C2 */
  644. FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_ENDING_HEAD_8, 0xFE ); /* 0x005 / 0x01C3 */
  645. FF_putShort( pucBuffer, ulPartitionOffset + OFS_PART_ENDING_SEC_TRACK_16, pxSet->pxPartitions[ xPartitionNumber ].ulSectorCount ); /* 0x006 / 0x01C4 */
  646. FF_putLong( pucBuffer, ulPartitionOffset + OFS_PART_STARTING_LBA_32, pxSet->pxPartitions[ xPartitionNumber ].ulStartLBA ); /* 0x008 / 0x01C6 This is important */
  647. FF_putLong( pucBuffer, ulPartitionOffset + OFS_PART_LENGTH_32, pxSet->pxPartitions[ xPartitionNumber ].ulSectorCount ); /* 0x00C / 0x01CA Equal to total sectors */
  648. ulPartitionOffset += 16;
  649. }
  650. pucBuffer[ FF_FAT_MBR_SIGNATURE + 0 ] = 0x55;
  651. pucBuffer[ FF_FAT_MBR_SIGNATURE + 1 ] = 0xAA;
  652. FF_ReleaseBuffer( pxSet->pxIOManager, pxSectorBuffer );
  653. FF_FlushCache( pxSet->pxIOManager );
  654. return xReturn;
  655. }
  656. /*-----------------------------------------------------------*/
  657. /**
  658. * @brief Create primary and extended partitions.
  659. * @param[in] pxSet: A set of parameters describing this format session.
  660. * @param[in] pParams: A set of variables describing the partitions.
  661. * @return A standard +FAT error code.
  662. */
  663. static FF_Error_t prvPartitionExtended( struct xPartitionSet * pxSet,
  664. FF_PartitionParameters_t * pParams )
  665. {
  666. /* Create at least 1 extended/logical partition */
  667. FF_Error_t xReturn = FF_ERR_NONE;
  668. int index;
  669. /* Start of the big extended partition */
  670. unsigned extendedLBA = pParams->ulHiddenSectors;
  671. /* Where to write the table */
  672. uint32_t ulLBA = 0;
  673. /* Contents of the table */
  674. FF_Part_t writeParts[ 4 ];
  675. BaseType_t xPartitionNumber;
  676. FF_Buffer_t * pxSectorBuffer;
  677. uint8_t * pucBuffer;
  678. uint32_t ulPartitionOffset; /**< Pointer within partition table */
  679. for( index = -1; index < pxSet->xPartitionCount; index++ )
  680. {
  681. uint32_t ulNextLBA;
  682. ( void ) memset( writeParts, 0, sizeof( writeParts ) );
  683. if( index < 0 )
  684. {
  685. /* We're at sector 0: */
  686. /* Write primary partitions, if any */
  687. /* Create big extended partition */
  688. uint32_t ulStartLBA = pParams->ulHiddenSectors;
  689. for( xPartitionNumber = 0; xPartitionNumber < pParams->xPrimaryCount; xPartitionNumber++ )
  690. {
  691. writeParts[ xPartitionNumber ].ulStartLBA = ulStartLBA;
  692. writeParts[ xPartitionNumber ].ulSectorCount = pxSet->pxPartitions[ xPartitionNumber ].ulSectorCount;
  693. writeParts[ xPartitionNumber ].ucActive = 0x80;
  694. writeParts[ xPartitionNumber ].ucPartitionID = 0x0B;
  695. ulStartLBA += writeParts[ xPartitionNumber ].ulSectorCount;
  696. index++;
  697. }
  698. /* _HT_ index = 0, 1, or 2. index < xPrimaryCount. */
  699. /* _HT_ xPartitionNumber == pParams->xPrimaryCount. */
  700. /* Now define the extended partition. */
  701. extendedLBA = ulStartLBA;
  702. writeParts[ xPartitionNumber ].ulStartLBA = ulStartLBA;
  703. writeParts[ xPartitionNumber ].ulSectorCount = pParams->ulSectorCount - ulStartLBA;
  704. writeParts[ xPartitionNumber ].ucActive = 0x80;
  705. writeParts[ xPartitionNumber ].ucPartitionID = FF_DOS_EXT_PART; /* 0x05 */
  706. ulNextLBA = ulStartLBA;
  707. }
  708. else
  709. {
  710. /* Create a logical partition with "ulSectorCount" sectors: */
  711. writeParts[ 0 ].ulStartLBA = pxSet->ulInterSpace;
  712. writeParts[ 0 ].ulSectorCount = pxSet->pxPartitions[ index ].ulSectorCount;
  713. writeParts[ 0 ].ucActive = 0x80;
  714. writeParts[ 0 ].ucPartitionID = 0x0B;
  715. if( index < pxSet->xPartitionCount - 1 )
  716. {
  717. /* Next extended partition */
  718. writeParts[ 1 ].ulStartLBA = pxSet->ulInterSpace + ulLBA - extendedLBA + writeParts[ 0 ].ulSectorCount;
  719. /* Compilers may warn about the out-of-bounds indexing 'pxSet->pxPartitions[index+1]'. */
  720. writeParts[ 1 ].ulSectorCount = pxSet->pxPartitions[ index + 1 ].ulSectorCount + pxSet->ulInterSpace;
  721. writeParts[ 1 ].ucActive = 0x80;
  722. writeParts[ 1 ].ucPartitionID = 0x05;
  723. }
  724. ulNextLBA = writeParts[ 1 ].ulStartLBA + extendedLBA;
  725. }
  726. pxSectorBuffer = FF_GetBuffer( pxSet->pxIOManager, ( uint32_t ) ulLBA, ( uint8_t ) FF_MODE_WRITE );
  727. {
  728. if( pxSectorBuffer == NULL )
  729. {
  730. return FF_ERR_DEVICE_DRIVER_FAILED;
  731. }
  732. }
  733. pucBuffer = pxSectorBuffer->pucBuffer;
  734. ( void ) memset( pucBuffer, 0, pxSet->pxIOManager->usSectorSize );
  735. ( void ) memcpy( pucBuffer + OFS_BPB_jmpBoot_24, "\xEB\x00\x90" "FreeRTOS", 11 ); /* Includes OFS_BPB_OEMName_64 */
  736. ulPartitionOffset = OFS_PTABLE_PART_0;
  737. for( xPartitionNumber = 0; xPartitionNumber < ffconfigMAX_PARTITIONS; xPartitionNumber++, ulPartitionOffset += 16 )
  738. {
  739. FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_ACTIVE_8, writeParts[ xPartitionNumber ].ucActive ); /* 0x01BE 0x80 if active */
  740. FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_START_HEAD_8, 1 ); /* 0x001 / 0x01BF */
  741. FF_putShort( pucBuffer, ulPartitionOffset + OFS_PART_START_SEC_TRACK_16, 1 ); /* 0x002 / 0x01C0 */
  742. FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_ID_NUMBER_8, writeParts[ xPartitionNumber ].ucPartitionID ); /* 0x004 / 0x01C2 */
  743. FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_ENDING_HEAD_8, 0xFE ); /* 0x005 / 0x01C3 */
  744. FF_putShort( pucBuffer, ulPartitionOffset + OFS_PART_ENDING_SEC_TRACK_16, writeParts[ xPartitionNumber ].ulSectorCount ); /* 0x006 / 0x01C4 */
  745. FF_putLong( pucBuffer, ulPartitionOffset + OFS_PART_STARTING_LBA_32, writeParts[ xPartitionNumber ].ulStartLBA ); /* 0x008 / 0x01C6 This is important */
  746. FF_putLong( pucBuffer, ulPartitionOffset + OFS_PART_LENGTH_32, writeParts[ xPartitionNumber ].ulSectorCount ); /* 0x00C / 0x01CA Equal to total sectors */
  747. }
  748. pucBuffer[ FF_FAT_MBR_SIGNATURE + 0 ] = 0x55;
  749. pucBuffer[ FF_FAT_MBR_SIGNATURE + 1 ] = 0xAA;
  750. FF_ReleaseBuffer( pxSet->pxIOManager, pxSectorBuffer );
  751. FF_FlushCache( pxSet->pxIOManager );
  752. ulLBA = ulNextLBA;
  753. }
  754. return xReturn;
  755. }
  756. /*-----------------------------------------------------------*/
  757. /**
  758. * @brief Create/initialise the partitions of a disk.
  759. * @param[in] pxDisk : The definition of the disk.
  760. * @param[in] pParams : A description of how the partitions shall be formatted.
  761. * @return A standard +FAT error code ( not an errno ).
  762. */
  763. FF_Error_t FF_Partition( FF_Disk_t * pxDisk,
  764. FF_PartitionParameters_t * pParams )
  765. {
  766. FF_Error_t xReturn = FF_ERR_NONE;
  767. struct xPartitionSet xSet;
  768. BaseType_t xNeedExtended; /* When more than 4 partitions are requested, extended partitions are needed. */
  769. uint32_t ulAvailable; /* The number of sectors available. */
  770. BaseType_t xPartitionNumber;
  771. uint32_t ulSummedSizes; /* Summed sizes as a percentage or as number of sectors. */
  772. uint32_t ulReservedSpace; /**< Space needed for the extended partitions. */
  773. memset( &( xSet ), 0, sizeof( xSet ) );
  774. /* Hidden space between 2 extended partitions */
  775. xSet.ulInterSpace = pParams->ulInterSpace ? pParams->ulInterSpace : 2048;
  776. /* The +FAT IO-manager. */
  777. xSet.pxIOManager = pxDisk->pxIOManager;
  778. /* Clear caching without flushing first. */
  779. FF_IOMAN_InitBufferDescriptors( xSet.pxIOManager );
  780. /* Avoid sanity checks by FF_BlockRead/Write. */
  781. xSet.pxIOManager->xPartition.ulTotalSectors = 0;
  782. /* Get the sum of sizes and number of actual partitions. */
  783. for( xPartitionNumber = 0; xPartitionNumber < ffconfigMAX_PARTITIONS; xPartitionNumber++ )
  784. {
  785. if( pParams->xSizes[ xPartitionNumber ] > 0 )
  786. {
  787. xSet.xPartitionCount++;
  788. ulSummedSizes += pParams->xSizes[ xPartitionNumber ];
  789. }
  790. }
  791. /* xSet.xPartitionCount is at most 'ffconfigMAX_PARTITIONS' */
  792. if( xSet.xPartitionCount == 0 )
  793. {
  794. xSet.xPartitionCount = 1;
  795. /* 'ffconfigMAX_PARTITIONS' must be 1 or more. */
  796. if( pParams->eSizeType == eSizeIsSectors )
  797. {
  798. pParams->xSizes[ 0 ] = pParams->ulSectorCount;
  799. }
  800. else
  801. {
  802. pParams->xSizes[ 0 ] = 100;
  803. }
  804. ulSummedSizes = pParams->xSizes[ 0 ];
  805. }
  806. /* Correct PrimaryCount if necessary. */
  807. if( pParams->xPrimaryCount > ( ( xSet.xPartitionCount > 4 ) ? 3 : xSet.xPartitionCount ) )
  808. {
  809. pParams->xPrimaryCount = ( xSet.xPartitionCount > 4 ) ? 3 : xSet.xPartitionCount;
  810. }
  811. /* Now see if extended is necessary. */
  812. xNeedExtended = ( xSet.xPartitionCount > pParams->xPrimaryCount ) ? pdTRUE : pdFALSE;
  813. if( xNeedExtended != pdFALSE )
  814. {
  815. if( pParams->ulHiddenSectors < 4096 )
  816. {
  817. pParams->ulHiddenSectors = 4096;
  818. }
  819. ulReservedSpace = xSet.ulInterSpace * ( xSet.xPartitionCount - pParams->xPrimaryCount );
  820. }
  821. else
  822. {
  823. /* There must be at least 1 hidden sector. */
  824. if( pParams->ulHiddenSectors < 1 )
  825. {
  826. pParams->ulHiddenSectors = 1;
  827. }
  828. ulReservedSpace = 0;
  829. }
  830. ulAvailable = pParams->ulSectorCount - pParams->ulHiddenSectors - ulReservedSpace;
  831. /* Check validity of Sizes */
  832. switch( pParams->eSizeType )
  833. {
  834. case eSizeIsQuota: /* Assign a quotum (sum of Sizes is free, all disk space will be allocated) */
  835. break;
  836. case eSizeIsPercent: /* Assign a percentage of the available space (sum of Sizes must be <= 100) */
  837. if( ulSummedSizes > 100 )
  838. {
  839. return FF_FORMATPARTITION | FF_ERR_IOMAN_BAD_MEMSIZE;
  840. }
  841. ulSummedSizes = 100;
  842. break;
  843. case eSizeIsSectors: /* Assign fixed number of sectors (512 byte each) */
  844. if( ulSummedSizes > ulAvailable )
  845. {
  846. return FF_FORMATPARTITION | FF_ERR_IOMAN_BAD_MEMSIZE;
  847. }
  848. break;
  849. }
  850. {
  851. uint32_t ulRemaining = ulAvailable;
  852. uint32_t ulLBA = pParams->ulHiddenSectors;
  853. /* Divide the available sectors among the partitions: */
  854. for( xPartitionNumber = 0; xPartitionNumber < xSet.xPartitionCount; xPartitionNumber++ )
  855. {
  856. if( pParams->xSizes[ xPartitionNumber ] > 0 )
  857. {
  858. uint32_t ulSize;
  859. switch( pParams->eSizeType )
  860. {
  861. case eSizeIsQuota: /* Assign a quotum (sum of Sizes is free, all disk space will be allocated) */
  862. case eSizeIsPercent: /* Assign a percentage of the available space (sum of Sizes must be <= 100) */
  863. ulSize = ( uint32_t ) ( ( ( uint64_t ) pParams->xSizes[ xPartitionNumber ] * ulAvailable ) / ulSummedSizes );
  864. break;
  865. case eSizeIsSectors: /* Assign fixed number of sectors (512 byte each) */
  866. default: /* Just for the compiler(s) */
  867. ulSize = pParams->xSizes[ xPartitionNumber ];
  868. break;
  869. }
  870. if( ulSize > ulRemaining )
  871. {
  872. ulSize = ulRemaining;
  873. }
  874. ulRemaining -= ulSize;
  875. xSet.pxPartitions[ xPartitionNumber ].ulSectorCount = ulSize;
  876. xSet.pxPartitions[ xPartitionNumber ].ucActive = 0x80;
  877. xSet.pxPartitions[ xPartitionNumber ].ulStartLBA = ulLBA; /* ulStartLBA might still change for logical partitions */
  878. xSet.pxPartitions[ xPartitionNumber ].ucPartitionID = 0x0B;
  879. ulLBA += ulSize;
  880. }
  881. }
  882. }
  883. if( xNeedExtended == pdFALSE )
  884. {
  885. xReturn = prvPartitionPrimary( &( xSet ) );
  886. }
  887. else
  888. {
  889. xReturn = prvPartitionExtended( &( xSet ), pParams );
  890. }
  891. return xReturn;
  892. }
  893. /*-----------------------------------------------------------*/