@@ -65,9 +65,31 @@ struct TextFile {
6565
6666#define NUM_FAT_BLOCKS CFG_UF2_NUM_BLOCKS
6767
68- #define RESERVED_SECTORS 1
69- #define ROOT_DIR_SECTORS 4
70- #define SECTORS_PER_FAT ((NUM_FAT_BLOCKS * 2 + 511) / 512)
68+ #define BPB_SECTOR_SIZE ( 512)
69+ #define BPB_SECTORS_PER_CLUSTER ( 1)
70+ #define BPB_RESERVED_SECTORS ( 1)
71+ #define BPB_NUMBER_OF_FATS ( 2)
72+ #define BPB_ROOT_DIR_ENTRIES ( 64)
73+ // Static assertions ensure CFG_UF2_NUM_BLOCKS will result in a valid file system.
74+ #define BPB_TOTAL_SECTORS CFG_UF2_NUM_BLOCKS // Configuration ... up to 0x10209 / 0x101e9?
75+ #define BPB_MEDIA_DESCRIPTOR_BYTE (0xF8)
76+ #define FAT_ENTRY_SIZE (2)
77+ #define FAT_ENTRIES_PER_SECTOR (BPB_SECTOR_SIZE / FAT_ENTRY_SIZE)
78+ // NOTE: MS specification explicitly allows FAT to be larger than necessary
79+ #define BPB_SECTORS_PER_FAT ( (BPB_TOTAL_SECTORS / FAT_ENTRIES_PER_SECTOR) + \
80+ ((BPB_TOTAL_SECTORS % FAT_ENTRIES_PER_SECTOR) ? 1 : 0))
81+ #define DIRENTRIES_PER_SECTOR (BPB_SECTOR_SIZE/sizeof(DirEntry))
82+ #define ROOT_DIR_SECTORS (BPB_ROOT_DIR_ENTRIES/DIRENTRIES_PER_SECTOR)
83+
84+ STATIC_ASSERT (BPB_SECTOR_SIZE == 512 ); // GhostFAT does not support other sector sizes (currently)
85+ STATIC_ASSERT (BPB_SECTORS_PER_CLUSTER == 1 ); // GhostFAT presumes one sector == one cluster (for simplicity)
86+ STATIC_ASSERT (BPB_NUMBER_OF_FATS == 2 ); // FAT highest compatibility
87+ STATIC_ASSERT (sizeof (DirEntry ) == 32 ); // FAT requirement
88+ STATIC_ASSERT (BPB_SECTOR_SIZE % sizeof (DirEntry ) == 0 ); // FAT requirement
89+ STATIC_ASSERT (BPB_ROOT_DIR_ENTRIES % DIRENTRIES_PER_SECTOR == 0 ); // FAT requirement
90+ STATIC_ASSERT (BPB_SECTOR_SIZE * BPB_SECTORS_PER_CLUSTER <= (32 * 1024 )); // FAT requirement (64k+ has known compatibility problems)
91+
92+ STATIC_ASSERT (ROOT_DIR_SECTORS == 4 ); // Not required ... just validating equal to prior code
7193
7294#define STR0 (x ) #x
7395#define STR (x ) STR0(x)
@@ -94,12 +116,12 @@ static struct TextFile const info[] = {
94116 // current.uf2 must be the last element and its content must be NULL
95117 {.name = "CURRENT UF2" , .content = NULL },
96118};
119+ // FAT requires a final unused entry
120+ STATIC_ASSERT (ARRAY_SIZE (info ) < BPB_ROOT_DIR_ENTRIES );
97121
98- // code presumes each non-UF2 file content fits in single sector
99- // Cannot programmatically statically assert .content length
100- // for each element above.
101- STATIC_ASSERT (ARRAY_SIZE (indexFile ) < 512 );
102-
122+ // GhostFAT presumes each non-UF2 file content fits in single sector
123+ STATIC_ASSERT (ARRAY_SIZE (infoUf2File ) < BPB_SECTOR_SIZE );
124+ STATIC_ASSERT (ARRAY_SIZE (indexFile ) < BPB_SECTOR_SIZE );
103125
104126#define NUM_FILES (ARRAY_SIZE(info))
105127#define NUM_DIRENTRIES (NUM_FILES + 1) // Code adds volume label as first root directory entry
@@ -109,28 +131,27 @@ STATIC_ASSERT(ARRAY_SIZE(indexFile) < 512);
109131#define UF2_FIRST_SECTOR (NUM_FILES + 1) // WARNING -- code presumes each non-UF2 file content fits in single sector
110132#define UF2_LAST_SECTOR (UF2_FIRST_SECTOR + UF2_SECTORS - 1)
111133
112- #define START_FAT0 RESERVED_SECTORS
113- #define START_FAT1 (START_FAT0 + SECTORS_PER_FAT )
114- #define START_ROOTDIR (START_FAT1 + SECTORS_PER_FAT )
134+ #define START_FAT0 BPB_RESERVED_SECTORS
135+ #define START_FAT1 (START_FAT0 + BPB_SECTORS_PER_FAT )
136+ #define START_ROOTDIR (START_FAT1 + BPB_SECTORS_PER_FAT )
115137#define START_CLUSTERS (START_ROOTDIR + ROOT_DIR_SECTORS)
116138
139+ STATIC_ASSERT (NUM_DIRENTRIES < BPB_ROOT_DIR_ENTRIES );
117140// all directory entries must fit in a single sector
118141// because otherwise current code overflows buffer
119- #define DIRENTRIES_PER_SECTOR (512/sizeof(DirEntry))
120-
121- STATIC_ASSERT (NUM_DIRENTRIES < DIRENTRIES_PER_SECTOR * ROOT_DIR_SECTORS );
142+ STATIC_ASSERT (NUM_DIRENTRIES < DIRENTRIES_PER_SECTOR );
122143
123144static FAT_BootBlock const BootBlock = {
124145 .JumpInstruction = {0xeb , 0x3c , 0x90 },
125146 .OEMInfo = "UF2 UF2 " ,
126147 .SectorSize = 512 ,
127148 .SectorsPerCluster = 1 ,
128- .ReservedSectors = RESERVED_SECTORS ,
149+ .ReservedSectors = BPB_RESERVED_SECTORS ,
129150 .FATCopies = 2 ,
130151 .RootDirectoryEntries = (ROOT_DIR_SECTORS * DIRENTRIES_PER_SECTOR ),
131152 .TotalSectors16 = NUM_FAT_BLOCKS - 2 ,
132153 .MediaDescriptor = 0xF8 ,
133- .SectorsPerFAT = SECTORS_PER_FAT ,
154+ .SectorsPerFAT = BPB_SECTORS_PER_FAT ,
134155 .SectorsPerTrack = 1 ,
135156 .Heads = 1 ,
136157 .PhysicalDriveNum = 0x80 , // to match MediaDescriptor of 0xF8
@@ -226,8 +247,8 @@ void read_block(uint32_t block_no, uint8_t *data) {
226247 } else if (block_no < START_ROOTDIR ) { // Requested FAT table sector
227248 sectionIdx -= START_FAT0 ;
228249 // logval("sidx", sectionIdx);
229- if (sectionIdx >= SECTORS_PER_FAT )
230- sectionIdx -= SECTORS_PER_FAT ; // second FAT is same as the first...
250+ if (sectionIdx >= BPB_SECTORS_PER_FAT )
251+ sectionIdx -= BPB_SECTORS_PER_FAT ; // second FAT is same as the first...
231252 if (sectionIdx == 0 ) {
232253 data [0 ] = 0xf8 ; // first FAT entry must match BPB MediaDescriptor
233254 // WARNING -- code presumes only one NULL .content for .UF2 file
0 commit comments