v0.2.0 - Hypervisor loading images

@add
* overwrite Gint "hypervisor" properly (gint_switch)
* load ELF (pie) images into "world context".
* add "environments" manager (used to load Casio or Gint drivers' contexts)
* add "world queue" to manage properly multiple world contexts

@update
* "hyp" builtin: add "os" module
* "hyp" builtin: add "os ls" commands
* "hyp" builtin: fix display alignment
This commit is contained in:
Yatis 2021-02-01 21:24:10 +01:00
parent 63db69e784
commit 759a8bd876
7 changed files with 234 additions and 38 deletions

View File

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

View File

@ -8,6 +8,7 @@
#include <gint/std/string.h>
#include <gint/std/stdlib.h>
#include <gint/std/stdio.h>
#include <gint/gint.h>
/* 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());
}

30
src/hypervisor/env.c Normal file
View File

@ -0,0 +1,30 @@
//---
// hypervisor:env - Environment manager
//---
#include "fxBoot/hypervisor.h"
#include <gint/drivers.h>
#include <gint/std/string.h>
/* 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);
}

37
src/hypervisor/gint.c Normal file
View File

@ -0,0 +1,37 @@
//---
// fxBoot:hypervisor:gint - Gint workaround
//---
#include "fxBoot/hypervisor.h"
#include <gint/atomic.h>
#include <gint/drivers.h>
/* 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();
}

View File

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

View File

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

View File

@ -3,10 +3,99 @@
//---
#include "fxBoot/hypervisor.h"
#include <gint/std/stdlib.h>
#include <gint/atomic.h>
#include <gint/drivers.h>
/* 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
//---