diff --git a/CMakeLists.txt b/CMakeLists.txt index b35c017..9e53f98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.15) -project(vxBoot VERSION 0.0.3 LANGUAGES C) +project(vxBoot VERSION 1.0.0 LANGUAGES C) include(GenerateG1A) include(GenerateG3A) @@ -8,7 +8,11 @@ find_package(Gint 2.1 REQUIRED) set(SOURCES src/main.c + src/gui/entry.c + src/gui/fx9860g.c + src/gui/fxcg50.c src/cli/parser.c + src/cli/entry.c src/fs/smemfs/mount.c src/fs/smemfs/pread.c src/terminal/close.c @@ -25,6 +29,7 @@ set(SOURCES src/loader/elf/image.c src/loader/error.c src/loader/entry.c + src/loader/kernel.c src/hardware/get_info.c ) # Shared assets, fx-9860G-only assets and fx-CG-50-only assets @@ -35,13 +40,13 @@ set(ASSETS_fx assets-fx/fonts/hexa.png ) set(ASSETS_cg - # ... + assets-cg/fonts/font8x9.png ) 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_compile_options(vxBoot PRIVATE -Wall -Wextra -Os -DVXBOOT_VERSION="${PROJECT_VERSION}") target_include_directories(vxBoot PRIVATE include/) if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G) diff --git a/assets-cg/fonts/font8x9.png b/assets-cg/fonts/font8x9.png new file mode 100644 index 0000000..af01487 Binary files /dev/null and b/assets-cg/fonts/font8x9.png differ diff --git a/assets-cg/fonts/fxconv-metadata.txt b/assets-cg/fonts/fxconv-metadata.txt new file mode 100644 index 0000000..c5beb94 --- /dev/null +++ b/assets-cg/fonts/fxconv-metadata.txt @@ -0,0 +1,8 @@ +font8x9.png: + type: font + name: font_fxcg50 + charset: print + grid.size: 8x11 + grid.padding: 1 + grid.border: 0 + height: 9 diff --git a/include/vxBoot/cli.h b/include/vxBoot/cli.h index 1d48b27..f53e8ed 100644 --- a/include/vxBoot/cli.h +++ b/include/vxBoot/cli.h @@ -4,6 +4,10 @@ #include #include + +/* cli_main() : main entry for the CLI */ +extern void cli_main(void); + extern int cli_parser_strtotab(int *argc, char ***argv, char const *str); extern void cli_parser_strtotab_quit(int *argc, char ***argv); diff --git a/include/vxBoot/config.h b/include/vxBoot/config.h new file mode 100644 index 0000000..901a028 --- /dev/null +++ b/include/vxBoot/config.h @@ -0,0 +1,9 @@ +#ifndef VXBOOT_CONFIG +# define VXBOOT_CONFIG 1 + +/* vxBoot version */ +#ifndef VXBOOT_VERSION +# define VXBOOT_VERSION "0.0.0" +#endif + +#endif /* VXBOOT_CONFIG */ diff --git a/include/vxBoot/gui.h b/include/vxBoot/gui.h new file mode 100644 index 0000000..a7ee1b5 --- /dev/null +++ b/include/vxBoot/gui.h @@ -0,0 +1,32 @@ +#ifndef __VXBOOT_GUI_H__ +# define __VXBOOT_GUI_H__ + +#include +#include + +/* internal GUI information */ +struct gui_meta { + struct { + int anchor; + int select; + int count; + int line; + } list; + struct { + int x; + int y; + int width; + int offset; + } scroll; +}; + +/* gui_main() : main entry for the GUI */ +extern void gui_main(void); + +/* gui_fx9860g_display() : fx9860-specific display */ +extern void gui_fx9860g_display(struct gui_meta *gui); + +/* gui_fxcg50_display() : fxcg50-specific display */ +extern void gui_fxcg50_display(struct gui_meta *gui); + +#endif /*__VXBOOT_GUI_H__*/ diff --git a/include/vxBoot/loader.h b/include/vxBoot/loader.h index 62e2f0d..a8f680a 100644 --- a/include/vxBoot/loader.h +++ b/include/vxBoot/loader.h @@ -114,6 +114,14 @@ struct ldimg { /* loader_scan() : scan the storage memory and try to find ELF PIE file */ extern int loader_scan(void); +/* loader_kernel_img_get() : get the image ID information */ +extern struct ldimg *loader_kernel_img_get(int id); + +/* loader_kernel_img_count() : count the number of kernel image found */ +extern int loader_kernel_img_count(void); + + + /* loader() : try to load a ELF PIE file */ #define LOADER_DEFAULT 0 #define LOADER_DUMP 1 diff --git a/src/cli/entry.c b/src/cli/entry.c new file mode 100644 index 0000000..45af8bf --- /dev/null +++ b/src/cli/entry.c @@ -0,0 +1,70 @@ +#include "vxBoot/cli.h" +#include "vxBoot/builtin.h" +#include "vxBoot/terminal.h" + +#include + +//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 = "ld", &ld_main}, + {.name = "hw", &hw_main}, + {.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); +} + +void cli_main(void) +{ + int (*builtin)(int, char**); + const char *usrline; + char buff[128]; + char **argv; + int argc; + int ret; + + /* CLI loop */ + ret = 0; + 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); + } +} diff --git a/src/gui/entry.c b/src/gui/entry.c new file mode 100644 index 0000000..3f7c415 --- /dev/null +++ b/src/gui/entry.c @@ -0,0 +1,137 @@ +#include "vxBoot/gui.h" +#include "vxBoot/loader.h" + +#include +#include + +//--- +// Private +//--- + + + + +//-- +// Public +//--- + + +/* gui_main() : main loop for the GUI display */ +void gui_main(void) +{ + struct gui_meta disp; + void (*display)(struct gui_meta*); + int key; + + + disp.list.anchor = 0; + disp.list.select = 0; + disp.list.count = loader_kernel_img_count(); +#ifdef FX9860G + disp.list.line = 5; + disp.scroll.y = 10; + disp.scroll.offset = 0; + if (disp.list.count - 6 > 0) { + disp.scroll.width = (6 * 48) / disp.list.count; + disp.scroll.offset = (38 - disp.scroll.width); + disp.scroll.offset /= (disp.list.count - 6); + } + display = &gui_fx9860g_display; +#endif +#ifdef FXCG50 + disp.list.line = 11; + disp.scroll.y = 21; + disp.scroll.offset = 0; + if (disp.list.count - 11 > 0) { + disp.scroll.width = 167 / (disp.list.count - 11); + disp.scroll.offset = (167 - disp.scroll.width); + disp.scroll.offset /= (disp.list.count - 11); + } + display = &gui_fxcg50_display; +#endif + while (1) { + dclear(C_BLACK); + (*display)(&disp); + dupdate(); + + key = getkey().key; + if (key == KEY_F6) + break; + if (key == KEY_EXE || key == KEY_SHIFT) { + loader( + loader_kernel_img_get(disp.list.select)->inode, + LOADER_DEFAULT + ); + } + if (key == KEY_UP) { + disp.list.select -= 1; + if (disp.list.select < 0) + disp.list.select = 0; + if (disp.list.select < disp.list.anchor) + disp.list.anchor -= 1; + } + if (key != KEY_DOWN) + continue; + disp.list.select += 1; + if (disp.list.select >= disp.list.count) + disp.list.select = disp.list.count - 1; + if (disp.list.select - disp.list.anchor >= disp.list.line) + disp.list.anchor += 1; + } + +} + +#if 0 +/* gui_main() : main loop for the GUI display */ +void gui_main(void) +{ + int select_height; + int disp_start; + int max_line; + int offsetW; + int offsetH; + int selected; + int lheight; + int loffset; + int lrest; + int count; + int key; + int pos; + int i; + + selected = 0; + disp_start = 0; + offsetW = (DWIDTH * 5) / 100; + offsetH = (DHEIGHT * 5) / 100; + select_height = DHEIGHT - (offsetH * 3) - 6; + select_height = select_height - (offsetH * 2) - 6; + max_line = (select_height / (FHEIGHT + 6)) + 1; + count = loader_kernel_img_count(); + lheight = (max_line * select_height) / count; + lrest = select_height - lheight; + while (1) { + dclear(C_BLACK); + dupdate(); + + key = getkey().key; + if (key == KEY_F6) + break; + if (key == KEY_EXE || key == KEY_SHIFT) { + loader( + loader_kernel_img_get(selected)->inode, + LOADER_DEFAULT + ); + } + if (key == KEY_UP) { + selected -= 1; + if (selected < 0) selected = 0; + if (selected < disp_start) disp_start -= 1; + } + if (key == KEY_DOWN) { + selected += 1; + if (selected >= count) selected = count - 1; + if (selected - disp_start >= max_line) disp_start += 1; + } + } +} +#endif diff --git a/src/gui/fx9860g.c b/src/gui/fx9860g.c new file mode 100644 index 0000000..6415020 --- /dev/null +++ b/src/gui/fx9860g.c @@ -0,0 +1,51 @@ +#include "vxBoot/gui.h" +#include "vxBoot/loader.h" + +#include + +#if FX9860G +/* fx9860g_display() : Hardcoded display for the fx9860g */ +void gui_fx9860g_display(struct gui_meta *disp) +{ + char const * name; + int posy; + int tmp; + int sy; + int i; + + dprint_opt( + DWIDTH / 2, 1, + C_WHITE, C_BLACK, + DTEXT_CENTER, DTEXT_TOP, + "VxBoot version %s", + VXBOOT_VERSION + ); + drect_border(8, 8, 120, 50, C_NONE, 1, C_WHITE); + if (disp->scroll.offset > 0) { + sy = disp->scroll.y + (disp->list.anchor * disp->scroll.offset); + dline(118, sy, 118, sy + disp->scroll.width, C_WHITE); + } + i = disp->list.anchor - 1; + while (++i < disp->list.count && i - disp->list.anchor < 6) { + posy = 10 + ((i - disp->list.anchor) * 7); + name = loader_kernel_img_get(i)->inode->name; + dtext(11, posy + 1, C_WHITE, name); + if (i != disp->list.select) + continue; + tmp = (disp->scroll.offset > 0) ? 116 : 118; + drect(10, posy, tmp, posy + 6, C_INVERT); + } + dprint_opt( + DWIDTH / 2, 54, + C_WHITE, C_BLACK, + DTEXT_CENTER, DTEXT_MIDDLE, + "Use arrows to select" + ); + dprint_opt( + DWIDTH / 2, 60, + C_WHITE, C_BLACK, + DTEXT_CENTER, DTEXT_MIDDLE, + "Press [EXE] to boot" + ); +} +#endif diff --git a/src/gui/fxcg50.c b/src/gui/fxcg50.c new file mode 100644 index 0000000..0694d7b --- /dev/null +++ b/src/gui/fxcg50.c @@ -0,0 +1,52 @@ +#include "vxBoot/gui.h" +#include "vxBoot/loader.h" +#include "vxBoot/config.h" + +#include + +/* fxcg50_display() : Hardcoded display for the fxcg50 */ +void gui_fxcg50_display(struct gui_meta *disp) +{ + char const * name; + int posy; + int tmp; + int sy; + int i; + + dprint_opt( + DWIDTH / 2, 5, + C_WHITE, C_BLACK, + DTEXT_CENTER, DTEXT_TOP, + "VxBoot version %s", + VXBOOT_VERSION + ); + drect_border(17, 18, 378, 189, C_NONE, 1, C_WHITE); + if (disp->scroll.offset > 0) { + sy = disp->scroll.y + (disp->list.anchor * disp->scroll.offset); + dline(375, sy, 375, sy + disp->scroll.width, C_WHITE); + } + i = disp->list.anchor - 1; + while (++i < disp->list.count && i - disp->list.anchor < 11) { + posy = 22 + ((i - disp->list.anchor) * 15); + name = loader_kernel_img_get(i)->inode->name; + dtext(22, posy + 2, C_WHITE, name); + if (i != disp->list.select) + continue; + tmp = (disp->scroll.offset > 0) ? 373 : 375; + drect(20, posy, tmp, posy + 13, C_INVERT); + } + + dprint_opt( + DWIDTH / 2, 200, + C_WHITE, C_BLACK, + DTEXT_CENTER, DTEXT_MIDDLE, + "Use arrows keys to select entry" + ); + dprint_opt( + DWIDTH / 2, 212, + C_WHITE, C_BLACK, + DTEXT_CENTER, DTEXT_MIDDLE, + "Press [EXE] to boot the selected OS" + ); + +} diff --git a/src/loader/kernel.c b/src/loader/kernel.c new file mode 100644 index 0000000..ac47f6d --- /dev/null +++ b/src/loader/kernel.c @@ -0,0 +1,35 @@ +#include "vxBoot/loader.h" + + +/* kernel image list */ +struct ldimg *kernel_img_list = NULL; + + +/* loader_kernel_img_get() : get the image ID information */ +struct ldimg *loader_kernel_img_get(int id) +{ + struct ldimg *img; + + img = kernel_img_list; + while (--id >= 0) { + if (img == NULL) + return NULL; + img = img->next; + } + return img; +} + +/* loader_kernel_img_count() : count the number of kernel image found */ +int loader_kernel_img_count(void) +{ + struct ldimg *img; + int counter; + + counter = 0; + img = kernel_img_list; + while (img != NULL) { + counter = counter + 1; + img = img->next; + } + return counter; +} diff --git a/src/loader/scan.c b/src/loader/scan.c index 8f32522..bc19006 100644 --- a/src/loader/scan.c +++ b/src/loader/scan.c @@ -6,18 +6,23 @@ #include + /* internal kernel image list */ -struct ldimg *kernel_img_list = NULL; +extern struct ldimg *kernel_img_list; - -/* hypervisor_get_image_list(): Dump all ELF file stored into the SMEM */ +/* hypervisor_get_image_list(): Dump all ELF file stored into the SMEM + * + * @note: + * on real calculator, all file transfered using USB are concidered to be + * 'archived', but on emulator they are concidered like file. */ static int loader_list_img(struct ldimg **image, struct smemfs_inode *inode) { if (inode == NULL) return (0); int counter = 0; - if (inode->type != BFile_Type_Archived) { + if (inode->type != BFile_Type_Archived + && inode->type != BFile_Type_File) { counter += loader_list_img(image, inode->child); goto anchor; } diff --git a/src/main.c b/src/main.c index 25c6c66..2f0db9e 100644 --- a/src/main.c +++ b/src/main.c @@ -1,56 +1,24 @@ #include "vxBoot/terminal.h" -#include "vxBoot/cli.h" -#include "vxBoot/builtin.h" #include "vxBoot/fs/smemfs.h" #include "vxBoot/loader.h" +#include "vxBoot/gui.h" +#include "vxBoot/cli.h" -#include #include -#include - -//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 = "ld", &ld_main}, - {.name = "hw", &hw_main}, - {.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; - /* change default font on fx9860 */ #ifdef FX9860G extern font_t font_hexa; dfont(&font_hexa); #endif +#ifdef FXCG50 + extern font_t font_fxcg50; + dfont(&font_fxcg50); +#endif /* early log */ terminal_open(); @@ -64,32 +32,9 @@ int main(void) smemfs_mount(); loader_scan(); - /* CLI loop */ - ret = 0; - 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); - } + /* GUI Loop */ + if (loader_kernel_img_count() >= 1) + gui_main(); + cli_main(); return (1); }