From 95333b656d73e37f82ef538f54a04acd1366e823 Mon Sep 17 00:00:00 2001 From: Yatis Date: Mon, 11 Jan 2021 12:41:31 +0100 Subject: [PATCH] add SMEM primitive (using Casio's BFile* syscall) + add "mnt" and "ls" builtin --- include/fxBoot/builtin.h | 10 +++ include/fxBoot/fs/smemfs.h | 49 ++++++++++++++ src/builtin/ls.c | 55 ++++++++++++++++ src/builtin/mnt.c | 18 ++++++ src/fs/smemfs/mount.c | 127 +++++++++++++++++++++++++++++++++++++ src/fs/smemfs/read.c | 71 +++++++++++++++++++++ src/main.c | 8 ++- 7 files changed, 337 insertions(+), 1 deletion(-) create mode 100644 include/fxBoot/builtin.h create mode 100644 include/fxBoot/fs/smemfs.h create mode 100644 src/builtin/ls.c create mode 100644 src/builtin/mnt.c create mode 100644 src/fs/smemfs/mount.c create mode 100644 src/fs/smemfs/read.c diff --git a/include/fxBoot/builtin.h b/include/fxBoot/builtin.h new file mode 100644 index 0000000..04cb9f9 --- /dev/null +++ b/include/fxBoot/builtin.h @@ -0,0 +1,10 @@ +#ifndef __FXBOOT_BUILTIN_H__ +# define __FXBOOT_BUILTIN_H__ + +#include +#include + +extern int mnt_main(int argc, char **argv); +extern int ls_main(int argc, char **argv); + +#endif /*__FXBOOT_BUILTIN_H__*/ diff --git a/include/fxBoot/fs/smemfs.h b/include/fxBoot/fs/smemfs.h new file mode 100644 index 0000000..49df46b --- /dev/null +++ b/include/fxBoot/fs/smemfs.h @@ -0,0 +1,49 @@ +#ifndef __FS_SMEMFS_H__ +# define __FS_SMEMFS_H__ + +#include +#include +#include + +//---- +// Internal structure used to provide Casio's syscall abstraction +//--- +/* Internal superblock use for the Casio's syscall abstraction */ +struct smemfs_superblock { + struct smemfs_inode *root_inode; + struct smemfs_inode *fake_root_inode; +}; + +/* Internal struct used to store SMEM dump */ +struct smemfs_inode { + /* File name */ + char name[32]; + + /* Internal file's information */ + int type; + size_t fsize; + size_t dsize; + + /* Internal abstraction information */ + struct smemfs_inode *child; + struct smemfs_inode *sibling; + struct smemfs_inode *parent; +}; + +//--- +// Dev symbols +//--- +#define SMEMFS_FAKE_ROOT_INODE ((void*)0xdeadbeef) +extern struct smemfs_superblock smemfs_superblock; + + +//--- +// primitive +//--- +extern struct smemfs_inode *smemfs_mount(void); + +extern ssize_t smemfs_read(struct smemfs_inode *inode, + void *buf, size_t count, off_t pos); + +extern struct smemfs_inode *smemfs_alloc_inode(void); +#endif /*__FS_SMEMFS_H__*/ diff --git a/src/builtin/ls.c b/src/builtin/ls.c new file mode 100644 index 0000000..3369b6d --- /dev/null +++ b/src/builtin/ls.c @@ -0,0 +1,55 @@ +//--- +// builtin:ls - list directory contents +//--- +#include "fxBoot/builtin.h" +#include "fxBoot/terminal.h" +#include "fxBoot/fs/smemfs.h" +#include + +static void smemfs_walk(struct smemfs_inode *inode, int level, uint32_t bitmap) +{ + const char *records; + + if (inode == NULL) + return; + + /* handle indentation */ + for (int i = 0; i < level; ++i) { + records = "\t"; + if ((bitmap & (1 << i)) != 0) + records = "|\t"; + terminal_write(records); + } + + /* handle file name and sibling dependencies */ + records = "|-- %s"; + bitmap |= 1 << level; + if (inode->sibling == NULL) { + records = "`-- %s"; + bitmap &= ~(1 << level); + } + terminal_write(records, inode->name); + + /* handle file type */ + if (inode->type == BFile_Type_Directory) { + terminal_write(":\n"); + smemfs_walk(inode->child, level + 1, bitmap); + smemfs_walk(inode->sibling, level, bitmap); + return; + } + terminal_write("\n"); + smemfs_walk(inode->sibling, level, bitmap); +} + +int ls_main(int argc, char **argv) +{ + (void)argc; + (void)argv; + if (smemfs_superblock.fake_root_inode != SMEMFS_FAKE_ROOT_INODE) { + terminal_write("smemfs not mounted !\n"); + return (84); + } + terminal_write("/\n"); + smemfs_walk(smemfs_superblock.root_inode, 0, 0x00000000); + return (0); +} diff --git a/src/builtin/mnt.c b/src/builtin/mnt.c new file mode 100644 index 0000000..d2f1b38 --- /dev/null +++ b/src/builtin/mnt.c @@ -0,0 +1,18 @@ +//--- +// builtin:mnt - Mount the SMEM file system +//--- +#include "fxBoot/builtin.h" +#include "fxBoot/fs/smemfs.h" +#include "fxBoot/terminal.h" + +int mnt_main(int argc, char **argv) +{ + (void)argc; + (void)argv; + if (smemfs_mount() != NULL) { + terminal_write("smemfs mounted !\n"); + return (0); + } + terminal_write("error when mounted smemfs :(\n"); + return (84); +} diff --git a/src/fs/smemfs/mount.c b/src/fs/smemfs/mount.c new file mode 100644 index 0000000..ca1f7a0 --- /dev/null +++ b/src/fs/smemfs/mount.c @@ -0,0 +1,127 @@ +//--- +// fxBoot:fs:smemfs:mount - Casio SMEM mount primtive +//--- +#include "fxBoot/fs/smemfs.h" +#include "fxBoot/terminal.h" +#include +#include +#include +#include + +/* Define the super block information */ +struct smemfs_superblock smemfs_superblock = { + .root_inode = NULL, + .fake_root_inode = NULL +}; + +/* wide_char_convert(): convert wide character to ASCII format */ +static size_t wide_char_convert(char *pathname, uint16_t *pathname_wc) +{ + size_t i; + + i = -1; + while (pathname_wc[++i] != 0x0000 && pathname_wc[i] != 0xffff) + pathname[i] = pathname_wc[i] & 0x00ff; + pathname[i] = '\0'; + return (i); +} + +/* dump_smem_level(): Dump one level of the SMEM FileSystem */ +static void dump_smem_level(struct smemfs_inode *parent, + struct smemfs_inode **sibling, + uint16_t *path, off_t cursor) +{ + struct BFile_FileInfo file_info; + struct smemfs_inode *inode; + uint16_t buffer[32]; + int handle; + int i; + + /* Generate searching path: + This format is used by the `Bfile_Find*()` syscall */ + if (parent != NULL) { + for (int j = 0; parent->name[j] != '\0'; ++j) + path[cursor++] = (uint16_t)(parent->name[j]); + path[cursor++] = '\\'; + } + path[cursor + 0] = '*'; + path[cursor + 1] = 0x0000; + + /* Find the first file: + The search buffer and the buffer which will content the file name is + the same. But it's not used at the same time so we can use this + tricky way to save some stack space. */ + if (BFile_FindFirst(path, &handle, buffer, &file_info) != 0) + return; + i = 0; + inode = NULL; + do { + /* Try to alloc new inode */ + *sibling = calloc(sizeof(struct smemfs_inode), 1); + if (*sibling == NULL) + break; + + /* Save the first inode (used after for directories checking) */ + if (i == 0) + inode = *sibling; + i = 1; + + /* Convert wide char to ASCII */ + wide_char_convert((*sibling)->name, buffer); + + /* Dump file informations */ + (*sibling)->type = file_info.type; + (*sibling)->fsize = file_info.file_size; + (*sibling)->dsize = file_info.data_size; + + /* Link node and get next sibling */ + (*sibling)->parent = parent; + sibling = &(*sibling)->sibling; + + /* try to find the next file information */ + } while (BFile_FindNext(handle, buffer, &file_info) == 0); + BFile_FindClose(handle); + + /* Now let's check all files to find directories */ + while (inode != NULL) { + if (inode->type == BFile_Type_Directory) + dump_smem_level(inode, &inode->child, path, cursor); + inode = inode->sibling; + } +} + +/* smemfs_mount(): Mount the file system + + We only use internal Casio's syscall, so this dummy primitive can + be ported easly. */ +struct smemfs_inode *smemfs_mount(void) +{ + uint16_t buffer[512]; + void *root_inode; + + /* switch to the Casio's OS */ + gint_switch_to_casio(); + + /* Check useless mount */ + root_inode = smemfs_superblock.root_inode; + if (root_inode == NULL) { + /* Generate fake root inode */ + smemfs_superblock.fake_root_inode = SMEMFS_FAKE_ROOT_INODE; + + /* Dump SMEM files organisation */ + smemfs_superblock.root_inode = NULL; + memcpy(buffer, u"\\\\fls0\\", 14); + dump_smem_level(smemfs_superblock.root_inode, + &smemfs_superblock.root_inode, + buffer, 7); + + /* Get the "fake" root inode */ + root_inode = smemfs_superblock.fake_root_inode; + } + + /* switch to the Gint kernel */ + gint_switch_to_gint(); + + /* Return the sector table to simulate the root inode. */ + return (root_inode); +} diff --git a/src/fs/smemfs/read.c b/src/fs/smemfs/read.c new file mode 100644 index 0000000..b77a0b0 --- /dev/null +++ b/src/fs/smemfs/read.c @@ -0,0 +1,71 @@ +//--- +// fxBoot:fs:smemfs:read - Casio SMEM read primtive +//--- +#include "fxBoot/fs/smemfs.h" +#include +#include +#include + +/* external symbols */ +extern uint32_t (*cpu_setVBR)(uint32_t vbr, void (*conf_intc)(int), int arg); + +/* generate_abolute_path(): Generate abolute path + + This function will generate the absolute path of a file because Casio's open + primitive doesn't handle cannonical path */ +static void generate_absolute_path(uint16_t *pathname, + struct smemfs_inode *inode, int *pos) +{ + /* Check root inode */ + if (inode == NULL) { + memcpy(pathname, u"\\\\fls0", 12); + *pos = 6; + return; + } + + /* Get the parent inode name */ + generate_absolute_path(pathname, inode->parent, pos); + + /* Insert the file name */ + pathname[(*pos)++] = '\\'; + for (int i = 0; inode->name[i] != '\0'; ) { + pathname[*pos] = inode->name[i]; + *pos = *pos + 1; + i = i + 1; + } + pathname[*pos] = '\0'; +} + +/* bfile_abstract(): */ + +/* smemfs_read(): Read primitive */ +ssize_t smemfs_read(struct smemfs_inode *inode, + void *buf, size_t count, off_t pos) +{ + uint16_t pathname[64]; + ssize_t read; + int handle; + + if (inode == NULL) + return (-1); + + /* Generate the absolute pathname with FONTCHARACTER format */ + generate_absolute_path(pathname, inode, &handle); + + /* Switch from gint to the OS after a short wait */ + gint_switch_to_casio(); + + /* Open, read and close the file using Casio's OS syscall */ + read = -1; + handle = BFile_Open(pathname, BFile_ReadOnly); + if (handle >= 0) { + read = BFile_Read(handle, buf, count, pos); + BFile_Close(handle); + } + + /* Then switch back to gint once the OS finishes working */ + gint_switch_to_gint(); + + /* return the number of byte readed */ + return (read); +} diff --git a/src/main.c b/src/main.c index d6df463..eeda9cc 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,6 @@ #include "fxBoot/terminal.h" #include "fxBoot/parser.h" +#include "fxBoot/builtin.h" #include #include #include @@ -9,7 +10,8 @@ struct { const char *name; int (*f)(int argc, char **argv); } cmd_list[] = { - {.name = "ls", NULL}, + {.name = "mnt", &mnt_main}, + {.name = "ls", &ls_main}, {.name = NULL, NULL} }; @@ -45,16 +47,20 @@ int main(void) usrline = "/[%d]>"; } terminal_write(usrline, ret); + ret = 0; if (terminal_read(buff, 128) <= 1) continue; /* parse and try to find the command */ if (parser_strtotab(&argc, &argv, buff) != 0) { terminal_write("error when processing \"%s\"", buff); + ret = 255; + continue; } builtin = check_cmd(argv[0]); if (builtin == NULL) { terminal_write("command \"%s\" not found...\n", argv[0]); + ret = 127; continue; }