vxKernel/src/hypervisor/table.c

120 lines
2.6 KiB
C

//---
// hypervisor:table - world allocator
//---
#include <vhex/hypervisor.h>
#include <string.h>
#include <stdlib.h>
/* internal world table */
static struct {
struct vhex_world *table;
size_t table_slot;
} hyp = {
.table = NULL,
.table_slot = 0
};
/* hypervisor_world_new() : create a new world with its name */
hyp_world_t hypervisor_world_new(char const * const restrict name, int flags)
{
struct vhex_driver *dtable;
hyp_world_t id;
/* try to find free world */
id = 0xb0cad0;
if (hyp.table != NULL) {
for (size_t i = 0; i < hyp.table_slot; ++i) {
if (HYP_WORLD_STATUS_STATE(hyp.table[i].status)
== HYP_WORLD_STATUS_STATE_UNUSED) {
id = i;
continue;
}
if (strcmp(hyp.table[i].name, name) == 0)
return (hyp_world_already_exists);
}
}
/* if no world is found, update the table */
if (id == 0xb0cad0) {
id = hyp.table_slot;
if (hyp.table_slot == 0)
hyp.table_slot = 1;
hyp.table = reallocarray(
hyp.table,
hyp.table_slot * 2,
sizeof(struct vhex_world)
);
for (size_t i = hyp.table_slot; i < hyp.table_slot * 2; ++i) {
hyp.table[i].status = HYP_WORLD_STATUS_STATE_UNUSED;
hyp.table[i].driver = NULL;
hyp.table[i].name = NULL;
}
hyp.table_slot = hyp.table_slot * 2;
}
/* initialize the world */
hyp.table[id].name = strdup(name);
hyp.table[id].status = HYP_WORLD_STATUS_SET(
flags,
HYP_WORLD_STATUS_STATE_UNINIT
);
if (hyp.table[id].driver == NULL) {
hyp.table[id].driver = malloc(
vhex_driver_count() * sizeof(*hyp.table[id].driver)
);
dtable = vhex_driver_table();
for (int i = 0; i < vhex_driver_count(); ++i) {
hyp.table[id].driver[i].context = malloc(
dtable[i].state_size
);
}
}
return (id);
}
/* hypervisor_world_find() : find a world using its name */
hyp_world_t hypervisor_world_find(char const * const restrict name)
{
if (hyp.table != NULL) {
for (size_t i = 0; i < hyp.table_slot; ++i) {
if (strcmp(hyp.table[i].name, name) == 0)
return (i);
}
}
return (hyp_world_not_found);
}
/* hypervisor_world_get() : get a word using its ID */
struct vhex_world *hypervisor_world_get(hyp_world_t id)
{
if (id < 0 || (size_t)id >= hyp.table_slot)
return (NULL);
if (HYP_WORLD_STATUS_STATE(hyp.table[id].status)
== HYP_WORLD_STATUS_STATE_UNUSED) {
return (NULL);
}
return (&hyp.table[id]);
}
/* hypervisor_world_delete() : remove world */
hyp_world_t hypervisor_world_delete(hyp_world_t id)
{
if (id < 0 || (size_t)id >= hyp.table_slot)
return (hyp_world_bad_id);
if (HYP_WORLD_STATUS_FLAGS(hyp.table[id].status)
== HYP_WORLD_STATUS_FLAG_UNDELETABLE) {
return (hyp_world_undeletable);
}
hyp.table[id].status = HYP_WORLD_STATUS_STATE_UNUSED;
}