Repository: incubator-mynewt-core Updated Branches: refs/heads/master a34f65387 -> e13e309d9
MYNEWT-728; support native arch armv7. Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/6d3edb39 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/6d3edb39 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/6d3edb39 Branch: refs/heads/master Commit: 6d3edb39595ad958b04a24e21d854429857bea84 Parents: 31d00cb Author: Marko Kiiskila <[email protected]> Authored: Wed Apr 19 15:30:36 2017 -0700 Committer: Marko Kiiskila <[email protected]> Committed: Wed Apr 19 15:30:36 2017 -0700 ---------------------------------------------------------------------- compiler/sim-armv7/compiler.yml | 41 ++ compiler/sim-armv7/pkg.yml | 28 ++ .../os/include/os/arch/sim-armv7/os/os_arch.h | 82 ++++ kernel/os/src/arch/sim-armv7/os_arch_sim.c | 457 +++++++++++++++++++ .../os/src/arch/sim-armv7/os_arch_stack_frame.s | 47 ++ kernel/os/src/arch/sim-armv7/os_fault.c | 39 ++ 6 files changed, 694 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6d3edb39/compiler/sim-armv7/compiler.yml ---------------------------------------------------------------------- diff --git a/compiler/sim-armv7/compiler.yml b/compiler/sim-armv7/compiler.yml new file mode 100644 index 0000000..79a710f --- /dev/null +++ b/compiler/sim-armv7/compiler.yml @@ -0,0 +1,41 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# Default. +compiler.path.cc: "gcc" +compiler.path.cpp: "g++" +compiler.path.as: "gcc" +compiler.path.archive: "ar" +compiler.path.objdump: "objdump" +compiler.path.objsize: "size" +compiler.path.objcopy: "objcopy" +compiler.flags.base: > + -Wall -Werror -ggdb -DARCH_sim +compiler.ld.resolve_circular_deps: true + +compiler.flags.default: [compiler.flags.base, -O1] +compiler.flags.debug: [compiler.flags.base, -O0] +compiler.as.flags: [-x, assembler-with-cpp] +compiler.ld.mapfile: false +compiler.ld.binfile: false + +# Linux. +compiler.flags.base.LINUX: > + -DMN_LINUX +compiler.ld.flags.LINUX: -lutil http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6d3edb39/compiler/sim-armv7/pkg.yml ---------------------------------------------------------------------- diff --git a/compiler/sim-armv7/pkg.yml b/compiler/sim-armv7/pkg.yml new file mode 100644 index 0000000..d5a7ec7 --- /dev/null +++ b/compiler/sim-armv7/pkg.yml @@ -0,0 +1,28 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: compiler/sim-armv7 +pkg.type: compiler +pkg.description: Compiler definition for native gcc compiler. +pkg.author: "Apache Mynewt <[email protected]>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - sim + - compiler + - gcc http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6d3edb39/kernel/os/include/os/arch/sim-armv7/os/os_arch.h ---------------------------------------------------------------------- diff --git a/kernel/os/include/os/arch/sim-armv7/os/os_arch.h b/kernel/os/include/os/arch/sim-armv7/os/os_arch.h new file mode 100644 index 0000000..80f886f --- /dev/null +++ b/kernel/os/include/os/arch/sim-armv7/os/os_arch.h @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _OS_ARCH_SIM_H +#define _OS_ARCH_SIM_H + +#include <mcu/mcu_sim.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct os_task; + +/* CPU status register */ +typedef unsigned int os_sr_t; +/* Stack type, aligned to a 32-bit word. */ +#define OS_STACK_PATTERN (0xdeadbeef) + +typedef unsigned int os_stack_t; +#define OS_ALIGNMENT (4) +#define OS_STACK_ALIGNMENT (16) + +/* + * Stack sizes for common OS tasks + */ +#define OS_SANITY_STACK_SIZE (1024) +#define OS_IDLE_STACK_SIZE (1024) + +/* + * The 'sim' architecture-specific code does not have as much control on + * stack usage as the real embedded architectures. + * + * For e.g. the space occupied by the signal handler frame on the task + * stack is entirely dependent on the host OS. + * + * Deal with this by scaling the stack size by a factor of 16. The scaling + * factor can be arbitrarily large because the stacks are allocated from + * BSS and thus don't add to either the executable size or resident + * memory. + */ +#define OS_STACK_ALIGN(__nmemb) \ + (OS_ALIGN(((__nmemb) * 16), OS_STACK_ALIGNMENT)) + +/* Enter a critical section, save processor state, and block interrupts */ +#define OS_ENTER_CRITICAL(__os_sr) (__os_sr = os_arch_save_sr()) +/* Exit a critical section, restore processor state and unblock interrupts */ +#define OS_EXIT_CRITICAL(__os_sr) (os_arch_restore_sr(__os_sr)) +#define OS_ASSERT_CRITICAL() (assert(os_arch_in_critical())) + +void _Die(char *file, int line); + +os_stack_t *os_arch_task_stack_init(struct os_task *, os_stack_t *, int); +void os_arch_ctx_sw(struct os_task *); +os_sr_t os_arch_save_sr(void); +void os_arch_restore_sr(os_sr_t sr); +int os_arch_in_critical(void); +os_error_t os_arch_os_init(void); +void os_arch_os_stop(void); +os_error_t os_arch_os_start(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_ARCH_SIM_H */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6d3edb39/kernel/os/src/arch/sim-armv7/os_arch_sim.c ---------------------------------------------------------------------- diff --git a/kernel/os/src/arch/sim-armv7/os_arch_sim.c b/kernel/os/src/arch/sim-armv7/os_arch_sim.c new file mode 100644 index 0000000..67d1a6e --- /dev/null +++ b/kernel/os/src/arch/sim-armv7/os_arch_sim.c @@ -0,0 +1,457 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "os/os.h" +#include "os_priv.h" + +#include <hal/hal_bsp.h> + +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <setjmp.h> +#include <signal.h> +#include <sys/time.h> +#include <assert.h> + +struct stack_frame { + int sf_mainsp; /* stack on which main() is executing */ + sigjmp_buf sf_jb; + struct os_task *sf_task; +}; + +/* + * Assert that 'sf_mainsp' and 'sf_jb' are at the specific offsets where + * os_arch_frame_init() expects them to be. + */ +CTASSERT(offsetof(struct stack_frame, sf_mainsp) == 0); +CTASSERT(offsetof(struct stack_frame, sf_jb) == 8); + +extern void os_arch_frame_init(struct stack_frame *sf); + +#define sim_setjmp(__jb) sigsetjmp(__jb, 0) +#define sim_longjmp(__jb, __ret) siglongjmp(__jb, __ret) + +#define OS_USEC_PER_TICK (1000000 / OS_TICKS_PER_SEC) + +static pid_t mypid; +static sigset_t allsigs, nosigs; +static void timer_handler(int sig); + +static bool suspended; /* process is blocked in sigsuspend() */ +static sigset_t suspsigs; /* signals delivered in sigsuspend() */ + +/* + * Called from 'os_arch_frame_init()' when setjmp returns indirectly via + * longjmp. The return value of setjmp is passed to this function as 'rc'. + */ +void +os_arch_task_start(struct stack_frame *sf, int rc) +{ + struct os_task *task; + + /* + * Interrupts are disabled when a task starts executing. This happens in + * two different ways: + * - via os_arch_os_start() for the first task. + * - via os_sched() for all other tasks. + * + * Enable interrupts before starting the task. + */ + OS_EXIT_CRITICAL(0); + + task = sf->sf_task; + task->t_func(task->t_arg); + + /* This should never return */ + assert(0); +} + +os_stack_t * +os_arch_task_stack_init(struct os_task *t, os_stack_t *stack_top, int size) +{ + struct stack_frame *sf; + + sf = (struct stack_frame *) ((uint8_t *) stack_top - sizeof(*sf)); + sf->sf_task = t; + + os_arch_frame_init(sf); + + return ((os_stack_t *)sf); +} + +void +os_arch_ctx_sw(struct os_task *next_t) +{ + /* + * gdb will stop execution of the program on most signals (e.g. SIGUSR1) + * whereas it passes SIGURG to the process without any special settings. + */ + kill(mypid, SIGURG); +} + +static void +ctxsw_handler(int sig) +{ + struct os_task *t, *next_t; + struct stack_frame *sf; + int rc; + + OS_ASSERT_CRITICAL(); + + /* + * Just record that this handler was called when the process was blocked. + * The handler will be called after sigsuspend() returns in the correct + * order. + */ + if (suspended) { + sigaddset(&suspsigs, sig); + return; + } + + t = os_sched_get_current_task(); + next_t = os_sched_next_task(); + if (t == next_t) { + /* + * Context switch not needed - just return. + */ + return; + } + + if (t) { + sf = (struct stack_frame *) t->t_stackptr; + + rc = sim_setjmp(sf->sf_jb); + if (rc != 0) { + OS_ASSERT_CRITICAL(); + return; + } + } + + os_sched_ctx_sw_hook(next_t); + + os_sched_set_current_task(next_t); + + sf = (struct stack_frame *) next_t->t_stackptr; + sim_longjmp(sf->sf_jb, 1); +} + +/* + * Disable signals and enter a critical section. + * + * Returns 1 if signals were already blocked and 0 otherwise. + */ +os_sr_t +os_arch_save_sr(void) +{ + int error; + sigset_t omask; + + error = sigprocmask(SIG_BLOCK, &allsigs, &omask); + assert(error == 0); + + /* + * If any one of the signals in 'allsigs' is present in 'omask' then + * we are already inside a critical section. + */ + return (sigismember(&omask, SIGALRM)); +} + +void +os_arch_restore_sr(os_sr_t osr) +{ + int error; + + OS_ASSERT_CRITICAL(); + assert(osr == 0 || osr == 1); + + if (osr == 1) { + /* Exiting a nested critical section */ + return; + } + + error = sigprocmask(SIG_UNBLOCK, &allsigs, NULL); + assert(error == 0); +} + +int +os_arch_in_critical(void) +{ + int error; + sigset_t omask; + + error = sigprocmask(SIG_SETMASK, NULL, &omask); + assert(error == 0); + + /* + * If any one of the signals in 'allsigs' is present in 'omask' then + * we are already inside a critical section. + */ + return (sigismember(&omask, SIGALRM)); +} + +static struct { + int num; + void (*handler)(int sig); +} signals[] = { + { SIGALRM, timer_handler }, + { SIGURG, ctxsw_handler }, +}; + +#define NUMSIGS (sizeof(signals)/sizeof(signals[0])) + +void +os_tick_idle(os_time_t ticks) +{ + int i, rc, sig; + struct itimerval it; + void (*handler)(int sig); + + OS_ASSERT_CRITICAL(); + + if (ticks > 0) { + /* + * Enter tickless regime and set the timer to fire after 'ticks' + * worth of time has elapsed. + */ + it.it_value.tv_sec = ticks / OS_TICKS_PER_SEC; + it.it_value.tv_usec = (ticks % OS_TICKS_PER_SEC) * OS_USEC_PER_TICK; + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = OS_USEC_PER_TICK; + rc = setitimer(ITIMER_REAL, &it, NULL); + assert(rc == 0); + } + + suspended = true; + sigemptyset(&suspsigs); + sigsuspend(&nosigs); /* Wait for a signal to wake us up */ + suspended = false; + + /* + * Call handlers for signals delivered to the process during sigsuspend(). + * The SIGALRM handler is called before any other handlers to ensure that + * OS time is always correct. + */ + if (sigismember(&suspsigs, SIGALRM)) { + timer_handler(SIGALRM); + } + for (i = 0; i < NUMSIGS; i++) { + sig = signals[i].num; + handler = signals[i].handler; + if (sig != SIGALRM && sigismember(&suspsigs, sig)) { + handler(sig); + } + } + + if (ticks > 0) { + /* + * Enable the periodic timer interrupt. + */ + it.it_value.tv_sec = 0; + it.it_value.tv_usec = OS_USEC_PER_TICK; + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = OS_USEC_PER_TICK; + rc = setitimer(ITIMER_REAL, &it, NULL); + assert(rc == 0); + } +} + +static void +signals_init(void) +{ + int i, error; + struct sigaction sa; + + sigemptyset(&nosigs); + sigemptyset(&allsigs); + for (i = 0; i < NUMSIGS; i++) { + sigaddset(&allsigs, signals[i].num); + } + + for (i = 0; i < NUMSIGS; i++) { + memset(&sa, 0, sizeof sa); + sa.sa_handler = signals[i].handler; + sa.sa_mask = allsigs; + sa.sa_flags = SA_RESTART; + error = sigaction(signals[i].num, &sa, NULL); + assert(error == 0); + } + + /* + * We use SIGALRM as a proxy for 'allsigs' to check if we are inside + * a critical section (for e.g. see os_arch_in_critical()). Make sure + * that SIGALRM is indeed present in 'allsigs'. + */ + assert(sigismember(&allsigs, SIGALRM)); +} + +static void +signals_cleanup(void) +{ + int i, error; + struct sigaction sa; + + for (i = 0; i < NUMSIGS; i++) { + memset(&sa, 0, sizeof sa); + sa.sa_handler = SIG_DFL; + error = sigaction(signals[i].num, &sa, NULL); + assert(error == 0); + } +} + +static void +timer_handler(int sig) +{ + struct timeval time_now, time_diff; + int ticks; + + static struct timeval time_last; + static int time_inited; + + OS_ASSERT_CRITICAL(); + + /* + * Just record that this handler was called when the process was blocked. + * The handler will be called after sigsuspend() returns in the proper + * order. + */ + if (suspended) { + sigaddset(&suspsigs, sig); + return; + } + + if (!time_inited) { + gettimeofday(&time_last, NULL); + time_inited = 1; + } + + gettimeofday(&time_now, NULL); + if (timercmp(&time_now, &time_last, <)) { + /* + * System time going backwards. + */ + time_last = time_now; + } else { + timersub(&time_now, &time_last, &time_diff); + + ticks = time_diff.tv_sec * OS_TICKS_PER_SEC; + ticks += time_diff.tv_usec / OS_USEC_PER_TICK; + + /* + * Update 'time_last' but account for the remainder usecs that did not + * contribute towards whole 'ticks'. + */ + time_diff.tv_sec = 0; + time_diff.tv_usec %= OS_USEC_PER_TICK; + timersub(&time_now, &time_diff, &time_last); + + os_time_advance(ticks); + } +} + +static void +start_timer(void) +{ + struct itimerval it; + int rc; + + memset(&it, 0, sizeof(it)); + it.it_value.tv_sec = 0; + it.it_value.tv_usec = OS_USEC_PER_TICK; + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = OS_USEC_PER_TICK; + + rc = setitimer(ITIMER_REAL, &it, NULL); + assert(rc == 0); +} + +static void +stop_timer(void) +{ + struct itimerval it; + int rc; + + memset(&it, 0, sizeof(it)); + + rc = setitimer(ITIMER_REAL, &it, NULL); + assert(rc == 0); +} + +os_error_t +os_arch_os_init(void) +{ + mypid = getpid(); + g_current_task = NULL; + + STAILQ_INIT(&g_os_task_list); + TAILQ_INIT(&g_os_run_list); + TAILQ_INIT(&g_os_sleep_list); + + /* + * Setup all interrupt handlers. + * + * This must be done early because task initialization uses critical + * sections which function correctly only when 'allsigs' is initialized. + */ + signals_init(); + + os_init_idle_task(); + + return OS_OK; +} + +os_error_t +os_arch_os_start(void) +{ + struct stack_frame *sf; + struct os_task *t; + os_sr_t sr; + + /* + * Disable interrupts before enabling any interrupt sources. Pending + * interrupts will be recognized when the first task starts executing. + */ + OS_ENTER_CRITICAL(sr); + assert(sr == 0); + + /* Enable the interrupt sources */ + start_timer(); + + t = os_sched_next_task(); + os_sched_set_current_task(t); + + g_os_started = 1; + + sf = (struct stack_frame *) t->t_stackptr; + sim_longjmp(sf->sf_jb, 1); + + return 0; +} + +/** + * Stops the tick timer and clears the "started" flag. This function is only + * implemented for sim. + */ +void +os_arch_os_stop(void) +{ + stop_timer(); + signals_cleanup(); + g_os_started = 0; +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6d3edb39/kernel/os/src/arch/sim-armv7/os_arch_stack_frame.s ---------------------------------------------------------------------- diff --git a/kernel/os/src/arch/sim-armv7/os_arch_stack_frame.s b/kernel/os/src/arch/sim-armv7/os_arch_stack_frame.s new file mode 100644 index 0000000..460d54a --- /dev/null +++ b/kernel/os/src/arch/sim-armv7/os_arch_stack_frame.s @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#define sigsetjmp __sigsetjmp + + .text + .p2align 4, 0x90 /* align on 16-byte boundary and fill with NOPs */ + + .globl os_arch_frame_init + /* + * void os_arch_frame_init(struct stack_frame *sf) + */ +os_arch_frame_init: + mov r1, sp + mov sp, r0 /* stack for the task starts from sf */ + sub sp, sp, #20 + str r1, [sp, #12] + str lr, [sp, #16] /* Store LR there */ + str r0, [sp, #4] /* Store sf pointer to stack */ + add r0, r0, #8 /* $r0 = sf->sf_jb */ + mov r1, #0 + bl __sigsetjmp + cmp r0, #0 /* If $r0 == 0 then return */ + beq end + mov r1, r0 + ldr r0, [sp, #4] + bl os_arch_task_start +end: + ldr r1, [sp, #16] /* return $sp for the callee */ + ldr sp, [sp, #12] + mov pc, r1 http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6d3edb39/kernel/os/src/arch/sim-armv7/os_fault.c ---------------------------------------------------------------------- diff --git a/kernel/os/src/arch/sim-armv7/os_fault.c b/kernel/os/src/arch/sim-armv7/os_fault.c new file mode 100644 index 0000000..964202e --- /dev/null +++ b/kernel/os/src/arch/sim-armv7/os_fault.c @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "os/os.h" +#include "os_priv.h" + +void +__assert_func(const char *file, int line, const char *func, const char *e) +{ + char msg[256]; + + if (file) { + snprintf(msg, sizeof(msg), "assert @ %s:%d\n", file, line); + } else { + snprintf(msg, sizeof(msg), "assert @ %p\n", + __builtin_return_address(0)); + } + write(1, msg, strlen(msg)); + _exit(1); +}
