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:
parent
759a8bd876
commit
9ef129e788
|
@ -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__*/
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -34,4 +34,3 @@ void gint_switch(void (*function)(void))
|
|||
function();
|
||||
gint_switch_to_gint();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "fxBoot/hypervisor.h"
|
||||
#include "fxBoot/fs/smemfs.h"
|
||||
#include "fxBoot/elf.h"
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue