brfs.c 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422
  1. // Bart's RAM File System (BRFS)
  2. /*
  3. Implementing in BDOS on PCB v3:
  4. - BDOS only uses ~340 pages of 256 bytes -> 90000 bytes
  5. - SPI flash has 65536 pages of 256 bytes -> 16777216 bytes
  6. - With current verilog implementation, only 32MiB of RAM is addressable, so BRFS should be used somewhere in the first 32MiB
  7. - With current BDOS memory map, BRFS should be placed in the first 8MiB available as BDOS Program Code
  8. - Lets use the last 4MiB of this space for BRFS (0x100000 - 0x200000)
  9. */
  10. #define BRFS_SUPPORTED_VERSION 1
  11. #define BRFS_RAM_STORAGE_ADDR 0x100000 // From 4th MiB
  12. // Addresses in SPI Flash
  13. // Note that each section should be in a different 4KiB sector in SPI Flash
  14. #define BRFS_SPIFLASH_SUPERBLOCK_ADDR 0xDF000 // One sector before FAT
  15. #define BRFS_SPIFLASH_FAT_ADDR 0xE0000 // Can be 32768 words (128KiB) for 32MiB of 256word blocks
  16. #define BRFS_SPIFLASH_BLOCK_ADDR 0x100000 // From first MiB
  17. //#define MAX_PATH_LENGTH 127 // Set by BDOS
  18. #define MAX_OPEN_FILES 16 // Can be set higher, but 4 is good for testing
  19. // Length of structs, should not be changed
  20. #define SUPERBLOCK_SIZE 16
  21. #define DIR_ENTRY_SIZE 8
  22. #define BRFS_MAX_BLOCKS 65536 // 64KiB
  23. word brfs_changed_blocks[BRFS_MAX_BLOCKS >> 5]; // Bitmap of changed blocks, each block has 1 bit
  24. // 16 words long
  25. struct brfs_superblock
  26. {
  27. word total_blocks;
  28. word words_per_block;
  29. word label[10]; // 1 char per word
  30. word brfs_version;
  31. word reserved[3];
  32. };
  33. // 8 words long
  34. struct brfs_dir_entry
  35. {
  36. word filename[4]; // 4 chars per word
  37. word modify_date; // TBD when RTC added to FPGC
  38. word flags; // 32 flags, from right to left: directory, hidden
  39. word fat_idx; // idx of first FAT block
  40. word filesize; // file size in words, not bytes
  41. };
  42. word *brfs_ram_storage = (word*) BRFS_RAM_STORAGE_ADDR; // RAM storage of file system
  43. // Variables for open files
  44. word brfs_cursors[MAX_OPEN_FILES]; // Cursor position offset from start of file
  45. word brfs_file_pointers[MAX_OPEN_FILES]; // FAT idx of open file
  46. struct brfs_dir_entry* brfs_dir_entry_pointers[MAX_OPEN_FILES]; // Pointer to dir entry of open file
  47. /**
  48. * Create a hexdump like dump of a section of memory
  49. * addr: address of the section
  50. * len: length of the section in words
  51. * linesize: number of words per line to print
  52. */
  53. void brfs_dump_section(word* addr, word len, word linesize)
  54. {
  55. char buf[16];
  56. word i;
  57. for (i = 0; i < len; i++)
  58. {
  59. itoah(addr[i], buf);
  60. if (strlen(buf+2) == 1)
  61. uprintc('0');
  62. uprint(buf+2);
  63. uprintc(' ');
  64. // newline every linesize words
  65. // also print last linesize words as chars if alphanum
  66. if (i != 0 && MATH_modU(i+1, linesize) == 0)
  67. {
  68. uprint(" ");
  69. word j;
  70. for (j = i - (linesize-1); j < i+1; j++)
  71. {
  72. if (isalnum(addr[j]) || addr[j] == ' ')
  73. uprintc(addr[j]);
  74. else
  75. uprintc('.');
  76. }
  77. uprintc('\n');
  78. }
  79. }
  80. }
  81. /**
  82. * Create a raw filesystem dump over UART
  83. * fatsize: size of the FAT table in words
  84. * datasize: size of the data section in words
  85. */
  86. void brfs_dump(word fatsize, word datasize)
  87. {
  88. // Superblock dump
  89. uprintln("Superblock:");
  90. brfs_dump_section(brfs_ram_storage, SUPERBLOCK_SIZE, 16);
  91. // FAT dump
  92. uprintln("\nFAT:");
  93. brfs_dump_section(brfs_ram_storage+SUPERBLOCK_SIZE, fatsize, 16);
  94. // Datablock dump
  95. uprintln("\nData:");
  96. brfs_dump_section(brfs_ram_storage+SUPERBLOCK_SIZE+fatsize, datasize, 32);
  97. uprintln("\nOpen files:");
  98. word i;
  99. for (i = 0; i < MAX_OPEN_FILES; i++)
  100. {
  101. uprint("FP");
  102. uprintDec(i+1);
  103. uprint(":");
  104. uprint(" FAT idx: ");
  105. uprintDec(brfs_file_pointers[i]);
  106. uprint(" Cursor: ");
  107. uprintDec(brfs_cursors[i]);
  108. uprint(" Size: ");
  109. uprintDec(brfs_dir_entry_pointers[i] ? brfs_dir_entry_pointers[i]->filesize : 0);
  110. uprintc('\n');
  111. }
  112. }
  113. /**
  114. * Return the FAT index of a directory, or -1 if not found
  115. * dir_path: full path of the directory
  116. */
  117. word brfs_get_fat_idx_of_dir(char* dir_path)
  118. {
  119. // Check length of path
  120. if (strlen(dir_path) > MAX_PATH_LENGTH)
  121. {
  122. uprintln("Path too long!");
  123. return -1;
  124. }
  125. // Start with root directory
  126. word current_dir_fat_idx = 0;
  127. // Check if root directory is requested
  128. if (strcmp(dir_path, "/") == 0)
  129. {
  130. return current_dir_fat_idx;
  131. }
  132. // Copy dir_path, size + 1 for null terminator
  133. // Since strtok modifies the string
  134. char dir_path_copy[MAX_PATH_LENGTH+1];
  135. strcpy(dir_path_copy, dir_path);
  136. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  137. word* brfs_data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  138. word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
  139. // Split path by '/' and traverse directories
  140. char* token = strtok(dir_path_copy, "/");
  141. while (token != (word*)-1)
  142. {
  143. // Find token in current directory
  144. word* dir_addr = brfs_data_block_addr + (current_dir_fat_idx * superblock->words_per_block);
  145. word found_dir = 0; // Keep track if token is found in current directory
  146. word i;
  147. for (i = 0; i < dir_entries_max; i++)
  148. {
  149. struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (dir_addr + (i * sizeof(struct brfs_dir_entry)));
  150. if (dir_entry->filename[0] != 0)
  151. {
  152. char decompressed_filename[17];
  153. strdecompress(decompressed_filename, (char*)&(dir_entry->filename));
  154. // Also check for directory flag
  155. if (strcmp(decompressed_filename, token) == 0 && dir_entry->flags == 1)
  156. {
  157. // Found token in current directory
  158. // Set current directory to token's FAT index
  159. current_dir_fat_idx = dir_entry->fat_idx;
  160. found_dir = 1;
  161. break;
  162. }
  163. }
  164. }
  165. // If token not found in current directory, return -1
  166. if (!found_dir)
  167. {
  168. uprint("Directory ");
  169. uprint(dir_path);
  170. uprintln(" not found!");
  171. return -1;
  172. }
  173. token = strtok((word*)-1, "/");
  174. }
  175. return current_dir_fat_idx;
  176. }
  177. /**
  178. * Given the address of the FAT table and the number of blocks, find the next free block
  179. * Returns -1 if no free block is found
  180. * fat_addr: address of the FAT table
  181. * blocks: number of blocks in the FAT table
  182. */
  183. word brfs_find_next_free_block(word* fat_addr, word blocks)
  184. {
  185. word i = 0;
  186. word* fat_ptr = fat_addr;
  187. while (i < blocks)
  188. {
  189. if (*fat_ptr == 0)
  190. {
  191. return i;
  192. }
  193. fat_ptr++;
  194. i++;
  195. }
  196. return -1;
  197. }
  198. /**
  199. * Given the address of a directory data block and the maximum number of entries, find the next free directory entry
  200. * Returns -1 if no free entry is found
  201. * dir_addr: address of the directory data block (not the FAT idx)
  202. * dir_entries_max: maximum number of entries in the directory
  203. */
  204. word brfs_find_next_free_dir_entry(word* dir_addr, word dir_entries_max)
  205. {
  206. word i = 0;
  207. word* dir_ptr = dir_addr;
  208. while (i < dir_entries_max)
  209. {
  210. if (*dir_ptr == 0)
  211. {
  212. return i;
  213. }
  214. dir_ptr += sizeof(struct brfs_dir_entry);
  215. i++;
  216. }
  217. return -1;
  218. }
  219. /**
  220. * Create a single directory entry
  221. * dir_entry: pointer to the directory entry to be created
  222. * filename: name of the file, max 16 chars and uncompressed
  223. * fat_idx: index of the first FAT block of the file/directory
  224. * filesize: size of the file in words
  225. * flags: flags of the file/directory
  226. */
  227. void brfs_create_single_dir_entry(struct brfs_dir_entry* dir_entry, char* filename, word fat_idx, word filesize, word flags)
  228. {
  229. // Initialize to 0
  230. memset((char*)dir_entry, 0, sizeof(*dir_entry));
  231. // Set filename
  232. char compressed_filename[4] = {0,0,0,0};
  233. strcompress(compressed_filename, filename);
  234. memcpy((char*)&(dir_entry->filename), compressed_filename, sizeof(compressed_filename));
  235. // Set other fields
  236. dir_entry->fat_idx = fat_idx;
  237. dir_entry->flags = flags;
  238. dir_entry->filesize = filesize;
  239. }
  240. /**
  241. * Initialize a directory with . and .. entries
  242. * dir_addr: address of the directory data block
  243. * dir_entries_max: maximum number of entries in the directory
  244. * dir_fat_idx: index of the FAT block of the directory
  245. * parent_fat_idx: index of the FAT block of the parent directory
  246. */
  247. void brfs_init_directory(word* dir_addr, word dir_entries_max, word dir_fat_idx, word parent_fat_idx)
  248. {
  249. // Get block size from superblock
  250. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  251. word block_size = superblock->words_per_block;
  252. // Set data block of dir_fat_idx to 0
  253. memset(dir_addr, 0, block_size);
  254. // Create . entry
  255. struct brfs_dir_entry dir_entry;
  256. brfs_create_single_dir_entry(&dir_entry, ".", dir_fat_idx, dir_entries_max*sizeof(struct brfs_dir_entry), 1);
  257. // Copy to first data entry
  258. memcpy(dir_addr, (char*)&dir_entry, sizeof(dir_entry));
  259. // Create .. entry
  260. brfs_create_single_dir_entry(&dir_entry, "..", parent_fat_idx, dir_entries_max*sizeof(struct brfs_dir_entry), 1);
  261. // Copy to second data entry
  262. memcpy(dir_addr+sizeof(dir_entry), (char*)&dir_entry, sizeof(dir_entry));
  263. // Set FAT table
  264. brfs_ram_storage[SUPERBLOCK_SIZE + dir_fat_idx] = -1;
  265. // Set changed block
  266. brfs_changed_blocks[dir_fat_idx >> 5] |= (1 << (dir_fat_idx & 31));
  267. }
  268. /**
  269. * Format the ram storage as a BRFS filesystem
  270. * Also writes the superblock to SPI Flash
  271. * blocks: number of blocks in the filesystem
  272. * words_per_block: number of bytes per block
  273. * label: label of the filesystem
  274. * full_format: if 1, initialize data section to 0
  275. */
  276. void brfs_format(word blocks, word words_per_block, char* label, word full_format)
  277. {
  278. // Create a superblock
  279. struct brfs_superblock superblock;
  280. // Initialize to 0
  281. memset((char*)&superblock, 0, sizeof(superblock));
  282. // Set values of superblock
  283. superblock.total_blocks = blocks;
  284. superblock.words_per_block = words_per_block;
  285. strcpy((char*)&superblock.label, label);
  286. superblock.brfs_version = BRFS_SUPPORTED_VERSION;
  287. // Copy superblock to head of ram addr
  288. memcpy(brfs_ram_storage, (char*)&superblock, sizeof(superblock));
  289. // Create FAT
  290. memset(brfs_ram_storage + SUPERBLOCK_SIZE, 0, blocks);
  291. // Create Data section
  292. if (full_format)
  293. {
  294. memset(brfs_ram_storage + SUPERBLOCK_SIZE + blocks, 0, blocks * words_per_block);
  295. }
  296. // Initialize root dir
  297. word dir_entries_max = words_per_block / sizeof(struct brfs_dir_entry);
  298. brfs_init_directory(brfs_ram_storage + SUPERBLOCK_SIZE + blocks, dir_entries_max, 0, 0);
  299. // Clear open files and cursors
  300. memset(brfs_file_pointers, 0, sizeof(brfs_file_pointers));
  301. memset(brfs_cursors, 0, sizeof(brfs_cursors));
  302. // Set all dir entry pointers to 0
  303. word i;
  304. for (i = 0; i < MAX_OPEN_FILES; i++)
  305. {
  306. brfs_dir_entry_pointers[i] = 0;
  307. }
  308. // For all blocks that have just been formatted, set changed block
  309. word j;
  310. for (j = 0; j < blocks; j++)
  311. {
  312. brfs_changed_blocks[j >> 5] |= (1 << (j & 31));
  313. }
  314. // Write superblock to SPI Flash
  315. spiflash_sector_erase(BRFS_SPIFLASH_SUPERBLOCK_ADDR);
  316. spiflash_write_page_in_words((char*)&superblock, BRFS_SPIFLASH_SUPERBLOCK_ADDR, sizeof(superblock));
  317. }
  318. /**
  319. * Create a new directory in the directory of parent_dir_path
  320. * Returns 1 on success, 0 on error
  321. * parent_dir_path: full path of the parent directory
  322. * dirname: name of the new directory
  323. */
  324. word brfs_create_directory(char* parent_dir_path, char* dirname)
  325. {
  326. // Check length of dirname
  327. if (strlen(dirname) >= 16)
  328. {
  329. uprintln("Directory name too long!");
  330. return 0;
  331. }
  332. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  333. word* brfs_data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  334. // Find first free FAT block
  335. word next_free_block = brfs_find_next_free_block(brfs_ram_storage + SUPERBLOCK_SIZE, superblock->total_blocks);
  336. if (next_free_block == -1)
  337. {
  338. uprintln("No free blocks left!");
  339. return 0;
  340. }
  341. // Find data block address of parent directory path
  342. word parent_dir_fat_idx = brfs_get_fat_idx_of_dir(parent_dir_path);
  343. if (parent_dir_fat_idx == -1)
  344. {
  345. uprint("Parent directory ");
  346. uprint(parent_dir_path);
  347. uprintln(" not found!");
  348. return 0;
  349. }
  350. // Check if file or folder already exists
  351. word* parent_dir_addr = brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block);
  352. word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
  353. word i;
  354. for (i = 0; i < dir_entries_max; i++)
  355. {
  356. struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (parent_dir_addr + (i * sizeof(struct brfs_dir_entry)));
  357. if (dir_entry->filename[0] != 0)
  358. {
  359. char decompressed_filename[17];
  360. strdecompress(decompressed_filename, (char*)&(dir_entry->filename));
  361. if (strcmp(decompressed_filename, dirname) == 0)
  362. {
  363. uprint(dirname);
  364. uprintln(" already exists!");
  365. return 0;
  366. }
  367. }
  368. }
  369. // Find first free dir entry
  370. word next_free_dir_entry = brfs_find_next_free_dir_entry(
  371. brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block),
  372. superblock->words_per_block / sizeof(struct brfs_dir_entry)
  373. );
  374. if (next_free_dir_entry == -1)
  375. {
  376. uprintln("No free dir entries left!");
  377. return 0;
  378. }
  379. // Create dir entry
  380. struct brfs_dir_entry new_entry;
  381. brfs_create_single_dir_entry(&new_entry, dirname, next_free_block, dir_entries_max*sizeof(struct brfs_dir_entry), 1);
  382. // Copy dir entry to first free dir entry
  383. memcpy(
  384. brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block) + (next_free_dir_entry * sizeof(struct brfs_dir_entry)),
  385. (char*)&new_entry,
  386. sizeof(new_entry)
  387. );
  388. // Initialize directory
  389. brfs_init_directory(
  390. brfs_data_block_addr + (next_free_block * superblock->words_per_block),
  391. dir_entries_max,
  392. next_free_block,
  393. parent_dir_fat_idx
  394. );
  395. // Update changed block
  396. brfs_changed_blocks[next_free_block >> 5] |= (1 << (next_free_block & 31));
  397. brfs_changed_blocks[parent_dir_fat_idx >> 5] |= (1 << (parent_dir_fat_idx & 31));
  398. return 1;
  399. }
  400. /**
  401. * Create a new file in the directory of parent_dir_path
  402. * Returns 1 on success, 0 on error
  403. * parent_dir_path: full path of the parent directory
  404. * filename: name of the new file
  405. */
  406. word brfs_create_file(char* parent_dir_path, char* filename)
  407. {
  408. // Check length of filename
  409. if (strlen(filename) >= 16)
  410. {
  411. uprintln("Filename too long!");
  412. return 0;
  413. }
  414. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  415. word* brfs_data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  416. // Find first free FAT block
  417. word next_free_block = brfs_find_next_free_block(brfs_ram_storage + SUPERBLOCK_SIZE, superblock->total_blocks);
  418. if (next_free_block == -1)
  419. {
  420. uprintln("No free blocks left!");
  421. return 0;
  422. }
  423. // Find data block address of parent directory path
  424. word parent_dir_fat_idx = brfs_get_fat_idx_of_dir(parent_dir_path);
  425. if (parent_dir_fat_idx == -1)
  426. {
  427. uprint("Parent directory ");
  428. uprint(parent_dir_path);
  429. uprintln(" not found!");
  430. return 0;
  431. }
  432. // Check if file or folder already exists
  433. word* parent_dir_addr = brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block);
  434. word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
  435. word i;
  436. for (i = 0; i < dir_entries_max; i++)
  437. {
  438. struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (parent_dir_addr + (i * sizeof(struct brfs_dir_entry)));
  439. if (dir_entry->filename[0] != 0)
  440. {
  441. char decompressed_filename[17];
  442. strdecompress(decompressed_filename, (char*)&(dir_entry->filename));
  443. if (strcmp(decompressed_filename, filename) == 0)
  444. {
  445. uprint(filename);
  446. uprintln(" already exists!");
  447. return 0;
  448. }
  449. }
  450. }
  451. // Find first free dir entry
  452. word next_free_dir_entry = brfs_find_next_free_dir_entry(
  453. brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block),
  454. superblock->words_per_block / sizeof(struct brfs_dir_entry)
  455. );
  456. if (next_free_dir_entry == -1)
  457. {
  458. uprintln("No free dir entries left!");
  459. return 0;
  460. }
  461. // Create file entry
  462. struct brfs_dir_entry new_entry;
  463. brfs_create_single_dir_entry(&new_entry, filename, next_free_block, 0, 0);
  464. // Copy dir entry to first free dir entry
  465. memcpy(
  466. brfs_data_block_addr + (parent_dir_fat_idx * superblock->words_per_block) + (next_free_dir_entry * sizeof(struct brfs_dir_entry)),
  467. (char*)&new_entry,
  468. sizeof(new_entry)
  469. );
  470. // Initialize file by setting data to 0
  471. memset(
  472. brfs_data_block_addr + (next_free_block * superblock->words_per_block),
  473. 0,
  474. superblock->words_per_block
  475. );
  476. // Update FAT
  477. brfs_ram_storage[SUPERBLOCK_SIZE + next_free_block] = -1;
  478. // Update changed block
  479. brfs_changed_blocks[next_free_block >> 5] |= (1 << (next_free_block & 31));
  480. return 1;
  481. }
  482. /**
  483. * Reads all directory entries of a directory into a buffer
  484. * dir_path: full path of the directory
  485. * buffer: buffer to store the directory entries
  486. * Returns the number of entries read, or -1 on error
  487. */
  488. word brfs_read_directory(char* dir_path, struct brfs_dir_entry* buffer)
  489. {
  490. // Find data block address of parent directory path
  491. word dir_fat_idx = brfs_get_fat_idx_of_dir(dir_path);
  492. if (dir_fat_idx == -1)
  493. {
  494. uprint("Parent directory ");
  495. uprint(dir_path);
  496. uprintln(" not found!");
  497. return -1;
  498. }
  499. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  500. word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->words_per_block);
  501. word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
  502. word entries_read = 0;
  503. word i;
  504. for (i = 0; i < dir_entries_max; i++)
  505. {
  506. struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (dir_addr + (i * sizeof(struct brfs_dir_entry)));
  507. if (dir_entry->filename[0] != 0)
  508. {
  509. memcpy(buffer, dir_entry, sizeof(struct brfs_dir_entry));
  510. buffer++;
  511. entries_read++;
  512. }
  513. }
  514. return entries_read;
  515. }
  516. /**
  517. * Open a file for reading and writing
  518. * Returns the file pointer (FAT idx of file), or -1 on error
  519. * file_path: full path of the file
  520. */
  521. word brfs_open_file(char* file_path)
  522. {
  523. // Split filename from path using basename and dirname
  524. char dirname_output[MAX_PATH_LENGTH];
  525. char* file_path_basename = basename(file_path);
  526. char* file_path_dirname = dirname(dirname_output, file_path);
  527. // Find data block address of parent directory path
  528. word dir_fat_idx = brfs_get_fat_idx_of_dir(file_path_dirname);
  529. if (dir_fat_idx == -1)
  530. {
  531. uprint("Parent directory ");
  532. uprint(file_path_dirname);
  533. uprintln(" not found!");
  534. return -1;
  535. }
  536. // Find file in directory
  537. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  538. word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->words_per_block);
  539. word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
  540. word i;
  541. for (i = 0; i < dir_entries_max; i++)
  542. {
  543. struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (dir_addr + (i * sizeof(struct brfs_dir_entry)));
  544. if (dir_entry->filename[0] != 0)
  545. {
  546. char decompressed_filename[17];
  547. strdecompress(decompressed_filename, (char*)&(dir_entry->filename));
  548. // Also check for directory flag to be 0
  549. if (strcmp(decompressed_filename, file_path_basename) == 0 && dir_entry->flags == 0)
  550. {
  551. // Found file
  552. // Check if file is already open
  553. word j;
  554. for (j = 0; j < MAX_OPEN_FILES; j++)
  555. {
  556. if (brfs_file_pointers[j] == dir_entry->fat_idx)
  557. {
  558. uprint("File ");
  559. uprint(file_path_basename);
  560. uprintln(" already open!");
  561. return -1;
  562. }
  563. }
  564. // Find first free file pointer
  565. word next_free_file_pointer = -1;
  566. for (j = 0; j < MAX_OPEN_FILES; j++)
  567. {
  568. if (brfs_file_pointers[j] == 0)
  569. {
  570. next_free_file_pointer = j;
  571. break;
  572. }
  573. }
  574. if (next_free_file_pointer == -1)
  575. {
  576. uprintln("All files already opened!");
  577. return -1;
  578. }
  579. // Open file
  580. brfs_file_pointers[next_free_file_pointer] = dir_entry->fat_idx;
  581. brfs_cursors[next_free_file_pointer] = 0;
  582. brfs_dir_entry_pointers[next_free_file_pointer] = dir_entry;
  583. return brfs_file_pointers[next_free_file_pointer];
  584. }
  585. }
  586. }
  587. uprint("File ");
  588. uprint(file_path_basename);
  589. uprintln(" not found!");
  590. return -1;
  591. }
  592. /**
  593. * Close an opened file
  594. * Returns 1 on success, 0 on error
  595. * file_pointer: file pointer returned by brfs_open_file
  596. */
  597. word brfs_close_file(word file_pointer)
  598. {
  599. // Find file pointer
  600. word i;
  601. for (i = 0; i < MAX_OPEN_FILES; i++)
  602. {
  603. if (brfs_file_pointers[i] == file_pointer)
  604. {
  605. // Close file
  606. brfs_file_pointers[i] = 0;
  607. brfs_cursors[i] = 0;
  608. brfs_dir_entry_pointers[i] = 0;
  609. return 1;
  610. }
  611. }
  612. uprintln("File not found!");
  613. return 0;
  614. }
  615. /**
  616. * Delete a file by removing all FAT blocks and the directory entry
  617. * Deletes a directory only if it is empty
  618. * Returns 1 on success, 0 on error
  619. * file_path: full path of the file
  620. */
  621. word brfs_delete(char* file_path)
  622. {
  623. // Split filename from path using basename and dirname
  624. char dirname_output[MAX_PATH_LENGTH];
  625. char* file_path_basename = basename(file_path);
  626. char* file_path_dirname = dirname(dirname_output, file_path);
  627. // Find data block address of parent directory path
  628. word dir_fat_idx = brfs_get_fat_idx_of_dir(file_path_dirname);
  629. if (dir_fat_idx == -1)
  630. {
  631. uprint("Parent directory ");
  632. uprint(file_path_dirname);
  633. uprintln(" not found!");
  634. return 0;
  635. }
  636. // Find file in directory
  637. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  638. word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->words_per_block);
  639. word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
  640. word i;
  641. for (i = 0; i < dir_entries_max; i++)
  642. {
  643. struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (dir_addr + (i * sizeof(struct brfs_dir_entry)));
  644. if (dir_entry->filename[0] != 0)
  645. {
  646. char decompressed_filename[17];
  647. strdecompress(decompressed_filename, (char*)&(dir_entry->filename));
  648. if (strcmp(decompressed_filename, file_path_basename) == 0)
  649. {
  650. if ((dir_entry->flags & 0x01) == 1)
  651. {
  652. // Check if directory is empty
  653. struct brfs_dir_entry buffer[128]; // 128 to be safe
  654. word num_entries = brfs_read_directory(file_path, buffer);
  655. if (num_entries > 2)
  656. {
  657. uprint("Directory ");
  658. uprint(file_path_basename);
  659. uprintln(" is not empty!");
  660. return 0;
  661. }
  662. }
  663. // Check if file is already open
  664. word j;
  665. for (j = 0; j < MAX_OPEN_FILES; j++)
  666. {
  667. if (brfs_file_pointers[j] == dir_entry->fat_idx)
  668. {
  669. uprint("File ");
  670. uprint(file_path_basename);
  671. uprintln(" is open!");
  672. return 0;
  673. }
  674. }
  675. // Delete fat blocks
  676. word current_fat_idx = dir_entry->fat_idx;
  677. word next_fat_idx;
  678. while (current_fat_idx != -1)
  679. {
  680. next_fat_idx = brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx];
  681. brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx] = 0;
  682. brfs_changed_blocks[current_fat_idx >> 5] |= (1 << (current_fat_idx & 31));
  683. current_fat_idx = next_fat_idx;
  684. }
  685. // Delete entry
  686. memset((char*)dir_entry, 0, sizeof(struct brfs_dir_entry));
  687. // Update changed block
  688. brfs_changed_blocks[dir_fat_idx >> 5] |= (1 << (dir_fat_idx & 31));
  689. return 1;
  690. }
  691. }
  692. }
  693. uprint("File ");
  694. uprint(file_path_basename);
  695. uprintln(" not found!");
  696. return 0;
  697. }
  698. /**
  699. * Set the cursor of an opened file
  700. * Returns 1 on success, 0 on error
  701. * file_pointer: file pointer returned by brfs_open_file
  702. * cursor: new cursor position in words
  703. */
  704. word brfs_set_cursor(word file_pointer, word cursor)
  705. {
  706. if (file_pointer == 0)
  707. {
  708. uprintln("File not open!");
  709. return 0;
  710. }
  711. // Find file pointer
  712. word i;
  713. for (i = 0; i < MAX_OPEN_FILES; i++)
  714. {
  715. if (brfs_file_pointers[i] == file_pointer)
  716. {
  717. // Set cursor
  718. if (cursor < 0 || cursor > brfs_dir_entry_pointers[i]->filesize)
  719. {
  720. cursor = brfs_dir_entry_pointers[i]->filesize;
  721. }
  722. brfs_cursors[i] = cursor;
  723. return 1;
  724. }
  725. }
  726. uprintln("File not found!");
  727. return 0;
  728. }
  729. /**
  730. * Get the cursor of an opened file
  731. * Returns the cursor position in words, or -1 on error
  732. * file_pointer: file pointer returned by brfs_open_file
  733. */
  734. word brfs_get_cursor(word file_pointer)
  735. {
  736. if (file_pointer == 0)
  737. {
  738. uprintln("File not open!");
  739. return -1;
  740. }
  741. // Find file pointer
  742. word i;
  743. for (i = 0; i < MAX_OPEN_FILES; i++)
  744. {
  745. if (brfs_file_pointers[i] == file_pointer)
  746. {
  747. // Get cursor
  748. return brfs_cursors[i];
  749. }
  750. }
  751. uprintln("File not found!");
  752. return -1;
  753. }
  754. /**
  755. * Get the FAT index of a file at the cursor
  756. * Returns the FAT index, or 0 on error
  757. * file_pointer: file pointer returned by brfs_open_file
  758. * cursor: cursor position of opened file
  759. */
  760. word brfs_get_fat_idx_at_cursor(word file_pointer, word cursor)
  761. {
  762. if (file_pointer == 0)
  763. {
  764. uprintln("File not open!");
  765. return 0;
  766. }
  767. // Get FAT index of file at cursor
  768. word current_fat_idx = file_pointer;
  769. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  770. // Loop through FAT until cursor is reached
  771. while (cursor > superblock->words_per_block)
  772. {
  773. current_fat_idx = brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx];
  774. if (current_fat_idx == -1)
  775. {
  776. uprintln("Cursor is out of bounds!");
  777. return 0;
  778. }
  779. cursor -= superblock->words_per_block;
  780. }
  781. return current_fat_idx;
  782. }
  783. /**
  784. * Read a file from the cursor position
  785. * Returns 1 on success, or 0 on error
  786. * file_pointer: file pointer returned by brfs_open_file
  787. * buffer: buffer to read the file into
  788. * length: number of words to read
  789. */
  790. word brfs_read(word file_pointer, word* buffer, word length)
  791. {
  792. if (file_pointer == 0)
  793. {
  794. uprintln("File not open!");
  795. return 0;
  796. }
  797. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  798. word* data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  799. // Find file pointer
  800. word i;
  801. for (i = 0; i < MAX_OPEN_FILES; i++)
  802. {
  803. if (brfs_file_pointers[i] == file_pointer)
  804. {
  805. if (length < 0)
  806. {
  807. uprintln("Length cannot be negative!");
  808. return 0;
  809. }
  810. // Trunctate length to file size - cursor
  811. if (length > brfs_dir_entry_pointers[i]->filesize - brfs_cursors[i])
  812. {
  813. length = brfs_dir_entry_pointers[i]->filesize - brfs_cursors[i];
  814. }
  815. // Get FAT index of file at cursor
  816. word current_fat_idx = brfs_get_fat_idx_at_cursor(file_pointer, brfs_cursors[i]);
  817. if (current_fat_idx == 0)
  818. {
  819. uprintln("Error getting FAT index at cursor!");
  820. return 0;
  821. }
  822. // Loop:
  823. // - calculate words until end of block (or up to length)
  824. // - read words until end of block (or up to length)
  825. // - decrease length by words read
  826. // - get next block from FAT
  827. // - repeat until length is 0
  828. while (length > 0)
  829. {
  830. word words_until_end_of_block = superblock->words_per_block - (MATH_modU(brfs_cursors[i], superblock->words_per_block));
  831. word words_to_read = words_until_end_of_block > length ? length : words_until_end_of_block;
  832. // Copy words to buffer
  833. memcpy(buffer, data_block_addr + (current_fat_idx * superblock->words_per_block) + MATH_modU(brfs_cursors[i], superblock->words_per_block), words_to_read);
  834. // Update cursor and length
  835. brfs_cursors[i] += words_to_read;
  836. length -= words_to_read;
  837. buffer += words_to_read;
  838. // Get next block from FAT
  839. current_fat_idx = brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx];
  840. if (current_fat_idx == -1 && length > 0)
  841. {
  842. uprintln("There is no next block in the file!");
  843. return 0;
  844. }
  845. }
  846. return 1;
  847. }
  848. }
  849. uprintln("File not found!");
  850. return 0;
  851. }
  852. /**
  853. * Write a file from the cursor position
  854. * Returns 1 on success, or 0 on error
  855. * file_pointer: file pointer returned by brfs_open_file
  856. * buffer: buffer to write to the file
  857. * length: number of words to write
  858. */
  859. word brfs_write(word file_pointer, word* buffer, word length)
  860. {
  861. if (file_pointer == 0)
  862. {
  863. uprintln("File not open!");
  864. return 0;
  865. }
  866. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  867. word* data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  868. // Find file pointer
  869. word i;
  870. for (i = 0; i < MAX_OPEN_FILES; i++)
  871. {
  872. if (brfs_file_pointers[i] == file_pointer)
  873. {
  874. if (length < 0)
  875. {
  876. uprintln("Length cannot be negative!");
  877. return 0;
  878. }
  879. // Get FAT index of file at cursor
  880. word current_fat_idx = brfs_get_fat_idx_at_cursor(file_pointer, brfs_cursors[i]);
  881. if (current_fat_idx == 0)
  882. {
  883. uprintln("Error getting FAT index at cursor!");
  884. return 0;
  885. }
  886. // Loop:
  887. // - calculate words until end of block (or up to length)
  888. // - write words until end of block (or up to length)
  889. // - decrease length by words written
  890. // - get next block from FAT, or find next free block if end of block
  891. // - if next block is needed, update FAT
  892. // - repeat until length is 0
  893. while (length > 0)
  894. {
  895. word cursor_in_block = MATH_modU(brfs_cursors[i], superblock->words_per_block);
  896. word words_until_end_of_block = superblock->words_per_block - cursor_in_block;
  897. word words_to_write = words_until_end_of_block > length ? length : words_until_end_of_block;
  898. // Copy words to buffer
  899. memcpy(data_block_addr + (current_fat_idx * superblock->words_per_block) + cursor_in_block, buffer, words_to_write);
  900. // Update changed block
  901. brfs_changed_blocks[current_fat_idx >> 5] |= (1 << (current_fat_idx & 31));
  902. // Update cursor and length
  903. brfs_cursors[i] += words_to_write;
  904. length -= words_to_write;
  905. buffer += words_to_write;
  906. // Get next block from FAT, or find next free block if end of block
  907. if (words_until_end_of_block == words_to_write && length > 0)
  908. {
  909. word next_fat_idx = brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx];
  910. // Check if next block is already allocated
  911. if (next_fat_idx != -1)
  912. {
  913. current_fat_idx = next_fat_idx;
  914. }
  915. else
  916. {
  917. // Find next free block
  918. word next_free_block = brfs_find_next_free_block(brfs_ram_storage + SUPERBLOCK_SIZE, superblock->total_blocks);
  919. if (next_free_block == -1)
  920. {
  921. uprintln("No free blocks left!");
  922. return 0;
  923. }
  924. // Update FAT
  925. brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx] = next_free_block;
  926. // Go to next block
  927. current_fat_idx = next_free_block;
  928. // Set next block to -1 to indicate end of file
  929. brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx] = -1;
  930. // Update changed block
  931. brfs_changed_blocks[current_fat_idx >> 5] |= (1 << (current_fat_idx & 31));
  932. }
  933. }
  934. }
  935. // Update file size in dir entry if we wrote past the current size
  936. if (brfs_cursors[i] > brfs_dir_entry_pointers[i]->filesize)
  937. {
  938. brfs_dir_entry_pointers[i]->filesize = brfs_cursors[i];
  939. }
  940. return 1;
  941. }
  942. }
  943. uprintln("File not found!");
  944. return 0;
  945. }
  946. /**
  947. * Stat a file or directory
  948. * Returns the directory entry, or -1 on error
  949. */
  950. struct brfs_dir_entry* brfs_stat(char* file_path)
  951. {
  952. // Remove all trailing slashes
  953. while (strlen(file_path) > 1 && file_path[strlen(file_path)-1] == '/')
  954. {
  955. file_path[strlen(file_path)-1] = 0;
  956. }
  957. // Split filename from path using basename and dirname
  958. char dirname_output[MAX_PATH_LENGTH];
  959. char* file_path_basename = basename(file_path);
  960. char* file_path_dirname = dirname(dirname_output, file_path);
  961. // Find data block address of parent directory path
  962. word dir_fat_idx = brfs_get_fat_idx_of_dir(file_path_dirname);
  963. if (dir_fat_idx == -1)
  964. {
  965. uprint("Parent directory ");
  966. uprint(file_path_dirname);
  967. uprintln(" not found!");
  968. return (struct brfs_dir_entry*)-1;
  969. }
  970. // Find file in directory
  971. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  972. word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->words_per_block);
  973. word dir_entries_max = superblock->words_per_block / sizeof(struct brfs_dir_entry);
  974. word i;
  975. for (i = 0; i < dir_entries_max; i++)
  976. {
  977. struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (dir_addr + (i * sizeof(struct brfs_dir_entry)));
  978. if (dir_entry->filename[0] != 0)
  979. {
  980. char decompressed_filename[17];
  981. strdecompress(decompressed_filename, (char*)&(dir_entry->filename));
  982. // Also check for directory flag to be 0
  983. if (strcmp(decompressed_filename, file_path_basename) == 0)
  984. {
  985. return dir_entry;
  986. }
  987. }
  988. }
  989. uprint("File or directory ");
  990. uprint(file_path_basename);
  991. uprintln(" not found!");
  992. return (struct brfs_dir_entry*)-1;
  993. }
  994. /**
  995. * Check if a block has changed by comparing it to the flash, returns 1 if changed and 0 if not
  996. * Note: this is slow and should eventually be replaced by a list of changed blocks
  997. * block_idx: index of the block
  998. */
  999. word brfs_check_block_changed(word block_idx)
  1000. {
  1001. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  1002. word* data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  1003. word spi_data_buffer[256];
  1004. if (superblock->words_per_block > 256)
  1005. {
  1006. uprintln("Error: words_per_block should be <= 256 for this function!");
  1007. return 0;
  1008. }
  1009. // Read block from flash, and enable bytes to word
  1010. spiflash_read_from_address(spi_data_buffer, BRFS_SPIFLASH_BLOCK_ADDR + block_idx * superblock->words_per_block, superblock->words_per_block, 1);
  1011. // Compare block to flash
  1012. return memcmp(data_block_addr + (block_idx * superblock->words_per_block), spi_data_buffer, superblock->words_per_block);
  1013. }
  1014. /**
  1015. * Write the FAT table to SPI flash by performing three steps:
  1016. * 1. Check which FAT entries have changed
  1017. * 2. Erase the 4KiB sectors that contain these FAT entries
  1018. * 3. Write each changed FAT entry to flash by using 16 page writes per sector
  1019. */
  1020. void brfs_write_fat_to_flash()
  1021. {
  1022. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  1023. word* data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  1024. // 1 sector = 4KiB = 1024 words = 1024 FAT entries
  1025. // 1 word contains 32 flags for changed blocks/FAT entries
  1026. // 1024/32 = 32 words in the changed_blocks array per sector
  1027. uprintln("---Writing FAT to SPI Flash---");
  1028. // Loop over brfs_changed_blocks in 32 word parts
  1029. // Assumes length of brfs_changed_blocks is a multiple of 32
  1030. word i;
  1031. for (i = 0; i < sizeof(brfs_changed_blocks); i+=32)
  1032. {
  1033. // Check if any value within brfs_changed_blocks[i:i+32] is not 0
  1034. word j;
  1035. word changed = 0;
  1036. for (j = 0; j < 32; j++)
  1037. {
  1038. if (brfs_changed_blocks[i+j] != 0)
  1039. {
  1040. changed = 1;
  1041. break;
  1042. }
  1043. }
  1044. if (changed)
  1045. {
  1046. // Erase sector
  1047. word addr = BRFS_SPIFLASH_FAT_ADDR; // Workaround because of large static number
  1048. addr += (i >> 5) * 4096; // Sector idx * bytes per sector
  1049. spiflash_sector_erase(addr);
  1050. uprint("Erased sector ");
  1051. uprintDec(i >> 5);
  1052. uprint(" at address ");
  1053. uprintHex(addr);
  1054. uprintln("");
  1055. // Write sector by writing 16 pages k of 64 words
  1056. // Does not check for boundaries of actual FAT table size,
  1057. // so it can write garbage if block size is not a multiple of 1024
  1058. word k;
  1059. for (k = 0; k < 1024; k+=64)
  1060. {
  1061. addr = BRFS_SPIFLASH_FAT_ADDR; // Workaround because of large static number
  1062. addr += (i >> 5) * 4096; // Sector idx * bytes per sector
  1063. addr += k << 2; // 64 words * 4 bytes per word
  1064. word* fat_addr_ram = brfs_ram_storage + SUPERBLOCK_SIZE + (i << 5) + k;
  1065. spiflash_write_page_in_words(fat_addr_ram, addr, 64);
  1066. uprint("Wrote FAT entries ");
  1067. uprintDec((i << 5) + k);
  1068. uprint(":");
  1069. uprintDec((i << 5) + k + 63);
  1070. uprint(" from RAM addr ");
  1071. uprintHex((word)fat_addr_ram);
  1072. uprint(" to SPI Flash addr ");
  1073. uprintHex(addr);
  1074. uprintln("");
  1075. }
  1076. }
  1077. }
  1078. uprintln("---Finished writing FAT to SPI Flash---");
  1079. }
  1080. /**
  1081. * Write a sector (4KiB) to SPI flash
  1082. * sector_idx: index of the sector
  1083. */
  1084. void brfs_write_sector_to_flash(word sector_idx)
  1085. {
  1086. word spi_addr = BRFS_SPIFLASH_BLOCK_ADDR; // Workaround because of large static number
  1087. spi_addr += sector_idx * 4096; // Sector idx * bytes per sector
  1088. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  1089. word* data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  1090. word brfs_sector_addr = data_block_addr + sector_idx * (4096 >> 2); // Divided by 4 because of word size
  1091. // Write sector by writing 16 pages k of 64 words
  1092. // Does not check for boundaries of actual FAT table size,
  1093. // so it can write garbage if block size is not a multiple of 1024
  1094. word k;
  1095. for (k = 0; k < 1024; k+=64)
  1096. {
  1097. spiflash_write_page_in_words(brfs_sector_addr + k, spi_addr + (k << 2), 64);
  1098. uprint("Wrote sector ");
  1099. uprintDec(sector_idx);
  1100. uprint(":");
  1101. uprintDec(sector_idx + 15);
  1102. uprint(" from RAM addr ");
  1103. uprintHex((word)(brfs_sector_addr + k));
  1104. uprint(" to SPI Flash addr ");
  1105. uprintHex(spi_addr + (k << 2));
  1106. uprintln("");
  1107. }
  1108. }
  1109. /**
  1110. * Write the data blocks to SPI flash by performing three steps:
  1111. * 1. Check which blocks have changed
  1112. * 2. Erase the 4KiB sectors that contain these blocks
  1113. * 3. Write each erased sector with the new block data by using 16 page writes per sector
  1114. */
  1115. void brfs_write_blocks_to_flash()
  1116. {
  1117. // Loop over all blocks
  1118. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  1119. word* data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  1120. // Check if block size is <= 4KiB
  1121. if (superblock->words_per_block > 1024)
  1122. {
  1123. uprintln("Error: block size should be <= 4KiB");
  1124. return;
  1125. }
  1126. // Check if block size is a multiple of 64
  1127. if (superblock->words_per_block & 63)
  1128. {
  1129. uprintln("Error: block size should be a multiple of 64");
  1130. return;
  1131. }
  1132. uprintln("---Writing blocks to SPI Flash---");
  1133. word blocks_per_sector = MATH_divU(4096, superblock->words_per_block * 4);
  1134. uprint("Blocks per sector: ");
  1135. uprintDec(blocks_per_sector);
  1136. uprintln("");
  1137. // Erase 4KiB sectors that contain changed blocks
  1138. // This code is written such that it only erases each sector once, even if multiple blocks in the sector have changed
  1139. word i;
  1140. word sector_to_erase = -1;
  1141. for (i = 0; i < superblock->total_blocks; i++)
  1142. {
  1143. if (brfs_changed_blocks[i >> 5] & (1 << (i & 31)))
  1144. {
  1145. if (sector_to_erase == -1)
  1146. {
  1147. sector_to_erase = MATH_divU(i, blocks_per_sector);
  1148. }
  1149. else if (sector_to_erase != MATH_divU(i, blocks_per_sector))
  1150. {
  1151. word addr = BRFS_SPIFLASH_BLOCK_ADDR; // Workaround because of large static number
  1152. addr += sector_to_erase * 4096;
  1153. spiflash_sector_erase(addr);
  1154. uprint("Erased sector ");
  1155. uprintDec(sector_to_erase);
  1156. uprint(" at address ");
  1157. uprintHex(addr);
  1158. uprintln("");
  1159. brfs_write_sector_to_flash(sector_to_erase);
  1160. sector_to_erase = MATH_divU(i, blocks_per_sector);
  1161. }
  1162. }
  1163. }
  1164. if (sector_to_erase != -1)
  1165. {
  1166. word addr = BRFS_SPIFLASH_BLOCK_ADDR; // Workaround because of large static number
  1167. addr += sector_to_erase * 4096;
  1168. spiflash_sector_erase(addr);
  1169. uprint("Erased sector ");
  1170. uprintDec(sector_to_erase);
  1171. uprint(" at address ");
  1172. uprintHex(addr);
  1173. uprintln("");
  1174. brfs_write_sector_to_flash(sector_to_erase);
  1175. }
  1176. uprintln("---Finished writing blocks to SPI Flash---");
  1177. }
  1178. /**
  1179. * Write the FAT and data blocks to SPI flash
  1180. * Superblock should already be written to flash during format
  1181. */
  1182. void brfs_write_to_flash()
  1183. {
  1184. brfs_write_fat_to_flash();
  1185. brfs_write_blocks_to_flash();
  1186. // Reset changed blocks
  1187. memset(brfs_changed_blocks, 0, sizeof(brfs_changed_blocks));
  1188. }
  1189. /**
  1190. * Checks if given superblock is valid
  1191. * Returns 1 if valid, 0 if invalid
  1192. */
  1193. word brfs_superblock_is_valid(struct brfs_superblock* superblock)
  1194. {
  1195. // Check if brfs version is correct
  1196. if (superblock->brfs_version != BRFS_SUPPORTED_VERSION)
  1197. {
  1198. uprint("BRFS version ");
  1199. uprintDec(superblock->brfs_version);
  1200. uprint(" is not supported by this implementation (");
  1201. uprintDec(BRFS_SUPPORTED_VERSION);
  1202. uprintln(")!");
  1203. return 0;
  1204. }
  1205. // Check if total blocks is > 0 and a multiple of 64
  1206. if (superblock->total_blocks == 0 || superblock->total_blocks & 63)
  1207. {
  1208. uprintln("Error: total blocks should be > 0 and a multiple of 64");
  1209. return 0;
  1210. }
  1211. // Check if block size is > 0
  1212. if (superblock->words_per_block == 0)
  1213. {
  1214. uprintln("Error: block size should be > 0");
  1215. return 0;
  1216. }
  1217. // Check if words per block is > 0 and <= 2048
  1218. if (superblock->words_per_block == 0 || superblock->words_per_block > 2048)
  1219. {
  1220. uprintln("Error: words per block should be > 0 and <= 2048");
  1221. return 0;
  1222. }
  1223. return 1;
  1224. }
  1225. /**
  1226. * Read the superblock, FAT and data blocks from SPI flash
  1227. * Returns 1 on success, or 0 on error
  1228. */
  1229. word brfs_read_from_flash()
  1230. {
  1231. // Read superblock from flash
  1232. spiflash_read_from_address(brfs_ram_storage, BRFS_SPIFLASH_SUPERBLOCK_ADDR, SUPERBLOCK_SIZE, 1);
  1233. // Perform validity checks on superblock
  1234. struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
  1235. if (!brfs_superblock_is_valid(superblock))
  1236. {
  1237. uprintln("Error: superblock is not valid!");
  1238. return 0;
  1239. }
  1240. word* data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
  1241. // Read FAT from flash
  1242. spiflash_read_from_address(brfs_ram_storage + SUPERBLOCK_SIZE, BRFS_SPIFLASH_FAT_ADDR, superblock->total_blocks, 1);
  1243. // Read data blocks from flash
  1244. spiflash_read_from_address(data_block_addr, BRFS_SPIFLASH_BLOCK_ADDR, superblock->total_blocks * superblock->words_per_block, 1);
  1245. return 1;
  1246. }