diff --git a/include/fxBoot/hypervisor.h b/include/fxBoot/hypervisor.h index 7607722..c7c2f5e 100644 --- a/include/fxBoot/hypervisor.h +++ b/include/fxBoot/hypervisor.h @@ -29,6 +29,7 @@ struct hworld { /* hardware context */ struct { struct cpuctx cpu; + void *drivers; } context; /* memory information */ @@ -42,7 +43,17 @@ struct hworld { /* private information (used by the hypeviseur) */ struct { struct smemfs_inode *inode; - struct worldctx *next; + struct hworld *next; + enum { + HYPERVISOR_STATUS_CREATED = 0, + HYPERVISOR_STATUS_INIT = 1, + HYPERVISOR_STATUS_RUNNING = 2, + HYPERVISOR_STATUS_DEAD = 3, + } status; + enum { + HYPERVISOR_ENV_GINT = 0, + HYPERVISOR_ENV_CASIO = 1, + } env; } private; }; @@ -104,4 +115,19 @@ extern int hypervisor_loader_list(struct himage **list); (out) list List that will be destroyed and set to NULL */ extern void hypervisor_loader_list_destroy(struct himage **list); + +//--- +// World interface +//--- +/* */ +extern struct hworld *hypervisor_wswitch_create(void); +extern int hypervisor_wswitch_destroy(struct hworld *world); +extern int hypervisor_wswitch_queue_register(struct hworld *world); +extern int hypervisor_wswitch_queue_unregister(struct hworld *world); +extern struct hworld *hypervisor_wswitch_queue_get(void); + +//--- +// Environment interface +//--- +extern int hypervisor_env_set(struct hworld *hworld); #endif /*__FXBOOT_LOADER_H__*/ diff --git a/src/builtin/hyp.c b/src/builtin/hyp.c index d441144..2d0f506 100644 --- a/src/builtin/hyp.c +++ b/src/builtin/hyp.c @@ -8,6 +8,7 @@ #include #include +#include #include /* internal structiure used to handle the hypervisor module */ @@ -65,7 +66,7 @@ static struct smemfs_inode *smemfs_get(struct smemfs_inode *inode, //--- // Module management //--- - +/* hyp_img_module(): Handle argument for the image module part */ static int hyp_img_module(int argc, char **argv) { if (argc < 2) @@ -80,31 +81,29 @@ static int hyp_img_module(int argc, char **argv) } return (0); } -#if 0 if (strcmp(argv[2], "load") == 0) { if (argc < 3) { terminal_write("image ID missing\n"); return (84); } - int id = 0; - struct smemfs_inode *file; + int id = atoi(argv[3]); int counter = 0; - id = atoi(argv[3]); - file = smemfs_get(smemfs_superblock.root_inode, - &counter, id); - if (file == NULL) { + struct himage *img = hypinfo.images; + while (img != NULL) { + if (counter == id) + break; + counter = counter + 1; + img = img->next; + } + if (img == NULL) { terminal_write("image ID invalid\n"); return (84); } - struct worldctx *worldctx = calloc(sizeof(struct worldctx), 1); - if (hypervisor_loader(worldctx, file) != 0) + if (hypervisor_loader(img) != 0) return (84); - worldctx->private.next = hyp_info.os_list; - hyp_info.os_list = worldctx; terminal_write("image successfully loaded\n"); return (0); } -#endif error: terminal_write("\"hyp img\" requires at least 1 argument\n"); @@ -117,33 +116,35 @@ error: return (1); } -#if 0 +/* hyp_os_module(): Handle argument for the os module part */ static int hyp_os_module(int argc, char **argv) { if (argc < 2) goto error; if (strcmp(argv[2], "ls") == 0) { int counter = 0; - struct worldctx *worldctx = hyp_info.os_list; - while (worldctx != NULL) { - terminal_write("[%d] - %s\n", counter, worldctx->private.file->name); - terminal_write("|-- cpu context:\n"); - for (int i = 0; i < 16; ++i) - terminal_write("| |-- r%d: %p\n", i, worldctx->context.cpu.reg[i]); - terminal_write("| |-- gbr: %p\n", worldctx->context.cpu.gbr); - terminal_write("| |-- macl: %p\n", worldctx->context.cpu.macl); - terminal_write("| |-- mach: %p\n", worldctx->context.cpu.mach); - terminal_write("| |-- ssr: %p\n", worldctx->context.cpu.ssr); - terminal_write("| |-- spc: %p\n", worldctx->context.cpu.spc); - terminal_write("| `-- pr: %p\n", worldctx->context.cpu.pr); - terminal_write("`-- memory:\n"); - terminal_write(" |-- entry: %p\n", worldctx->memory.program.start); - terminal_write(" `-- size : %do\n", worldctx->memory.program.size); - worldctx = worldctx->private.next; + char line[32]; + struct hworld *world = hypervisor_wswitch_queue_get(); + int sp = (terminal.winsize.ws_col - 4) / 3; + snprintf(line, 32, "%%-3s%%-%ds%%-%ds%%s\n", sp, sp); + terminal_write(line, "ID", "NAME", "ENV", "SIZE"); + snprintf(line, 32, "%%-3d%%-%ds%%-%ds%%do\n", sp, sp); + const char *env = NULL; + while (world != NULL) { + env = "Casio"; + if (world->private.env == HYPERVISOR_ENV_GINT) + env = "Gint"; + terminal_write(line, + counter, + world->private.inode->name, + env, + world->memory.program.size); + world = world->private.next; counter = counter + 1; } return (0); } +#if 0 if (strcmp(argv[2], "run") == 0) { if (argc < 3) { terminal_write("OS ID missing\n"); @@ -172,6 +173,7 @@ static int hyp_os_module(int argc, char **argv) gint_switch_to_gint(); return (0); } +#endif error: terminal_write("\"hyp os\" requiere at least 1 argument\n"); @@ -184,6 +186,7 @@ error: return (1); } +#if 0 /* install the hypervisor */ static int hyp_install(void) { @@ -223,8 +226,8 @@ int hyp_main(int argc, char **argv) if (argc > 1) { if (strcmp(argv[1], "img") == 0) return (hyp_img_module(argc, argv)); - //if (strcmp(argv[1], "os") == 0) - // return (hyp_os_module(argc, argv)); + if (strcmp(argv[1], "os") == 0) + return (hyp_os_module(argc, argv)); //if (strcmp(argv[1], "install") == 0) // return (hyp_install()); } diff --git a/src/hypervisor/env.c b/src/hypervisor/env.c new file mode 100644 index 0000000..a2a647f --- /dev/null +++ b/src/hypervisor/env.c @@ -0,0 +1,30 @@ +//--- +// hypervisor:env - Environment manager +//--- +#include "fxBoot/hypervisor.h" + +#include +#include + +/* hidden Gint world information */ +extern void *kernel_env_casio; +extern void *kernel_env_gint; + +//--- +// Env API +//--- +/* hypervisor_env_set(): Set the appropriate environment */ +int hypervisor_env_set(struct hworld *world) +{ + if (world == NULL) + return (-1); + void *env = NULL; + switch (world->private.env) { + case HYPERVISOR_ENV_CASIO: env = kernel_env_casio; break; + case HYPERVISOR_ENV_GINT: env = kernel_env_gint; break; + default: + return (-2); + } + drivers_context_duplicate(world->context.drivers, env); + return (0); +} diff --git a/src/hypervisor/gint.c b/src/hypervisor/gint.c new file mode 100644 index 0000000..cd19b7c --- /dev/null +++ b/src/hypervisor/gint.c @@ -0,0 +1,37 @@ +//--- +// fxBoot:hypervisor:gint - Gint workaround +//--- +#include "fxBoot/hypervisor.h" + +#include +#include + +/* external symbols */ +extern void *kernel_env_casio; +extern void *kernel_env_gint; + +/* gint_switch_to_casio(): Restore Casio's environment */ +void gint_switch_to_casio(void) +{ + drivers_wait(); + drivers_switch(kernel_env_gint, kernel_env_casio); + //hypervisor_install(); +} + +/* gint_switch_to_gint(): Restore Gint's environment */ +void gint_switch_to_gint(void) +{ + drivers_wait(); + drivers_switch(kernel_env_casio, kernel_env_gint); + //hypervisor_install(); +} + +/* gint_switch(): Temporarily switch out of gint */ +void gint_switch(void (*function)(void)) +{ + gint_switch_to_casio(); + if(function != NULL) + function(); + gint_switch_to_gint(); +} + diff --git a/src/hypervisor/internal/elf.h b/src/hypervisor/internal/elf.h index d4039d5..d22f929 100644 --- a/src/hypervisor/internal/elf.h +++ b/src/hypervisor/internal/elf.h @@ -7,6 +7,11 @@ #include "fxBoot/fs/smemfs.h" #include "fxBoot/elf.h" +//--- +// Main API +//--- +extern int hypervisor_elf_loader(struct hworld *, struct smemfs_inode *); + //--- // Error helpers //--- diff --git a/src/hypervisor/loader.c b/src/hypervisor/loader.c index c8dd54f..be3aa81 100644 --- a/src/hypervisor/loader.c +++ b/src/hypervisor/loader.c @@ -45,11 +45,17 @@ anchor: /* hypervisor_loader(): Load a ELF (must be PIE) and start it */ int hypervisor_loader(struct himage *image) { - (void)image; - //TODO: create a new world context - //TODO: try to load the image - //TODO: link the new world context - //TODO: perform a world switch. + struct hworld *world; + + world = hypervisor_wswitch_create(); + if (world == NULL) + return (-1); + if (hypervisor_elf_loader(world, image->private) != 0) { + hypervisor_wswitch_destroy(world); + return (-2); + } + hypervisor_wswitch_queue_register(world); + hypervisor_env_set(world); return (0); } diff --git a/src/hypervisor/wswitch.c b/src/hypervisor/wswitch.c index e524a8c..63aca9d 100644 --- a/src/hypervisor/wswitch.c +++ b/src/hypervisor/wswitch.c @@ -3,10 +3,99 @@ //--- #include "fxBoot/hypervisor.h" +#include +#include +#include + /* internal globals information */ HYPERVISOR_BSS void *hypervisor_current_vbr = NULL; HYPERVISOR_BSS struct hworld *hypervisor_world_queue = NULL; +//--- +// World API +//--- +/* hypervisor_wswitch_create(): Create a new world */ +struct hworld *hypervisor_wswitch_create(void) +{ + struct hworld *world; + + world = hypervisor_world_queue; + while (world != NULL) { + if (world->private.status != HYPERVISOR_STATUS_DEAD) { + world = world->private.next; + continue; + } + world->private.status = HYPERVISOR_STATUS_INIT; + return (world); + } + world = calloc(sizeof(struct hworld), 1); + if (world != NULL) { + world->private.status = HYPERVISOR_STATUS_CREATED; + world->private.env = HYPERVISOR_ENV_CASIO; + } + return (world); +} + +/* void hypervisor_wswitch_destroy(): Destroy the world */ +int hypervisor_wswitch_destroy(struct hworld *world) +{ + if (world == NULL) + return (-1); + if (world->private.status != HYPERVISOR_STATUS_CREATED + &&world->private.status != HYPERVISOR_STATUS_INIT) { + return (-2); + } + if (world->memory.program.start != NULL) // <-- move me + free(world->memory.program.start); // <-- loader unload + if (world->context.drivers != NULL) + drivers_context_destroy(world->context.drivers); + world->private.inode = NULL; + if (world->private.status == HYPERVISOR_STATUS_INIT) { + world->private.status = HYPERVISOR_STATUS_DEAD; + return (0); + } + free(world); + return (0); +} + +//--- +// Queue API +//--- +/* hypervisor_wswitch_queue_register(): Register the new world */ +int hypervisor_wswitch_queue_register(struct hworld *world) +{ + if (world == NULL) + return (-1); + world->private.next = hypervisor_world_queue; + hypervisor_world_queue = world; + return (0); +} + +/* hypervisor_wswich_queue_get(): Get the world queue */ +struct hworld *hypervisor_wswitch_queue_get(void) +{ + return (hypervisor_world_queue); +} + +/* hypervisor_wswitch_queue_unregister(): Unregister a world */ +int hypervisor_wswitch_queue_unregister(struct hworld *target) +{ + struct hworld **world; + + world = &hypervisor_world_queue; + while (*world != NULL) { + if (*world != target) { + world = &(*world)->private.next; + continue; + } + *world = (*world)->private.next; + if (target->private.status != HYPERVISOR_STATUS_DEAD) + hypervisor_wswitch_destroy(target); + return (0); + } + return (-1); +} + //--- // User API //---