fxBoot/src/hypervisor/wswitch.c

166 lines
4.6 KiB
C

//---
// hypervisor:wsiwtch - hypervisor world switch
//---
#include "fxBoot/hypervisor.h"
#include "fxBoot/terminal.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;
extern struct hworld *hypervisor_world_current;
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);
world->context.cpu.reg[15] = (uintptr_t)world->stack.user;
return (world);
}
/* 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);
}
return (hypervisor_wswitch_world_alloc());
}
/* 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;
world->private.status = HYPERVISOR_STATUS_INIT;
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
//---
/* hypervisor_wswitch(): Perform a world switch */
int hypervisor_wswitch(struct hworld *world)
{
if (world == NULL)
return (-1);
if (world->private.status != HYPERVISOR_STATUS_INIT)
return (-2);
int retval;
hypervisor_install();
tracer_set_session(world->private.debug.tracer);
terminal_error("world switch to:\ncurr: %p\nnext: %p\n",
hypervisor_world_current, world);
__asm__ volatile (
"mov %0, r4;"
"trapa #0;"
"mov r0, %0;"
: "=r"(retval) : "r"(world) : "r4", "r0");
return (retval);
}