vxBoot (0.0.1) - First commit
@add <> terminal device <> builtin - ls (file listing), help (some information message)) <> smemfs - SMEM file system abstraction <> small CLI to interact with the core
This commit is contained in:
commit
7993f4b88f
|
@ -0,0 +1,14 @@
|
|||
# Build files
|
||||
/build-fx
|
||||
/build-cg
|
||||
/*.g1a
|
||||
/*.g3a
|
||||
|
||||
# Python bytecode
|
||||
__pycache__/
|
||||
|
||||
# Common IDE files
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
.vscode
|
||||
commit.txt
|
|
@ -0,0 +1,46 @@
|
|||
cmake_minimum_required(VERSION 3.15)
|
||||
project(vxBoot)
|
||||
|
||||
include(GenerateG1A)
|
||||
include(GenerateG3A)
|
||||
include(Fxconv)
|
||||
find_package(Gint 2.1 REQUIRED)
|
||||
|
||||
set(SOURCES
|
||||
src/main.c
|
||||
src/cli/parser.c
|
||||
src/fs/smemfs/mount.c
|
||||
src/fs/smemfs/pread.c
|
||||
src/terminal/close.c
|
||||
src/terminal/open.c
|
||||
src/terminal/read.c
|
||||
src/terminal/util.c
|
||||
src/terminal/write.c
|
||||
src/builtin/ls.c
|
||||
src/builtin/help.c
|
||||
)
|
||||
# Shared assets, fx-9860G-only assets and fx-CG-50-only assets
|
||||
set(ASSETS
|
||||
# ...
|
||||
)
|
||||
set(ASSETS_fx
|
||||
# ...
|
||||
)
|
||||
set(ASSETS_cg
|
||||
# ...
|
||||
)
|
||||
|
||||
fxconv_declare_assets(${ASSETS} ${ASSETS_fx} ${ASSETS_cg} WITH_METADATA)
|
||||
|
||||
add_executable(vxBoot ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}})
|
||||
target_compile_options(vxBoot PRIVATE -Wall -Wextra -Os)
|
||||
target_include_directories(vxBoot PRIVATE include/)
|
||||
target_link_libraries(vxBoot Gint::Gint)
|
||||
|
||||
if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
|
||||
generate_g1a(TARGET vxBoot OUTPUT "vxBoot.g1a"
|
||||
NAME "vxBoot" ICON assets-fx/icon.png)
|
||||
elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50)
|
||||
generate_g3a(TARGET vxBoot OUTPUT "vxBoot.g3a"
|
||||
NAME "vxBoot" ICONS assets-cg/icon-uns.png assets-cg/icon-sel.png)
|
||||
endif()
|
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 7.3 KiB |
|
@ -0,0 +1,11 @@
|
|||
#ifndef __VXBOOT_BUILTIN_H__
|
||||
# define __VXBOOT_BUILTIN_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern int ls_main(int argc, char **argv);
|
||||
extern int os_main(int argc, char **argv);
|
||||
extern int help_main(int argc, char **argv);
|
||||
|
||||
#endif /*__VXBOOT_BUILTIN_H__*/
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef __VXBOOT_PARSER_H__
|
||||
# define __VXBOOT_PARSER_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern int cli_parser_strtotab(int *argc, char ***argv, char const *str);
|
||||
extern void cli_parser_strtotab_quit(int *argc, char ***argv);
|
||||
|
||||
#endif /*__VXBOOT_PARSER_H__*/
|
|
@ -0,0 +1,52 @@
|
|||
#ifndef __VXBOOT_FS_SMEMFS_H__
|
||||
# define __VXBOOT_FS_SMEMFS_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
//----
|
||||
// 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;
|
||||
|
||||
|
||||
//---
|
||||
// Primitives
|
||||
//---
|
||||
extern struct smemfs_inode *smemfs_mount(void);
|
||||
|
||||
extern ssize_t smemfs_pread(struct smemfs_inode *inode,
|
||||
void *buf, size_t count, off_t pos);
|
||||
|
||||
extern struct smemfs_inode *smemfs_alloc_inode(void);
|
||||
|
||||
#endif /*__VXBOOT_FS_SMEMFS_H__*/
|
|
@ -0,0 +1,79 @@
|
|||
#ifndef __VXBOOT_TERMINAL_H__
|
||||
# define __VXBOOT_TERMINAL_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
/* internal terminal hardcoded information */
|
||||
#define TERM_PRIVATE_WATERMARK (0xdeadbeef)
|
||||
#define TERM_RDBUFFER_NBLINE (32)
|
||||
|
||||
/* hardcoded font size (TODO: dynamic !) */
|
||||
#ifdef FXCG50
|
||||
#define FWIDTH 8
|
||||
#define FHEIGHT 9
|
||||
#endif
|
||||
#ifdef FX9860G
|
||||
#define FWIDTH 5
|
||||
#define FHEIGHT 7
|
||||
#endif
|
||||
|
||||
/* define terminal structure */
|
||||
struct terminal {
|
||||
/* windows information */
|
||||
struct {
|
||||
unsigned short ws_col;
|
||||
unsigned short ws_row;
|
||||
unsigned short ws_xpixel;
|
||||
unsigned short ws_ypixel;
|
||||
unsigned short ft_xpixel;
|
||||
unsigned short ft_ypixel;
|
||||
} winsize;
|
||||
|
||||
/* cursor information */
|
||||
struct {
|
||||
unsigned short x;
|
||||
unsigned short y;
|
||||
} cursor;
|
||||
|
||||
/* buffer information */
|
||||
struct {
|
||||
uint8_t *data;
|
||||
off_t cursor;
|
||||
size_t size;
|
||||
} buffer;
|
||||
|
||||
/* private information */
|
||||
struct {
|
||||
struct {
|
||||
int id;
|
||||
} timer;
|
||||
uint32_t watermark;
|
||||
struct {
|
||||
int fg;
|
||||
int bg;
|
||||
} color;
|
||||
} private;
|
||||
};
|
||||
|
||||
/* define the terminal */
|
||||
extern struct terminal terminal;
|
||||
|
||||
//---
|
||||
// User interface
|
||||
//---
|
||||
extern int terminal_open(void);
|
||||
extern int terminal_write(const char *format, ...);
|
||||
extern int terminal_read(void *buffer, size_t nb);
|
||||
extern int terminal_close(void);
|
||||
|
||||
//---
|
||||
// Internal interface
|
||||
//---
|
||||
extern void terminal_clear(void);
|
||||
extern int terminal_cursor_handler(void);
|
||||
extern void terminal_buffer_display(void);
|
||||
extern void terminal_buffer_insert(char *buffer, size_t nb);
|
||||
|
||||
#endif /*__FXBOOT_TERMINAL_H__*/
|
|
@ -0,0 +1,21 @@
|
|||
#include "vxBoot/builtin.h"
|
||||
#include "vxBoot/terminal.h"
|
||||
|
||||
int help_main(int argc, char **argv)
|
||||
{
|
||||
//TODO : use arguments ?
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
terminal_write(
|
||||
"VxBoot was created by Yatis for the sole purpose of being able to load Vhex -"
|
||||
" an experimental operating system touching many sensitive things on the "
|
||||
"machine.\n"
|
||||
"\n"
|
||||
"The available commands are:\n"
|
||||
" help - display this help message\n"
|
||||
" ls - list files in storage memory\n"
|
||||
" os - allows you to interact with the bootstraper\n"
|
||||
);
|
||||
return (0);
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
#include "vxBoot/builtin.h"
|
||||
#include "vxBoot/terminal.h"
|
||||
#include "vxBoot/fs/smemfs.h"
|
||||
|
||||
#include <gint/bfile.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* ls_help() : Display the hep message */
|
||||
static void ls_help(void)
|
||||
{
|
||||
terminal_write(
|
||||
"NAME\n"
|
||||
" ls - list directory contents\n"
|
||||
"\n"
|
||||
"SYNOPSIS\n"
|
||||
" ls [-h|--help]\n"
|
||||
"\n"
|
||||
"DESCRIPTION\n"
|
||||
" List file information about FILEs (from the root directory only). The"
|
||||
" display is inspired from the utilitary `tree` in UNIX environment.\n"
|
||||
"\n"
|
||||
" -h,--help\n"
|
||||
" Display this help message\n"
|
||||
);
|
||||
}
|
||||
|
||||
/* inode_walk() : walk onto the filesystem and display files */
|
||||
static void inode_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 = "|-- (%x) %s";
|
||||
bitmap |= 1 << level;
|
||||
if (inode->sibling == NULL) {
|
||||
records = "`-- (%x) %s";
|
||||
bitmap &= ~(1 << level);
|
||||
}
|
||||
terminal_write(records, inode->type, inode->name);
|
||||
|
||||
/* handle file type */
|
||||
if (inode->type == BFile_Type_Directory) {
|
||||
terminal_write(":\n");
|
||||
inode_walk(inode->child, level + 1, bitmap);
|
||||
inode_walk(inode->sibling, level, bitmap);
|
||||
return;
|
||||
}
|
||||
terminal_write("\n");
|
||||
inode_walk(inode->sibling, level, bitmap);
|
||||
}
|
||||
|
||||
/* ls_main() : entry of the "ls" builtin */
|
||||
int ls_main(int argc, char **argv)
|
||||
{
|
||||
if (smemfs_superblock.fake_root_inode != SMEMFS_FAKE_ROOT_INODE) {
|
||||
terminal_write("smemfs not mounted !\n");
|
||||
return (84);
|
||||
}
|
||||
if (argc > 1 && strcmp(argv[1], "-help") == 0) {
|
||||
ls_help();
|
||||
return (0);
|
||||
}
|
||||
terminal_write("/:\n");
|
||||
inode_walk(smemfs_superblock.root_inode, 0, 0x00000000);
|
||||
return (0);
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
#include "vxBoot/cli.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* define external symbols */
|
||||
extern int cli_parser_strtotab(int *argc, char ***argv, char const *str);
|
||||
extern void cli_parser_strtotab_quit(int *argc, char ***argv);
|
||||
|
||||
/* parser_get_word(): Get the word at the current cursor location. */
|
||||
static int parser_get_word(char ***tab, size_t *tab_pos,
|
||||
char const *str, int *counter)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* skip until separator */
|
||||
i = -1;
|
||||
while (str[++i] != '\0'
|
||||
&& str[i] != '\n'
|
||||
&& str[i] != ' '
|
||||
&& str[i] != '\t');
|
||||
|
||||
/* dump the word of needed */
|
||||
if (*tab != NULL) {
|
||||
(*tab)[*tab_pos] = (char*)calloc(1, i + 1);
|
||||
if ((*tab)[*tab_pos] == NULL)
|
||||
return (-1);
|
||||
memset((*tab)[*tab_pos], 0, i + 1);
|
||||
strncpy((*tab)[(*tab_pos)++], str, i);
|
||||
}
|
||||
|
||||
/* update the internal counter */
|
||||
(*counter)++;
|
||||
return (i);
|
||||
}
|
||||
|
||||
/* parser_get_inibitor()
|
||||
|
||||
This function will get the content of an inhibitor (and check if the
|
||||
inhibitor characteres are alone or not). */
|
||||
static int parser_get_inibitor(char ***tab, size_t *tab_pos,
|
||||
char const *str, int *counter)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* get the inibitor end */
|
||||
i = 0;
|
||||
while (str[++i] != '\0' && str[i] != '\"');
|
||||
if (str[i] != '\"')
|
||||
return (0);
|
||||
|
||||
/* dump the word if needed */
|
||||
if (*tab != NULL) {
|
||||
(*tab)[*tab_pos] = (char*)calloc(1, i + 1);
|
||||
if ((*tab)[*tab_pos] == NULL)
|
||||
return (-1);
|
||||
memset((*tab)[*tab_pos], 0, i + 1);
|
||||
strncpy((*tab)[(*tab_pos)++], str + 1, i - 1);
|
||||
}
|
||||
|
||||
/* update the internal counter */
|
||||
(*counter)++;
|
||||
return (i + 1);
|
||||
}
|
||||
|
||||
/* parser_setup_arg()
|
||||
|
||||
This function removes useless spaces, tabs and handle '\"' inhibitor.
|
||||
Return the number of word(s) stored in "str". */
|
||||
static int parser_entry(char ***tab, char const *str)
|
||||
{
|
||||
size_t tab_pos;
|
||||
int counter;
|
||||
int sz;
|
||||
|
||||
str--;
|
||||
sz = 0;
|
||||
counter = 0;
|
||||
tab_pos = 0;
|
||||
while (*(++str) != '\0' && *str != '\n' && sz >= 0) {
|
||||
if (*str == '\"') {
|
||||
sz = parser_get_inibitor(tab, &tab_pos, str, &counter);
|
||||
if (sz > 0) {
|
||||
str = &str[sz];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (*str != ' ' && *str != '\t') {
|
||||
sz = parser_get_word(tab, &tab_pos, str, &counter) - 1;
|
||||
if (sz > 0)
|
||||
str = &str[sz];
|
||||
}
|
||||
}
|
||||
return (counter);
|
||||
}
|
||||
|
||||
/* cli_parser_strtotab()
|
||||
Generate word table and indicated the number of word find in the string. */
|
||||
int cli_parser_strtotab(int *argc, char ***argv, char const *str)
|
||||
{
|
||||
if (argc == NULL || argv == NULL || str == NULL)
|
||||
return (-1);
|
||||
|
||||
/* Get the number of word. */
|
||||
*argv = NULL;
|
||||
*argc = parser_entry(argv, str);
|
||||
if (*argc <= 0)
|
||||
return (-2);
|
||||
|
||||
*argv = (char **)calloc(1, sizeof(char *) * (*argc + 1));
|
||||
if (*argv == NULL)
|
||||
return (-3);
|
||||
|
||||
/* Dump all word. */
|
||||
if (parser_entry(argv, str) != *argc) {
|
||||
cli_parser_strtotab_quit(argc, argv);
|
||||
return (-4);
|
||||
}
|
||||
(*argv)[*argc] = NULL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* cli_parser_strtotab_quit()
|
||||
Free all allocated memory generated by "strtotab()" */
|
||||
void cli_parser_strtotab_quit(int *argc, char ***argv)
|
||||
{
|
||||
if (argc == NULL || argv == NULL)
|
||||
return;
|
||||
if (*argv == NULL) {
|
||||
*argc = 0;
|
||||
return;
|
||||
}
|
||||
while (--(*argc) >= 0) {
|
||||
if ((*argv)[*argc] != NULL)
|
||||
free((*argv)[*argc]);
|
||||
}
|
||||
free(*argv);
|
||||
*argv = NULL;
|
||||
*argc = 0;
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
#include "vxBoot/fs/smemfs.h"
|
||||
#include "vxBoot/terminal.h"
|
||||
|
||||
#include <gint/bfile.h>
|
||||
#include <gint/gint.h>
|
||||
#include <gint/defs/call.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
inode = NULL;
|
||||
do {
|
||||
/* Try to alloc new inode */
|
||||
*sibling = calloc(1, sizeof(struct smemfs_inode));
|
||||
if (*sibling == NULL)
|
||||
break;
|
||||
|
||||
/* Save the first inode (used after for directories checking) */
|
||||
if (inode == NULL)
|
||||
inode = *sibling;
|
||||
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Return the sector table to simulate the root inode. */
|
||||
return (root_inode);
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
#include "vxBoot/fs/smemfs.h"
|
||||
|
||||
#include <gint/bfile.h>
|
||||
#include <gint/gint.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* internal struct */
|
||||
struct __file_info {
|
||||
uint16_t pathname[256];
|
||||
void *buf;
|
||||
size_t count;
|
||||
off_t pos;
|
||||
};
|
||||
|
||||
/* 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)
|
||||
{
|
||||
if (inode == NULL) {
|
||||
memcpy(pathname, u"\\\\fls0", 12);
|
||||
*pos = 6;
|
||||
return;
|
||||
}
|
||||
|
||||
generate_absolute_path(pathname, inode->parent, pos);
|
||||
|
||||
pathname[(*pos)++] = '\\';
|
||||
for (int i = 0; inode->name[i] != '\0'; ) {
|
||||
pathname[*pos] = inode->name[i];
|
||||
*pos = *pos + 1;
|
||||
i = i + 1;
|
||||
}
|
||||
pathname[*pos] = '\0';
|
||||
}
|
||||
|
||||
/* __smemfs_pread() : involved in Casio's world */
|
||||
static void __smemfs_pread(struct __file_info *info, ssize_t *read)
|
||||
{
|
||||
int handle;
|
||||
|
||||
*read = -1;
|
||||
handle = BFile_Open(info->pathname, BFile_ReadOnly);
|
||||
if (handle >= 0) {
|
||||
*read = BFile_Read(handle, info->buf, info->count, info->pos);
|
||||
BFile_Close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
/* smemfs_read(): Read primitive */
|
||||
ssize_t smemfs_pread(struct smemfs_inode *inode,
|
||||
void *buf, size_t count, off_t pos)
|
||||
{
|
||||
struct __file_info file_info = {
|
||||
.buf = buf,
|
||||
.count = count,
|
||||
.pos = pos
|
||||
};
|
||||
ssize_t read;
|
||||
int tmp;
|
||||
|
||||
if (inode == NULL)
|
||||
return (-1);
|
||||
|
||||
tmp = 0;
|
||||
generate_absolute_path(file_info.pathname, inode, &tmp);
|
||||
|
||||
gint_world_switch(GINT_CALL(
|
||||
(void*)&__smemfs_pread,
|
||||
(void*)&file_info, &read
|
||||
));
|
||||
|
||||
return (read);
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
#include "vxBoot/terminal.h"
|
||||
#include "vxBoot/cli.h"
|
||||
#include "vxBoot/builtin.h"
|
||||
#include "vxBoot/fs/smemfs.h"
|
||||
|
||||
#include <gint/keyboard.h>
|
||||
#include <gint/display.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
//TODO: better API for the command-line parser
|
||||
|
||||
/* internal builtin list */
|
||||
struct {
|
||||
const char *name;
|
||||
int (*f)(int argc, char **argv);
|
||||
} cmd_list[] = {
|
||||
{.name = "ls", &ls_main},
|
||||
{.name = "os", NULL},
|
||||
{.name = "help", &help_main},
|
||||
{.name = NULL, NULL}
|
||||
};
|
||||
|
||||
/* try to find the appropriate command */
|
||||
static int (*check_cmd(char *cmd))(int, char**)
|
||||
{
|
||||
for (int i = 0; cmd_list[i].name != NULL; ++i) {
|
||||
if (strcmp(cmd, cmd_list[i].name) != 0)
|
||||
continue;
|
||||
if (cmd_list[i].f == NULL)
|
||||
terminal_write("command exist but not implemented\n");
|
||||
return (cmd_list[i].f);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* entry of the bootloader */
|
||||
int main(void)
|
||||
{
|
||||
int (*builtin)(int, char**);
|
||||
const char *usrline;
|
||||
char buff[128];
|
||||
char **argv;
|
||||
int argc;
|
||||
int ret;
|
||||
|
||||
/* automated hook */
|
||||
/* TODO: better way to execute early command */
|
||||
smemfs_mount();
|
||||
|
||||
ret = 0;
|
||||
terminal_open();
|
||||
terminal_write("Welcome to vxBoot, the bootstrapper for the Vhex kernel!\n");
|
||||
terminal_write("Type `help` for instruction on how to use vxBoot\n");
|
||||
while (1) {
|
||||
/* get user command */
|
||||
usrline = (ret != 0) ? "/[%d]>" : "/>";
|
||||
terminal_write(usrline, ret);
|
||||
ret = 0;
|
||||
if (terminal_read(buff, 128) <= 1)
|
||||
continue;
|
||||
|
||||
/* parse and try to find the command */
|
||||
if (cli_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;
|
||||
}
|
||||
|
||||
/* execute the command and free'd allocated memories */
|
||||
ret = builtin(argc, argv);
|
||||
cli_parser_strtotab_quit(&argc, &argv);
|
||||
}
|
||||
return (1);
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#include "vxBoot/terminal.h"
|
||||
|
||||
#include <gint/timer.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* terminal_close(): Uninitialize the terminal */
|
||||
int terminal_close(void)
|
||||
{
|
||||
if (terminal.private.watermark != TERM_PRIVATE_WATERMARK)
|
||||
return (-1);
|
||||
if (terminal.private.timer.id >= 0)
|
||||
timer_stop(terminal.private.timer.id);
|
||||
if (terminal.buffer.data != NULL)
|
||||
free(terminal.buffer.data);
|
||||
terminal.private.watermark = TERM_PRIVATE_WATERMARK;
|
||||
return (0);
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
#include "vxBoot/terminal.h"
|
||||
|
||||
#include <gint/display.h>
|
||||
#include <gint/timer.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* internal symbols */
|
||||
struct terminal terminal;
|
||||
|
||||
/* terminal_open(): Initialize and open the terminal */
|
||||
int terminal_open(void)
|
||||
{
|
||||
if (terminal.private.watermark == TERM_PRIVATE_WATERMARK)
|
||||
terminal_close();
|
||||
memset(&terminal, 0x00, sizeof(struct terminal));
|
||||
terminal.private.timer.id = -1;
|
||||
terminal.winsize.ws_xpixel = DWIDTH;
|
||||
terminal.winsize.ws_ypixel = DHEIGHT;
|
||||
terminal.winsize.ft_xpixel = FWIDTH + 1;
|
||||
terminal.winsize.ft_ypixel = FHEIGHT + 1;
|
||||
terminal.winsize.ws_col = DWIDTH / terminal.winsize.ft_xpixel;
|
||||
terminal.winsize.ws_row = DHEIGHT / terminal.winsize.ft_ypixel;
|
||||
terminal.buffer.size = terminal.winsize.ws_row
|
||||
* terminal.winsize.ws_col
|
||||
* TERM_RDBUFFER_NBLINE
|
||||
* sizeof(uint8_t);
|
||||
terminal.buffer.data = calloc(1, terminal.buffer.size);
|
||||
if (terminal.buffer.data == NULL) {
|
||||
terminal_close();
|
||||
return (-1);
|
||||
}
|
||||
terminal.private.timer.id = timer_configure(
|
||||
TIMER_ANY,
|
||||
250000,
|
||||
GINT_CALL(terminal_cursor_handler)
|
||||
);
|
||||
if (terminal.private.timer.id < 0) {
|
||||
terminal_close();
|
||||
return (-1);
|
||||
}
|
||||
terminal.private.color.bg = C_BLACK;
|
||||
terminal.private.color.fg = C_WHITE;
|
||||
terminal.private.watermark = TERM_PRIVATE_WATERMARK;
|
||||
return (0);
|
||||
}
|
|
@ -0,0 +1,245 @@
|
|||
#include "vxBoot/terminal.h"
|
||||
|
||||
#include <gint/keyboard.h>
|
||||
#include <gint/display.h>
|
||||
#include <gint/timer.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* internal structure used to store many information */
|
||||
struct {
|
||||
struct {
|
||||
unsigned short x;
|
||||
unsigned short y;
|
||||
int visible;
|
||||
off_t saved;
|
||||
} cursor;
|
||||
struct {
|
||||
uint8_t alpha: 1;
|
||||
uint8_t shift: 1;
|
||||
uint8_t ctrl: 1;
|
||||
uint8_t exit: 1;
|
||||
uint8_t const: 4;
|
||||
} mode;
|
||||
struct {
|
||||
size_t max;
|
||||
size_t size;
|
||||
off_t cursor;
|
||||
char *data;
|
||||
} buffer;
|
||||
} term_rdinfo;
|
||||
|
||||
//---
|
||||
//
|
||||
//---
|
||||
void term_display_all(void)
|
||||
{
|
||||
/* stop the timer too avoid interrupt-loop */
|
||||
if (terminal.private.timer.id >= 0)
|
||||
timer_pause(terminal.private.timer.id);
|
||||
|
||||
/* mark special characte that the cursor is here */
|
||||
if (term_rdinfo.cursor.visible == 1)
|
||||
term_rdinfo.buffer.data[term_rdinfo.buffer.cursor] |= 0x80;
|
||||
|
||||
/* restore terminal context */
|
||||
terminal.cursor.x = term_rdinfo.cursor.x;
|
||||
terminal.cursor.y = term_rdinfo.cursor.y;
|
||||
terminal.buffer.cursor = term_rdinfo.cursor.saved;
|
||||
terminal_buffer_insert(term_rdinfo.buffer.data,
|
||||
term_rdinfo.buffer.size);
|
||||
|
||||
/* display management */
|
||||
dclear(terminal.private.color.bg);
|
||||
terminal_buffer_display();
|
||||
dupdate();
|
||||
|
||||
/* remove cursor mark */
|
||||
term_rdinfo.buffer.data[term_rdinfo.buffer.cursor] &= ~0x80;
|
||||
|
||||
/* restart the timer */
|
||||
if (terminal.private.timer.id >= 0)
|
||||
timer_start(terminal.private.timer.id);
|
||||
}
|
||||
|
||||
//---
|
||||
// Callback function
|
||||
//---
|
||||
|
||||
int terminal_cursor_handler(void)
|
||||
{
|
||||
term_rdinfo.cursor.visible ^= 1;
|
||||
term_display_all();
|
||||
return (0);
|
||||
}
|
||||
|
||||
//---
|
||||
// buffer functions
|
||||
//---
|
||||
|
||||
/* term_buffer_remove(): Remove character based on current cursor position */
|
||||
static void term_buffer_remove(void)
|
||||
{
|
||||
/* check if this action is possible */
|
||||
if (term_rdinfo.buffer.cursor == 0)
|
||||
return;
|
||||
/* move data if needed */
|
||||
if (term_rdinfo.buffer.cursor < term_rdinfo.buffer.size - 1) {
|
||||
memcpy(
|
||||
&term_rdinfo.buffer.data[term_rdinfo.buffer.cursor - 1],
|
||||
&term_rdinfo.buffer.data[term_rdinfo.buffer.cursor],
|
||||
term_rdinfo.buffer.size - term_rdinfo.buffer.cursor
|
||||
);
|
||||
}
|
||||
/* force NULL-char and update cursor/size */
|
||||
term_rdinfo.buffer.cursor = term_rdinfo.buffer.cursor - 1;
|
||||
term_rdinfo.buffer.data[--term_rdinfo.buffer.size - 1] = '\0';
|
||||
}
|
||||
|
||||
/* term_buffer_insert() - Insert character based on current cursor position */
|
||||
static int term_buffer_insert(char n)
|
||||
{
|
||||
/* save space for the "\n\0" (EOL) */
|
||||
if (term_rdinfo.buffer.size + 1 >= term_rdinfo.buffer.max)
|
||||
return (-1);
|
||||
/* move data if needed */
|
||||
if (term_rdinfo.buffer.cursor < term_rdinfo.buffer.size - 1) {
|
||||
off_t i = term_rdinfo.buffer.size + 1;
|
||||
while (--i >= term_rdinfo.buffer.cursor) {
|
||||
term_rdinfo.buffer.data[i] =
|
||||
term_rdinfo.buffer.data[i - 1];
|
||||
}
|
||||
}
|
||||
/* insert the character and force NULL-char */
|
||||
term_rdinfo.buffer.data[term_rdinfo.buffer.cursor++] = n;
|
||||
term_rdinfo.buffer.data[++term_rdinfo.buffer.size] = '\0';
|
||||
return (0);
|
||||
}
|
||||
|
||||
//---
|
||||
// key handling
|
||||
//---
|
||||
|
||||
// TODO
|
||||
// - F_UP -> history
|
||||
// - F_DOWN -> history
|
||||
static int term_key_handle_special(key_event_t key_event)
|
||||
{
|
||||
switch (key_event.key) {
|
||||
case KEY_SHIFT: term_rdinfo.mode.shift ^= 1; return (1);
|
||||
case KEY_ALPHA: term_rdinfo.mode.alpha ^= 1; return (1);
|
||||
case KEY_OPTN: term_rdinfo.mode.ctrl ^= 1; return (1);
|
||||
case KEY_DOT: term_buffer_insert(' '); return (1);
|
||||
case KEY_DEL: term_buffer_remove(); return (1);
|
||||
case KEY_EXE:
|
||||
/* Add End Of Line character */
|
||||
term_rdinfo.buffer.data[term_rdinfo.buffer.size - 1] = '\n';
|
||||
term_rdinfo.buffer.data[term_rdinfo.buffer.size] = '\0';
|
||||
|
||||
/* indicate that the EXE key has been pressed. */
|
||||
term_rdinfo.mode.exit = 1;
|
||||
return (1);
|
||||
case KEY_LEFT:
|
||||
if (term_rdinfo.buffer.cursor > 0)
|
||||
term_rdinfo.buffer.cursor -= 1;
|
||||
return (1);
|
||||
case KEY_RIGHT:
|
||||
if (term_rdinfo.buffer.cursor < term_rdinfo.buffer.size - 1)
|
||||
term_rdinfo.buffer.cursor += 1;
|
||||
return (1);
|
||||
default:
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/* term_buffer_update() - Update the internal buffer with the given key code */
|
||||
static int term_key_buffer_update(key_event_t key_event)
|
||||
{
|
||||
static const uint8_t keylist_alpha[] = {
|
||||
KEY_XOT, KEY_LOG, KEY_LN, KEY_SIN, KEY_COS, KEY_TAN,
|
||||
KEY_FRAC, KEY_FD, KEY_LEFTP, KEY_RIGHTP, KEY_COMMA, KEY_ARROW,
|
||||
KEY_7, KEY_8, KEY_9,
|
||||
KEY_4, KEY_5, KEY_6, KEY_MUL, KEY_DIV,
|
||||
KEY_1, KEY_2, KEY_3, KEY_PLUS, KEY_MINUS,
|
||||
KEY_0, 0xff
|
||||
};
|
||||
static const uint8_t keylist_num[] = {
|
||||
KEY_0, KEY_1, KEY_2, KEY_3, KEY_4,
|
||||
KEY_5, KEY_6, KEY_7, KEY_8, KEY_9,
|
||||
KEY_PLUS, KEY_MINUS, KEY_MUL, KEY_DIV,
|
||||
KEY_LEFTP, KEY_RIGHTP, KEY_COMMA, KEY_POWER,
|
||||
KEY_DOT, KEY_FD, KEY_ARROW, 0xff
|
||||
};
|
||||
static const char keylist_num_char[] = "0123456789+-x/(),^.|_";
|
||||
const uint8_t *keycode_list;
|
||||
char character;
|
||||
int i;
|
||||
|
||||
/* Get the appropriate key list. */
|
||||
keycode_list = keylist_alpha;
|
||||
if (term_rdinfo.mode.shift == 1)
|
||||
keycode_list = keylist_num;
|
||||
|
||||
/* Try to find the pressed key. */
|
||||
i = -1;
|
||||
while (keycode_list[++i] != 0xff && keycode_list[i] != key_event.key);
|
||||
if (keycode_list[i] != key_event.key)
|
||||
return (0);
|
||||
|
||||
/* handle mode then update the buffer */
|
||||
if (term_rdinfo.mode.shift == 0) {
|
||||
character = 'a' + i;
|
||||
if (term_rdinfo.mode.alpha == 1)
|
||||
character = 'A' + i;;
|
||||
} else {
|
||||
character = keylist_num_char[i];
|
||||
}
|
||||
term_buffer_insert(character);
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// primitive
|
||||
//---
|
||||
int terminal_read(void *buffer, size_t nb)
|
||||
{
|
||||
key_event_t key;
|
||||
|
||||
/* check obvious error */
|
||||
if (buffer == NULL || nb == 0)
|
||||
return (0);
|
||||
|
||||
/* initialize internal data */
|
||||
memset(&term_rdinfo, 0x00, sizeof(term_rdinfo));
|
||||
memset(buffer, 0x00, nb);
|
||||
|
||||
/* save terminal information */
|
||||
term_rdinfo.cursor.saved = terminal.buffer.cursor;
|
||||
term_rdinfo.cursor.x = terminal.cursor.x;
|
||||
term_rdinfo.cursor.y = terminal.cursor.y;
|
||||
term_rdinfo.buffer.data = buffer;
|
||||
term_rdinfo.buffer.size = 1;
|
||||
term_rdinfo.buffer.max = nb;
|
||||
|
||||
/* start cursor blink timer */
|
||||
if (terminal.private.timer.id >= 0)
|
||||
timer_start(terminal.private.timer.id);
|
||||
|
||||
/* keyboard handling */
|
||||
while (term_rdinfo.mode.exit == 0) {
|
||||
/* handle pressed keys */
|
||||
key = getkey_opt(GETKEY_REP_ALL | GETKEY_MENU, NULL);
|
||||
if (term_key_handle_special(key) == 0)
|
||||
term_key_buffer_update(key);
|
||||
|
||||
/* display */
|
||||
term_display_all();
|
||||
}
|
||||
|
||||
/* stop the timer */
|
||||
if (terminal.private.timer.id >= 0)
|
||||
timer_pause(terminal.private.timer.id);
|
||||
return (term_rdinfo.buffer.size);
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
#include "vxBoot/terminal.h"
|
||||
|
||||
#include <gint/display.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
//---
|
||||
// Update the internal buffer
|
||||
//---
|
||||
|
||||
/* terminal_buffer_insert() : insert string anywhere in the output buffer */
|
||||
void terminal_buffer_insert(char *buffer, size_t nb)
|
||||
{
|
||||
size_t dump;
|
||||
void *start;
|
||||
|
||||
/* calculate the "real" number of byte to dump into the buffer */
|
||||
dump = nb;
|
||||
start = &buffer[0];
|
||||
if (dump > terminal.buffer.size) {
|
||||
dump -= terminal.buffer.size;
|
||||
start = &buffer[nb - dump];
|
||||
}
|
||||
|
||||
/* dump the buffer (be carful with the circular effect) */
|
||||
if (terminal.buffer.cursor + dump > terminal.buffer.size) {
|
||||
memcpy(
|
||||
&terminal.buffer.data[terminal.buffer.cursor],
|
||||
start,
|
||||
terminal.buffer.size - terminal.buffer.cursor
|
||||
);
|
||||
dump -= terminal.buffer.size - terminal.buffer.cursor;
|
||||
terminal.buffer.cursor = 0;
|
||||
}
|
||||
memcpy(&terminal.buffer.data[terminal.buffer.cursor], start, dump);
|
||||
terminal.buffer.cursor += dump;
|
||||
}
|
||||
|
||||
|
||||
//---
|
||||
// Display the internal buffer
|
||||
//---
|
||||
|
||||
/* terminal_vertical_update() - Update vertical cursor */
|
||||
static void terminal_vertical_update(void)
|
||||
{
|
||||
if (terminal.cursor.y + 1 < terminal.winsize.ws_col) {
|
||||
terminal.cursor.y = terminal.cursor.y + 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* earlyterm_horizontal_update() - Update horizotal cursor */
|
||||
static int terminal_horizontal_update(void)
|
||||
{
|
||||
terminal.cursor.x = terminal.cursor.x + 1;
|
||||
if (terminal.cursor.x >= terminal.winsize.ws_col) {
|
||||
terminal_vertical_update();
|
||||
terminal.cursor.x = 0;
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* line_discipline() - Check "special" char */
|
||||
static int terminal_line_discipline(char n)
|
||||
{
|
||||
int offset;
|
||||
|
||||
switch (n) {
|
||||
case '\0':
|
||||
return (1);
|
||||
case '\n':
|
||||
terminal.cursor.x = 0;
|
||||
terminal_vertical_update();
|
||||
return (1);
|
||||
case '\b':
|
||||
if (terminal.cursor.x > 0)
|
||||
terminal.cursor.x = terminal.cursor.x - 1;
|
||||
return (1);
|
||||
case '\v':
|
||||
terminal_vertical_update();
|
||||
return (1);
|
||||
case '\r':
|
||||
terminal.cursor.x = 0;
|
||||
return (1);
|
||||
case '\t':
|
||||
/* Check if we need a new line or not. */
|
||||
offset = terminal.cursor.x - ((terminal.cursor.x / 5) * 5);
|
||||
offset = 5 - offset;
|
||||
while (--offset >= 0)
|
||||
terminal_horizontal_update();
|
||||
return (1);
|
||||
default:
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/* terminal_buffer_write() : display the buffer on screen */
|
||||
void terminal_buffer_display(void)
|
||||
{
|
||||
uint8_t *buffer;
|
||||
uint16_t tmp;
|
||||
int cursor;
|
||||
int x;
|
||||
int y;
|
||||
int i;
|
||||
|
||||
/* Due to potential special char, we sould find the "real" starting
|
||||
index for the internal buffer */
|
||||
terminal.cursor.x = 0;
|
||||
terminal.cursor.y = 0;
|
||||
i = terminal.buffer.cursor - 1;
|
||||
buffer = &terminal.buffer.data[0];
|
||||
while (1) {
|
||||
/* decrease the cursor and avoid circular effect */
|
||||
if (--i < 0)
|
||||
i = terminal.buffer.size - 1;
|
||||
|
||||
/* check loop condition */
|
||||
if (i == (int)terminal.buffer.cursor)
|
||||
break;
|
||||
|
||||
/* check EOL */
|
||||
if (buffer[i] == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
/* handle the character (only to force update cursors) */
|
||||
if (terminal_line_discipline(buffer[i] & 0x7f) == 0)
|
||||
terminal_horizontal_update();
|
||||
if (terminal.cursor.y >= terminal.winsize.ws_row)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Display character per character because we need to check special
|
||||
behaviour (like cariege return, line feed, ...) */
|
||||
terminal.cursor.x = 0;
|
||||
terminal.cursor.y = 0;
|
||||
while (1) {
|
||||
/* update the index */
|
||||
if (++i >= (int)terminal.buffer.size)
|
||||
i = 0;
|
||||
if (i == (int)terminal.buffer.cursor)
|
||||
break;
|
||||
|
||||
/* get the cursor and remove the potential cursor marker */
|
||||
cursor = ((buffer[i] & 0x80) != 0);
|
||||
buffer[i] &= 0x7f;
|
||||
|
||||
/* display part (character + cursor if needed) */
|
||||
x = terminal.cursor.x * terminal.winsize.ft_xpixel;
|
||||
y = terminal.cursor.y * terminal.winsize.ft_ypixel;
|
||||
if (terminal_line_discipline(buffer[i]) == 0) {
|
||||
tmp = buffer[i] << 8;
|
||||
dtext(x, y, terminal.private.color.fg, (void*)&tmp);
|
||||
terminal_horizontal_update();
|
||||
}
|
||||
if (cursor != 0) {
|
||||
dline(x,
|
||||
y + terminal.winsize.ft_ypixel,
|
||||
x + terminal.winsize.ft_xpixel - 2,
|
||||
y + terminal.winsize.ft_ypixel,
|
||||
terminal.private.color.fg);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#include "vxBoot/terminal.h"
|
||||
|
||||
#include <gint/display.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* terminal_write() - printf wrapper for the terminal device */
|
||||
int terminal_write(const char *format, ...)
|
||||
{
|
||||
char buffer[1024];
|
||||
va_list ap;
|
||||
int nb;
|
||||
|
||||
/* process the format */
|
||||
va_start(ap, format);
|
||||
nb = vsnprintf(buffer, 1024, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* update the internal buffer */
|
||||
terminal_buffer_insert(buffer, nb);
|
||||
|
||||
/* display the internal buffer */
|
||||
dclear(terminal.private.color.bg);
|
||||
terminal_buffer_display();
|
||||
dupdate();
|
||||
return (nb);
|
||||
}
|
Loading…
Reference in New Issue