Skip to content

Commit

Permalink
libsel4platsupport: add global context
Browse files Browse the repository at this point in the history
Signed-off-by: Axel Heider <axelheider@gmx.de>
  • Loading branch information
axel-h committed Apr 4, 2024
1 parent f56797b commit 9cf8949
Showing 1 changed file with 60 additions and 49 deletions.
109 changes: 60 additions & 49 deletions libsel4platsupport/src/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,28 @@ enum serial_setup_status {
START_FAILSAFE_SETUP,
SETUP_COMPLETE
};
static enum serial_setup_status setup_status = NOT_INITIALIZED;

typedef struct {
enum serial_setup_status setup_status;
#ifndef USE_DEBUG_PUTCHAR
seL4_CPtr device_cap;
vspace_t *vspace;
simple_t *simple;
vka_t *vka;
#endif /* not USE_DEBUG_PUTCHAR */
} ctx_t;

/* Some globals for tracking initialisation variables. This is currently just to avoid
* passing parameters down to the platform code for backwards compatibility reasons. This
* is strictly to avoid refactoring all existing platform code */
static vspace_t *vspace = NULL;
static UNUSED simple_t *simple = NULL;
static vka_t *vka = NULL;
static ctx_t ctx = {
.setup_status = NOT_INITIALIZED
};

/* To keep failsafe setup we need actual memory for a simple and a vka */
static simple_t _simple_mem;
static vka_t _vka_mem;
static seL4_CPtr device_cap = 0;

extern char __executable_start[];

#ifndef USE_DEBUG_PUTCHAR
Expand All @@ -64,26 +73,26 @@ static void *__map_device_page(void *cookie, uintptr_t paddr, size_t size,
{
seL4_Error err;

if (0 != device_cap) {
if (0 != ctx.device_cap) {
/* we only support a single page for the serial device. */
abort();
UNREACHABLE();
}

vka_object_t dest;
int bits = CTZ(size);
err = sel4platsupport_alloc_frame_at(vka, paddr, bits, &dest);
err = sel4platsupport_alloc_frame_at(ctx.vka, paddr, bits, &dest);
if (err) {
ZF_LOGE("Failed to get cap for serial device frame");
abort();
UNREACHABLE();
}

device_cap = dest.cptr;
ctx.device_cap = dest.cptr;

if ((setup_status == START_REGULAR_SETUP) && vspace) {
if ((ctx.setup_status == START_REGULAR_SETUP) && ctx.vspace) {
/* map device page regularly */
void *vaddr = vspace_map_pages(vspace, &dest.cptr, NULL, seL4_AllRights, 1, bits, 0);
void *vaddr = vspace_map_pages(ctx.vspace, &dest.cptr, NULL, seL4_AllRights, 1, bits, 0);
if (!vaddr) {
ZF_LOGE("Failed to map serial device");
abort();
Expand All @@ -96,10 +105,10 @@ static void *__map_device_page(void *cookie, uintptr_t paddr, size_t size,
* an error. Find a properly aligned virtual address and try to map the
* device cap there.
*/
if ((setup_status == START_FAILSAFE_SETUP) || !vspace) {
if ((ctx.setup_status == START_FAILSAFE_SETUP) || !ctx.vspace) {
seL4_Word header_start = (seL4_Word)__executable_start - PAGE_SIZE_4K;
seL4_Word vaddr = (header_start - BIT(bits)) & ~(BIT(bits) - 1);
err = seL4_ARCH_Page_Map(device_cap, seL4_CapInitThreadPD, vaddr, seL4_AllRights, 0);
err = seL4_ARCH_Page_Map(ctx.device_cap, seL4_CapInitThreadPD, vaddr, seL4_AllRights, 0);
if (err) {
ZF_LOGE("Failed to map serial device in failsafe mode");
abort();
Expand All @@ -108,7 +117,7 @@ static void *__map_device_page(void *cookie, uintptr_t paddr, size_t size,
return (void *)vaddr;
}

ZF_LOGE("invalid setup state %d", setup_status);
ZF_LOGE("invalid setup state %d", ctx.setup_status);
abort();
}

Expand All @@ -128,16 +137,18 @@ static ps_io_ops_t io_ops = {
void platsupport_undo_serial_setup(void)
{
/* Re-initialise some structures. */
setup_status = NOT_INITIALIZED;
if (device_cap) {
ctx.setup_status = NOT_INITIALIZED;
#ifndef USE_DEBUG_PUTCHAR
if (ctx.device_cap) {
cspacepath_t path;
seL4_ARCH_Page_Unmap(device_cap);
vka_cspace_make_path(vka, device_cap, &path);
seL4_ARCH_Page_Unmap(ctx.device_cap);
vka_cspace_make_path(ctx.vka, ctx.device_cap, &path);
vka_cnode_delete(&path);
vka_cspace_free(vka, device_cap);
device_cap = 0;
vka_cspace_free(ctx.vka, ctx.device_cap);
ctx.device_cap = 0;
}
vka = NULL;
ctx.vka = NULL;
#endif /* not USE_DEBUG_PUTCHAR */
}

/* Initialise serial input interrupt. */
Expand All @@ -148,75 +159,75 @@ void platsupport_serial_input_init_IRQ(void)
int platsupport_serial_setup_io_ops(ps_io_ops_t *io_ops)
{
int err = 0;
if (setup_status == SETUP_COMPLETE) {
if (ctx.setup_status == SETUP_COMPLETE) {
return 0;
}
err = __plat_serial_init(io_ops);
if (!err) {
setup_status = SETUP_COMPLETE;
ctx.setup_status = SETUP_COMPLETE;
}
return err;
}

int platsupport_serial_setup_bootinfo_failsafe(void)
{
int err = 0;
if (setup_status == SETUP_COMPLETE) {
if (ctx.setup_status == SETUP_COMPLETE) {
return 0;
}
memset(&_simple_mem, 0, sizeof(simple_t));
memset(&_vka_mem, 0, sizeof(vka_t));
#ifdef USE_DEBUG_PUTCHAR
/* only support putchar on a debug kernel */
setup_status = SETUP_COMPLETE;
ctx.setup_status = SETUP_COMPLETE;
#else /* not USE_DEBUG_PUTCHAR */
setup_status = START_FAILSAFE_SETUP;
ctx.setup_status = START_FAILSAFE_SETUP;
simple_default_init_bootinfo(&_simple_mem, platsupport_get_bootinfo());
simple = &_simple_mem;
vka = &_vka_mem;
simple_make_vka(simple, vka);
ctx.vka = &_vka_mem;
simple_make_vka(&_simple_mem, ctx.vka);
#ifdef CONFIG_ARCH_X86
sel4platsupport_get_io_port_ops(&io_ops.io_port_ops, simple, vka);
sel4platsupport_get_io_port_ops(&io_ops.io_port_ops, &_simple_mem, ctx.vka);
#endif
err = platsupport_serial_setup_io_ops(&io_ops);
#endif /* [not] USE_DEBUG_PUTCHAR */
return err;
}

int platsupport_serial_setup_simple(
vspace_t *_vspace __attribute__((unused)),
simple_t *_simple __attribute__((unused)),
vka_t *_vka __attribute__((unused)))
vspace_t *vspace __attribute__((unused)),
simple_t *simple __attribute__((unused)),
vka_t *vka __attribute__((unused)))
{
int err = 0;
switch (setup_status) {
switch (ctx.setup_status) {
case SETUP_COMPLETE:
return 0;
case NOT_INITIALIZED:
break; /* continue below */
default:
ZF_LOGE("Trying to initialise a partially initialised serial. Current setup status is %d\n", setup_status);
ZF_LOGE("Trying to initialise a partially initialised serial. Current setup status is %d\n", ctx.setup_status);
assert(!"You cannot recover");
return -1;
}

#ifdef USE_DEBUG_PUTCHAR
/* only support putchar on a debug kernel */
setup_status = SETUP_COMPLETE;
ctx.setup_status = SETUP_COMPLETE;
#else /* not USE_DEBUG_PUTCHAR */
/* start setup */
setup_status = START_REGULAR_SETUP;
vspace = _vspace;
simple = _simple;
vka = _vka;
ctx.setup_status = START_REGULAR_SETUP;
ctx.vspace = vspace;
ctx.simple = simple;
ctx.vka = vka;
#ifdef CONFIG_ARCH_X86
sel4platsupport_get_io_port_ops(&io_ops.io_port_ops, simple, vka);
sel4platsupport_get_io_port_ops(&io_ops.io_port_ops, ctx.simple, ctx.vka);
#endif
err = platsupport_serial_setup_io_ops(&io_ops);
/* done */
vspace = NULL;
simple = NULL;
/* Don't reset vka here */
/* setup done. We still need vka in platsupport_undo_serial_setup(), the
* rest can be cleared
*/
ctx.vspace = NULL;
ctx.simple = NULL;
#endif /* [not] USE_DEBUG_PUTCHAR */
return err;
}
Expand All @@ -226,7 +237,7 @@ int platsupport_serial_setup_simple(
*/
static int fallback_serial_setup()
{
switch (setup_status) {
switch (ctx.setup_status) {

case SETUP_COMPLETE:
return 0; /* we don't except to be called in thi state */
Expand All @@ -240,12 +251,12 @@ static int fallback_serial_setup()
}

#ifdef CONFIG_LIB_SEL4_PLAT_SUPPORT_USE_SEL4_DEBUG_PUTCHAR
setup_status = SETUP_COMPLETE;
ctx.setup_status = SETUP_COMPLETE;
ZF_LOGI("using kernel syscalls for char I/O");
#else /* not CONFIG_LIB_SEL4_PLAT_SUPPORT_USE_SEL4_DEBUG_PUTCHAR */
/* Attempt failsafe initialization to be able to print something. */
int err = platsupport_serial_setup_bootinfo_failsafe();
if (err || (START_REGULAR_SETUP != setup_status)) {
if (err || (START_REGULAR_SETUP != ctx.setup_status)) {
/* Setup failed, so printing an error may not output anything. */
ZF_LOGE("You attempted to print before initialising the"
" libsel4platsupport serial device!");
Expand All @@ -269,7 +280,7 @@ static int fallback_serial_setup()

void LIBSEL4_IO __arch_putchar(int c)
{
if (setup_status != SETUP_COMPLETE) {
if (ctx.setup_status != SETUP_COMPLETE) {
if (0 != fallback_serial_setup()) {
abort(); /* ToDo: hopefully this does not print anything */
UNREACHABLE();
Expand All @@ -288,7 +299,7 @@ size_t LIBSEL4_IO __arch_write(char *data, size_t count)

int __arch_getchar(void)
{
if (setup_status != SETUP_COMPLETE) {
if (ctx.setup_status != SETUP_COMPLETE) {
if (0 != fallback_serial_setup()) {
abort(); /* ToDo: hopefully this does not print anything */
UNREACHABLE();
Expand Down

0 comments on commit 9cf8949

Please sign in to comment.