commit b089b00882c30eefb8633f382e1085a10f59c542 Author: Yann MAGNIN Date: Thu Apr 20 16:25:05 2023 +0200 fsctl - v0.0.0-1 : project architecture + fugue root dirent handling (WIP) *common* | add build system | add neovim ALE configuration | first Fugue File System abstraction (maxi WIP) | first menus (ROM, FS info, FAT viewer, ...) (WIP) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..587e79b --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# Build files +/build-fx +/build-cg +/build-cg-push +/*.g1a +/*.g3a + +# Python bytecode +__pycache__/ + +# Common IDE files +*.sublime-project +*.sublime-workspace +.vscode + +# custom +commit.txt diff --git a/.nvimrc b/.nvimrc new file mode 100644 index 0000000..9d47202 --- /dev/null +++ b/.nvimrc @@ -0,0 +1,58 @@ +" Force-display trailing whitespaces +highlight ExtraWhitespace ctermbg=red guibg=red +match ExtraWhitespace /\s\+$/ +autocmd BufWinEnter * match ExtraWhitespace /\s\+$/ +autocmd InsertEnter * match ExtraWhitespace /\s\+\%#\@ +#include + +#include "fsctl/fugue/bits/fs.h" + +/* fugue_dir : Fugue directory abstraction */ +struct fugue_dir +{ + /* middle-level information */ + uintptr_t current_dir_addr; + uintptr_t cluster_addr_start; + uintptr_t cluster_addr_end; + uint32_t cluster_idx; + + /* low-level information */ + struct { + fugue_fs_t fs; + } _private; + +}; +typedef struct fugue_dir fugue_dir_t; + +#endif /* FSCTL_FUGUE_BITS_DIR_H */ diff --git a/include/fsctl/fugue/bits/fat.h b/include/fsctl/fugue/bits/fat.h new file mode 100644 index 0000000..61738a9 --- /dev/null +++ b/include/fsctl/fugue/bits/fat.h @@ -0,0 +1,94 @@ +#ifndef FSCTL_FUGUE_BITS_FAT_H +#define FSCTL_FUGUE_BITS_FAT_H 1 + +#include +#include + +/* struct fugue_fat_vbr : Volume Boot Record (hardcoded for Fugue) */ +struct fugue_fat_vbr +{ + // common boot structure + uint8_t BS_jmpBoot[3]; + uint8_t BS_OEMName[8]; + + // BIOS parameter Block + uint16_t BPB_BytsPerSec; + uint8_t BPB_SecPerClus; + uint16_t BPB_RsvdSecCnt; + uint8_t BPB_NumFATs; + uint16_t BPB_RootEntCnt; + uint16_t BPB_TotSec16; + uint8_t BPB_Media; + uint16_t BPB_FATSz16; + uint16_t BPB_SecPerTrk; + uint16_t BPB_NumHeads; + uint32_t BPB_HiddSec; + uint32_t BPB_TotSec32; + + // Extended BIOS Parameter Block + uint8_t BS_DrvNum; + uint8_t BS_Reserved1; + uint8_t BS_BootSig; + uint8_t BS_VolID[4]; + uint8_t BS_VolLab[11]; + uint8_t BS_FilSysType[8]; + uint8_t _unused[448]; + + // Signature + uint8_t Signature_word[2]; +} __attribute__((packed)); + +/* FUGUE_DIR_ATTR_* : Attribute information */ +#define FUGUE_DIR_ATTR_RDONLY 0x01 +#define FUGUE_DIR_ATTR_HIDDEN 0x02 +#define FUGUE_DIR_ATTR_SYSTEM 0x04 +#define FUGUE_DIR_ATTR_VOLUME 0x08 +#define FUGUE_DIR_ATTR_DIR 0x10 +#define FUGUE_DIR_ATTR_ARCHIVE 0x20 +#define FUGUE_DIR_ATTR_DEVICE 0x40 +#define FUGUE_DIR_ATTR_LFN 0x0f + +/* fugue_fat_dir : directory strcuture information */ +struct fugue_fat_dir +{ + uint8_t DIR_Name[8]; + uint8_t DIR_Exts[3]; + uint8_t DIR_Attr; + uint8_t _unknown0[1+1+2+2+2]; + uint16_t DIR_FstClusHI; + uint8_t _unknown1[2+2]; + uint16_t DIR_FstClusLO; + uint32_t DIR_FileSize; +} __attribute__((packed)); + +/* fugue_fat_dir_name : Fugue directory name strcuture */ +struct fugue_fat_dir_name +{ + struct { + uint8_t :2; + uint8_t last :1; + uint8_t :1; + uint8_t id :4; + } DIR_Secquence; + uint16_t DIR_Char0; + uint16_t DIR_Char1; + uint16_t DIR_Char2; + uint16_t DIR_Char3; + uint16_t DIR_Char4; + uint8_t DIR_Attr; // must be 0x0f + uint8_t DIR_Type; // must be 0x00 + uint8_t checksum; + uint16_t DIR_Char5; + uint16_t DIR_Char6; + uint16_t DIR_Char7; + uint16_t DIR_Char8; + uint16_t DIR_Char9; + uint16_t DIR_Char10; + uint16_t DIR_FstClus; // must be 0x0000 + uint16_t DIR_Char11; + uint16_t DIR_Char12; +} __attribute__((packed)); + + + +#endif /* FSCTL_FUGUE_BITS_FAT_H */ diff --git a/include/fsctl/fugue/bits/file.h b/include/fsctl/fugue/bits/file.h new file mode 100644 index 0000000..44025dc --- /dev/null +++ b/include/fsctl/fugue/bits/file.h @@ -0,0 +1,20 @@ +#ifndef FSCTL_FUGUE_BITS_FILE_H +#define FSCTL_FUGUE_BITS_FILE_H 1 + +#include +#include + +/* FUGUE_FILE_TYPE_* : supported file types */ +#define FUGUE_FILE_TYPE_DIR 0x01 +#define FUGUE_FILE_TYPE_FILE 0x02 + +/* struct fugue_file : Fugue file abstraction */ +struct fugue_file +{ + char name[210]; + int type; + uint32_t size; +}; +typedef struct fugue_file fugue_file_t; + +#endif /* FSCTL_FUGUE_BITS_FILE_H */ diff --git a/include/fsctl/fugue/bits/fs.h b/include/fsctl/fugue/bits/fs.h new file mode 100644 index 0000000..a343fc0 --- /dev/null +++ b/include/fsctl/fugue/bits/fs.h @@ -0,0 +1,48 @@ +#ifndef FSCTL_FUGUE_BITS_FS_H +#define FSCTL_FUGUE_BITS_FS_H 1 + +#include +#include + +/* fugue_fs : Fugue File System abstraction */ +struct fugue_fs +{ + /* fs properties */ + struct { + char const *type; + size_t capacity; + size_t free; + size_t used; + int cluster_nb; + int cluster_resv; + int cluster_free; + int cluster_dead; + int cluster_used; + int cluster_error; + size_t cluster_size; + int cluster_nb_sector; + int sector_size; + int sector_data_nb; + int sector_root_nb; + size_t fats_size; + size_t fat0_size; + size_t fat1_size; + int fat_sec; + } props; + + /* debug-level information */ + struct { + int a; //TODO + } _logs; + + /* memory related and low-level information */ + struct { + struct fugue_fat_vbr *vbr; + void *fat0; + void *fat1; + void *root; + } _private; +}; +typedef struct fugue_fs fugue_fs_t; + +#endif /* FSCTL_FUGUE_BITS_FS_H */ diff --git a/include/fsctl/fugue/cluster.h b/include/fsctl/fugue/cluster.h new file mode 100644 index 0000000..fef40cb --- /dev/null +++ b/include/fsctl/fugue/cluster.h @@ -0,0 +1,16 @@ +#ifndef FSCTL_FUGUE_CLUSTER_H +#define FSCTL_FUGUE_CLUSTER_H 1 + +#include "fsctl/fugue/bits/fs.h" + +//--- +// Public +//--- + +/* fugue_cluster_is_valid() : check cluster validity */ +extern int fugue_cluster_is_valid(fugue_fs_t *fs, int cluster_idx); + +/* fugue_cluster_find_next() : find the next cluster address if available */ +extern uintptr_t fugue_cluster_find_next(fugue_fs_t *fs, uint32_t cluster_idx); + +#endif /* FSCTL_FUGUE_CLUSTER_H */ diff --git a/include/fsctl/fugue/dirent.h b/include/fsctl/fugue/dirent.h new file mode 100644 index 0000000..224907f --- /dev/null +++ b/include/fsctl/fugue/dirent.h @@ -0,0 +1,21 @@ +#ifndef FSCTL_FUGUE_DIRENT_H +#define FSCTL_FUGUE_DIRENT_H 1 + +#include "fsctl/fugue/bits/dir.h" +#include "fsctl/fugue/bits/file.h" + +//--- +// API +//--- + +/* fugue_dirent_dir_fetch() : fetch the current dir blob and walk to next */ +extern void *fugue_dirent_dir_fetch(fugue_dir_t *dirent); + +/* fugue_dirent_name_fetch() : fetch fragment */ +extern int fugue_dirent_name_fetch( + fugue_dir_t *dirent, + fugue_file_t *file, + void *dir +); + +#endif /* FSCTL_FUGUE_DIRENT_H */ diff --git a/include/fsctl/fugue/fat.h b/include/fsctl/fugue/fat.h new file mode 100644 index 0000000..ce82d74 --- /dev/null +++ b/include/fsctl/fugue/fat.h @@ -0,0 +1,13 @@ +#ifndef FSCTL_FUGUE_FAT_H +#define FSCTL_FUGUE_FAT_H 1 + +#include "fsctl/fugue/bits/fs.h" + +//--- +// API +//--- + +/* fugue_fat_is_vaild() : Check the complet FATs validity */ +extern int fugue_fat_is_vaild(fugue_fs_t *fs); + +#endif /* FSCTL_FUGUE_FAT_H */ diff --git a/include/fsctl/fugue/sector.h b/include/fsctl/fugue/sector.h new file mode 100644 index 0000000..90f1bf8 --- /dev/null +++ b/include/fsctl/fugue/sector.h @@ -0,0 +1,16 @@ +#ifndef FSCTL_FUGUE_SECTOR_H +#define FSCTL_FUGUE_SECTOR_H 1 + +#include "fsctl/fugue/bits/fat.h" + +//--- +// Public +//--- + +/* fugue_sector_is_vbr() : check if the given address is a potential VBR */ +extern int fugue_sector_is_vbr(struct fugue_fat_vbr *vbr); + +/* fugue_sector_is_invalid() : check if the sector is invalide */ +extern int fugue_sector_is_invalid(void *sector); + +#endif /* FSCTL_FUGUE_SECTOR_H */ diff --git a/include/fsctl/fugue/utils.h b/include/fsctl/fugue/utils.h new file mode 100644 index 0000000..bb4e984 --- /dev/null +++ b/include/fsctl/fugue/utils.h @@ -0,0 +1,16 @@ +#ifndef FSCTL_FUGUE_UTILS_H +#define FSCTL_FUGUE_UTILS_H 1 + +/* FAT_TO_WORD() : helper for 16bit value */ +#define FAT_WORD(x) \ + (((x & 0xff00) >> 8) | ((x & 0x00ff) << 8)) + +/* FAT_LONG() : helper for 32bit value */ +#define FAT_LONG(x) ( \ + ((x & 0xff000000) >> 24) \ + | ((x & 0x00ff0000) >> 8) \ + | ((x & 0x0000ff00) << 8) \ + | ((x & 0x000000ff) << 24) \ +) + +#endif /* FSCTL_FUGUE_UTILS_H */ diff --git a/include/fsctl/menu.h b/include/fsctl/menu.h new file mode 100644 index 0000000..bd04faa --- /dev/null +++ b/include/fsctl/menu.h @@ -0,0 +1,4 @@ +#include "fsctl/menu/fat.h" +#include "fsctl/menu/rom.h" +#include "fsctl/menu/info.h" +#include "fsctl/menu/list.h" diff --git a/include/fsctl/menu/fat.h b/include/fsctl/menu/fat.h new file mode 100644 index 0000000..3ec7573 --- /dev/null +++ b/include/fsctl/menu/fat.h @@ -0,0 +1,13 @@ +#ifndef FSCTL_MENU_FAT_H +#define FSCTL_MENU_FAT_H 1 + +/* fat_menu_init() : init menu */ +extern void fat_menu_init(void); + +/* fat_menu_display() : display menu */ +extern void fat_menu_display(void); + +/* fat_menu_keyboard() : handle keyboard */ +extern void fat_menu_keyboard(int key); + +#endif /* FSCTL_MENU_FAT_H */ diff --git a/include/fsctl/menu/info.h b/include/fsctl/menu/info.h new file mode 100644 index 0000000..140a2c0 --- /dev/null +++ b/include/fsctl/menu/info.h @@ -0,0 +1,13 @@ +#ifndef FSCTL_MENU_INFO_H +#define FSCTL_MENU_INFO_H 1 + +/* info_menu_init() : init menu */ +extern void info_menu_init(void); + +/* info_menu_display() : display menu */ +extern void info_menu_display(void); + +/* info_menu_keyboard() : handle keyboard */ +extern void info_menu_keyboard(int key); + +#endif /* FSCTL_MENU_INFO_H */ diff --git a/include/fsctl/menu/list.h b/include/fsctl/menu/list.h new file mode 100644 index 0000000..3dcfd02 --- /dev/null +++ b/include/fsctl/menu/list.h @@ -0,0 +1,13 @@ +#ifndef FSCTL_MENU_LIST_H +#define FSCTL_MENU_LIST_H 1 + +/* list_menu_init() : init menu */ +extern void list_menu_init(void); + +/* list_menu_display() : display menu */ +extern void list_menu_display(void); + +/* list_menu_keyboard() : handle keyboard */ +extern void list_menu_keyboard(int key); + +#endif /* FSCTL_MENU_LIST_H */ diff --git a/include/fsctl/menu/rom.h b/include/fsctl/menu/rom.h new file mode 100644 index 0000000..259e703 --- /dev/null +++ b/include/fsctl/menu/rom.h @@ -0,0 +1,13 @@ +#ifndef FSCTL_MENU_ROM_H +#define FSCTL_MENU_ROM_H 1 + +/* rom_menu_init() : init menu */ +extern void rom_menu_init(void); + +/* rom_menu_display() : display menu */ +extern void rom_menu_display(void); + +/* rom_menu_keyboard() : handle keyboard */ +extern void rom_menu_keyboard(int key); + +#endif /* FSCTL_MENU_ROM_H */ diff --git a/include/fsctl/utils/display.h b/include/fsctl/utils/display.h new file mode 100644 index 0000000..3c06189 --- /dev/null +++ b/include/fsctl/utils/display.h @@ -0,0 +1,47 @@ +#ifndef FSCTL_MENU_UTILS_H +#define FSCTL_MENU_UTILS_H 1 + +#include +#include + +//--- +// Helpers +//--- + +#define _printXY(x, y, ...) \ + dprint((x * 10) + 3, (y * 12) + 5, C_BLACK, __VA_ARGS__) + +#define _rectXY(x, y, color) \ + drect_border( \ + (x * 12) + 3 + 85, \ + (y * 12) + 3, \ + (x * 12) + 3 + 85 + 12, \ + (y * 12) + 3 + 12, \ + color, \ + 1, \ + C_BLACK \ + ) + +#define _lrectXY(x, y, color) \ + drect_border( \ + (x * 48) + 3 + 85, \ + (y * 12) + 3, \ + (x * 48) + 3 + 85 + 48, \ + (y * 12) + 3 + 12, \ + color, \ + 1, \ + C_BLACK \ + ) +#define _lrectTextXY(x, y, hex) \ + dprint_opt( \ + (x * 48) + 3 + 85 + 24, \ + (y * 12) + 3 + 6, \ + C_BLACK, \ + C_NONE, \ + DTEXT_CENTER, \ + DTEXT_MIDDLE, \ + "%04X", \ + hex \ +) + +#endif /* FUGUE_MENU_ROM_H */ diff --git a/include/fsctl/utils/fs_table.h b/include/fsctl/utils/fs_table.h new file mode 100644 index 0000000..614980d --- /dev/null +++ b/include/fsctl/utils/fs_table.h @@ -0,0 +1,47 @@ +#ifndef FSCTL_UTILS_FS_TABLE_H +#define FSCTL_UTILS_FS_TABLE_H 1 + +#include +#include + +#include "fsctl/fugue/bits/fs.h" + +//--- +// Types +//--- + +/* struct fs_table : FS table entry information */ +struct fs_table +{ + bool is_valid; + uintptr_t vbr; + fugue_fs_t fs; +}; +typedef struct fs_table fs_table_t; + +//--- +// API +//--- + +/* fs_table_init() : initialize FS table */ +extern void fs_table_init(void); + +/* fs_table_update() : try to update internal fs table */ +extern int fs_table_update(fugue_fs_t *fs); + +/* fs_table_info() : get fs table information */ +extern int fs_table_info(fugue_fs_t *fs, int *fs_idx, int *nb_fs); + +/* fs_table_dtitle() : display FS table title menu */ +extern void fs_table_dtitle(void); + +/* fs_table_select() : select a FS if available */ +extern int fs_table_select(int idx); + +/* fs_table_select_left() : try to change to the idx - 1 */ +extern int fs_table_select_left(void); + +/* fs_table_select_right() : try to change to the idx + 1 */ +extern int fs_table_select_right(void); + +#endif /* FSCTL_UTILS_FS_TABLE_H */ diff --git a/src/fugue/core/cluster.c b/src/fugue/core/cluster.c new file mode 100644 index 0000000..0509466 --- /dev/null +++ b/src/fugue/core/cluster.c @@ -0,0 +1,43 @@ +#include "fsctl/fugue/cluster.h" +#include "fsctl/fugue/sector.h" +#include "fsctl/fugue/utils.h" + +//--- +// Public +//--- + +/* fugue_cluster_is_valid() : check cluster validity */ +//TODO : support FAT12 / FAT32 +int fugue_cluster_is_valid(fugue_fs_t *fs, int cluster_idx) +{ + void *sector; + uint16_t id; + + id = FAT_WORD(((uint16_t *)fs->_private.fat0)[cluster_idx]); + if (id == 0x0000) + return 0; + if (cluster_idx == 0) + return 0; + + /* special check for the root fake cluster */ + if (cluster_idx == 1) + { + if (id != 0xffff) + return -1; + return 0; + } + + cluster_idx -= 2; + sector = (void*)((uintptr_t)(fs->props.cluster_nb_sector * cluster_idx)); + sector = (void*)((uintptr_t)sector + fs->props.sector_root_nb); + sector = (void*)((uintptr_t)sector * 512); + sector = (void*)((uintptr_t)sector + (uintptr_t)fs->_private.root); + + for (int i = 0 ; i < fs->props.cluster_nb_sector ; i++) + { + if (fugue_sector_is_invalid(sector)) + return -2; + sector = (void *)((uintptr_t)sector + 512); + } + return 0; +} diff --git a/src/fugue/core/dirent.c b/src/fugue/core/dirent.c new file mode 100644 index 0000000..f368b5b --- /dev/null +++ b/src/fugue/core/dirent.c @@ -0,0 +1,85 @@ +#include "fsctl/fugue/dirent.h" +#include "fsctl/fugue/cluster.h" +#include "fsctl/fugue/bits/fat.h" + +//--- +// Internals +//--- + +/* _fugue_dirent_checksum() : Fugue checksum handling */ +static uint8_t _fugue_dirent_checksum(uintptr_t directory) +{ + uint8_t *block; + uint8_t checksum; + int a; + int b; + + checksum = 0; + block = (void *)directory; + for (int i = 0 ; i < 11 ; ++i) + { + checksum = checksum & 0xff; + a = checksum / 2; + b = checksum * 128; + checksum = a | b; + checksum = checksum + block[i]; + } + checksum = checksum & 0xff; + return checksum; +} + +//--- +// Public +//--- + +/* fugue_dirent_dir_fetch() : fetch the current dir blob and walk to next */ +void *fugue_dirent_dir_fetch(fugue_dir_t *dirent) +{ + void *dir; + + dir = (void*)dirent->current_dir_addr; + if (dir == NULL) + return NULL; + + dirent->current_dir_addr += 32; + if (dirent->current_dir_addr < dirent->cluster_addr_end) + return dir; + + dirent->cluster_addr_start = fugue_cluster_find_next( + &dirent->_private.fs, + dirent->cluster_idx + ); + dirent->cluster_addr_end = dirent->cluster_addr_start; + if (dirent->cluster_addr_start != 0x00000000) + dirent->cluster_addr_end += dirent->_private.fs.props.cluster_size; + return dir; +} + +/* fugue_dirent_name_fetch() : fetch fragment */ +int fugue_dirent_name_fetch(fugue_dir_t *dirent, fugue_file_t *file, void *dir) +{ + struct fugue_fat_dir_name *lfn; + + lfn = (void *)dir; + + //--- + // check directory block validity + //--- + + if (lfn->DIR_Attr != FUGUE_DIR_ATTR_LFN) + return -1; + if (lfn->DIR_Type != 0x00) + return -2; + if (lfn->DIR_FstClus != 0x0000) + return -3; + //TODO : check Secquence validity + if (lfn->checksum != _fugue_dirent_checksum(dirent->current_dir_addr)) + return -5; + + //--- + // Dump name fragment + //--- + + //TODO: dump + return -1; +} diff --git a/src/fugue/core/fat.c b/src/fugue/core/fat.c new file mode 100644 index 0000000..dfe3f55 --- /dev/null +++ b/src/fugue/core/fat.c @@ -0,0 +1,74 @@ +#include "fsctl/fugue/fat.h" +#include "fsctl/fugue/sector.h" +#include "fsctl/fugue/utils.h" + +//--- +// Public +//--- + +/* fugue_fat_is_vaild() : Check the complet FATs validity */ +int fugue_fat_is_vaild(fugue_fs_t *fs) +{ + uint16_t *cluster_map; + uint32_t *sector; + uint16_t cluster; + + /* check FATID and root value */ + sector = (void *)fs->_private.fat0; + if (((uint8_t*)sector)[0] != 0xf8 || ((uint8_t*)sector)[1] != 0xff) + return -1; + if (((uint8_t*)sector)[2] != 0xff || ((uint8_t*)sector)[3] != 0xff) + return -1; + sector = (void *)fs->_private.fat1; + if (((uint8_t*)sector)[0] != 0xf8 || ((uint8_t*)sector)[1] != 0xff) + return -1; + if (((uint8_t*)sector)[2] != 0xff || ((uint8_t*)sector)[3] != 0xff) + return -1; + + /* check complet valid FAT + * @note + * - full Fugue FAT area take 5120 bytes -> 10x512 -> 10 sectors + * - also check the root reserved sectors */ + sector = (void*)fs->_private.fat0; + for (int i = 0 ; i < 10 + fs->props.sector_root_nb ; i++) + { + if (fugue_sector_is_invalid(sector)) + return -1; + sector = (void *)((uintptr_t)sector + 512); + } + + /* follows each cluster and check that all sector are used */ + cluster_map = (void *)fs->_private.fat1; + fs->props.cluster_resv = 0; + fs->props.cluster_free = 0; + fs->props.cluster_used = 0; + fs->props.cluster_dead = 0; + fs->props.cluster_error = 0; + for (int i = 1 ; i < 256 ; i++) + { + cluster = FAT_WORD(cluster_map[i]); + if (cluster == 0x0000) { + fs->props.cluster_free += 1; + continue; + } + if (cluster == 0x0001) { + fs->props.cluster_resv += 1; + continue; + } + if (cluster == 0xfff7) { + fs->props.cluster_dead += 1; + continue; + } + if (cluster >= 0xfff8) { + fs->props.cluster_used += 1; + continue; + } + if (cluster < (fs->props.cluster_nb + 1)) { + fs->props.cluster_used += 1; + continue; + } + fs->props.cluster_error += 1; + fs->props.test = cluster; + } + return 0; +} diff --git a/src/fugue/core/sector.c b/src/fugue/core/sector.c new file mode 100644 index 0000000..bbecca1 --- /dev/null +++ b/src/fugue/core/sector.c @@ -0,0 +1,89 @@ +#include + +#include "fsctl/fugue/sector.h" +#include "fsctl/fugue/utils.h" + +//--- +// Public +//--- + +/* fugue_sector_is_vbr() : check if the given address is a potential VBR */ +int fugue_sector_is_vbr(struct fugue_fat_vbr *vbr) +{ + static const struct fugue_fat_vbr fugue_fat_vbr = { + /* common boot information */ + .BS_jmpBoot = { 0xeb, 0x3c, 0x90 }, + .BS_OEMName = "MSDOS5.0", + + /* BIOS Parameter Block */ + .BPB_BytsPerSec = 512, + .BPB_SecPerClus = 8, // <--- not hardcoded by Casio + .BPB_RsvdSecCnt = 0, // <--- not hardcoded by Casio + .BPB_NumFATs = 2, + .BPB_RootEntCnt = 0, // <--- not hardcoded by Casio + .BPB_TotSec16 = 0, // <--- not hardcoded + .BPB_Media = 0xf8, + .BPB_FATSz16 = 0, // <--- not hardcoded + .BPB_SecPerTrk = 0, // <--- not hardcoded + .BPB_HiddSec = 0, // <--- not hardcoded + .BPB_TotSec32 = 0, // <--- not hardcoded + + /* Extended BIOS Parameter Block */ + .BS_DrvNum = 0x80, + .BS_Reserved1 = 0, + .BS_BootSig = 0x29, + .BS_VolID = {0x00, 0x00, 0x00, 0x00}, + .BS_VolLab = "CASIO ", + .BS_FilSysType = "FAT16 ", + + /* signature */ + .Signature_word = {0x55, 0xaa} + }; + + //--- + // VBR global hardcoded value check + //--- + + /* check common boot information */ + if (memcmp(vbr, &fugue_fat_vbr, 11) != 0) + return -1; + + /* check BIOS Parameter Block */ + if (FAT_WORD(vbr->BPB_BytsPerSec) != fugue_fat_vbr.BPB_BytsPerSec) + return -1; + if (vbr->BPB_NumFATs != fugue_fat_vbr.BPB_NumFATs) + return -1; + if (vbr->BPB_Media != fugue_fat_vbr.BPB_Media) + return -1; + + /* check Extended BIOS Parameter Block */ + if (memcmp(&(vbr->BS_DrvNum), &(fugue_fat_vbr.BS_DrvNum), 474) != 0) + return -1; + + /* check signature */ + if (vbr->Signature_word[0] != fugue_fat_vbr.Signature_word[0]) + return -1; + if (vbr->Signature_word[1] != fugue_fat_vbr.Signature_word[1]) + return -1; + + //--- + // FAT validity check + //--- + + return 0; +} + +/* fugue_sector_is_invalid() : check if the sector is invalide */ +int fugue_sector_is_invalid(void *sector) +{ + int x; + + for (x = 0 ; x < 512 / 2 ; x++) + { + if (((uint32_t *)sector)[x] != 0xffffffff) + break; + } + if (x >= (512 / 4)) + return -1; + return 0; +} diff --git a/src/fugue/dir.c b/src/fugue/dir.c new file mode 100644 index 0000000..644a993 --- /dev/null +++ b/src/fugue/dir.c @@ -0,0 +1,144 @@ +#include + +#include "fsctl/fugue.h" +#include "fsctl/fugue/bits/fat.h" +#include "fsctl/fugue/dirent.h" +#include "fsctl/fugue/utils.h" +#include "fsctl/utils/fs_table.h" + +//--- +// Internals +//--- + +//--- +// Public +//--- + +/* fugue_fs_opendir() : opendir-like function */ +int fugue_fs_opendir(fugue_dir_t *dir) +{ + fugue_fs_t fs; + + if (dir == NULL) + return -1; + if (fs_table_info(&fs, NULL, NULL) != 0) + return -2; + memset(dir, 0x00, sizeof(fugue_dir_t)); + memcpy(&dir->_private.fs, &fs, sizeof(fugue_fs_t)); + dir->current_dir_addr = (uintptr_t)fs._private.root; + dir->cluster_addr = (uintptr_t)fs._private.root; + dir->cluster_size = fs.props.sector_root_nb * 512; + return 0; +} + +/* fugue_fs_readdir() : readdir-like function */ +int fugue_fs_readdir(fugue_dir_t *dirent, fugue_file_t *file) +{ + struct fugue_fat_dir *dir; + fugue_dir_t dirent_backup; + bool error; + bool vfat; + + if (dirent == NULL) + return -1; + if (file == NULL) + return -1; + if (dirent->current_dir_addr == 0x00000000) + return -2; + + memset(file, 0x00, sizeof(fugue_file_t)); + memcpy(&dirent_backup, dirent, sizeof(fugue_dir_t)); + + vfat = false; + error = false; + while (error == false) + { + /* fetch the current FAT directory and walk */ + dir = fugue_dirent_dir_fetch(dirent); + if (dir == NULL) { + error = true; + continue; + } + + //--- + // handle special name behaviour + //--- + + switch(dir->DIR_Name[0]) + { + /* handle free directory */ + case 0x00: + //fugue_logger_warn("opendir: wierd empty directory block ") + error = true; + continue; + + /* dot and dotdot special file */ + case '.': + if (memcmp(dir->DIR_Name, ". ", 2) == 0) + memcpy(file->name, ".", 2); + if (memcmp(dir->DIR_Name, ".. ", 3) == 0) + memcpy(file->name, "..", 3); + if (vfat == true) + //fugue_logger_warn("opendir: wierd directory block ") + file->type = FUGUE_FILE_TYPE_DIR; + file->size = FAT_LONG(dir->DIR_FileSize); + return 0; + + /* removed entry */ + case 0x05: + case 0xe5: + //fugue_logger_notice("opendir : removed entry"); + memset(file, 0x00, sizeof(fugue_file_t)); + vfat = false; + continue; + } + + //--- + // handle directory attribute + //--- + + switch(dir->DIR_Attr) + { + /* handle file name fragment */ + case FUGUE_DIR_ATTR_VNAME: + fugue_dirent_name_fetch(dirent, file); + vfat = true; + break; + + /* file handling */ + case FUGUE_DIR_ATTR_RDONLY: + case FUGUE_DIR_ATTR_HIDDEN: + case FUGUE_DIR_ATTR_SYSTEM: + case FUGUE_DIR_ATTR_DIR: + case FUGUE_DIR_ATTR_ARCHIVE: + case FUGUE_DIR_ATTR_DEVICE: + //TODO : file type + file->type = FUGUE_FILE_TYPE_FILE; + file->size = FAT_LONG(dir->DIR_FileSize); + return 0; + + /* other attribute not handled */ + default: + //fugue_logger_warn("opendir : unsupported attribute ") + error = true; + break; + } + } + + /* error handling */ + memcpy(dirent, &dirent_backup, sizeof(fugue_dir_t)); + memset(file, 0x00, sizeof(fugue_file_t)); + return -1; +} + +/* fugue_fs_closedir() : closedir-like function */ +int fugue_fs_closedir(fugue_dir_t *dir) +{ + if (dir == NULL) + return -1; + memset(dir, 0x00, sizeof(fugue_dir_t)); + dir->current_dir_addr = 0x00000000; + dir->cluster_addr = 0x00000000; + dir->cluster_size = 0; + return 0; +} diff --git a/src/fugue/mount.c b/src/fugue/mount.c new file mode 100644 index 0000000..240fb75 --- /dev/null +++ b/src/fugue/mount.c @@ -0,0 +1,103 @@ +#include + +#include "fsctl/fugue.h" +#include "fsctl/fugue/sector.h" +#include "fsctl/fugue/utils.h" +#include "fsctl/fugue/fat.h" + +//--- +// Public +//--- + +/* fugue_fs_mount() : try to initialize the FS */ +int fugue_fs_mount(fugue_fs_t *fsinfo, void *addr) +{ + fugue_fs_t fs; + struct fugue_fat_vbr *vbr; + uintptr_t FAT0_addr; + uintptr_t FAT1_addr; + int CountofClusters; + int RootDirSectors; + int TotCapacity; + int DataSec; + void *type; + int FATz; + + if (fugue_sector_is_vbr(addr) != 0) + return -1; + vbr = addr; + + //--- + // determine the number of cluster + // @note + // - hardcoded for FAT12 and FAT16 + //--- + + RootDirSectors = FAT_WORD(vbr->BPB_RootEntCnt) * 32; + RootDirSectors += FAT_WORD(vbr->BPB_BytsPerSec) - 1; + RootDirSectors /= FAT_WORD(vbr->BPB_BytsPerSec); + + DataSec = FAT_WORD(vbr->BPB_RsvdSecCnt); + DataSec += FAT_WORD(vbr->BPB_FATSz16) * vbr->BPB_NumFATs; + DataSec += RootDirSectors; + DataSec = FAT_WORD(vbr->BPB_TotSec16) - DataSec; + + CountofClusters = DataSec; + CountofClusters /= vbr->BPB_SecPerClus; + + TotCapacity = DataSec; + TotCapacity *= FAT_WORD(vbr->BPB_BytsPerSec); + + if (CountofClusters < 4085) { + type = "FAT12"; + } else if (CountofClusters < 65525) { + type = "FAT16"; + } else { + type = "FAT32"; + } + + //--- + // Analysing FAT intergrity + // @note + // - hardcoded for two Fugue + // - Fugue seems use a static offset of its FAT : 5120 (10 sectors) + // - Fugue doesn't have same sized FAT (FAT0=4608 && FAT1=512) + //--- + + //FATz = FAT_WORD(vbr->BPB_FATSz16); + //FATz *= FAT_WORD(vbr->BPB_BytsPerSec); + //FATz *= vbr->BPB_NumFATs; + FATz = 5120; + + FAT0_addr = FAT_WORD(vbr->BPB_RsvdSecCnt); + FAT0_addr *= FAT_WORD(vbr->BPB_BytsPerSec); + FAT0_addr += (uintptr_t)vbr; + + FAT1_addr = 4608; + FAT1_addr += FAT0_addr; + + //--- + // Save calculated information + //--- + + memset(&fs, 0x00, sizeof(fugue_fs_t)); + fs._private.vbr = addr; + fs.props.type = type; + fs.props.sector_data_nb = DataSec; + fs.props.sector_root_nb = RootDirSectors; + fs.props.cluster_nb = CountofClusters; + fs.props.cluster_size = vbr->BPB_SecPerClus * 512; + fs.props.cluster_nb_sector = vbr->BPB_SecPerClus; + fs.props.capacity = TotCapacity; + fs.props.fats_size = FATz; + fs.props.fat0_size = 4608; + fs.props.fat1_size = 512; + fs._private.fat0 = (void*)FAT0_addr; + fs._private.fat1 = (void*)FAT1_addr; + fs._private.root = (void*)(FAT0_addr + FATz); + + if (fugue_fat_is_vaild(&fs) != 0) + return -1; + memcpy(fsinfo, &fs, sizeof(fugue_fs_t)); + return 0; +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..4a04643 --- /dev/null +++ b/src/main.c @@ -0,0 +1,54 @@ +#include +#include +#include + +#include "fsctl/menu.h" + +//--- +// Public +//--- + +int main(void) +{ + int key; + int tab; + + rom_menu_init(); + info_menu_init(); + fat_menu_init(); + list_menu_init(); + + tab = 0; + while (1) + { + dclear(C_WHITE); + if (tab == 0) { rom_menu_display(); } + if (tab == 1) { info_menu_display(); } + if (tab == 2) { fat_menu_display(); } + if (tab == 3) { list_menu_display(); } + dupdate(); + + switch (key = getkey().key) + { + case KEY_F1: + tab = 0; + break; + case KEY_F2: + tab = 1; + break; + case KEY_F3: + tab = 2; + break; + case KEY_F4: + tab = 3; + break; + default: + if (tab == 0) { rom_menu_keyboard(key); } + if (tab == 1) { info_menu_keyboard(key); } + if (tab == 2) { fat_menu_keyboard(key); } + if (tab == 3) { list_menu_keyboard(key); } + } + } + + return 1; +} diff --git a/src/menu/fat.c b/src/menu/fat.c new file mode 100644 index 0000000..af9c147 --- /dev/null +++ b/src/menu/fat.c @@ -0,0 +1,96 @@ +#include + +#include +#include + +#include "fsctl/menu.h" +#include "fsctl/fugue.h" +#include "fsctl/fugue/cluster.h" +#include "fsctl/fugue/utils.h" +#include "fsctl/utils/fs_table.h" +#include "fsctl/utils/display.h" + +//--- +// internals +//--- + +/* internal information */ +static int clus_idx = 0; + +/* fat_cluster_is_valid() : check cluster information */ +static int fat_cluster_is_valid(fugue_fs_t *fs, int idx) +{ + switch (fugue_cluster_is_valid(fs, idx)) + { + case 0: + return C_WHITE; + default: + return C_RED; + } +} + +//--- +// Public +//--- + +/* fat_menu_init() : init menu */ +void fat_menu_init(void) +{ + clus_idx = 0; +} + +/* fat1_menu_display() : display menu */ +void fat_menu_display(void) +{ + fugue_fs_t fs; + uint16_t *table; + int idx; + + fs_table_dtitle(); + if (fs_table_info(&fs, NULL, NULL) != 0) + return; + + idx = clus_idx; + table = fs._private.fat1; + for (int y = 1 ; y < 18 ; y++) + { + _printXY(0, y, "%p", &table[idx]); + for (int x = 0 ; x < 6 ; x++) + { + _lrectXY(x, y, fat_cluster_is_valid(&fs, idx)); + _lrectTextXY(x, y, FAT_WORD(table[idx])); + idx += 1; + } + } +} + +/* fat_menu_keyboard() : handle keyboard */ +void fat_menu_keyboard(int key) +{ + switch (key) + { + case KEY_SHIFT: + clus_idx += 6; + break; + case KEY_ALPHA: + clus_idx -= 6; + break; + case KEY_EXIT: + clus_idx = 0; + break; + case KEY_DOWN: + clus_idx += 6 * 17; + break; + case KEY_UP: + clus_idx -= 6 * 17; + break; + case KEY_LEFT: + fs_table_select_left(); + break; + case KEY_RIGHT: + fs_table_select_right(); + break; + } + if (clus_idx < 0) + clus_idx = 0; +} diff --git a/src/menu/info.c b/src/menu/info.c new file mode 100644 index 0000000..3f22432 --- /dev/null +++ b/src/menu/info.c @@ -0,0 +1,59 @@ +#include + +#include "fsctl/menu/info.h" +#include "fsctl/fugue.h" +#include "fsctl/utils/display.h" +#include "fsctl/utils/fs_table.h" + +//--- +// Public +//--- + +/* info_menu_init() : init menu */ +void info_menu_init(void) +{ + ; +} + +/* info_menu_display() : display menu */ +//TODO : logger display +void info_menu_display(void) +{ + fugue_fs_t fs; + int y; + + fs_table_dtitle(); + if (fs_table_info(&fs, NULL, NULL) != 0) + return; + + y = 0; + _printXY(0, ++y, "FS type = %s", fs.props.type); + _printXY(0, ++y, "capacity = %d", fs.props.capacity); + _printXY(0, ++y, "cluster free = %d", fs.props.cluster_free); + _printXY(0, ++y, "cluster used = %d", fs.props.cluster_used); + _printXY(0, ++y, "cluster dead = %d", fs.props.cluster_dead); + _printXY(0, ++y, "cluster errs = %d", fs.props.cluster_error); + _printXY(0, ++y, "cluster resv = %d", fs.props.cluster_resv); + _printXY(0, ++y, "cluster number = %d", fs.props.cluster_nb); + _printXY(0, ++y, "cluster number = %x", fs.props.cluster_nb); + _printXY(0, ++y, "FAT0 = %p", fs._private.fat0); + _printXY(0, ++y, "FAT1 = %p", fs._private.fat1); + _printXY(0, ++y, "FATs size = %d", fs.props.fats_size); + _printXY(0, ++y, "FAT0 size = %d", fs.props.fat0_size); + _printXY(0, ++y, "FAT1 size = %d", fs.props.fat1_size); + _printXY(0, ++y, "Root addr = %p", fs._private.root); +} + +/* info_menu_keyboard() : handle keyboard */ +void info_menu_keyboard(int key) +{ + switch(key) + { + case KEY_LEFT: + fs_table_select_left(); + break; + case KEY_RIGHT: + fs_table_select_right(); + break; + } +} diff --git a/src/menu/list.c b/src/menu/list.c new file mode 100644 index 0000000..9ad8b06 --- /dev/null +++ b/src/menu/list.c @@ -0,0 +1,46 @@ +#include "fsctl/menu.h" +#include "fsctl/fugue.h" +#include "fsctl/utils/fs_table.h" +#include "fsctl/utils/display.h" + +//--- +// Public +//--- + +/* list_menu_init() : init menu */ +void list_menu_init(void) +{ + ; +} + +/* fat1_menu_display() : display menu */ +void list_menu_display(void) +{ + fugue_dir_t dir; + fugue_file_t file; + int y; + + fs_table_dtitle(); + + y = 0; + fugue_fs_opendir(&dir); + while (fugue_fs_readdir(&dir, &file) == 0) + { + _printXY(0, ++y, "(%d) %s", file.size, file.name); + } + fugue_fs_closedir(&dir); +} + +/* list_menu_keyboard() : handle keyboard */ +void list_menu_keyboard(int key) +{ + switch(key) + { + case KEY_LEFT: + fs_table_select_left(); + break; + case KEY_RIGHT: + fs_table_select_right(); + break; + } +} diff --git a/src/menu/rom.c b/src/menu/rom.c new file mode 100644 index 0000000..2a5934b --- /dev/null +++ b/src/menu/rom.c @@ -0,0 +1,103 @@ +#include "fsctl/menu.h" +#include "fsctl/fugue.h" +#include "fsctl/utils/fs_table.h" +#include "fsctl/utils/display.h" + +//--- +// internals +//--- + +/* internal information */ +static uintptr_t addr_base; +static uintptr_t addr_test; + +/* sector_is_vbr() : check VBR validity */ +static int sector_is_vbr(int *color, struct fugue_fat_vbr *vbr) +{ + fugue_fs_t fs; + + if (fugue_fs_mount(&fs, vbr) == 0) { + *color = C_GREEN; + fs_table_update(&fs); + return 0; + } + return -1; +} + +/* sector_is_unused() : check if the sector has been erased */ +static int sector_is_unused(int *color, uint32_t *addr) +{ + for (int i = 0 ; i < 512 / 4 ; i++) { + if (addr[i] != 0xffffffff) + return -1; + } + *color = C_RED; + return 0; +} + +/* sector_check() : check various operation on sector */ +static int sector_check(void *addr) +{ + int color; + + if ( + sector_is_unused(&color, addr) != 0 + && sector_is_vbr(&color, addr) != 0 + ) + return C_WHITE; + return color; +} + +//--- +// Public +//--- + +/* rom_menu_init() : init menu */ +void rom_menu_init(void) +{ + /* skip first 16Mo (OS stuff) */ + addr_base = 0xa1000000; + addr_test = 0xa1000000; +} + +/* rom_menu_display() : display menu */ +void rom_menu_display(void) +{ + addr_test = addr_base; + for (int y = 0 ; y < 18 ; y++) + { + _printXY(0, y, "%p", addr_test); + for (int x = 0 ; x < 25 ; x++) + { + _rectXY(x, y, sector_check((void *)addr_test)); + addr_test += 512; + if (addr_test >= 0xa2000000) + return; + } + } +} + +/* rom_menu_keyboard() : handle keyboard */ +void rom_menu_keyboard(int key) +{ + switch (key) + { + case KEY_DOWN: + addr_base += 25 * 512; + break; + case KEY_UP: + addr_base -= 25 * 512; + break; + case KEY_EXIT: + addr_base = 0xa0000000; + break; + case KEY_RIGHT: + addr_base += 25 * 18 * 512; + break; + case KEY_LEFT: + addr_base -= 25 * 18 * 512; + break; + } + if (addr_base < 0xa0000000) + addr_base = 0xa0000000; +} diff --git a/src/utils/fs_table.c b/src/utils/fs_table.c new file mode 100644 index 0000000..c702148 --- /dev/null +++ b/src/utils/fs_table.c @@ -0,0 +1,123 @@ +#include +#include + +#include + +#include "fsctl/utils/fs_table.h" + +//--- +// Internals +//--- + +/* fs_table_list : FS table list */ +static struct { + fs_table_t *table; + int idx; + int slots; +} fs_table; + +/* fs_table_append() : append the new vbr information */ +static int fs_table_append(fugue_fs_t *fs) +{ + fs_table_t *check; + + check = reallocarray( + fs_table.table, + fs_table.slots + 1, + sizeof(fs_table_t) + ); + if (check == NULL) + return -1; + + memcpy(&check[fs_table.slots].fs, fs, sizeof(fugue_fs_t)); + fs_table.table = check; + fs_table.slots = fs_table.slots + 1; + if (fs_table.idx < 0) + fs_table.idx = 0; + return 0; +} + +//--- +// Public +//--- + +/* fs_table_init() : initialize FS table */ +void fs_table_init(void) +{ + fs_table.table = NULL; + fs_table.idx = -1, + fs_table.slots = 0; +} + +/* fs_table_update() : try to update internal fs table */ +int fs_table_update(fugue_fs_t *fs) +{ + for (int i = 0 ; i < fs_table.slots ; i++) + { + if (fs_table.table[i].fs._private.vbr == fs->_private.vbr) + return 0; + } + return fs_table_append(fs); +} + +/* fs_table_info() : get fs table information */ +int fs_table_info(fugue_fs_t *fs, int *fs_idx, int *nb_fs) +{ + if (fs_table.table == NULL) + return -1; + if (fs != NULL) + memcpy(fs, &fs_table.table[fs_table.idx].fs, sizeof(fugue_fs_t)); + if (fs_idx != NULL) + *fs_idx = fs_table.idx; + if (nb_fs != NULL) + *nb_fs = fs_table.slots; + return 0; +} + +/* fs_table_dtitle() : display FS table title menu */ +void fs_table_dtitle(void) +{ + fugue_fs_t *fs; + + if (fs_table.table == NULL) + { + dprint(2, 2, C_BLACK, "No File System found"); + drect(0, 0, DWIDTH, 14, C_INVERT); + return; + } + + fs = &fs_table.table[fs_table.idx].fs; + dprint(2, 2, C_BLACK, "VBR: %p", fs->_private.vbr); + dprint_opt( + DWIDTH, 2, + C_BLACK, C_NONE, + DTEXT_RIGHT, DTEXT_TOP, + "%d/%d", + fs_table.idx + 1, + fs_table.slots + ); + drect(0, 0, DWIDTH, 13, C_INVERT); +} + +/* fs_table_select() : select a FS if available */ +int fs_table_select(int idx) +{ + if (fs_table.table == NULL) + return -1; + if (idx >= fs_table.slots) + return -2; + fs_table.idx = idx; + return 0; +} + +/* fs_table_select_left() : try to change to the idx - 1 */ +int fs_table_select_left(void) +{ + return fs_table_select(fs_table.idx - 1); +} + +/* fs_table_select_right() : try to change to the idx + 1 */ +int fs_table_select_right(void) +{ + return fs_table_select(fs_table.idx + 1); +}