diff --git a/cpu/native/include/native_internal.h b/cpu/native/include/native_internal.h index 1829fe65c0..16e64e276a 100644 --- a/cpu/native/include/native_internal.h +++ b/cpu/native/include/native_internal.h @@ -237,7 +237,29 @@ extern ucontext_t *_native_isr_context; */ extern void _native_isr_leave(void); +/** + * @brief Makes ISR context so that execution continues at `func` when the context is applied + * + * @param func Function executed when `_native_isr_context` is applied + */ +static inline void _native_isr_context_make(void (*func)(void)) { + _native_isr_context->uc_stack.ss_sp = _isr_stack; + _native_isr_context->uc_stack.ss_size = sizeof(_isr_stack); + _native_isr_context->uc_stack.ss_flags = 0; + /* Create the ISR context, will execute _isr_schedule_and_switch */ + makecontext(_native_isr_context, func, 0); +} + +/** + * @brief Retrieves user context + * @returns `ucontext_t` + */ +static inline ucontext_t* _native_user_context(void) { + /* Use intermediate cast to uintptr_t to silence -Wcast-align. + * stacks are manually word aligned in thread_static_init() */ + return (ucontext_t *)(uintptr_t)thread_get_active()->sp; +} /** @} */ /* MARK: - Native Process State */ diff --git a/cpu/native/include/util/ucontext.h b/cpu/native/include/util/ucontext.h new file mode 100644 index 0000000000..5880dce198 --- /dev/null +++ b/cpu/native/include/util/ucontext.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2013 - 2016 Ludwig Knüpfer + * Copyright (C) 2025 carl-tud + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#ifndef UTIL_UCONTEXT_H +#define UTIL_UCONTEXT_H + +#if USE_LIBUCONTEXT +# include +#else +# include +#endif /* USE_LIBUCONTEXT */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup cpu_native + * @{ + */ + +/* MARK: - Context accessors */ +/** + * @name Context accessors + * @{ + */ + +/** + * @brief Retrieves function pointer generated during calls to `makecontext`/`setcontext`/`swapcontext` + * @param context `ucontext_t` + * @returns Function pointer (does not need to be start of a function, points to instruction) + */ +static inline uintptr_t _context_get_fptr(ucontext_t *context) { +# if defined(__FreeBSD__) /* FreeBSD */ + return (uintptr_t)((struct sigcontext *)context)->sc_eip; +# elif defined(__linux__) /* Linux */ +# if defined(__arm__) + return (uintptr_t)((ucontext_t *)context)->uc_mcontext.arm_pc; +# elif defined(__x86_64__) + return (uintptr_t)((ucontext_t *)context)->uc_mcontext.gregs[REG_RIP]; +# elif defined(__i386__) + return (uintptr_t)((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP]; +# else +# error "Unsupported Linux architecture" +# endif +# else +# error "Operating system unsupported" +# endif +} + +/** + * @brief Retrieves function pointer generated during calls to `makecontext`/`setcontext`/`swapcontext` + * @param context `ucontext_t` + * @param func Function pointer + */ +static inline void _context_set_fptr(ucontext_t *context, uintptr_t func) { +# if defined(__FreeBSD__) /* FreeBSD */ + ((struct sigcontext *)context)->sc_eip = (unsigned int)func; +# elif defined(__linux__) /* Linux */ +# if defined(__arm__) + ((ucontext_t *)context)->uc_mcontext.arm_lr = func; + ((ucontext_t *)context)->uc_mcontext.arm_pc = func; +# elif defined(__x86_64__) + ((ucontext_t *)context)->uc_mcontext.gregs[REG_RIP] = (greg_t)func; +# elif defined(__i386__) + ((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP] = func; +# else +# error "Unsupported Linux architecture" +# endif +# else +# error "Operating system unsupported" +# endif +} +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* UTIL_UCONTEXT_H */ diff --git a/cpu/native/irq_cpu.c b/cpu/native/irq_cpu.c index 27e05a24ba..b42d7d593f 100644 --- a/cpu/native/irq_cpu.c +++ b/cpu/native/irq_cpu.c @@ -323,36 +323,22 @@ void native_signal_action(int sig, siginfo_t *info, void *context) return; } - native_isr_context.uc_stack.ss_sp = __isr_stack; - native_isr_context.uc_stack.ss_size = sizeof(__isr_stack); - native_isr_context.uc_stack.ss_flags = 0; - makecontext(&native_isr_context, native_irq_handler, 0); - /* Use intermediate cast to uintptr_t to silence -Wcast-align. - * stacks are manually word aligned in thread_stack_init() */ - _native_cur_ctx = (ucontext_t *)(uintptr_t)thread_get_active()->sp; + /* We will switch to the ISR context with ISR stack */ + _native_isr_context_make(_native_call_sig_handlers_and_switch); + + /* Current user thread context */ + _native_current_context = _native_user_context(); DEBUG_IRQ("\n\n\t\tnative_signal_action: return to _native_sig_leave_tramp\n\n"); /* disable interrupts in context */ - isr_set_sigmask((ucontext_t *)context); + _set_sigmask((ucontext_t *)context); _native_in_isr = 1; -#if defined(__FreeBSD__) - _native_saved_eip = ((struct sigcontext *)context)->sc_eip; - ((struct sigcontext *)context)->sc_eip = (unsigned int)&_native_sig_leave_tramp; -#else /* Linux */ -#if defined(__arm__) - _native_saved_eip = ((ucontext_t *)context)->uc_mcontext.arm_pc; - ((ucontext_t *)context)->uc_mcontext.arm_pc = (unsigned int)&_native_sig_leave_tramp; -#else /* Linux/x86 */ - #ifdef __x86_64__ - _native_saved_eip = ((ucontext_t *)context)->uc_mcontext.gregs[REG_RIP]; - ((ucontext_t *)context)->uc_mcontext.gregs[REG_RIP] = (uintptr_t)&_native_sig_leave_tramp; - #else - //printf("\n\033[31mEIP:\t%p\ngo switching\n\n\033[0m", (void*)((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP]); - _native_saved_eip = ((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP]; - ((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP] = (unsigned int)&_native_sig_leave_tramp; - #endif -#endif -#endif + + /* Get PC/LR. This is where we will resume execution on the userspace thread. */ + _native_user_fptr = (uintptr_t)_context_get_fptr((ucontext_t *)context); + + /* Now we want to go to _native_sig_leave_tramp before resuming execution at _native_user_fptr. */ + _context_set_fptr(context, (uintptr_t)_native_sig_leave_tramp); } static void _set_signal_handler(int sig, bool add) @@ -487,10 +473,7 @@ void native_interrupt_init(void) err(EXIT_FAILURE, "native_interrupt_init: getcontext"); } - native_isr_context.uc_stack.ss_sp = __isr_stack; - native_isr_context.uc_stack.ss_size = sizeof(__isr_stack); - native_isr_context.uc_stack.ss_flags = 0; - _native_isr_ctx = &native_isr_context; + _native_isr_context_make(_native_call_sig_handlers_and_switch); static stack_t sigstk; sigstk.ss_sp = malloc(SIGSTKSZ); diff --git a/cpu/native/native_cpu.c b/cpu/native/native_cpu.c index ab070b595b..af243efd45 100644 --- a/cpu/native/native_cpu.c +++ b/cpu/native/native_cpu.c @@ -55,30 +55,6 @@ extern netdev_tap_t netdev_tap; static ucontext_t _end_context; -/** - * make the new context assign `_native_in_isr = 0` before resuming - */ -static void _native_mod_ctx_leave_sigh(ucontext_t *ctx) -{ -#if defined(__FreeBSD__) - _native_saved_eip = ((struct sigcontext *)ctx)->sc_eip; - ((struct sigcontext *)ctx)->sc_eip = (unsigned int)&_native_sig_leave_handler; -#else /* Linux */ -#if defined(__arm__) - _native_saved_eip = ((ucontext_t *)ctx)->uc_mcontext.arm_pc; - ((ucontext_t *)ctx)->uc_mcontext.arm_pc = (unsigned int)&_native_sig_leave_handler; -#else /* Linux/x86 */ - #ifdef __x86_64__ - _native_saved_eip = ctx->uc_mcontext.gregs[REG_RIP]; - ctx->uc_mcontext.gregs[REG_RIP] = (unsigned long)&_native_sig_leave_handler; - #else - _native_saved_eip = ctx->uc_mcontext.gregs[REG_EIP]; - ctx->uc_mcontext.gregs[REG_EIP] = (unsigned int)&_native_sig_leave_handler; - #endif -#endif -#endif -} - /** * TODO: implement */ diff --git a/cpu/native/syscalls.c b/cpu/native/syscalls.c index 34f9ff2d2a..222162b4a7 100644 --- a/cpu/native/syscalls.c +++ b/cpu/native/syscalls.c @@ -39,6 +39,7 @@ # include "time_units.h" # include "ztimer64.h" #endif + #include "stdio_base.h" #include "kernel_defines.h" @@ -80,15 +81,10 @@ void _native_syscall_leave(void) ) { _native_in_isr = 1; - /* Use intermediate cast to uintptr_t to silence -Wcast-align. - * stacks are manually word aligned in thread_static_init() */ - _native_cur_ctx = (ucontext_t *)(uintptr_t)thread_get_active()->sp; - native_isr_context.uc_stack.ss_sp = __isr_stack; - native_isr_context.uc_stack.ss_size = __isr_stack_size; - native_isr_context.uc_stack.ss_flags = 0; - native_interrupts_enabled = 0; - makecontext(&native_isr_context, native_irq_handler, 0); - if (swapcontext(_native_cur_ctx, &native_isr_context) == -1) { + _native_interrupts_enabled = false; + + _native_isr_context_make(_native_call_sig_handlers_and_switch); + if (swapcontext(_native_user_context(), _native_isr_context) == -1) { err(EXIT_FAILURE, "_native_syscall_leave: swapcontext"); } }