diff --git a/libsel4platsupport/src/common.c b/libsel4platsupport/src/common.c index 7eac97ef..d0fccd97 100644 --- a/libsel4platsupport/src/common.c +++ b/libsel4platsupport/src/common.c @@ -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 @@ -64,7 +73,7 @@ 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(); @@ -72,18 +81,18 @@ static void *__map_device_page(void *cookie, uintptr_t paddr, size_t size, 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(); @@ -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(); @@ -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(); } @@ -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. */ @@ -148,12 +159,12 @@ 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; } @@ -161,22 +172,21 @@ int platsupport_serial_setup_io_ops(ps_io_ops_t *io_ops) 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 */ @@ -184,39 +194,40 @@ int platsupport_serial_setup_bootinfo_failsafe(void) } 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; } @@ -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 */ @@ -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!"); @@ -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(); @@ -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();