v0.3.0 - Hypervisor installation

@add
* hypervisor installation (VBR switch)
* hypervisor's VBR handlers which redirect events with the "world's" VBR
* hypervisor TRAPA ABI that can be used to perform hypercall

@update
* "hyp" builtin: add "install" module
* "hyp" builtin: "hyp install debug" command
* "hyp" builtin: "hyp install now" command
This commit is contained in:
Yatis 2021-02-05 20:54:04 +01:00
parent 759a8bd876
commit 9ef129e788
9 changed files with 508 additions and 176 deletions

View File

@ -25,11 +25,25 @@ struct cpuctx {
uint32_t pr;
};
#define HYPERVISOR_STACK_KERNEL_SIZE (2 * 1024)
#define HYPERVISOR_STACK_USER_SIZE (10 * 1024)
/* hworld: Wolrd context, used by the hypervisor
Be careful, many information are completely hardcoded in some assembly
sources. So, if you may change or update this structur, check all assembly
file. */
struct hworld {
/* hardware context */
/* stack information (NEVER CHANGE THE ORDER )*/
struct {
void *kernel;
void *user;
} stack;
/* hardware context (NEVER CHANGE THE ORDER OF "drivers" AND "cpu") */
struct {
struct cpuctx cpu;
void *drivers;
struct cpuctx cpu;
} context;
/* memory information */
@ -38,6 +52,14 @@ struct hworld {
void *start;
size_t size;
} program;
struct {
void *kernel;
void *user;
struct {
size_t kernel;
size_t user;
} size;
} stack;
} memory;
/* private information (used by the hypeviseur) */
@ -119,15 +141,28 @@ extern void hypervisor_loader_list_destroy(struct himage **list);
//---
// World interface
//---
/* */
extern struct hworld *hypervisor_wswitch_create(void);
extern int hypervisor_wswitch(struct hworld *world);
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);
extern struct hworld *hypervisor_wswitch_world_alloc(void);
extern void hypervisor_wswitch_world_free(struct hworld **world);
//---
// Environment interface
//---
extern int hypervisor_env_set(struct hworld *hworld);
//---
// Installer interface
//---
extern int hypervisor_install(void);
//---
// "Kernel" interface
//---
//extern int hypervisor_kernel_world_yield(struct hworld*c, struct hworld *n);
//extern int hypervisor_kernel_world_switch(struct hworld*c, struct hworld *n);
#endif /*__FXBOOT_LOADER_H__*/

View File

@ -19,50 +19,6 @@ struct {
uint32_t installed;
} hypinfo;
#if 0
//---
// SMEM abstraction
//---
static void smemfs_find(struct smemfs_inode *inode, char *buffer, int *counter)
{
const char *ext;
if (inode == NULL)
return;
smemfs_find(inode->child, buffer, counter);
ext = strrchr(inode->name, '.');
if (ext != NULL) {
if (strcmp(ext, ".elf") == 0) {
terminal_write("[%d] %s\n", *counter, inode->name);
*counter += 1;
}
}
smemfs_find(inode->sibling, buffer, counter);
}
static struct smemfs_inode *smemfs_get(struct smemfs_inode *inode,
int *counter, int id)
{
struct smemfs_inode *file;
const char *ext;
if (inode == NULL)
return (NULL);
file = smemfs_get(inode->child, counter, id);
if (file != NULL)
return (file);
ext = strrchr(inode->name, '.');
if (ext != NULL) {
if (strcmp(ext, ".elf") == 0) {
if (*counter == id)
return (inode);
*counter += 1;
}
}
return (smemfs_get(inode->sibling, counter, id));
}
#endif
//---
// Module management
//---
@ -86,8 +42,8 @@ static int hyp_img_module(int argc, char **argv)
terminal_write("image ID missing\n");
return (84);
}
int id = atoi(argv[3]);
int counter = 0;
int id = atoi(argv[3]);
struct himage *img = hypinfo.images;
while (img != NULL) {
if (counter == id)
@ -144,36 +100,28 @@ static int hyp_os_module(int argc, char **argv)
}
return (0);
}
#if 0
if (strcmp(argv[2], "run") == 0) {
if (argc < 3) {
terminal_write("OS ID missing\n");
return (84);
}
int id = atoi(argv[3]);
int counter = 0;
struct worldctx *worldctx = hyp_info.os_list;
while (worldctx != NULL) {
int id = atoi(argv[3]);
struct hworld *world = hypervisor_wswitch_queue_get();
while (world != NULL) {
if (counter == id)
break;
worldctx = worldctx->private.next;
counter = counter + 1;
world = world->private.next;
}
if (worldctx == NULL) {
terminal_write("OS ID invalid\n");
if (world == NULL) {
terminal_write("image ID invalid\n");
return (84);
}
/* Switch from gint to the OS after a short wait */
gint_switch_to_casio();
/* call Casio's specific code */
((void(*)(void))(uintptr_t)worldctx->context.cpu.spc)();
/* Then switch back to gint once the OS finishes working */
gint_switch_to_gint();
if (hypervisor_wswitch(world) != 0)
return (84);
return (0);
}
#endif
error:
terminal_write("\"hyp os\" requiere at least 1 argument\n");
@ -186,28 +134,37 @@ error:
return (1);
}
#if 0
/* install the hypervisor */
static int hyp_install(void)
/* hyp_install(): Installer interface */
static int hyp_install(int argc, char **argv)
{
/* extern void *bhyp_rom;
extern void *bhyp_ram;
extern void *zhyp;
extern void *hypervisor_vbr_exch;
extern void *hypervisor_vbr_tlbh;
extern void *hypervisor_vbr_inth;
extern void *hypervisor_vbr;
// check if the hypervisor is already installed.
if (hyp_info.installed == 0xdeb0cad0) {
terminal_write("hypervisor already installed\n");
return (1);
if (argc < 2)
goto error;
if (strcmp(argv[2], "debug") == 0) {
terminal_write("VBR: %p\n", hypervisor_vbr_exch - 0x100);
terminal_write("exch: %p\n", hypervisor_vbr_exch);
terminal_write("tlbh: %p\n", hypervisor_vbr_tlbh);
terminal_write("inth: %p\n", hypervisor_vbr_inth);
return (0);
}
// install the hypervisor
if (hyperisor_install() != 0) {
terminal_write("hypervisor installation fail :(\n");
return (84);
}*/
if (strcmp(argv[2], "now") == 0) {
hypervisor_install();
terminal_write("installed at <%p>\n", hypervisor_vbr);
return (0);
}
error:
terminal_write("\"hyp install\" requiere at least 1 argument\n");
terminal_write("\n");
terminal_write("Hypervisor installer\n");
terminal_write("\n");
terminal_write("commands:\n");
terminal_write(" debug Display hypervisor low level information\n");
return (0);
}
#endif
//---
// Entry
@ -228,8 +185,13 @@ int hyp_main(int argc, char **argv)
return (hyp_img_module(argc, argv));
if (strcmp(argv[1], "os") == 0)
return (hyp_os_module(argc, argv));
//if (strcmp(argv[1], "install") == 0)
// return (hyp_install());
if (strcmp(argv[1], "install") == 0)
return (hyp_install(argc, argv));
if (strcmp(argv[1], "trap") == 0) {
int allo;
__asm__ volatile ("trapa #0; mov r0, %0":"=r"(allo));
return (allo);
}
}
/* error or helper */

View File

@ -34,4 +34,3 @@ void gint_switch(void (*function)(void))
function();
gint_switch_to_gint();
}

View File

@ -1,35 +0,0 @@
#if 0
.section .hypervisor.text, "ax"
.global _hypervisor_install
.align 2
_hypervisor_install:
/* check if the hypervisor is installed */
stc vbr, r0
mov.l hypervisor_vbr, r1
cmp/eq r1, r0
bf install
rts
mov #-1, r0
install:
/* Block all interrupts by setting IMASK=15 */
mov #0xf, r0
shll2 r0
shll2 r0
stc sr, r2
or r2, r0
ldc r0, sr
/* install the hypervisor */
ldc r1, vbr
/* restore VBR then exit */
ldc r2, sr
rts
xor r0, r0
.align 4
hypervisor_vbr:
.long _hypervisor_vbr
#endif

View File

@ -3,12 +3,39 @@
//---
#include "fxBoot/hypervisor.h"
#include <gint/std/stdlib.h>
#include <gint/drivers.h>
#include <gint/cpu.h>
/* external VBR information */
extern void *hypervisor_vbr_inth;
extern void *hypervisor_vbr_exch;
extern void *hypervisor_vbr_tlbh;
/* internal information */
struct hworld *hypervisor_world_current;
struct hworld *hypervisor_world;
void *hypervisor_vbr_redirect;
void *hypervisor_vbr;
//---
// User API
//---
/* hypervisor_install(): Install the hypervisor */
int hypervisor_install(void)
{
//TODO:generate the world context for the interface
//TODO: switch VBR
/* generate the world context for the interface */
if (hypervisor_world == NULL) {
hypervisor_world = hypervisor_wswitch_world_alloc();
if (hypervisor_world == NULL)
return (-1);
hypervisor_world_current = hypervisor_world;
}
/* switch the VBR */
hypervisor_vbr = (void*)(hypervisor_vbr_exch - 0x100);
void * tmp = cpu_getVBR();
if (tmp != hypervisor_vbr)
hypervisor_vbr_redirect = cpu_setVBR(hypervisor_vbr);
return (0);
}

View File

@ -4,6 +4,7 @@
#include <stddef.h>
#include <stdint.h>
#include "fxBoot/hypervisor.h"
#include "fxBoot/fs/smemfs.h"
#include "fxBoot/elf.h"

128
src/hypervisor/kernel.S Normal file
View File

@ -0,0 +1,128 @@
/*
** hypervisor:kernel - low level world manipulation
*/
.section .gint.mapped, "ax"
.align 2
.global _hypervisor_kernel_abi
.global _hypervisor_kernel_world_switch
/* hypervisor_kernel_abi(): Kernel ABI entry */
_hypervisor_kernel_abi:
/* check trapa validity */
mov.l abi_trapa_reg, r1
mov.l @r1, r1
shlr2 r1
mov #1, r2
cmp/hi r1, r2
bf abi_error
/* involve syscall if possible */
shll2 r1
mova abi_syscall_table, r0
mov.l @(r0, r1), r3
tst r3, r3
bt abi_error
jmp @r3
nop
/* error handling */
abi_error:
mov #-1, r0
ldc r0, R0_BANK
rte
nop
.align 4
abi_trapa_reg:
.long 0xff000020
abi_syscall_table:
.long 0x00000000 ! _hypervisor_kernel_world_switch
.long 0x00000000
#if 0
/* hypervisor world_switch(): Performs a world switch */
_hypervisor_kernel_world_switch:
/* check potential error */
tst r4, r4
bt kernel_world_error
tst r5, r5
bt kernel_world_error
/* save the current context */
sts.l pr, @-r15
mov.l r4, @-r15
mov.l r5, @-r15
mov.l drivers_context_save, r0
jsr @r0
mov.l @r4, r4
mov.l @r15+, r5
mov.l @r15+, r4
ldc.l @r15+, pr
/* save cpu context */
add #92, r4
mov.l pr, @-r4
stc.l spc, @-r4
stc.l ssr, @-r4
sts.l mach, @-r4
sts.l macl, @-r4
stc.l gbr, @-r4
mov.l r15, @-r4
mov.l r14, @-r4
mov.l r13, @-r4
mov.l r12, @-r4
mov.l r11, @-r4
mov.l r10, @-r4
mov.l r9, @-r4
mov.l r8, @-r4
stc.l R7_BANK, @-r4
stc.l R6_BANK, @-r4
stc.l R5_BANK, @-r4
stc.l R4_BANK, @-r4
stc.l R3_BANK, @-r4
stc.l R2_BANK, @-r4
stc.l R1_BANK, @-r4
stc.l R0_BANK, @-r4
/* restore cpu context */
add #4, r5
ldc.l @r5+, R0_BANK
ldc.l @r5+, R1_BANK
ldc.l @r5+, R2_BANK
ldc.l @r5+, R3_BANK
ldc.l @r5+, R4_BANK
ldc.l @r5+, R5_BANK
ldc.l @r5+, R6_BANK
ldc.l @r5+, R7_BANK
mov.l @r5+, r8
mov.l @r5+, r9
mov.l @r5+, r10
mov.l @r5+, r11
mov.l @r5+, r12
mov.l @r5+, r13
mov.l @r5+, r14
mov.l @r5+, r15
ldc.l @r5+, gbr
lds.l @r5+, macl
lds.l @r5+, mach
ldc.l @r5+, ssr
ldc.l @r5+, spc
lds.l @r5+, pr
/* restore drivers context */
/* TODO */
/* force install hypervisor */
/* TODO */
/* perform the world switch */
rte
nop
kernel_world_error:
rts
mov #-2, r0
#endif

View File

@ -1,59 +1,232 @@
#if 0
.section .hypervisor.interrupt, "ax"
.global _hypervisor_inth
/*
** hypervisor:vbr - VBR handling
*/
.section .gint.mapped, "ax"
.align 2
_hypervisor_inth:
/* save interrupt related information */
.global _hypervisor_vbr_exch_reloc
.global _hypervisor_vbr_tlbh_reloc
.global _hypervisor_vbr_inth_reloc
/* hypervisor_vbr_exch_reloc(): Relocalized exception handler */
_hypervisor_vbr_exch_reloc:
/* check if it's a hypervisor call */
mov.l exch_hypervisor_world_current, r4
mov.l exch_hypervisor_world, r3
mov.l @r4, r4
mov.l @r3, r3
cmp/eq r3, r4
bf exch_normal_behaviour
exch_trap_behaviour:
/* check trapa exception and involve kernel ABI if needed */
mov.l exch_expevt_reg, r0
mov.l @r0, r0
mov #0x16, r1
shll2 r1
shll2 r1
cmp/eq r0, r1
bf exch_normal_behaviour
mov.l exch_kernel_abi, r0
jmp @r0
nop
exch_normal_behaviour:
/* normal behaviour */
stc.l spc, @-r4
stc.l ssr, @-r4
/* get the "real" tlb handler address */
mov.l exch_hypervisor_vbr_redirect, r1
mov.l @r1, r1
ldc r1, vbr
mov #0x01, r2
shll8 r2
add r2, r1
/* jump into the "real" tlb handler and be sure that it will
return here with the same invoromnent */
!stc sr, r2
mova exch_jmp_over, r0
ldc r0, spc
!ldc r2, ssr
jmp @r1
nop
.align 4
exch_jmp_over:
/* get kernel stack and restore tlb event related information */
mov.l exch_hypervisor_world_current, r4
mov.l @r4, r4
ldc.l @r4+, ssr
ldc.l @r4+, spc
/* force hypervisor VBR re-installation, because it possible that the
VBR has been changed during the handler */
mov.l exch_hypervisor_vbr_redirect, r0
mov.l exch_hypervisor_vbr, r1
stc vbr, r2
mov.l r2, @r0
ldc.l @r1+, vbr
/* clean return */
rte
nop
.align 4
exch_expevt_reg: .long 0xff000024
exch_kernel_abi: .long _hypervisor_kernel_abi
exch_hypervisor_world: .long _hypervisor_world
exch_hypervisor_world_current: .long _hypervisor_world_current
exch_hypervisor_vbr_redirect: .long _hypervisor_vbr_redirect
exch_hypervisor_vbr: .long _hypervisor_vbr
exch_end:
.zero 0x300 - (exch_end - _hypervisor_vbr_exch_reloc)
/* hypervisor_vbr_tlbh_reloc(): Relocalized TLB handler */
_hypervisor_vbr_tlbh_reloc:
/* get kernel stack and save tlb event related information */
mov.l tlbh_hypervisor_current_world, r4
mov.l @r4, r4
stc.l spc, @-r4
stc.l ssr, @-r4
/* get the "real" tlb handler address */
mov.l tlbh_hypervisor_vbr_redirect, r1
mov.l @r1, r1
ldc r1, vbr
mov #0x04, r2
shll8 r2
add r2, r1
/* jump into the "real" interrupt handler and be sure that it will
return here with the same invoromnent */
stc sr, r2
mova tlbh_jmp_over, r0
ldc r0, spc
ldc r2, ssr
jmp @r1
nop
.align 4
tlbh_jmp_over:
/* get kernel stack and restore tlb event related information */
mov.l tlbh_hypervisor_current_world, r4
mov.l @r4, r4
ldc.l @r4+, ssr
ldc.l @r4+, spc
/* force hypervisor VBR re-installation, because it possible that the
VBR has been changed during the handler */
mov.l tlbh_hypervisor_vbr_redirect, r0
mov.l tlbh_hypervisor_vbr, r1
stc vbr, r2
mov.l r2, @r0
ldc.l @r1+, vbr
/* clean return */
rte
nop
.align 4
tlbh_hypervisor_vbr_redirect: .long _hypervisor_vbr_redirect
tlbh_hypervisor_vbr: .long _hypervisor_vbr
tlbh_hypervisor_current_world: .long _hypervisor_world_current
tlbh_end:
.zero 0x200 - (tlbh_end - _hypervisor_vbr_tlbh_reloc)
/* hypervisor_vbr_inth_reloc(): Relocalized interrupt handler */
_hypervisor_vbr_inth_reloc:
/* switch kernel stack */
mov.l inth_hypervisor_current_world, r4
mov.l @r4, r4
mov.l r15, @(4, r4)
mov.l @r4, r15
/* save interrupt information */
stc.l gbr, @-r15
sts.l mach, @-r15
sts.l macl, @-r15
stc.l gbr, @-r15
stc.l spc, @-r15
stc.l ssr, @-r15
sts.l pr, @-r15
/* check manually the keyboard status to see if the we need to
perform a world switch */
mov.l hypervisor_wswitch_check, r0
jsr @r0
nop
mov.l r0, @-r15
/* TODO: involve keyboard scanner */
/* TODO: involved world switch to the hypervisor if needed */
/* involve the "real" vbr handler */
mov.l hypervisor_inth_second_part, r0
ldc r0, vbr
mov.l hypervisor_current_vbr, r0
mov.l @r0, r0
mov #0x06, r1
shll8 r1
add r1, r0
jsr @r0
/* switch stack before calling the real handler */
mov.l r15, @r4
mov.l @(4, r4), r15
/* get the "real" VBR interrupt handler address */
mov.l inth_hypervisor_vbr_redirect, r1
mov.l @r1, r1
ldc r1, vbr
mov #0x06, r2
shll8 r2
add r2, r1
/* jump into the "real" interrupt handler and be sure that it will
return here with the same invoromnent */
stc sr, r2
mova inth_jmp_over, r0
ldc r0, spc
ldc r2, ssr
jmp @r1
nop
hypervisor_inth_prologue:
/* check if world switch is requested */
mov.l @r15+, r0
tst r0, r0
bf.s hypervisor_inth_exit
mov.l hypervisor_wswitch, r0
jsr @r0
nop
.align 4
inth_jmp_over:
/* switch stack */
mov.l inth_hypervisor_current_world, r4
mov.l @r4, r4
mov.l r15, @(4, r4)
mov.l @r4, r15
/* force hypervisor VBR re-installation, because it possible that the
VBR has been changed during the handler */
mov.l inth_hypervisor_vbr_redirect, r0
mov.l inth_hypervisor_vbr, r1
stc vbr, r2
mov.l r2, @r0
ldc.l @r1+, vbr
hypervisor_inth_exit:
/* restore the saved information */
/* restore interrupt information */
lds.l @r15+, pr
ldc.l @r15+, ssr
ldc.l @r15+, spc
ldc.l @r15+, gbr
lds.l @r15+, macl
rte
lds.l @r15+, mach
ldc.l @r15+, gbr
/* switch stack and exit */
mov.l r15, @r4
mov.l @(4, r4), r15
/* Salut mon pote ! */
rte
nop
.align 4
hypervisor_wswitch_check: .long _hypervisor_worldswitch_check
hypervisor_wswitch: .long _hypervisor_worldswitch
hypervisor_current_vbr: .long _hypervisor_current_vbr
hypervisor_vbr: .long _hypervisor_vbr
hypervisor_inth_second_part: .long hypervisor_inth_prologue
#endif
inth_hypervisor_vbr: .long _hypervisor_vbr
inth_hypervisor_vbr_redirect: .long _hypervisor_vbr_redirect
inth_hypervisor_current_world: .long _hypervisor_world_current
/* define all symbols */
.section .gint.mappedrel, "aw"
.align 4
.global _hypervisor_vbr_exch
.global _hypervisor_vbr_tlbh
.global _hypervisor_vbr_inth
_hypervisor_vbr_exch: .long _hypervisor_vbr_exch_reloc
_hypervisor_vbr_tlbh: .long _hypervisor_vbr_tlbh_reloc
_hypervisor_vbr_inth: .long _hypervisor_vbr_inth_reloc

View File

@ -10,10 +10,57 @@
/* internal globals information */
HYPERVISOR_BSS void *hypervisor_current_vbr = NULL;
HYPERVISOR_BSS struct hworld *hypervisor_world_queue = NULL;
extern struct hworld *hypervisor_world;
//---
// World API
//---
/* hypervisor_wswitch_world_free(): Free'd allocated world */
void hypervisor_wswitch_world_free(struct hworld **world)
{
if (world == NULL || *world == NULL)
return;
if ((*world)->memory.stack.kernel != NULL)
free((*world)->memory.stack.kernel);
if ((*world)->memory.stack.user != NULL)
free((*world)->memory.stack.user);
if ((*world)->context.drivers != NULL)
drivers_context_destroy((*world)->context.drivers);
free(*world);
*world = NULL;
}
/* hypervisor_wswitch_world_alloc(): Allocate a new world */
struct hworld *hypervisor_wswitch_world_alloc(void)
{
struct hworld *world;
world = calloc(sizeof(struct hworld), 1);
if (world == NULL)
return (NULL);
world->private.status = HYPERVISOR_STATUS_CREATED;
world->private.env = HYPERVISOR_ENV_CASIO;
world->memory.stack.user = malloc(HYPERVISOR_STACK_USER_SIZE);
world->memory.stack.kernel = malloc(HYPERVISOR_STACK_KERNEL_SIZE);
world->context.drivers = drivers_context_create();
if (world->memory.stack.user == NULL
|| world->memory.stack.kernel == NULL
|| world->context.drivers == NULL) {
hypervisor_wswitch_world_free(&world);
return (NULL);
}
world->memory.stack.size.user = HYPERVISOR_STACK_USER_SIZE;
world->memory.stack.size.kernel = HYPERVISOR_STACK_USER_SIZE;
world->stack.kernel = world->memory.stack.kernel;
world->stack.kernel += HYPERVISOR_STACK_KERNEL_SIZE;
world->stack.kernel = (void*)((uintptr_t)world->stack.kernel & ~3);
world->stack.user = world->memory.stack.user;
world->stack.user += HYPERVISOR_STACK_USER_SIZE;
world->stack.user = (void*)((uintptr_t)world->stack.user & ~3);
return (world);
}
/* hypervisor_wswitch_create(): Create a new world */
struct hworld *hypervisor_wswitch_create(void)
{
@ -28,12 +75,7 @@ struct hworld *hypervisor_wswitch_create(void)
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);
return (hypervisor_wswitch_world_alloc());
}
/* void hypervisor_wswitch_destroy(): Destroy the world */
@ -68,6 +110,7 @@ int hypervisor_wswitch_queue_register(struct hworld *world)
return (-1);
world->private.next = hypervisor_world_queue;
hypervisor_world_queue = world;
world->private.status = HYPERVISOR_STATUS_INIT;
return (0);
}
@ -99,15 +142,14 @@ int hypervisor_wswitch_queue_unregister(struct hworld *target)
//---
// User API
//---
/* hypervisor_wswitch_check(): Check if a world switch is needed */
int hypervisor_wswitch_check(void)
{
//TODO: scan the KEYSC registers
}
/* hypervisor_wswitch(): Perform a world switch */
int hypervisor_wswitch(void)
int hypervisor_wswitch(struct hworld *world)
{
//TODO: display menu
//TODO: perform a world switch woth the next world context
if (world == NULL)
return (-1);
if (world->private.status != HYPERVISOR_STATUS_INIT)
return (-2);
hypervisor_install();
//hypervisor_kernel_world_yield(hypervisor_world, world);
return (0);
}