diff --git a/os/sb/host/sb.h b/os/sb/host/sb.h index 67634b3cf..9f98d3f32 100644 --- a/os/sb/host/sb.h +++ b/os/sb/host/sb.h @@ -32,6 +32,8 @@ #include "vfs.h" #include "errcodes.h" +#include "sbhdr.h" + /*===========================================================================*/ /* Module constants. */ /*===========================================================================*/ @@ -154,6 +156,11 @@ /* Module data structures and types. */ /*===========================================================================*/ +/** + * @brief Type of a mask of Virtual IRQs. + */ +typedef uint32_t sb_vrqmask_t; + /** * @brief Type of a sandbox manager global structure. */ @@ -244,6 +251,10 @@ typedef struct { * @brief Thread running in the sandbox. */ thread_t *tp; + /** + * @brief Pointer to the image header. + */ + const sb_header_t *sbhp; #if (CH_CFG_USE_MESSAGES == TRUE) || defined(__DOXYGEN__) /** * @brief Thread sending a message to the sandbox. @@ -256,6 +267,20 @@ typedef struct { */ event_source_t es; #endif +#if (SB_CFG_ENABLE_VRQ == TRUE) || defined(__DOXYGEN__) + /** + * @brief Global virtual IRQ status register. + */ + uint32_t vrq_isr; + /** + * @brief Mask of enabled virtual IRQ flags. + */ + sb_vrqmask_t vrq_enmask; + /** + * @brief Mask of pending virtual IRQ flags. + */ + sb_vrqmask_t vrq_wtmask; +#endif #if (SB_CFG_ENABLE_VFS == TRUE) || defined(__DOXYGEN__) /** * @brief VFS bindings for Posix API. @@ -289,7 +314,6 @@ extern "C" { #include "sbelf.h" #include "sbposix.h" #include "sbapi.h" -#include "sbhdr.h" #include "sbhost.h" #endif /* SBHOST_H */ diff --git a/os/sb/host/sbapi.c b/os/sb/host/sbapi.c index 899579af6..c639351f2 100644 --- a/os/sb/host/sbapi.c +++ b/os/sb/host/sbapi.c @@ -71,6 +71,18 @@ static void sb_api_loadelf(struct port_extctx *ectxp); #define SB_SVC12_HANDLER sb_api_loadelf /** @} */ +/** + * @name Standard API handlers + * @{ + */ +#if (SB_CFG_ENABLE_VRQ == TRUE) || defined(__DOXYGEN__) +#define SB_SVC252_HANDLER sb_vrq_disable +#define SB_SVC253_HANDLER sb_vrq_enable +#define SB_SVC254_HANDLER sb_vrq_getisr +#define SB_SVC255_HANDLER sb_vrq_return +#endif +/** @} */ + #define __SVC(x) asm volatile ("svc " #x) /* @@ -958,7 +970,6 @@ static thread_t *sb_msg_wait_timeout_s(sysinterval_t timeout) { return tp; } - static void sb_cleanup(void) { #if SB_CFG_ENABLE_VFS == TRUE sb_class_t *sbp = (sb_class_t *)chThdGetSelfX()->ctx.syscall.p; diff --git a/os/sb/host/sbapi.h b/os/sb/host/sbapi.h index 0939208fb..3a3d5b137 100644 --- a/os/sb/host/sbapi.h +++ b/os/sb/host/sbapi.h @@ -60,7 +60,7 @@ typedef void (*port_syscall_t)(struct port_extctx *ectx); #ifdef __cplusplus extern "C" { #endif - + void __sb_abort(msg_t msg); #ifdef __cplusplus } #endif diff --git a/os/sb/host/sbhost.c b/os/sb/host/sbhost.c index 6aa2f0c2b..6d96a2114 100644 --- a/os/sb/host/sbhost.c +++ b/os/sb/host/sbhost.c @@ -25,6 +25,8 @@ * @{ */ +#include + #include "ch.h" #include "sb.h" @@ -194,14 +196,8 @@ size_t sb_check_strings_array(sb_class_t *sbp, const char *pp[], size_t max) { */ void sbObjectInit(sb_class_t *sbp, const sb_config_t *config) { + memset((void *)sbp, 0, sizeof (sb_class_t)); sbp->config = config; - sbp->tp = NULL; -#if CH_CFG_USE_MESSAGES == TRUE - sbp->msg_tp = NULL; -#endif -#if CH_CFG_USE_EVENTS == TRUE - chEvtObjectInit(&sbp->es); -#endif } /** @@ -221,29 +217,28 @@ thread_t *sbStartThread(sb_class_t *sbp, const char *name, void *wsp, size_t size, tprio_t prio, const char *argv[], const char *envp[]) { thread_t *utp; - const sb_header_t *sbhp; const sb_config_t *config = sbp->config; void *usp, *uargv, *uenvp; size_t envsize, argsize, parsize; int uargc, uenvc; /* Header location.*/ - sbhp = (const sb_header_t *)(void *)config->regions[config->code_region].area.base; + sbp->sbhp = (const sb_header_t *)(void *)config->regions[config->code_region].area.base; /* Checking header magic numbers.*/ - if ((sbhp->hdr_magic1 != SB_HDR_MAGIC1) || - (sbhp->hdr_magic2 != SB_HDR_MAGIC2)) { + if ((sbp->sbhp->hdr_magic1 != SB_HDR_MAGIC1) || + (sbp->sbhp->hdr_magic2 != SB_HDR_MAGIC2)) { return NULL; } /* Checking header size and alignment.*/ - if (sbhp->hdr_size != sizeof (sb_header_t)) { + if (sbp->sbhp->hdr_size != sizeof (sb_header_t)) { return NULL; } /* Checking header entry point.*/ if (!chMemIsSpaceWithinX(&config->regions[config->code_region].area, - (const void *)sbhp->hdr_entry, + (const void *)sbp->sbhp->hdr_entry, (size_t)2)) { return NULL; } @@ -290,7 +285,7 @@ thread_t *sbStartThread(sb_class_t *sbp, const char *name, .wbase = (stkalign_t *)wsp, .wend = (stkalign_t *)wsp + (size / sizeof (stkalign_t)), .prio = prio, - .u_pc = sbhp->hdr_entry, + .u_pc = sbp->sbhp->hdr_entry, .u_psp = (uint32_t)usp, .arg = (void *)sbp }; @@ -303,7 +298,7 @@ thread_t *sbStartThread(sb_class_t *sbp, const char *name, utp = chThdCreateUnprivileged(&utd); /* For messages exchange.*/ - sbp->tp = utp; + sbp->tp = utp; return utp; } @@ -345,7 +340,6 @@ msg_t sbExec(sb_class_t *sbp, const char *pathname, const char *argv[], const char *envp[]) { const sb_config_t *config = sbp->config; memory_area_t ma = config->regions[0].area; - const sb_header_t *sbhp; msg_t ret; void *usp, *uargv, *uenvp; size_t envsize, argsize, parsize; @@ -396,21 +390,21 @@ msg_t sbExec(sb_class_t *sbp, const char *pathname, CH_RETURN_ON_ERROR(ret); /* Header location.*/ - sbhp = (const sb_header_t *)(void *)ma.base; + sbp->sbhp = (const sb_header_t *)(void *)ma.base; /* Checking header magic numbers.*/ - if ((sbhp->hdr_magic1 != SB_HDR_MAGIC1) || - (sbhp->hdr_magic2 != SB_HDR_MAGIC2)) { + if ((sbp->sbhp->hdr_magic1 != SB_HDR_MAGIC1) || + (sbp->sbhp->hdr_magic2 != SB_HDR_MAGIC2)) { return CH_RET_ENOEXEC; } /* Checking header size.*/ - if (sbhp->hdr_size != sizeof (sb_header_t)) { + if (sbp->sbhp->hdr_size != sizeof (sb_header_t)) { return CH_RET_ENOEXEC; } /* Checking header entry point.*/ - if (!chMemIsSpaceWithinX(&ma, (const void *)sbhp->hdr_entry, (size_t)2)) { + if (!chMemIsSpaceWithinX(&ma, (const void *)sbp->sbhp->hdr_entry, (size_t)2)) { return CH_RET_EFAULT; } @@ -420,7 +414,7 @@ msg_t sbExec(sb_class_t *sbp, const char *pathname, .wbase = (stkalign_t *)wsp, .wend = (stkalign_t *)wsp + (size / sizeof (stkalign_t)), .prio = prio, - .u_pc = sbhp->hdr_entry, + .u_pc = sbp->sbhp->hdr_entry, .u_psp = (uint32_t)usp, .arg = (void *)sbp }; diff --git a/os/sb/host/sbvrq.c b/os/sb/host/sbvrq.c index 0c384616d..33031b739 100644 --- a/os/sb/host/sbvrq.c +++ b/os/sb/host/sbvrq.c @@ -51,55 +51,157 @@ /* Module local functions. */ /*===========================================================================*/ +__STATIC_FORCEINLINE void vfq_makectx(sb_class_t *sbp, + struct port_extctx *ectxp, + uint32_t active_mask) { + uint32_t irqn = __CLZ(active_mask); + sbp->vrq_wtmask &= ~(1U << irqn); + + /* Building the return context.*/ + ectxp->r0 = irqn; + ectxp->pc = sbp->sbhp->hdr_vfq; /* TODO validate or let it eventually crash? */ + ectxp->xpsr = 0x01000000U; +#if CORTEX_USE_FPU == TRUE + ectxp->fpscr = FPU->FPDSCR; +#endif +} + /*===========================================================================*/ /* Module exported functions. */ /*===========================================================================*/ /** - * @brief Activates VRQs on the specified sandbox. + * @brief Triggers VRQs on the specified sandbox. + * @note This function must be called from IRQ context because + * it manipulates exception stack frames. * * @param[in] sbp pointer to a @p sb_class_t structure * @param[in] vmask mask of VRQs to be activated * @return The operation status. * @retval false if the activation has succeeded. * @retval true in case of sandbox stack overflow. + * + * @special */ -bool sbVRQSignalMaskI(sb_class_t *sbp, sb_vrqmask_t vmask) { +bool sbVRQTriggerFromISR(sb_class_t *sbp, sb_vrqmask_t vmask) { struct port_extctx *ectxp; - const sb_header_t *sbhp; - /* This IRQ could have preempted the sandbox itself or some other thread, - handling is different.*/ - if (sbp->tp->state == CH_STATE_CURRENT) { - /* Sandbox case, getting the current exception frame.*/ - ectxp = (struct port_extctx *)__get_PSP() - 1; + chSysLockFromISR(); - /* Checking if the new frame is within the sandbox else failure.*/ - if (!sb_is_valid_write_range(sbp, - (void *)ectxp, - sizeof (struct port_extctx))) { - return true; + /* Adding VRQ mask to the pending mask.*/ + sbp->vrq_wtmask |= vmask; + + /* Triggering the VRQ if required.*/ + if (sbp->vrq_isr == 0U) { + sb_vrqmask_t active_mask = sbp->vrq_wtmask & sbp->vrq_enmask; + + if (active_mask != 0U) { + + /* This IRQ could have preempted the sandbox itself or some other thread, + handling is different.*/ + if (sbp->tp->state == CH_STATE_CURRENT) { + /* Sandbox case, getting the current exception frame.*/ + ectxp = (struct port_extctx *)__get_PSP() - 1; + + /* Checking if the new frame is within the sandbox else failure.*/ + if (!sb_is_valid_write_range(sbp, + (void *)ectxp, + sizeof (struct port_extctx))) { + chSysUnlockFromISR(); + + return true; + } + } + else { + ectxp = sbp->tp->ctx.sp - 1; + + /* Checking if the new frame is within the sandbox else failure.*/ + if (!sb_is_valid_write_range(sbp, + (void *)ectxp, + sizeof (struct port_extctx))) { + chSysUnlockFromISR(); + + return true; + } + + /* Preventing leakage of information, clearing all register values, those + would come from outside the sandbox.*/ + memset((void *)ectxp, 0, sizeof (struct port_extctx)); + } + + /* Building the return context.*/ + vfq_makectx(sbp, ectxp, active_mask); + } + } + + chSysUnlockFromISR(); + + return false; +} + +void sb_vrq_disable(struct port_extctx *ectxp) { + sb_class_t *sbp = (sb_class_t *)chThdGetSelfX()->ctx.syscall.p; + + ectxp->r0 = sbp->vrq_isr; + sbp->vrq_isr |= SB_VRQ_ISR_DISABLED; +} + +void sb_vrq_enable(struct port_extctx *ectxp) { + sb_class_t *sbp = (sb_class_t *)chThdGetSelfX()->ctx.syscall.p; + + ectxp->r0 = sbp->vrq_isr; + sbp->vrq_isr &= ~SB_VRQ_ISR_DISABLED; + + /* Re-triggering the VRQ if required.*/ + if (sbp->vrq_isr == 0U) { + sb_vrqmask_t active_mask = sbp->vrq_wtmask & sbp->vrq_enmask; + + if (active_mask != 0U) { + /* Creating a context for return.*/ + ectxp--; + + /* Checking if the new frame is within the sandbox else failure.*/ + if (!sb_is_valid_write_range(sbp, + (void *)ectxp, + sizeof (struct port_extctx))) { + __sb_abort(CH_RET_EFAULT); + } + + /* Building the return context.*/ + vfq_makectx(sbp, ectxp, active_mask); + } + } +} + +void sb_vrq_getisr(struct port_extctx *ectxp) { + sb_class_t *sbp = (sb_class_t *)chThdGetSelfX()->ctx.syscall.p; + + ectxp->r0 = sbp->vrq_isr; +} + +void sb_vrq_return(struct port_extctx *ectxp) { + sb_class_t *sbp = (sb_class_t *)chThdGetSelfX()->ctx.syscall.p; + + if (((sbp->vrq_isr & SB_VRQ_ISR_IRQMODE) == 0U)) { + __sb_abort(CH_RET_EFAULT); + } + + /* Re-triggering the VRQ if required.*/ + if (sbp->vrq_isr == 0U) { + sb_vrqmask_t active_mask = sbp->vrq_wtmask & sbp->vrq_enmask; + + if (active_mask != 0U) { + /* Building the return context, reusing the current context structure.*/ + vfq_makectx(sbp, ectxp, active_mask); } } else { - ectxp = sbp->tp->ctx.sp - 1; + /* Ending IRQ mode.*/ + sbp->vrq_isr &= ~SB_VRQ_ISR_IRQMODE; - /* Checking if the new frame is within the sandbox else failure.*/ - if (!sb_is_valid_write_range(sbp, - (void *)ectxp, - sizeof (struct port_extctx))) { - return true; - } - - /* Preventing leakage of information, clearing all register values, those - would come from outside the sandbox.*/ - memset((void *)ectxp, 0, sizeof (struct port_extctx)); + /* Discarding the return current context, returning on the previous one.*/ + ectxp++; } - - /* Header location.*/ - sbhp = (const sb_header_t *)(void *)sbp->config->regions[sbp->config->code_region].area.base; - - return false; } #endif /* SB_CFG_ENABLE_VRQ == TRUE */ diff --git a/os/sb/host/sbvrq.h b/os/sb/host/sbvrq.h index 4dc73e4ad..2d4d6d16d 100644 --- a/os/sb/host/sbvrq.h +++ b/os/sb/host/sbvrq.h @@ -34,6 +34,14 @@ /* Module constants. */ /*===========================================================================*/ +/** + * @name Virtual ISR register bit definitions + * @{ + */ +#define SB_VRQ_ISR_DISABLED 1U +#define SB_VRQ_ISR_IRQMODE 2U +/** @} */ + /*===========================================================================*/ /* Module pre-compile time settings. */ /*===========================================================================*/ @@ -46,11 +54,6 @@ /* Module data structures and types. */ /*===========================================================================*/ -/** - * @brief Type of a mask of Virtual IRQs. - */ -typedef uint32_t sb_vrqmask_t; - /*===========================================================================*/ /* Module macros. */ /*===========================================================================*/ @@ -62,7 +65,11 @@ typedef uint32_t sb_vrqmask_t; #ifdef __cplusplus extern "C" { #endif - bool sbVRQSignalMaskI(sb_class_t *sbp, sb_vrqmask_t vmask); + bool sbVRQTriggerFromISR(sb_class_t *sbp, sb_vrqmask_t vmask); + void sb_vrq_disable(struct port_extctx *ectxp); + void sb_vrq_enable(struct port_extctx *ectxp); + void sb_vrq_getisr(struct port_extctx *ectxp); + void sb_vrq_return(struct port_extctx *ectxp); #ifdef __cplusplus } #endif