Repository: incubator-mynewt-core Updated Branches: refs/heads/develop 55570f1fc -> f8877700c
MIPS user Linux port added 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/3db61b0f Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/3db61b0f Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/3db61b0f Branch: refs/heads/develop Commit: 3db61b0ffeb2062ee23699f10a52a6a3f89aa9de Parents: a6e55c8 Author: julian <[email protected]> Authored: Mon Aug 15 10:41:57 2016 +0100 Committer: julian <[email protected]> Committed: Mon Nov 21 11:07:24 2016 +0000 ---------------------------------------------------------------------- compiler/simMIPS/compiler.yml | 38 ++ compiler/simMIPS/pkg.yml | 29 ++ libs/os/src/arch/simMIPS/os_arch_sim.c | 463 ++++++++++++++++++++ libs/os/src/arch/simMIPS/os_arch_stack_frame.s | 65 +++ libs/os/src/arch/simMIPS/os_fault.c | 34 ++ 5 files changed, 629 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3db61b0f/compiler/simMIPS/compiler.yml ---------------------------------------------------------------------- diff --git a/compiler/simMIPS/compiler.yml b/compiler/simMIPS/compiler.yml new file mode 100644 index 0000000..ebfdd97 --- /dev/null +++ b/compiler/simMIPS/compiler.yml @@ -0,0 +1,38 @@ +# +# 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: "mips-mti-linux-gnu-gcc" +compiler.path.as: "mips-mti-linux-gnu-gcc -x assembler-with-cpp" +compiler.path.archive: "mips-mti-linux-gnu-ar" +compiler.path.objdump: "mips-mti-linux-gnu-objdump" +compiler.path.objsize: "mips-mti-linux-gnu-size" +compiler.path.objcopy: "mips-mti-linux-gnu-objcopy" +compiler.flags.base: > + -std=gnu11 -EL -mips32r2 -Wall -Werror -ggdb +compiler.ld.resolve_circular_deps: true + +compiler.flags.default: [compiler.flags.base, -O1] +compiler.flags.debug: [compiler.flags.base, -O0] +compiler.ld.mapfile: 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/3db61b0f/compiler/simMIPS/pkg.yml ---------------------------------------------------------------------- diff --git a/compiler/simMIPS/pkg.yml b/compiler/simMIPS/pkg.yml new file mode 100644 index 0000000..99858eb --- /dev/null +++ b/compiler/simMIPS/pkg.yml @@ -0,0 +1,29 @@ +# +# 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 +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/3db61b0f/libs/os/src/arch/simMIPS/os_arch_sim.c ---------------------------------------------------------------------- diff --git a/libs/os/src/arch/simMIPS/os_arch_sim.c b/libs/os/src/arch/simMIPS/os_arch_sim.c new file mode 100644 index 0000000..9a96737 --- /dev/null +++ b/libs/os/src/arch/simMIPS/os_arch_sim.c @@ -0,0 +1,463 @@ +/** + * 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" + +#ifdef __APPLE__ +#define _XOPEN_SOURCE +#endif + +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <setjmp.h> +#include <signal.h> +#include <sys/time.h> +#include <assert.h> +#include <util/util.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; + + TAILQ_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(); + os_sanity_task_init(1); + + os_bsp_init(); + + 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/3db61b0f/libs/os/src/arch/simMIPS/os_arch_stack_frame.s ---------------------------------------------------------------------- diff --git a/libs/os/src/arch/simMIPS/os_arch_stack_frame.s b/libs/os/src/arch/simMIPS/os_arch_stack_frame.s new file mode 100644 index 0000000..e4ef39c --- /dev/null +++ b/libs/os/src/arch/simMIPS/os_arch_stack_frame.s @@ -0,0 +1,65 @@ +/** + * 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 + .globl _os_arch_frame_init + /* + * void os_arch_frame_init(struct stack_frame *sf) + */ + +os_arch_frame_init: + /* ABI stack frame */ + addi $sp, $sp, -24 /* 8 bytes for register save, 16 for args */ + sw $ra, 0x20($sp) /* push ra to stack */ + sw $s0, 0x16($sp) /* push s0 to the stack */ + + /* save and update sp to sf */ + move $s0, $a0 /* move sf to s0 */ + sw $sp, 0x0($s0) /* sf->mainsp = stack pointer */ + /* fairly sure sf will be 8 byte alligned anyway, but no harm in and vs move */ + and $sp, $s0, 0xfffffff1 /* stack pointer = sf 8 byte aligned */ + + /* call setjmp */ + addi $a0, $s0, 0x08 /* populate the arguments for sigsetjmp */ + move $a1, $zero + jal sigsetjmp /* sigsetjmp(sf->sf_jb, 0) */ + nop + + /* branch if starting task */ + bne $v0, $zero, os_arch_frame_init_start + nop + + /* back to main stack and return */ + lw $sp, 0x0($s0) /* back to main stack */ + lw $ra, 0x20($sp) /* pop ra from stack */ + lw $s0, 0x16($sp) /* pop s0 from the stack */ + addi $sp, $sp, 24 + jr $ra /* return */ + nop + +os_arch_frame_init_start: + move $a0, $s0 /* populate arguments for task */ + move $a1, $v0 + j os_arch_task_start /* jump to task, never to return */ + nop http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3db61b0f/libs/os/src/arch/simMIPS/os_fault.c ---------------------------------------------------------------------- diff --git a/libs/os/src/arch/simMIPS/os_fault.c b/libs/os/src/arch/simMIPS/os_fault.c new file mode 100644 index 0000000..15c40fe --- /dev/null +++ b/libs/os/src/arch/simMIPS/os_fault.c @@ -0,0 +1,34 @@ +/** + * 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]; + + snprintf(msg, sizeof(msg), "assert at %s:%d\n", file, line); + write(1, msg, strlen(msg)); + _exit(1); +}
