From c6553f64922e72eba8ab6f68b218a49af8970edf Mon Sep 17 00:00:00 2001 From: Ludwig Ortmann Date: Tue, 14 May 2013 18:31:47 +0200 Subject: [PATCH] interrupt handling rewrite (including uart0 integration, rt-extension removal) --- Makefile.base | 12 +- core/include/thread.h | 2 + cpu/native/hwtimer_cpu.c | 6 + cpu/native/include/cpu-conf.h | 3 +- cpu/native/include/cpu.h | 7 +- cpu/native/irq_cpu.c | 224 +++++++++++++++++++--------------- cpu/native/lpm_cpu.c | 43 ++++++- cpu/native/native_cpu.c | 34 ++---- cpu/native/tramp.S | 29 +++++ 9 files changed, 231 insertions(+), 129 deletions(-) create mode 100644 cpu/native/tramp.S diff --git a/Makefile.base b/Makefile.base index 8419c511af1c..392c07bafb23 100644 --- a/Makefile.base +++ b/Makefile.base @@ -1,5 +1,8 @@ ASMSRC = $(wildcard *.s) +ASSMSRC = $(wildcard *.S) ASMOBJ = $(ASMSRC:%.s=$(BINDIR)%.o) +ASMOBJ += $(ASSMSRC:%.S=$(BINDIR)%.o) + SRC = $(wildcard *.c) OBJ = $(SRC:%.c=$(BINDIR)%.o) DEP = $(SRC:%.c=$(BINDIR)%.d) @@ -7,8 +10,8 @@ DEP = $(SRC:%.c=$(BINDIR)%.d) include $(RIOTCPU)/Makefile.base include $(RIOTBOARD)/Makefile.base -$(BINDIR)$(MODULE).a: $(OBJ) $(ASMOBJ) - $(AR) -rc $(BINDIR)$(MODULE).a $(OBJ) $(ASMOBJ) +$(BINDIR)$(MODULE).a: $(OBJ) $(ASMOBJ) $(ASSMOBJ) + $(AR) -rc $(BINDIR)$(MODULE).a $(OBJ) $(ASMOBJ) $(ASSMOBJ) # pull in dependency info for *existing* .o files -include $(OBJ:.o=.d) @@ -22,7 +25,10 @@ $(BINDIR)%.o: %.c $(BINDIR)%.o: %.s @$(AS) $(ASFLAGS) $*.s -o $(BINDIR)$*.o +$(BINDIR)%.o: %.S + @gcc -c -m32 $*.S -o $(BINDIR)$*.o + # remove compilation products clean:: - rm -f $(BINDIR)$(MODULE).a $(OBJ) $(DEP) $(ASMOBJ) + rm -f $(BINDIR)$(MODULE).a $(OBJ) $(DEP) $(ASMOBJ) $(ASSMOBJ) diff --git a/core/include/thread.h b/core/include/thread.h index f4cb0bad5e1e..5e2e181b1742 100644 --- a/core/include/thread.h +++ b/core/include/thread.h @@ -17,7 +17,9 @@ #include /** Minimum stack size */ +#ifndef MINIMUM_STACK_SIZE #define MINIMUM_STACK_SIZE (sizeof(tcb_t)) +#endif /** * @brief Creates a new thread. diff --git a/cpu/native/hwtimer_cpu.c b/cpu/native/hwtimer_cpu.c index 608304d90a0d..bda90b6b5e4e 100644 --- a/cpu/native/hwtimer_cpu.c +++ b/cpu/native/hwtimer_cpu.c @@ -34,6 +34,8 @@ #include "debug.h" +#define HWTIMERMINOFFSET 1000 + static unsigned long native_hwtimer_now; static int native_hwtimer_irq[ARCH_MAXTIMERS]; @@ -172,6 +174,10 @@ void hwtimer_arch_unset(short timer) void hwtimer_arch_set(unsigned long offset, short timer) { DEBUG("hwtimer_arch_set(%li, %i)\n", offset, timer); + if (offset < HWTIMERMINOFFSET) { + offset = HWTIMERMINOFFSET; + DEBUG("hwtimer_arch_set: offset < MIN, set to: %i\n", offset); + } native_hwtimer_irq[timer] = 1; native_hwtimer_isset[timer] = 1; diff --git a/cpu/native/include/cpu-conf.h b/cpu/native/include/cpu-conf.h index f83318f58296..6156b05d94df 100644 --- a/cpu/native/include/cpu-conf.h +++ b/cpu/native/include/cpu-conf.h @@ -18,9 +18,10 @@ /* TODO: choose more sensibly? */ #define KERNEL_CONF_STACKSIZE_DEFAULT (16384) -#define KERNEL_CONF_STACKSIZE_IDLE (4096) +#define KERNEL_CONF_STACKSIZE_IDLE (16384) #define NATIVE_ISR_STACKSIZE (16384) #define TRANSCEIVER_STACK_SIZE (16384) +#define MINIMUM_STACK_SIZE (1024) /* for cc110x_ng */ #define RX_BUF_SIZE (10) diff --git a/cpu/native/include/cpu.h b/cpu/native/include/cpu.h index 0d64a967d35b..ad29479cf899 100644 --- a/cpu/native/include/cpu.h +++ b/cpu/native/include/cpu.h @@ -46,6 +46,11 @@ int unregister_interrupt(int sig); /* this should be defined elsewhere */ void thread_yield(void); -extern volatile ucontext_t *interrupted_contexts[MAXTHREADS]; +extern void _native_sig_leave_tramp(void); +extern ucontext_t *_native_cur_ctx, *_native_isr_ctx; +extern unsigned int _native_saved_eip; +extern int _native_in_isr; +extern int _native_in_syscall; +extern int _native_sigpend; /** @} */ #endif //_CPU_H diff --git a/cpu/native/irq_cpu.c b/cpu/native/irq_cpu.c index 0defac294998..70bc44054e22 100644 --- a/cpu/native/irq_cpu.c +++ b/cpu/native/irq_cpu.c @@ -1,9 +1,6 @@ /** * Native CPU irq.h implementation * - * uses POSIX real-time extension signals to create interrupts - * TODO: needs to be rewritten for better portability - * * Copyright (C) 2013 Ludwig Ortmann * * This file subject to the terms and conditions of the GNU General Public @@ -15,29 +12,41 @@ * @file * @author Ludwig Ortmann */ -#include #include +#include +#include + +// __USE_GNU for gregs[REG_EIP] access +#define __USE_GNU +#include +#undef __USE_GNU -#include +#include "irq.h" #include "cpu.h" #include "debug.h" static int native_interrupts_enabled; -static int native_in_irs; -static int last_sig; -static ucontext_t native_context; +int _native_sigpend; +int _native_in_isr; +int _native_in_syscall; +static ucontext_t native_isr_context; static sigset_t native_sig_set; static char __isr_stack[SIGSTKSZ]; extern volatile tcb_t *active_thread; +unsigned int _native_saved_eip; +ucontext_t *_native_cur_ctx, *_native_isr_ctx; +int _native_in_isr; + +static int pipefd[2]; + struct int_handler_t { void (*func)(void); }; static struct int_handler_t native_irq_handlers[255]; - -volatile ucontext_t *interrupted_contexts[MAXTHREADS]; +char sigalt_stk[SIGSTKSZ]; void print_thread_sigmask(ucontext_t *cp) { @@ -113,6 +122,7 @@ unsigned disableIRQ(void) unsigned int prev_state; sigset_t mask; + _native_in_syscall = 1; DEBUG("disableIRQ()\n"); if (sigfillset(&mask) == -1) { @@ -132,6 +142,16 @@ unsigned disableIRQ(void) } prev_state = native_interrupts_enabled; native_interrupts_enabled = 0; + if (_native_sigpend > 0) { + DEBUG("\n\n\t\treturn from syscall, calling native_irq_handler\n\n"); + _native_in_syscall = 0; + printf("calling swapcontext()\n"); + swapcontext(_native_cur_ctx, _native_isr_ctx); + } + else { + _native_in_syscall = 0; + } + DEBUG("disableIRQ(): return\n"); return prev_state; } @@ -143,6 +163,7 @@ unsigned enableIRQ(void) { unsigned int prev_state; + _native_in_syscall = 1; DEBUG("enableIRQ()\n"); if (sigprocmask(SIG_SETMASK, &native_sig_set, NULL) == -1) { @@ -153,6 +174,16 @@ unsigned enableIRQ(void) //print_sigmasks(); //native_print_signals(); + if (_native_sigpend > 0) { + DEBUG("\n\n\t\treturn from syscall, calling native_irq_handler\n\n"); + _native_in_syscall = 0; + printf("calling swapcontext()\n"); + swapcontext(_native_cur_ctx, _native_isr_ctx); + } + else { + _native_in_syscall = 0; + } + DEBUG("enableIRQ(): return\n"); return prev_state; } @@ -172,8 +203,8 @@ void restoreIRQ(unsigned state) int inISR(void) { - DEBUG("inISR()\n"); - return native_in_irs; + DEBUG("inISR(): %i\n", _native_in_isr); + return _native_in_isr; } @@ -187,104 +218,86 @@ void eINT(void) enableIRQ(); } +int _native_popsig(void) +{ + int nread, nleft, i; + int sig; + + nleft = sizeof(int); + i = 0; + while ((nleft>0) && ((nread = read(pipefd[0], &sig + i, nleft)) != -1)) { + i += nread; + nleft -= nread; + } + if (nread == -1) { + err(1, "_native_popsig(): read()"); + } + + return sig; +} + /** - * call signal handler, + * call signal handlers, * restore user context */ void native_irq_handler() { - if (last_sig == -1) { - errx(1, "XXX: internal error"); - } - if (native_irq_handlers[last_sig].func != NULL) { - DEBUG("calling interrupt handler for %i\n", last_sig); - native_irq_handlers[last_sig].func(); - } - else if (last_sig == SIGUSR1) { - DEBUG("ignoring SIGUSR1\n"); - } - else { - printf("XXX: no handler for signal %i\n", last_sig); - errx(1, "XXX: this should not have happened!\n"); + int sig; + + DEBUG("\n\n\t\tnative_irq_handler\n\n"); + while (_native_sigpend > 0) { + + sig = _native_popsig(); + _native_sigpend--; + + if (native_irq_handlers[sig].func != NULL) { + DEBUG("calling interrupt handler for %i\n", sig); + native_irq_handlers[sig].func(); + } + else if (sig == SIGUSR1) { + DEBUG("ignoring SIGUSR1\n"); + } + else { + printf("XXX: no handler for signal %i\n", sig); + errx(1, "XXX: this should not have happened!\n"); + } } - last_sig = -1; - native_in_irs = 0; + DEBUG("native_irq_handler(): return"); + _native_in_isr = 0; cpu_switch_context_exit(); } /** - * load isr context, save signal + * save signal, return to _native_sig_leave_tramp if possible */ void native_isr_entry(int sig, siginfo_t *info, void *context) { - /* - * This is how it goes: - * We create a new context "R" for the RIOT interrupt service - * routine. - * We save the current (signalhandler) context "S" to the active - * threads context. - * We then jump into the R context. - * Later, when jumping back into "S", we start out in the signal - * handler context only to immediately return into the context we - * originally left. This step is done by the kernel for us. - * - * So the thing to wrap your head around is that the active thread - * remains within in the signal handler context (which is pushed - * onto the active threads own stack by swapcontext) until the - * thread is activated again, at which point the kernel handles - * the context switch back onto the interrupted context for us. - * */ + DEBUG("\n\n\t\tnative_isr_entry\n\n"); + if (native_interrupts_enabled == 0) { + errx(1, "interrupts are off, but I caught a signal."); + } /* save the signal */ - last_sig = sig; + if (write(pipefd[1], &sig, sizeof(int)) == -1) { + err(1, "native_isr_entry(): write()"); + } + _native_sigpend++; /* indicate irs status */ - native_in_irs = 1; - if (getcontext(&native_context) == -1) { - err(1, "native_isr_entry(): getcontext()"); - } + makecontext(&native_isr_context, native_irq_handler, 0); + _native_cur_ctx = (ucontext_t*)active_thread->sp; - native_context.uc_stack.ss_sp = __isr_stack; - native_context.uc_stack.ss_size = SIGSTKSZ; - native_context.uc_stack.ss_flags = 0; - - /* XXX: disable interrupts - * -> sigfillset(&(native_context.uc_sigmask)); - * else: */ - //sigemptyset(&(native_context.uc_sigmask)); - if (sigfillset(&(native_context.uc_sigmask)) == -1) { - err(1, "native_isr_entry(): sigfillset()"); - } - - makecontext(&native_context, native_irq_handler, 0); - -#ifdef NATIVEUSESWAPCONTEXT - /** - * XXX: - * This seems to be the cause of undefined behavior. Try saving - * the context passed to this function and using setcontext to - * leave the handler. - * Also it is probably wise to makecontext the isr context - * elsewehere. - * */ - if ((swapcontext((ucontext_t*)active_thread->sp, &native_context)) == -1) { - err(1, "swapcontext failed"); + if (_native_in_syscall == 0) { + _native_in_isr = 1; + DEBUG("\n\n\t\treturn to _native_sig_leave_tramp\n\n"); + _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; + // TODO: change sigmask? } else { - DEBUG("returning to interrupted thread\n"); + DEBUG("\n\n\t\treturn to syscall\n\n"); } - native_in_irs = 0; - enableIRQ(); -#else - interrupted_contexts[thread_getpid()] = context; - /** - * signal masks are broken - */ - //active_thread->sp = context; - setcontext(&native_context); - DEBUG("\n\n\tnever reached\n\n\n"); -#endif } /** @@ -312,7 +325,7 @@ int register_interrupt(int sig, void *handler) err(1, "register_interrupt: sigemptyset"); } - sa.sa_flags = SA_RESTART | SA_SIGINFO; + sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; if (sigaction(sig, &sa, NULL)) { err(1, "register_interrupt: sigaction"); @@ -342,7 +355,7 @@ int unregister_interrupt(int sig) if (sigemptyset(&sa.sa_mask) == -1) { err(1, "unregister_interrupt: sigemptyset"); } - sa.sa_flags = SA_RESTART | SA_SIGINFO; + sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; if (sigaction(sig, &sa, NULL)) { err(1, "unregister_interrupt: sigaction"); @@ -363,6 +376,7 @@ void native_interrupt_init(void) DEBUG("XXX: native_interrupt_init()\n"); native_interrupts_enabled = 1; + _native_sigpend = 0; for (int i = 0; i<255; i++) { native_irq_handlers[i].func = NULL; @@ -372,7 +386,7 @@ void native_interrupt_init(void) if (sigemptyset(&sa.sa_mask) == -1) { err(1, "native_interrupt_init: sigemptyset"); } - sa.sa_flags = SA_RESTART | SA_SIGINFO; + sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; /* if (sigemptyset(&native_sig_set) == -1) { @@ -391,19 +405,31 @@ void native_interrupt_init(void) err(1, "native_interrupt_init: sigaction"); } - if (sigdelset(&native_sig_set, SIGALRM) == -1) { - err(1, "native_interrupt_init: sigdelset"); + if (getcontext(&native_isr_context) == -1) { + err(1, "native_isr_entry(): getcontext()"); } - if (sigaction(SIGALRM, &sa, NULL)) { - err(1, "native_interrupt_init: sigaction"); + if (sigfillset(&(native_isr_context.uc_sigmask)) == -1) { + err(1, "native_isr_entry(): sigfillset()"); } - if (sigprocmask(SIG_SETMASK, &native_sig_set, NULL) == -1) { - err(1, "native_interrupt_init(): sigprocmask"); + native_isr_context.uc_stack.ss_sp = __isr_stack; + native_isr_context.uc_stack.ss_size = SIGSTKSZ; + native_isr_context.uc_stack.ss_flags = 0; + _native_isr_ctx = &native_isr_context; + + static stack_t sigstk; + sigstk.ss_sp = sigalt_stk; + sigstk.ss_size = SIGSTKSZ; + sigstk.ss_flags = 0; + if (sigaltstack(&sigstk, NULL) < 0) { + err(1, "main: sigaltstack"); } + makecontext(&native_isr_context, native_irq_handler, 0); + + _native_in_syscall = 0; - for (int i = 0; i #include #include +#ifdef MODULE_UART0 +#include +#include +#endif #include "lpm.h" #include "debug.h" +#include "cpu.h" +#ifdef MODULE_UART0 +#include "board.h" +#endif static enum lpm_mode native_lpm; @@ -31,6 +39,32 @@ void lpm_init(void) return; } +void _native_lpm_sleep() +{ +#ifdef MODULE_UART0 + int retval; + retval = select(1, &_native_uart_rfds, NULL, NULL, NULL); + DEBUG("_native_lpm_sleep: retval: %i\n", retval); + if (retval != -1) { + DEBUG("\n\n\t\treturn from syscall, calling _native_handle_uart0_input\n\n"); + makecontext(_native_isr_ctx, _native_handle_uart0_input, 0); + swapcontext(_native_cur_ctx, _native_isr_ctx); + } + else if (errno != EINTR) { + err(1, "lpm_set(): select()"); + } +#else + pause(); +#endif + + if (_native_sigpend > 0) { + DEBUG("\n\n\t\treturn from syscall, calling native_irq_handler\n\n"); + _native_in_syscall = 0; + _native_in_isr = 1; + swapcontext(_native_cur_ctx, _native_isr_ctx); + } +} + /** * LPM_IDLE uses sleep() to wait for interrupts * LPM_OFF exits process @@ -40,7 +74,7 @@ enum lpm_mode lpm_set(enum lpm_mode target) { enum lpm_mode last_lpm; - DEBUG("lpm_set(%i)\n", target); + //DEBUG("lpm_set(%i)\n", target); last_lpm = native_lpm; native_lpm = target; @@ -51,8 +85,11 @@ enum lpm_mode lpm_set(enum lpm_mode target) break; case LPM_IDLE: - DEBUG("lpm_set(): pause()\n"); - pause(); + //DEBUG("lpm_set(): pause()\n"); + + _native_in_syscall = 1; + //pause(); + _native_lpm_sleep(); break; /* XXX: unfinished modes: */ diff --git a/cpu/native/native_cpu.c b/cpu/native/native_cpu.c index 962fd4f9b7f5..89337e7495c2 100644 --- a/cpu/native/native_cpu.c +++ b/cpu/native/native_cpu.c @@ -26,7 +26,7 @@ #include "debug.h" extern volatile tcb_t *active_thread; -static ucontext_t native_context; +static ucontext_t end_context; static char __isr_stack[SIGSTKSZ]; /** @@ -63,7 +63,7 @@ char *thread_stack_init(void *task_func, void *stack_start, int stacksize) p->uc_stack.ss_sp = stk; p->uc_stack.ss_size = stacksize; p->uc_stack.ss_flags = 0; - p->uc_link = &native_context; + p->uc_link = &end_context; if (sigemptyset(&(p->uc_sigmask)) == -1) { err(1, "thread_stack_init(): sigemptyset()"); } @@ -82,13 +82,8 @@ void cpu_switch_context_exit(void) sched_run(); DEBUG("XXX: cpu_switch_context_exit(): calling setcontext(%s)\n\n", active_thread->name); - if (interrupted_contexts[thread_getpid()] == NULL) { - ctx = (ucontext_t*)(active_thread->sp); - } - else { - ctx = interrupted_contexts[thread_getpid()]; - interrupted_contexts[thread_getpid()] = NULL; - } + ctx = (ucontext_t*)(active_thread->sp); + eINT(); // XXX: workaround for bug (?) in sched_task_exit if (setcontext(ctx) == -1) { err(1, "cpu_switch_context_exit(): setcontext():"); } @@ -103,13 +98,7 @@ void thread_yield() DEBUG("thread_yield()\n"); - if (interrupted_contexts[thread_getpid()] == NULL) { - oc = (ucontext_t*)(active_thread->sp); - } - else { - oc = interrupted_contexts[thread_getpid()]; - interrupted_contexts[thread_getpid()] = NULL; - } + oc = (ucontext_t*)(active_thread->sp); sched_run(); @@ -127,13 +116,14 @@ void thread_yield() void native_cpu_init() { - if (getcontext(&native_context) == -1) { - err(1, "native_context(): getcontext()"); + if (getcontext(&end_context) == -1) { + err(1, "end_context(): getcontext()"); } - native_context.uc_stack.ss_sp = __isr_stack; - native_context.uc_stack.ss_size = SIGSTKSZ; - native_context.uc_stack.ss_flags = 0; - makecontext(&native_context, sched_task_exit, 0); + end_context.uc_stack.ss_sp = __isr_stack; + end_context.uc_stack.ss_size = SIGSTKSZ; + end_context.uc_stack.ss_flags = 0; + makecontext(&end_context, sched_task_exit, 0); + puts("RIOT native cpu initialized."); } /** @} */ diff --git a/cpu/native/tramp.S b/cpu/native/tramp.S new file mode 100644 index 000000000000..427f485ff16c --- /dev/null +++ b/cpu/native/tramp.S @@ -0,0 +1,29 @@ +.text + +.extern $_native_saved_eip +.extern $_native_isr_ctx +.extern $_native_cur_ctx +.extern $_native_in_isr + +.globl _native_sig_leave_tramp + +_native_sig_leave_tramp: + pushl %eax + pushf + pushl %ebp + pushl %esp + + movl %esp, %ebp + subl $24, %esp + movl $_native_isr_ctx, 4(%esp) + movl $_native_cur_ctx, (%esp) + call swapcontext + + addl $24, %esp + popl %esp + popl %ebp + popf + popl %eax + movl $0x0, _native_in_isr; + + jmp *_native_saved_eip