diff --git a/core/include/kernel_intern.h b/core/include/kernel_intern.h index ca50b55e36..95c7877eb9 100644 --- a/core/include/kernel_intern.h +++ b/core/include/kernel_intern.h @@ -18,7 +18,7 @@ void kernel_init(void); void board_init_drivers(void); -char *thread_stack_init(void *task_func, void *stack_start); +char *thread_stack_init(void *task_func, void *stack_start, int stack_size); void sched_task_exit(void); void thread_print_stack (void); int thread_measure_stack_usage(char* stack); diff --git a/core/thread.c b/core/thread.c index d38580de07..8ba7e15bd1 100644 --- a/core/thread.c +++ b/core/thread.c @@ -143,7 +143,7 @@ int thread_create(char *stack, int stacksize, char priority, int flags, void (*f return -EOVERFLOW; } - cb->sp = thread_stack_init(function,stack+stacksize); + cb->sp = thread_stack_init(function,stack,stacksize); cb->stack_start = stack; cb->stack_size = total_stacksize; diff --git a/cpu/makefile b/cpu/makefile index 1923199987..25ef332df1 100644 --- a/cpu/makefile +++ b/cpu/makefile @@ -14,6 +14,10 @@ ifeq ($(CPU),msp430x16x) DIRS = msp430-common msp430x16x endif +ifeq ($(CPU),native) + DIRS = native +endif + .PHONY: cpus .PHONY: $(DIRS) @@ -28,6 +32,5 @@ clean: @$(MAKE) -C cc430 clean @$(MAKE) -C msp430-common clean @$(MAKE) -C msp430x16x clean - - + @$(MAKE) -C native clean diff --git a/cpu/native/atomic_cpu.c b/cpu/native/atomic_cpu.c new file mode 100644 index 0000000000..632b35e9dc --- /dev/null +++ b/cpu/native/atomic_cpu.c @@ -0,0 +1,20 @@ +#include +#include +#include "debug.h" + +unsigned int atomic_set_return(unsigned int* val, unsigned int set) +{ + unsigned int old_val; + unsigned int old_state; + + DEBUG("atomic_set_return\n"); + + old_state = disableIRQ(); + + old_val = *val; + *val = set; + + restoreIRQ(old_state); + + return old_val; +} diff --git a/cpu/native/hwtimer_cpu.c b/cpu/native/hwtimer_cpu.c new file mode 100644 index 0000000000..8c995dff6a --- /dev/null +++ b/cpu/native/hwtimer_cpu.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include "hwtimer.h" +#include "hwtimer_arch.h" + +#include "hwtimer_cpu.h" +#include "cpu.h" +#include "cpu-conf.h" + +#include "debug.h" + +#define HWTIMER_MINTICKS (1000) + +static unsigned long native_hwtimer_now; +static int native_hwtimer_irq[ARCH_MAXTIMERS]; +static timer_t native_hwtimer_timer[ARCH_MAXTIMERS]; +static void (*int_handler)(int); + +void ticks2ts(unsigned long ticks, struct timespec *tp) +{ + tp->tv_sec = ticks / HWTIMER_SPEED; + tp->tv_nsec = (ticks % HWTIMER_SPEED)*1000 ; +} + +unsigned long ts2ticks(struct timespec *tp) +{ + /* TODO: check for overflow */ + return((tp->tv_sec * HWTIMER_SPEED) + (tp->tv_nsec/1000)); +} + +void hwtimer_isr_timer() +{ + DEBUG("hwtimer_isr_timer()\n"); + + for (int i = 0; i + +/* TODO: choose more sensibly? */ +#ifndef KERNEL_CONF_STACKSIZE_DEFAULT +#define KERNEL_CONF_STACKSIZE_DEFAULT 8192 +#endif + +#define KERNEL_CONF_STACKSIZE_IDLE 2048 +#define NATIVE_ISR_STACKSIZE 8192 + +#define _SIG_UNDEF SIGRTMIN + 0 +#define _SIG_TIMER SIGRTMIN + 10 // check hwtimer_cpu.h for compliance +#define _SIG_LTC4150 SIGRTMIN + 20 + +/* TODO: check for overflow (SIGRTMAX) */ + +#endif /* CPUCONF_H_ */ diff --git a/cpu/native/include/cpu.h b/cpu/native/include/cpu.h new file mode 100644 index 0000000000..1bd2dc12db --- /dev/null +++ b/cpu/native/include/cpu.h @@ -0,0 +1,22 @@ +#ifndef _CPU_H +#define _CPU_H + +#include + +#include "kernel_intern.h" +#include "sched.h" +#include "debug.h" + +#include "cpu-conf.h" + +/* TODO: choose better value? */ +#define F_CPU 1000000 + +void dINT(void); +void eINT(void); + +int register_interrupt(int sig, void *handler); +int unregister_interrupt(int sig); +void thread_yield(void); + +#endif //_CPU_H diff --git a/cpu/native/include/hwtimer_cpu.h b/cpu/native/include/hwtimer_cpu.h new file mode 100644 index 0000000000..c4f0bedeb5 --- /dev/null +++ b/cpu/native/include/hwtimer_cpu.h @@ -0,0 +1,9 @@ +#ifndef HWTIMER_CPU_H_ +#define HWTIMER_CPU_H_ + +/* TODO: choose more appropriate values here? */ +#define ARCH_MAXTIMERS 4 +#define HWTIMER_SPEED 1000000 +#define HWTIMER_MAXTICKS (0xFFFFFFFF) + +#endif /* HWTIMER_CPU_H_ */ diff --git a/cpu/native/irq_cpu.c b/cpu/native/irq_cpu.c new file mode 100644 index 0000000000..d19f4cb8e6 --- /dev/null +++ b/cpu/native/irq_cpu.c @@ -0,0 +1,257 @@ +#include +#include + +#include +#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; +static sigset_t native_sig_set; +static char __isr_stack[SIGSTKSZ]; +extern volatile tcb_t *active_thread; + +struct int_handler_t { + void (*func)(void); +}; +static struct int_handler_t native_irq_handlers[255]; + +unsigned disableIRQ(void) +{ + unsigned int prev_state; + sigset_t mask; + + DEBUG("disableIRQ()\n"); + + if (sigfillset(&mask) == -1) { + err(1, "disableIRQ(): sigfillset"); + } + if (native_interrupts_enabled == 1) { + if (sigprocmask(SIG_SETMASK, &mask, &native_sig_set) == -1) { + err(1, "disableIRQ(): sigprocmask"); + } + } + else { + if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1) { + err(1, "disableIRQ(): sigprocmask()"); + } + } + prev_state = native_interrupts_enabled; + native_interrupts_enabled = 0; + + return prev_state; +} + +unsigned enableIRQ(void) +{ + unsigned int prev_state; + + DEBUG("enableIRQ()\n"); + + if (sigprocmask(SIG_SETMASK, &native_sig_set, NULL) == -1) { + err(1, "enableIRQ(): sigprocmask()"); + } + prev_state = native_interrupts_enabled; + native_interrupts_enabled = 1; + + return prev_state; +} + +void restoreIRQ(unsigned state) +{ + DEBUG("restoreIRQ()\n"); + + if (state == 1) { + enableIRQ(); + } + else { + disableIRQ(); + } + return; +} + +int inISR(void) +{ + DEBUG("inISR()\n"); + return native_in_irs; +} + + +void dINT(void) +{ + disableIRQ(); +} + +void eINT(void) +{ + enableIRQ(); +} + +/** + * call signal handler, + * restore user context + */ +void native_irq_handler() +{ + if (native_irq_handlers[last_sig].func != NULL) { + DEBUG("calling interrupt handler for %i\n", last_sig); + native_irq_handlers[last_sig].func(); + } + else { + printf("XXX: no handler for signal %i\n", last_sig); + errx(1, "XXX: this should not have happened!\n"); + } + native_in_irs = 0; + cpu_switch_context_exit(); +} + + +/** + * load isr context, save signal + */ +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. + * */ + + /* save the signal */ + last_sig = sig; + /* indicate irs status */ + native_in_irs = 1; + + if (getcontext(&native_context) == -1) { + err(1, "native_isr_entry(): getcontext()"); + } + + 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); + + if ((swapcontext((ucontext_t*)active_thread->sp, &native_context)) == -1) { + err(1, "swapcontext failed"); + } + else { + DEBUG("returning to interrupted thread\n"); + } + native_in_irs = 0; + enableIRQ(); +} + +/** + * TODO: check sa_flags for appropriateness + * TODO: use appropriate data structure (hashmap?) for signal + * handlers. + */ +int register_interrupt(int sig, void *handler) +{ + struct sigaction sa; + DEBUG("XXX: register_interrupt()\n"); + + if (sigaddset(&native_sig_set, sig)) { + err(1, "register_interrupt: sigaddset"); + } + + native_irq_handlers[sig].func = handler; + + sa.sa_sigaction = (void*) native_isr_entry; + + if (sigemptyset(&sa.sa_mask) == -1) { + err(1, "register_interrupt: sigemptyset"); + } + + sa.sa_flags = SA_RESTART | SA_SIGINFO; + + if (sigaction(sig, &sa, NULL)) { + err(1, "register_interrupt: sigaction"); + } + + return 0; +} + +/** + * TODO: see register_interrupt + * TODO: ignore signal + */ +int unregister_interrupt(int sig) +{ + struct sigaction sa; + DEBUG("XXX: unregister_interrupt()\n"); + + if (sigdelset(&native_sig_set, sig) == -1) { + err(1, "unregister_interrupt: sigdelset"); + } + native_irq_handlers[sig].func = NULL; + + sa.sa_sigaction = SIG_IGN; + if (sigemptyset(&sa.sa_mask) == -1) { + err(1, "unregister_interrupt: sigemptyset"); + } + sa.sa_flags = SA_RESTART | SA_SIGINFO; + + if (sigaction(sig, &sa, NULL)) { + err(1, "register_interrupt: sigaction"); + } + return 0; +} + + +/** + * TODO: see register_interrupt + */ +void native_interrupt_init(void) +{ + struct sigaction sa; + DEBUG("XXX: native_interrupt_init()\n"); + + for (int i = 0; i<255; i++) { + native_irq_handlers[i].func = NULL; + } + + sa.sa_sigaction = (void*) native_isr_entry; + if (sigemptyset(&sa.sa_mask) == -1) { + err(1, "native_interrupt_init: sigemptyset"); + } + sa.sa_flags = SA_RESTART | SA_SIGINFO; + + if (sigemptyset(&native_sig_set) == -1) { + err(1, "native_interrupt_init: sigemptyset"); + } + if (sigaddset(&native_sig_set, SIGUSR1) == -1) { + err(1, "native_interrupt_init: sigaddset"); + } + + if (sigaction(SIGUSR1, &sa, NULL)) { + err(1, "native_interrupt_init: sigaction"); + } + + puts("RIOT native interrupts/signals initialized."); +} diff --git a/cpu/native/lpm_cpu.c b/cpu/native/lpm_cpu.c new file mode 100644 index 0000000000..6ace2d2d40 --- /dev/null +++ b/cpu/native/lpm_cpu.c @@ -0,0 +1,81 @@ +#include +#include + +#include "lpm.h" +#include "debug.h" + +static enum lpm_mode native_lpm; + +void lpm_init(void) +{ + DEBUG("lpm_init()\n"); + native_lpm = LPM_ON; + return; +} + +enum lpm_mode lpm_set(enum lpm_mode target) +{ + enum lpm_mode last_lpm; + + DEBUG("lpm_set(%i)\n", target); + + last_lpm = native_lpm; + native_lpm = target; + + switch(native_lpm) /* @contiki :-p */ + { + case LPM_ON: + break; + + case LPM_IDLE: + DEBUG("lpm_set(): pause()\n"); + pause(); + break; + + /* XXX: unfinished modes: */ + case LPM_SLEEP: + /*TODO: implement*/ + printf("XXX: lpm_set(): LPM_SLEEP not implemented\n"); + //sigsuspend(); + + case LPM_POWERDOWN: + /*TODO: implement*/ + printf("XXX: lpm_set(): LPM_POWERDOWN not implemented\n"); + //sigsuspend(); + + case LPM_OFF: + printf("lpm_set(): exit()\n"); + exit(0); + break; + + default: + DEBUG("XXX: unsupported power mode: %i\n", native_lpm); + exit(1); + } + + return last_lpm; +} + +void lpm_awake(void) +{ + DEBUG("XXX: lpm_awake()\n"); + native_lpm = LPM_ON; + return; +} + +void lpm_begin_awake(void) +{ + DEBUG("XXX: lpm_begin_awake()\n"); + return; +} + +void lpm_end_awake(void) +{ + DEBUG("XXX: lpm_end_awake()\n"); + native_lpm = LPM_ON; + return; +} +enum lpm_mode lpm_get(void) +{ + return native_lpm; +} diff --git a/cpu/native/makefile b/cpu/native/makefile new file mode 100644 index 0000000000..f496a1e1a5 --- /dev/null +++ b/cpu/native/makefile @@ -0,0 +1,16 @@ +MODULE = cpu + +INCLUDES = -I../include -I$(RIOTBASE)/core/include +DIRS = +ifneq (,$(findstring rtc,$(USEMODULE))) + DIRS += rtc +endif + +all: $(BINDIR)$(MODULE).a + @for i in $(DIRS) ; do $(MAKE) -C $$i ; done ; + +include $(RIOTBASE)/makefile.base + +clean:: + @for i in $(DIRS) ; do $(MAKE) -C $$i clean ; done ; + diff --git a/cpu/native/native_cpu.c b/cpu/native/native_cpu.c new file mode 100644 index 0000000000..eae5378542 --- /dev/null +++ b/cpu/native/native_cpu.c @@ -0,0 +1,97 @@ +#include +#include +#include + +#include "kernel_intern.h" +#include "sched.h" + +#include "cpu.h" +#include "cpu-conf.h" +#include "debug.h" + +extern volatile tcb_t *active_thread; +static ucontext_t native_context; +static char __isr_stack[SIGSTKSZ]; + +/** + * TODO: implement + */ +void thread_print_stack(void) +{ + DEBUG("XXX: thread_print_stack()\n"); + return; +} + +char *thread_stack_init(void *task_func, void *stack_start, int stacksize) +{ + unsigned int *stk; + ucontext_t *p; + + DEBUG("thread_stack_init()\n"); + + stk = stack_start; + +#ifdef NATIVESPONTOP + p = (ucontext_t*)stk; + stk += sizeof(ucontext_t)/sizeof(void*); + stacksize -= sizeof(ucontext_t); +#else + p = (ucontext_t*)(stk + ((stacksize-sizeof(ucontext_t))/sizeof(void*))); + stacksize -= sizeof(ucontext_t); +#endif + + if (getcontext(p) == -1) { + err(1, "thread_stack_init(): getcontext()"); + } + + p->uc_stack.ss_sp = stk; + p->uc_stack.ss_size = stacksize; + p->uc_stack.ss_flags = 0; + p->uc_link = &native_context; + if (sigemptyset(&(p->uc_sigmask)) == -1) { + err(1, "thread_stack_init(): sigemptyset()"); + } + + makecontext(p, task_func, 0); + + return (char *) p; +} + +void cpu_switch_context_exit(void) +{ + DEBUG("XXX: cpu_switch_context_exit()\n"); + //active_thread = sched_threads[0]; + sched_run(); + + DEBUG("XXX: cpu_switch_context_exit(): calling setcontext(%s)\n\n", active_thread->name); + if (setcontext((ucontext_t*)(active_thread->sp)) == -1) { + err(1, "cpu_switch_context_exit(): setcontext():"); + } +} + +void thread_yield() +{ + ucontext_t *oc; + + DEBUG("thread_yield()\n"); + + oc = (ucontext_t*)(active_thread->sp); + sched_run(); + + DEBUG("thread_yield(): calling swapcontext(%s)\n\n", active_thread->name); + if (swapcontext(oc, (ucontext_t*)(active_thread->sp)) == -1) { + err(1, "thread_yield(): swapcontext()"); + } +} + +void native_cpu_init() +{ + if (getcontext(&native_context) == -1) { + err(1, "native_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); + puts("RIOT native cpu initialized."); +} diff --git a/cpu/native/rtc/makefile b/cpu/native/rtc/makefile new file mode 100644 index 0000000000..b3b66a79c8 --- /dev/null +++ b/cpu/native/rtc/makefile @@ -0,0 +1,6 @@ +INCLUDES = -I$(RIOTBASE)/drivers/include -I$(RIOTBASE)/core/include + +MODULE =rtc + +include $(MAKEBASE)/makefile.base + diff --git a/cpu/native/rtc/posix-rtc.c b/cpu/native/rtc/posix-rtc.c new file mode 100644 index 0000000000..6b98084a61 --- /dev/null +++ b/cpu/native/rtc/posix-rtc.c @@ -0,0 +1,59 @@ +#include + +#include "debug.h" + +#include + +static int native_rtc_enabled; + +/** + * @brief Initializes the RTC for calendar mode + */ +void rtc_init(void) +{ + native_rtc_enabled = 0; + printf("native rtc initialized\n"); +} + +/** + * @brief Starts the RTC + */ +void rtc_enable(void) +{ + DEBUG("rtc_enable\n"); + native_rtc_enabled = 1; +} + +/** + * @brief Stops the RTC + */ +void rtc_disable(void) +{ + DEBUG("rtc_disable()\n"); + native_rtc_enabled = 0; +} + +/** + * @brief Sets the current time in broken down format directly from to RTC + * @param[in] localt Pointer to structure with time to set + */ +void rtc_set_localtime(struct tm* localt) +{ + DEBUG("rtc_set_localtime()\n"); + printf("setting time not supported."); +} + +/** + * @brief Returns the current time in broken down format directly from the RTC + * @param[out] localt Pointer to structure to receive time + */ +void rtc_get_localtime(struct tm* localt) +{ + time_t t; + if(native_rtc_enabled == 1) { + t = time(NULL); + if (localtime_r(&t, localt) == NULL) { + err(1, "rtc_get_localtime: localtime_r"); + } + } +} diff --git a/cpu/native/startup.c b/cpu/native/startup.c new file mode 100644 index 0000000000..d19c3d0565 --- /dev/null +++ b/cpu/native/startup.c @@ -0,0 +1,15 @@ +#include +#include + +extern void board_init(void); + +__attribute__ ((constructor)) static void startup(void) +{ + native_cpu_init(); + native_interrupt_init(); + + board_init(); + + puts("RIOT native hardware initialization complete.\n"); + kernel_init(); +} diff --git a/makefile.base b/makefile.base index 8e781605f1..49daf55740 100644 --- a/makefile.base +++ b/makefile.base @@ -20,6 +20,9 @@ ifeq ($(CPU),cc430) INCLUDES += -I$(MAKEBASE)/cpu/msp430-common/include/ INCLUDES += -I$(MAKEBASE)/cpu/cc430/include/ endif +ifeq ($(CPU),native) + INCLUDES += -I$(MAKEBASE)/cpu/native/include/ +endif ifeq ($(BOARD),msba2) INCLUDES += -I$(RIOTBOARD)/msba2/include/ INCLUDES += -I$(RIOTBOARD)/msba2-common/include/