ff_ramdisk.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  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. /* Standard includes. */
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <stdarg.h>
  30. #include <stdio.h>
  31. /* Scheduler include files. */
  32. #include "FreeRTOS.h"
  33. #include "task.h"
  34. #include "semphr.h"
  35. #include "portmacro.h"
  36. /* FreeRTOS+FAT includes. */
  37. #include "ff_headers.h"
  38. #include "ff_ramdisk.h"
  39. #include "ff_sys.h"
  40. #define ramHIDDEN_SECTOR_COUNT 8
  41. #define ramPRIMARY_PARTITIONS 1
  42. #define ramHUNDRED_64_BIT 100ULL
  43. #define ramSECTOR_SIZE 512UL
  44. #define ramPARTITION_NUMBER 0 /* Only a single partition is used. */
  45. #define ramBYTES_PER_KB ( 1024ull )
  46. #define ramSECTORS_PER_KB ( ramBYTES_PER_KB / 512ull )
  47. /* Used as a magic number to indicate that an FF_Disk_t structure is a RAM
  48. * disk. */
  49. #define ramSIGNATURE 0x41404342
  50. /*-----------------------------------------------------------*/
  51. /*
  52. * The function that writes to the media - as this is implementing a RAM disk
  53. * the media is just a RAM buffer.
  54. */
  55. static int32_t prvWriteRAM( uint8_t * pucBuffer,
  56. uint32_t ulSectorNumber,
  57. uint32_t ulSectorCount,
  58. FF_Disk_t * pxDisk );
  59. /*
  60. * The function that reads from the media - as this is implementing a RAM disk
  61. * the media is just a RAM buffer.
  62. */
  63. static int32_t prvReadRAM( uint8_t * pucBuffer,
  64. uint32_t ulSectorNumber,
  65. uint32_t ulSectorCount,
  66. FF_Disk_t * pxDisk );
  67. #ifndef RAMDISK_ALREADY_PARTITIONED
  68. /*
  69. * This is the driver for a RAM disk. Unlike most media types, RAM disks are
  70. * volatile so are created anew each time the system is booted. As the disk is
  71. * new and just created, it must also be partitioned and formatted.
  72. */
  73. static FF_Error_t prvPartitionAndFormatDisk( FF_Disk_t * pxDisk );
  74. #endif
  75. /*-----------------------------------------------------------*/
  76. /* This is the prototype of the function used to initialise the RAM disk driver.
  77. * Other media drivers do not have to have the same prototype.
  78. *
  79. * In this example:
  80. + pcName is the name to give the disk within FreeRTOS+FAT's virtual file system.
  81. + pucDataBuffer is the start of the RAM to use as the disk.
  82. + ulSectorCount is effectively the size of the disk, each sector is 512 bytes.
  83. + xIOManagerCacheSize is the size of the IO manager's cache, which must be a
  84. + multiple of the sector size, and at least twice as big as the sector size.
  85. */
  86. FF_Disk_t * FF_RAMDiskInit( char * pcName,
  87. uint8_t * pucDataBuffer,
  88. uint32_t ulSectorCount,
  89. size_t xIOManagerCacheSize )
  90. {
  91. FF_Error_t xError;
  92. FF_Disk_t * pxDisk = NULL;
  93. FF_CreationParameters_t xParameters;
  94. /* Check the validity of the xIOManagerCacheSize parameter. */
  95. configASSERT( ( xIOManagerCacheSize % ramSECTOR_SIZE ) == 0 );
  96. configASSERT( ( xIOManagerCacheSize >= ( 2 * ramSECTOR_SIZE ) ) );
  97. /* Attempt to allocated the FF_Disk_t structure. */
  98. pxDisk = ( FF_Disk_t * ) pvPortMalloc( sizeof( FF_Disk_t ) );
  99. if( pxDisk != NULL )
  100. {
  101. /* Start with every member of the structure set to zero. */
  102. memset( pxDisk, '\0', sizeof( FF_Disk_t ) );
  103. /* Clear the entire space. */
  104. #ifndef RAMDISK_ALREADY_PARTITIONED
  105. memset( pucDataBuffer, '\0', ulSectorCount * ramSECTOR_SIZE );
  106. #endif
  107. /* The pvTag member of the FF_Disk_t structure allows the structure to be
  108. * extended to also include media specific parameters. The only media
  109. * specific data that needs to be stored in the FF_Disk_t structure for a
  110. * RAM disk is the location of the RAM buffer itself - so this is stored
  111. * directly in the FF_Disk_t's pvTag member. */
  112. pxDisk->pvTag = ( void * ) pucDataBuffer;
  113. /* The signature is used by the disk read and disk write functions to
  114. * ensure the disk being accessed is a RAM disk. */
  115. pxDisk->ulSignature = ramSIGNATURE;
  116. /* The number of sectors is recorded for bounds checking in the read and
  117. * write functions. */
  118. pxDisk->ulNumberOfSectors = ulSectorCount;
  119. /* Create the IO manager that will be used to control the RAM disk. */
  120. memset( &xParameters, '\0', sizeof( xParameters ) );
  121. xParameters.pucCacheMemory = NULL;
  122. xParameters.ulMemorySize = xIOManagerCacheSize;
  123. xParameters.ulSectorSize = ramSECTOR_SIZE;
  124. xParameters.fnWriteBlocks = prvWriteRAM;
  125. xParameters.fnReadBlocks = prvReadRAM;
  126. xParameters.pxDisk = pxDisk;
  127. /* Driver is reentrant so xBlockDeviceIsReentrant can be set to pdTRUE.
  128. * In this case the semaphore is only used to protect FAT data
  129. * structures. */
  130. xParameters.pvSemaphore = ( void * ) xSemaphoreCreateRecursiveMutex();
  131. xParameters.xBlockDeviceIsReentrant = pdFALSE;
  132. pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xError );
  133. if( ( pxDisk->pxIOManager != NULL ) && ( FF_isERR( xError ) == pdFALSE ) )
  134. {
  135. /* Record that the RAM disk has been initialised. */
  136. pxDisk->xStatus.bIsInitialised = pdTRUE;
  137. #ifdef RAMDISK_ALREADY_PARTITIONED
  138. xError = FF_ERR_NONE;
  139. #else
  140. /* Create a partition on the RAM disk. NOTE! The disk is only
  141. * being partitioned here because it is a new RAM disk. It is
  142. * known that the disk has not been used before, and cannot already
  143. * contain any partitions. Most media drivers will not perform
  144. * this step because the media will have already been partitioned. */
  145. xError = prvPartitionAndFormatDisk( pxDisk );
  146. #endif
  147. if( FF_isERR( xError ) == pdFALSE )
  148. {
  149. /* Record the partition number the FF_Disk_t structure is, then
  150. * mount the partition. */
  151. pxDisk->xStatus.bPartitionNumber = ramPARTITION_NUMBER;
  152. /* Mount the partition. */
  153. xError = FF_Mount( pxDisk, ramPARTITION_NUMBER );
  154. FF_PRINTF( "FF_RAMDiskInit: FF_Mount: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
  155. }
  156. if( FF_isERR( xError ) == pdFALSE )
  157. {
  158. /* The partition mounted successfully, add it to the virtual
  159. * file system - where it will appear as a directory off the file
  160. * system's root directory. */
  161. FF_FS_Add( pcName, pxDisk );
  162. }
  163. }
  164. else
  165. {
  166. FF_PRINTF( "FF_RAMDiskInit: FF_CreateIOManger: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
  167. /* The disk structure was allocated, but the disk's IO manager could
  168. * not be allocated, so free the disk again. */
  169. FF_RAMDiskDelete( pxDisk );
  170. pxDisk = NULL;
  171. }
  172. }
  173. else
  174. {
  175. FF_PRINTF( "FF_RAMDiskInit: Malloc failed\n" );
  176. }
  177. return pxDisk;
  178. }
  179. /*-----------------------------------------------------------*/
  180. BaseType_t FF_RAMDiskDelete( FF_Disk_t * pxDisk )
  181. {
  182. if( pxDisk != NULL )
  183. {
  184. pxDisk->ulSignature = 0;
  185. pxDisk->xStatus.bIsInitialised = 0;
  186. if( pxDisk->pxIOManager != NULL )
  187. {
  188. FF_DeleteIOManager( pxDisk->pxIOManager );
  189. }
  190. vPortFree( pxDisk );
  191. }
  192. return pdPASS;
  193. }
  194. /*-----------------------------------------------------------*/
  195. static int32_t prvReadRAM( uint8_t * pucDestination,
  196. uint32_t ulSectorNumber,
  197. uint32_t ulSectorCount,
  198. FF_Disk_t * pxDisk )
  199. {
  200. int32_t lReturn;
  201. uint8_t * pucSource;
  202. if( pxDisk != NULL )
  203. {
  204. if( pxDisk->ulSignature != ramSIGNATURE )
  205. {
  206. /* The disk structure is not valid because it doesn't contain a
  207. * magic number written to the disk when it was created. */
  208. lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
  209. }
  210. else if( pxDisk->xStatus.bIsInitialised == pdFALSE )
  211. {
  212. /* The disk has not been initialised. */
  213. lReturn = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG;
  214. }
  215. else if( ulSectorNumber >= pxDisk->ulNumberOfSectors )
  216. {
  217. /* The start sector is not within the bounds of the disk. */
  218. lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
  219. }
  220. else if( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) < ulSectorCount )
  221. {
  222. /* The end sector is not within the bounds of the disk. */
  223. lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
  224. }
  225. else
  226. {
  227. /* Obtain the pointer to the RAM buffer being used as the disk. */
  228. pucSource = ( uint8_t * ) pxDisk->pvTag;
  229. /* Move to the start of the sector being read. */
  230. pucSource += ( ramSECTOR_SIZE * ulSectorNumber );
  231. /* Copy the data from the disk. As this is a RAM disk this can be
  232. * done using memcpy(). */
  233. memcpy( ( void * ) pucDestination,
  234. ( void * ) pucSource,
  235. ( size_t ) ( ulSectorCount * ramSECTOR_SIZE ) );
  236. lReturn = FF_ERR_NONE;
  237. }
  238. }
  239. else
  240. {
  241. lReturn = FF_ERR_NULL_POINTER | FF_ERRFLAG;
  242. }
  243. return lReturn;
  244. }
  245. /*-----------------------------------------------------------*/
  246. static int32_t prvWriteRAM( uint8_t * pucSource,
  247. uint32_t ulSectorNumber,
  248. uint32_t ulSectorCount,
  249. FF_Disk_t * pxDisk )
  250. {
  251. int32_t lReturn = FF_ERR_NONE;
  252. uint8_t * pucDestination;
  253. if( pxDisk != NULL )
  254. {
  255. if( pxDisk->ulSignature != ramSIGNATURE )
  256. {
  257. /* The disk structure is not valid because it doesn't contain a
  258. * magic number written to the disk when it was created. */
  259. lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
  260. }
  261. else if( pxDisk->xStatus.bIsInitialised == pdFALSE )
  262. {
  263. /* The disk has not been initialised. */
  264. lReturn = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG;
  265. }
  266. else if( ulSectorNumber >= pxDisk->ulNumberOfSectors )
  267. {
  268. /* The start sector is not within the bounds of the disk. */
  269. lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
  270. }
  271. else if( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) < ulSectorCount )
  272. {
  273. /* The end sector is not within the bounds of the disk. */
  274. lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
  275. }
  276. else
  277. {
  278. /* Obtain the location of the RAM being used as the disk. */
  279. pucDestination = ( uint8_t * ) pxDisk->pvTag;
  280. /* Move to the sector being written to. */
  281. pucDestination += ( ramSECTOR_SIZE * ulSectorNumber );
  282. /* Write to the disk. As this is a RAM disk the write can use a
  283. * memcpy(). */
  284. memcpy( ( void * ) pucDestination,
  285. ( void * ) pucSource,
  286. ( size_t ) ulSectorCount * ( size_t ) ramSECTOR_SIZE );
  287. lReturn = FF_ERR_NONE;
  288. }
  289. }
  290. else
  291. {
  292. lReturn = FF_ERR_NULL_POINTER | FF_ERRFLAG;
  293. }
  294. return lReturn;
  295. }
  296. /*-----------------------------------------------------------*/
  297. #ifndef RAMDISK_ALREADY_PARTITIONED
  298. static FF_Error_t prvPartitionAndFormatDisk( FF_Disk_t * pxDisk )
  299. {
  300. FF_PartitionParameters_t xPartition;
  301. FF_Error_t xError;
  302. /* Create a single partition that fills all available space on the disk. */
  303. memset( &xPartition, '\0', sizeof( xPartition ) );
  304. xPartition.ulSectorCount = pxDisk->ulNumberOfSectors;
  305. xPartition.ulHiddenSectors = ramHIDDEN_SECTOR_COUNT;
  306. xPartition.xPrimaryCount = ramPRIMARY_PARTITIONS;
  307. xPartition.eSizeType = eSizeIsQuota;
  308. /* Partition the disk */
  309. xError = FF_Partition( pxDisk, &xPartition );
  310. FF_PRINTF( "FF_Partition: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
  311. if( FF_isERR( xError ) == pdFALSE )
  312. {
  313. /* Format the partition. */
  314. xError = FF_Format( pxDisk, ramPARTITION_NUMBER, pdTRUE, pdTRUE );
  315. FF_PRINTF( "FF_RAMDiskInit: FF_Format: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
  316. }
  317. return xError;
  318. }
  319. /*-----------------------------------------------------------*/
  320. #endif
  321. BaseType_t FF_RAMDiskShowPartition( FF_Disk_t * pxDisk )
  322. {
  323. FF_Error_t xError;
  324. uint64_t ullFreeSectors;
  325. uint32_t ulTotalSizeKB, ulFreeSizeKB;
  326. int iPercentageFree;
  327. FF_IOManager_t * pxIOManager;
  328. const char * pcTypeName = "unknown type";
  329. BaseType_t xReturn = pdPASS;
  330. if( pxDisk == NULL )
  331. {
  332. xReturn = pdFAIL;
  333. }
  334. else
  335. {
  336. pxIOManager = pxDisk->pxIOManager;
  337. FF_PRINTF( "Reading FAT and calculating Free Space\n" );
  338. switch( pxIOManager->xPartition.ucType )
  339. {
  340. case FF_T_FAT12:
  341. pcTypeName = "FAT12";
  342. break;
  343. case FF_T_FAT16:
  344. pcTypeName = "FAT16";
  345. break;
  346. case FF_T_FAT32:
  347. pcTypeName = "FAT32";
  348. break;
  349. default:
  350. pcTypeName = "UNKOWN";
  351. break;
  352. }
  353. FF_GetFreeSize( pxIOManager, &xError );
  354. ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster;
  355. if( pxIOManager->xPartition.ulDataSectors == ( uint32_t ) 0 )
  356. {
  357. iPercentageFree = 0;
  358. }
  359. else
  360. {
  361. iPercentageFree = ( int ) ( ( ramHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) /
  362. ( ( uint64_t ) pxIOManager->xPartition.ulDataSectors ) );
  363. }
  364. ulTotalSizeKB = pxIOManager->xPartition.ulDataSectors / ramSECTORS_PER_KB;
  365. ulFreeSizeKB = ( uint32_t ) ( ullFreeSectors / ramSECTORS_PER_KB );
  366. /* It is better not to use the 64-bit format such as %Lu because it
  367. * might not be implemented. */
  368. FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber );
  369. FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName );
  370. FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel );
  371. FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors );
  372. FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster );
  373. FF_PRINTF( "Size %8lu KB\n", ulTotalSizeKB );
  374. FF_PRINTF( "FreeSize %8lu KB ( %d perc free )\n", ulFreeSizeKB, iPercentageFree );
  375. }
  376. return xReturn;
  377. }
  378. /*-----------------------------------------------------------*/
  379. void FF_RAMDiskFlush( FF_Disk_t * pxDisk )
  380. {
  381. if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != 0 ) && ( pxDisk->pxIOManager != NULL ) )
  382. {
  383. FF_FlushCache( pxDisk->pxIOManager );
  384. }
  385. }
  386. /*-----------------------------------------------------------*/