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)
This commit is contained in:
Yann MAGNIN 2023-04-20 16:25:05 +02:00
commit b089b00882
35 changed files with 1579 additions and 0 deletions

17
.gitignore vendored Normal file
View File

@ -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

58
.nvimrc Normal file
View File

@ -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\+\%#\@<!$/
autocmd InsertLeave * match ExtraWhitespace /\s\+$/
autocmd BufWinLeave * call clearmatches()
" indicate the compiler to use
let g:ale_asm_gcc_executable = 'sh-elf-vhex-gcc'
let g:ale_c_gcc_executable = 'sh-elf-vhex-gcc'
let g:ale_c_cc_executable = 'sh-elf-vhex-gcc'
let g:ale_cpp_gcc_executable = 'sh-elf-vhex-gcc'
" Find GiteaPC include directory information
let s:_hdrflags = [
\ '-I./include/',
\ '-I'.$HOME.'/.local/share/giteapc/Lephenixnoir/gint/include/',
\ ]
let s:_cflags = [
\ '-DFXCG50',
\ '-std=c11',
\ '-Wall',
\ '-Wextra',
\ ]
let s:_asmflags = [
\ '-DFXCG50',
\ '-x assembler-with-cpp',
\ '-Wall',
\ '-Wextra',
\ '-m4-nofpu',
\ '-mb',
\ '-Wa,--dsp',
\ ]
" convert table into string
let s:_hdrflags = join(s:_hdrflags)
let s:_asmflags = join(s:_asmflags)
let s:_cflags = join(s:_cflags)
" Patch option
" @note
" - we setup cpp because header file is considered ad C++ file
" - we force sh-elf-vhex for assembly file only
let g:ale_asm_gcc_options = s:_asmflags
let g:ale_c_gcc_options = s:_cflags.' '.s:_hdrflags
let g:ale_c_cc_options = s:_cflags.' '.s:_hdrflags
let g:ale_cpp_cc_options = s:_cflags.' '.s:_hdrflags
let g:ale_cpp_gcc_options = s:_cflags.' '.s:_hdrflags
" Enable completion
let g:ale_completion_enabled = 1
" Enable linter when enter is pressed
let g:ale_lint_on_enter = 1
" Force display non-printable chars
set list

41
CMakeLists.txt Normal file
View File

@ -0,0 +1,41 @@
cmake_minimum_required(VERSION 3.15)
project(fsctl)
include(GenerateG3A)
find_package(Gint 2.9 REQUIRED)
set(SOURCES
src/main.c
# fugue
src/fugue/mount.c
src/fugue/dir.c
src/fugue/core/cluster.c
src/fugue/core/sector.c
src/fugue/core/fat.c
# menu
src/menu/rom.c
src/menu/info.c
src/menu/fat.c
src/menu/list.c
#utils
src/utils/fs_table.c
)
add_executable(fsctl ${SOURCES})
target_compile_options(fsctl PRIVATE -Wall -Wextra -Os)
target_link_libraries(fsctl Gint::Gint)
target_include_directories(fsctl PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
message(FATAL_ERROR "not supported device for now")
elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50)
generate_g3a(
TARGET fsctl
OUTPUT "fsctl.g3a"
NAME "fsctl"
ICONS assets-cg/icon-uns.png assets-cg/icon-sel.png
)
endif()

BIN
assets-cg/icon-cg.xcf Normal file

Binary file not shown.

BIN
assets-cg/icon-sel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
assets-cg/icon-uns.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

24
include/fsctl/fugue.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef FSCTL_FUGUE_H
#define FSCTL_FUGUE_H 1
#include "fsctl/fugue/bits/fs.h"
#include "fsctl/fugue/bits/dir.h"
#include "fsctl/fugue/bits/file.h"
//---
// API
//---
/* fugue_fs_mount() : try to initialize the FS */
extern int fugue_fs_mount(fugue_fs_t *fsinfo, void *addr);
/* fugue_fs_opendir() : opendir-like function */
extern int fugue_fs_opendir(fugue_dir_t *dir);
/* fugue_fs_readdir() : readdir-like function */
extern int fugue_fs_readdir(fugue_dir_t *dirent, fugue_file_t *file);
/* fugue_fs_closedir() : closedir-like function */
extern int fugue_fs_closedir(fugue_dir_t *dir);
#endif /* FSCTL_FUGUE_H */

View File

@ -0,0 +1,26 @@
#ifndef FSCTL_FUGUE_BITS_DIR_H
#define FSCTL_FUGUE_BITS_DIR_H 1
#include <stdint.h>
#include <string.h>
#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 */

View File

@ -0,0 +1,94 @@
#ifndef FSCTL_FUGUE_BITS_FAT_H
#define FSCTL_FUGUE_BITS_FAT_H 1
#include <stdint.h>
#include <stddef.h>
/* 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 */

View File

@ -0,0 +1,20 @@
#ifndef FSCTL_FUGUE_BITS_FILE_H
#define FSCTL_FUGUE_BITS_FILE_H 1
#include <stdint.h>
#include <stddef.h>
/* 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 */

View File

@ -0,0 +1,48 @@
#ifndef FSCTL_FUGUE_BITS_FS_H
#define FSCTL_FUGUE_BITS_FS_H 1
#include <stdint.h>
#include <stddef.h>
/* 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 */

View File

@ -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 */

View File

@ -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 */

13
include/fsctl/fugue/fat.h Normal file
View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

4
include/fsctl/menu.h Normal file
View File

@ -0,0 +1,4 @@
#include "fsctl/menu/fat.h"
#include "fsctl/menu/rom.h"
#include "fsctl/menu/info.h"
#include "fsctl/menu/list.h"

13
include/fsctl/menu/fat.h Normal file
View File

@ -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 */

13
include/fsctl/menu/info.h Normal file
View File

@ -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 */

13
include/fsctl/menu/list.h Normal file
View File

@ -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 */

13
include/fsctl/menu/rom.h Normal file
View File

@ -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 */

View File

@ -0,0 +1,47 @@
#ifndef FSCTL_MENU_UTILS_H
#define FSCTL_MENU_UTILS_H 1
#include <gint/display.h>
#include <gint/keyboard.h>
//---
// 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 */

View File

@ -0,0 +1,47 @@
#ifndef FSCTL_UTILS_FS_TABLE_H
#define FSCTL_UTILS_FS_TABLE_H 1
#include <stdbool.h>
#include <stdint.h>
#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 */

43
src/fugue/core/cluster.c Normal file
View File

@ -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;
}

85
src/fugue/core/dirent.c Normal file
View File

@ -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;
}

74
src/fugue/core/fat.c Normal file
View File

@ -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;
}

89
src/fugue/core/sector.c Normal file
View File

@ -0,0 +1,89 @@
#include <string.h>
#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;
}

144
src/fugue/dir.c Normal file
View File

@ -0,0 +1,144 @@
#include <string.h>
#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;
}

103
src/fugue/mount.c Normal file
View File

@ -0,0 +1,103 @@
#include <string.h>
#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;
}

54
src/main.c Normal file
View File

@ -0,0 +1,54 @@
#include <gint/display.h>
#include <gint/keyboard.h>
#include <string.h>
#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;
}

96
src/menu/fat.c Normal file
View File

@ -0,0 +1,96 @@
#include <string.h>
#include <gint/display.h>
#include <gint/keyboard.h>
#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;
}

59
src/menu/info.c Normal file
View File

@ -0,0 +1,59 @@
#include <string.h>
#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;
}
}

46
src/menu/list.c Normal file
View File

@ -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;
}
}

103
src/menu/rom.c Normal file
View File

@ -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;
}

123
src/utils/fs_table.c Normal file
View File

@ -0,0 +1,123 @@
#include <stdlib.h>
#include <string.h>
#include <gint/display.h>
#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);
}