diff --git a/lib/miosix-kernel/meson.build b/lib/miosix-kernel/meson.build
index 97f95692..1df6df1e 100644
--- a/lib/miosix-kernel/meson.build
+++ b/lib/miosix-kernel/meson.build
@@ -26,3 +26,14 @@ miosix_cm4f_inc = miosix_inc + ['lib/miosix-kernel/miosix/arch/cortexM4F']
miosix_cm4f_src = miosix_src + ['lib/miosix-kernel/miosix/arch/cortexM4F/portability.cpp',
'lib/miosix-kernel/miosix/arch/common/core/interrupts_cortexMx.cpp']
miosix_cm4f_def = miosix_def + {'_ARCH_CORTEXM4' : ''}
+
+
+##
+## ARM Cortex M7
+##
+miosix_cm7_inc = miosix_inc + ['lib/miosix-kernel/miosix/arch/cortexM7']
+miosix_cm7_src = miosix_src + ['lib/miosix-kernel/miosix/arch/cortexM7/portability.cpp',
+ 'lib/miosix-kernel/miosix/arch/common/core/cache_cortexMx.cpp',
+ 'lib/miosix-kernel/miosix/arch/common/core/mpu_cortexMx.cpp',
+ 'lib/miosix-kernel/miosix/arch/common/core/interrupts_cortexMx.cpp']
+miosix_cm7_def = miosix_def + {'_ARCH_CORTEXM7' : ''}
diff --git a/lib/miosix-kernel/miosix/arch/common/core/cache_cortexMx.h b/lib/miosix-kernel/miosix/arch/common/core/cache_cortexMx.h
index 2c0e6667..24687d6f 100644
--- a/lib/miosix-kernel/miosix/arch/common/core/cache_cortexMx.h
+++ b/lib/miosix-kernel/miosix/arch/common/core/cache_cortexMx.h
@@ -122,6 +122,9 @@ void IRQconfigureCache(const unsigned int *xramBase=nullptr, unsigned int xramSi
*/
inline void markBufferBeforeDmaWrite(const void *buffer, int size)
{
+ (void) buffer;
+ (void) size;
+
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT==1)
// You may think that since the cache is configured as write-through,
// there's nothing to do before the DMA can read a memory buffer just
@@ -145,7 +148,11 @@ inline void markBufferBeforeDmaWrite(const void *buffer, int size)
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT==1)
void markBufferAfterDmaRead(void *buffer, int size);
#else
-inline void markBufferAfterDmaRead(void *buffer, int size) {}
+inline void markBufferAfterDmaRead(void *buffer, int size)
+{
+ (void) buffer;
+ (void) size;
+}
#endif
} //namespace miosix
diff --git a/lib/miosix-kernel/miosix/arch/cortexM7/arch_settings.h b/lib/miosix-kernel/miosix/arch/cortexM7/arch_settings.h
new file mode 100644
index 00000000..01235ec6
--- /dev/null
+++ b/lib/miosix-kernel/miosix/arch/cortexM7/arch_settings.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * Copyright (C) 2012-2021 by Terraneo Federico *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * As a special exception, if other files instantiate templates or use *
+ * macros or inline functions from this file, or you compile this file *
+ * and link it with other works to produce a work based on this file, *
+ * this file does not by itself cause the resulting work to be covered *
+ * by the GNU General Public License. However the source code for this *
+ * file must still be made available in accordance with the GNU General *
+ * Public License. This exception does not invalidate any other reasons *
+ * why a work based on this file might be covered by the GNU General *
+ * Public License. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#pragma once
+
+namespace miosix {
+
+/**
+ * \addtogroup Settings
+ * \{
+ */
+
+/// \internal size of vector to store registers during ctx switch
+/// ((10+16)*4=104Bytes). Only sp, r4-r11, EXC_RETURN and s16-s31 are saved
+/// here, since r0-r3,r12,lr,pc,xPSR, old sp and s0-s15,fpscr are saved by
+/// hardware on the process stack on Cortex M4F CPUs. EXC_RETURN, or the lr,
+/// value to use to return from the exception is necessary to know if the
+/// thread has used fp regs, as an extension specific to Cortex-M4F CPUs.
+const unsigned char CTXSAVE_SIZE=10+16;
+
+/// \internal some architectures save part of the context on their stack.
+/// ((8+17)*4=100Bytes). This constant is used to increase the stack size by
+/// the size of context save frame. If zero, this architecture does not save
+/// anything on stack during context save. Size is in bytes, not words.
+/// 8 registers=r0-r3,r12,lr,pc,xPSR
+/// 17 registers=s0-s15,fpscr
+/// MUST be divisible by 4.
+const unsigned int CTXSAVE_ON_STACK=(8+17)*4;
+
+/// \internal stack alignment for this specific architecture
+const unsigned int CTXSAVE_STACK_ALIGNMENT=8;
+
+/**
+ * \}
+ */
+
+} //namespace miosix
diff --git a/lib/miosix-kernel/miosix/arch/cortexM7/portability.cpp b/lib/miosix-kernel/miosix/arch/cortexM7/portability.cpp
new file mode 100644
index 00000000..0ae6eacb
--- /dev/null
+++ b/lib/miosix-kernel/miosix/arch/cortexM7/portability.cpp
@@ -0,0 +1,385 @@
+/***************************************************************************
+ * Copyright (C) 2010-2021 by Terraneo Federico *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * As a special exception, if other files instantiate templates or use *
+ * macros or inline functions from this file, or you compile this file *
+ * and link it with other works to produce a work based on this file, *
+ * this file does not by itself cause the resulting work to be covered *
+ * by the GNU General Public License. However the source code for this *
+ * file must still be made available in accordance with the GNU General *
+ * Public License. This exception does not invalidate any other reasons *
+ * why a work based on this file might be covered by the GNU General *
+ * Public License. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#include "interfaces/portability.h"
+#include "kernel/kernel.h"
+#include "kernel/error.h"
+#include "interfaces/bsp.h"
+#include "kernel/scheduler/scheduler.h"
+#include "kernel/scheduler/tick_interrupt.h"
+#include "core/interrupts.h"
+#include "kernel/process.h"
+#include
+#include
+#include
+#include
+
+/**
+ * \internal
+ * timer interrupt routine.
+ * Since inside naked functions only assembler code is allowed, this function
+ * only calls the ctxsave/ctxrestore macros (which are in assembler), and calls
+ * the implementation code in ISR_preempt()
+ */
+void SysTick_Handler() __attribute__((naked));
+void SysTick_Handler()
+{
+ saveContext();
+ //Call ISR_preempt(). Name is a C++ mangled name.
+ asm volatile("bl _ZN14miosix_private11ISR_preemptEv");
+ restoreContext();
+}
+
+/**
+ * \internal
+ * software interrupt routine.
+ * Since inside naked functions only assembler code is allowed, this function
+ * only calls the ctxsave/ctxrestore macros (which are in assembler), and calls
+ * the implementation code in ISR_yield()
+ */
+void SVC_Handler() __attribute__((naked));
+void SVC_Handler()
+{
+ saveContext();
+ //Call ISR_yield(). Name is a C++ mangled name.
+ asm volatile("bl _ZN14miosix_private9ISR_yieldEv");
+ restoreContext();
+}
+
+#ifdef SCHED_TYPE_CONTROL_BASED
+/**
+ * \internal
+ * Auxiliary timer interupt routine.
+ * Used for variable lenght bursts in control based scheduler.
+ * Since inside naked functions only assembler code is allowed, this function
+ * only calls the ctxsave/ctxrestore macros (which are in assembler), and calls
+ * the implementation code in ISR_yield()
+ */
+void TIM3_IRQHandler() __attribute__((naked));
+void TIM3_IRQHandler()
+{
+ saveContext();
+ //Call ISR_auxTimer(). Name is a C++ mangled name.
+ asm volatile("bl _ZN14miosix_private12ISR_auxTimerEv");
+ restoreContext();
+}
+#endif //SCHED_TYPE_CONTROL_BASED
+
+namespace miosix_private {
+
+/**
+ * \internal
+ * Called by the timer interrupt, preempt to next thread
+ * Declared noinline to avoid the compiler trying to inline it into the caller,
+ * which would violate the requirement on naked functions. Function is not
+ * static because otherwise the compiler optimizes it out...
+ */
+void ISR_preempt() __attribute__((noinline));
+void ISR_preempt()
+{
+ IRQstackOverflowCheck();
+ miosix::IRQtickInterrupt();
+}
+
+/**
+ * \internal
+ * Called by the software interrupt, yield to next thread
+ * Declared noinline to avoid the compiler trying to inline it into the caller,
+ * which would violate the requirement on naked functions. Function is not
+ * static because otherwise the compiler optimizes it out...
+ */
+void ISR_yield() __attribute__((noinline));
+void ISR_yield()
+{
+ #ifdef WITH_PROCESSES
+ // WARNING: Temporary fix. Rationale:
+ // This fix is intended to avoid kernel or process faulting due to
+ // another process actions. Consider the case in which a process statically
+ // allocates a big array such that there is no space left for saving
+ // context data. If the process issues a system call, in the following
+ // interrupt the context is saved, but since there is no memory available
+ // for all the context data, a mem manage interrupt is set to 'pending'. Then,
+ // a fake syscall is issued, based on the value read on the stack (which
+ // the process hasn't set due to the memory fault and is likely to be 0);
+ // this syscall is usually a yield (due to the value of 0 above),
+ // which can cause the scheduling of the kernel thread. At this point,
+ // the pending mem fault is issued from the kernel thread, causing the
+ // kernel fault and reboot. This is caused by the mem fault interrupt
+ // having less priority of the other interrupts.
+ // This fix checks if there is a mem fault interrupt pending, and, if so,
+ // it clears it and returns before calling the previously mentioned fake
+ // syscall.
+ if(SCB->SHCSR & (1<<13))
+ {
+ if(miosix::Thread::IRQreportFault(miosix_private::FaultData(
+ MP,0,0)))
+ {
+ SCB->SHCSR &= ~(1<<13); //Clear MEMFAULTPENDED bit
+ return;
+ }
+ }
+ #endif // WITH_PROCESSES
+ IRQstackOverflowCheck();
+
+ #ifdef WITH_PROCESSES
+ //If processes are enabled, check the content of r3. If zero then it
+ //it is a simple yield, otherwise handle the syscall
+ //Note that it is required to use ctxsave and not cur->ctxsave because
+ //at this time we do not know if the active context is user or kernel
+ unsigned int threadSp=ctxsave[0];
+ unsigned int *processStack=reinterpret_cast(threadSp);
+ if(processStack[3]!=miosix::SYS_YIELD)
+ miosix::Thread::IRQhandleSvc(processStack[3]);
+ else miosix::Scheduler::IRQfindNextThread();
+ #else //WITH_PROCESSES
+ miosix::Scheduler::IRQfindNextThread();
+ #endif //WITH_PROCESSES
+}
+
+#ifdef SCHED_TYPE_CONTROL_BASED
+/**
+ * \internal
+ * Auxiliary timer interupt routine.
+ * Used for variable lenght bursts in control based scheduler.
+ */
+void ISR_auxTimer() __attribute__((noinline));
+void ISR_auxTimer()
+{
+ IRQstackOverflowCheck();
+ miosix::Scheduler::IRQfindNextThread();//If the kernel is running, preempt
+ if(miosix::kernel_running!=0) miosix::tick_skew=true;
+ TIM3->SR=0;
+}
+#endif //SCHED_TYPE_CONTROL_BASED
+
+void IRQstackOverflowCheck()
+{
+ const unsigned int watermarkSize=miosix::WATERMARK_LEN/sizeof(unsigned int);
+ for(unsigned int i=0;iwatermark[i]!=miosix::WATERMARK_FILL)
+ miosix::errorHandler(miosix::STACK_OVERFLOW);
+ }
+ if(miosix::cur->ctxsave[0] < reinterpret_cast(
+ miosix::cur->watermark+watermarkSize))
+ miosix::errorHandler(miosix::STACK_OVERFLOW);
+}
+
+void IRQsystemReboot()
+{
+ NVIC_SystemReset();
+}
+
+void initCtxsave(unsigned int *ctxsave, void *(*pc)(void *), unsigned int *sp,
+ void *argv)
+{
+ unsigned int *stackPtr=sp;
+ stackPtr--; //Stack is full descending, so decrement first
+ *stackPtr=0x01000000; stackPtr--; //--> xPSR
+ *stackPtr=reinterpret_cast(
+ &miosix::Thread::threadLauncher); stackPtr--; //--> pc
+ *stackPtr=0xffffffff; stackPtr--; //--> lr
+ *stackPtr=0; stackPtr--; //--> r12
+ *stackPtr=0; stackPtr--; //--> r3
+ *stackPtr=0; stackPtr--; //--> r2
+ *stackPtr=reinterpret_cast(argv); stackPtr--; //--> r1
+ *stackPtr=reinterpret_cast(pc); //--> r0
+
+ ctxsave[0]=reinterpret_cast(stackPtr); //--> psp
+ //leaving the content of r4-r11 uninitialized
+ ctxsave[9]=0xfffffffd; //EXC_RETURN=thread mode, use psp, no floating ops
+ //leaving the content of s16-s31 uninitialized
+}
+
+#ifdef WITH_PROCESSES
+
+//
+// class FaultData
+//
+
+void FaultData::print() const
+{
+ switch(id)
+ {
+ case MP:
+ iprintf("* Attempted data access @ 0x%x (PC was 0x%x)\n",arg,pc);
+ break;
+ case MP_NOADDR:
+ iprintf("* Invalid data access (PC was 0x%x)\n",pc);
+ break;
+ case MP_XN:
+ iprintf("* Attempted instruction fetch @ 0x%x\n",pc);
+ break;
+ case UF_DIVZERO:
+ iprintf("* Dvide by zero (PC was 0x%x)\n",pc);
+ break;
+ case UF_UNALIGNED:
+ iprintf("* Unaligned memory access (PC was 0x%x)\n",pc);
+ break;
+ case UF_COPROC:
+ iprintf("* Attempted coprocessor access (PC was 0x%x)\n",pc);
+ break;
+ case UF_EXCRET:
+ iprintf("* Invalid exception return sequence (PC was 0x%x)\n",pc);
+ break;
+ case UF_EPSR:
+ iprintf("* Attempted access to the EPSR (PC was 0x%x)\n",pc);
+ break;
+ case UF_UNDEF:
+ iprintf("* Undefined instruction (PC was 0x%x)\n",pc);
+ break;
+ case UF_UNEXP:
+ iprintf("* Unexpected usage fault (PC was 0x%x)\n",pc);
+ break;
+ case HARDFAULT:
+ iprintf("* Hardfault (PC was 0x%x)\n",pc);
+ break;
+ case BF:
+ iprintf("* Busfault @ 0x%x (PC was 0x%x)\n",arg,pc);
+ break;
+ case BF_NOADDR:
+ iprintf("*Busfault (PC was 0x%x)\n",pc);
+ break;
+ }
+}
+
+void initCtxsave(unsigned int *ctxsave, void *(*pc)(void *), unsigned int *sp,
+ void *argv, unsigned int *gotBase)
+{
+ unsigned int *stackPtr=sp;
+ stackPtr--; //Stack is full descending, so decrement first
+ *stackPtr=0x01000000; stackPtr--; //--> xPSR
+ *stackPtr=reinterpret_cast(pc); stackPtr--; //--> pc
+ *stackPtr=0xffffffff; stackPtr--; //--> lr
+ *stackPtr=0; stackPtr--; //--> r12
+ *stackPtr=0; stackPtr--; //--> r3
+ *stackPtr=0; stackPtr--; //--> r2
+ *stackPtr=0; stackPtr--; //--> r1
+ *stackPtr=reinterpret_cast(argv); //--> r0
+
+ ctxsave[0]=reinterpret_cast(stackPtr); //--> psp
+ ctxsave[6]=reinterpret_cast(gotBase); //--> r9
+ //leaving the content of r4-r8,r10-r11 uninitialized
+ ctxsave[9]=0xfffffffd; //EXC_RETURN=thread mode, use psp, no floating ops
+ //leaving the content of s16-s31 uninitialized
+}
+
+#endif //WITH_PROCESSES
+
+void IRQportableStartKernel()
+{
+ //Enable fault handlers
+ SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk
+ | SCB_SHCSR_MEMFAULTENA_Msk;
+ //Enable traps for division by zero. Trap for unaligned memory access
+ //was removed as gcc starting from 4.7.2 generates unaligned accesses by
+ //default (https://www.gnu.org/software/gcc/gcc-4.7/changes.html)
+ SCB->CCR |= SCB_CCR_DIV_0_TRP_Msk;
+ NVIC_SetPriorityGrouping(7);//This should disable interrupt nesting
+ NVIC_SetPriority(SVCall_IRQn,3);//High priority for SVC (Max=0, min=15)
+ NVIC_SetPriority(SysTick_IRQn,3);//High priority for SysTick (Max=0, min=15)
+ NVIC_SetPriority(MemoryManagement_IRQn,2);//Higher priority for MemoryManagement (Max=0, min=15)
+ SysTick->LOAD=SystemCoreClock/miosix::TICK_FREQ;
+ //Start SysTick, set to generate interrupts
+ SysTick->CTRL=SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk |
+ SysTick_CTRL_CLKSOURCE_Msk;
+
+ #ifdef WITH_PROCESSES
+ //NOTE: if caches are enabled, the MPU will be enabled also if processes are
+ //not enabled, so this is here for the rare configuration of caches disabled
+ //but processes enabled
+ miosix::IRQenableMPUatBoot();
+ #endif //WITH_PROCESSES
+ #ifdef SCHED_TYPE_CONTROL_BASED
+ AuxiliaryTimer::IRQinit();
+ #endif //SCHED_TYPE_CONTROL_BASED
+
+ //create a temporary space to save current registers. This data is useless
+ //since there's no way to stop the sheduler, but we need to save it anyway.
+ unsigned int s_ctxsave[miosix::CTXSAVE_SIZE];
+ ctxsave=s_ctxsave;//make global ctxsave point to it
+ //Note, we can't use enableInterrupts() now since the call is not mathced
+ //by a call to disableInterrupts()
+ __enable_fault_irq();
+ __enable_irq();
+ miosix::Thread::yield();
+ //Never reaches here
+}
+
+void sleepCpu()
+{
+ __WFI();
+}
+
+#ifdef SCHED_TYPE_CONTROL_BASED
+void AuxiliaryTimer::IRQinit()
+{
+ RCC->APB1ENR|=RCC_APB1ENR_TIM3EN;
+ RCC_SYNC();
+ DBGMCU->APB1FZ|=DBGMCU_APB1_FZ_DBG_TIM3_STOP; //Tim3 stops while debugging
+ TIM3->CR1=0; //Upcounter, not started, no special options
+ TIM3->CR2=0; //No special options
+ TIM3->SMCR=0; //No external trigger
+ TIM3->CNT=0; //Clear timer
+ //get timer frequency considering APB1 prescaler
+ //consider that timer clock is twice APB1 clock when the APB1 prescaler has
+ //a division factor greater than 2
+ int timerClock=SystemCoreClock;
+ int apb1prescaler=(RCC->CFGR>>10) & 7;
+ if(apb1prescaler>4) timerClock>>=(apb1prescaler-4);
+ TIM3->PSC=(timerClock/miosix::AUX_TIMER_CLOCK)-1;
+ TIM3->ARR=0xffff; //Count from zero to 0xffff
+ TIM3->DIER=TIM_DIER_CC1IE; //Enable interrupt on compare
+ TIM3->CCR1=0xffff; //This will be initialized later with setValue
+ NVIC_SetPriority(TIM3_IRQn,3);//High priority for TIM3 (Max=0, min=15)
+ NVIC_EnableIRQ(TIM3_IRQn);
+ TIM3->CR1=TIM_CR1_CEN; //Start timer
+ //This is very important: without this the prescaler shadow register may
+ //not be updated
+ TIM3->EGR=TIM_EGR_UG;
+}
+
+int AuxiliaryTimer::IRQgetValue()
+{
+ return static_cast(TIM3->CNT);
+}
+
+void AuxiliaryTimer::IRQsetValue(int x)
+{
+ TIM3->CR1=0; //Stop timer since changing CNT or CCR1 while running fails
+ TIM3->CNT=0;
+ TIM3->CCR1=static_cast(std::min(x,0xffff));
+ TIM3->CR1=TIM_CR1_CEN; //Start timer again
+ //The above instructions cause a spurious if not called within the
+ //timer 2 IRQ (This happens if called from an SVC).
+ //Clearing the pending bit prevents this spurious interrupt
+ TIM3->SR=0;
+ NVIC_ClearPendingIRQ(TIM3_IRQn);
+}
+#endif //SCHED_TYPE_CONTROL_BASED
+
+} //namespace miosix_private
diff --git a/lib/miosix-kernel/miosix/arch/cortexM7/portability_impl.h b/lib/miosix-kernel/miosix/arch/cortexM7/portability_impl.h
new file mode 100644
index 00000000..032962b0
--- /dev/null
+++ b/lib/miosix-kernel/miosix/arch/cortexM7/portability_impl.h
@@ -0,0 +1,207 @@
+/***************************************************************************
+ * Copyright (C) 2010, 2011, 2012 by Terraneo Federico *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * As a special exception, if other files instantiate templates or use *
+ * macros or inline functions from this file, or you compile this file *
+ * and link it with other works to produce a work based on this file, *
+ * this file does not by itself cause the resulting work to be covered *
+ * by the GNU General Public License. However the source code for this *
+ * file must still be made available in accordance with the GNU General *
+ * Public License. This exception does not invalidate any other reasons *
+ * why a work based on this file might be covered by the GNU General *
+ * Public License. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+//Miosix kernel
+
+#ifndef PORTABILITY_IMPL_H
+#define PORTABILITY_IMPL_H
+
+#include "interfaces/arch_registers.h"
+#include "interfaces/portability.h"
+#include "config/miosix_settings.h"
+
+/**
+ * \addtogroup Drivers
+ * \{
+ */
+
+/*
+ * This pointer is used by the kernel, and should not be used by end users.
+ * this is a pointer to a location where to store the thread's registers during
+ * context switch. It requires C linkage to be used inside asm statement.
+ * Registers are saved in the following order:
+ * *ctxsave+100 --> s31
+ * ...
+ * *ctxsave+40 --> s16
+ * *ctxsave+36 --> lr (contains EXC_RETURN whose bit #4 tells if fpu is used)
+ * *ctxsave+32 --> r11
+ * *ctxsave+28 --> r10
+ * *ctxsave+24 --> r9
+ * *ctxsave+20 --> r8
+ * *ctxsave+16 --> r7
+ * *ctxsave+12 --> r6
+ * *ctxsave+8 --> r5
+ * *ctxsave+4 --> r4
+ * *ctxsave+0 --> psp
+ */
+extern "C" {
+extern volatile unsigned int *ctxsave;
+}
+const int stackPtrOffsetInCtxsave=0; ///< Allows to locate the stack pointer
+
+/**
+ * \internal
+ * \def saveContext()
+ * Save context from an interrupt
+ * Must be the first line of an IRQ where a context switch can happen.
+ * The IRQ must be "naked" to prevent the compiler from generating context save.
+ *
+ * A note on the dmb instruction, without it a race condition was observed
+ * between pauseKernel() and IRQfindNextThread(). pauseKernel() uses an strex
+ * instruction to store a value in the global variable kernel_running which is
+ * tested by the context switch code in IRQfindNextThread(). Without the memory
+ * barrier IRQfindNextThread() would occasionally read the previous value and
+ * perform a context switch while the kernel was paused, leading to deadlock.
+ * The failure was only observed within the exception_test() in the testsuite
+ * running on the stm32f429zi_stm32f4discovery.
+ */
+#define saveContext() \
+{ \
+ asm volatile(" mrs r1, psp \n"/*get PROCESS stack ptr */ \
+ " ldr r0, =ctxsave \n"/*get current context */ \
+ " ldr r0, [r0] \n" \
+ " stmia r0!, {r1,r4-r11,lr} \n"/*save r1(psp),r4-r11,lr */ \
+ " lsls r2, lr, #27 \n"/*check if bit #4 is set */ \
+ " bmi 0f \n" \
+ " vstmia.32 r0, {s16-s31} \n"/*save s16-s31 if we need*/ \
+ "0: dmb \n" \
+ ); \
+}
+
+/**
+ * \def restoreContext()
+ * Restore context in an IRQ where saveContext() is used. Must be the last line
+ * of an IRQ where a context switch can happen. The IRQ must be "naked" to
+ * prevent the compiler from generating context restore.
+ */
+#define restoreContext() \
+{ \
+ asm volatile(" ldr r0, =ctxsave \n"/*get current context */ \
+ " ldr r0, [r0] \n" \
+ " ldmia r0!, {r1,r4-r11,lr} \n"/*load r1(psp),r4-r11,lr */ \
+ " lsls r2, lr, #27 \n"/*check if bit #4 is set */ \
+ " bmi 0f \n" \
+ " vldmia.32 r0, {s16-s31} \n"/*restore s16-s31 if need*/ \
+ "0: msr psp, r1 \n"/*restore PROCESS sp*/ \
+ " bx lr \n"/*return*/ \
+ ); \
+}
+
+/**
+ * \}
+ */
+
+namespace miosix_private {
+
+/**
+ * \addtogroup Drivers
+ * \{
+ */
+
+inline void doYield()
+{
+ asm volatile("movs r3, #0\n\t"
+ "svc 0"
+ :::"r3");
+}
+
+inline void doDisableInterrupts()
+{
+ // Documentation says __disable_irq() disables all interrupts with
+ // configurable priority, so also SysTick and SVC.
+ // No need to disable faults with __disable_fault_irq()
+ __disable_irq();
+ //The new fastDisableInterrupts/fastEnableInterrupts are inline, so there's
+ //the need for a memory barrier to avoid aggressive reordering
+ asm volatile("":::"memory");
+}
+
+inline void doEnableInterrupts()
+{
+ __enable_irq();
+ //The new fastDisableInterrupts/fastEnableInterrupts are inline, so there's
+ //the need for a memory barrier to avoid aggressive reordering
+ asm volatile("":::"memory");
+}
+
+inline bool checkAreInterruptsEnabled()
+{
+ register int i;
+ asm volatile("mrs %0, primask \n\t":"=r"(i));
+ if(i!=0) return false;
+ return true;
+}
+
+#ifdef WITH_PROCESSES
+
+//
+// class SyscallParameters
+//
+
+inline SyscallParameters::SyscallParameters(unsigned int *context) :
+ registers(reinterpret_cast(context[0])) {}
+
+inline int SyscallParameters::getSyscallId() const
+{
+ return registers[3];
+}
+
+inline unsigned int SyscallParameters::getFirstParameter() const
+{
+ return registers[0];
+}
+
+inline unsigned int SyscallParameters::getSecondParameter() const
+{
+ return registers[1];
+}
+
+inline unsigned int SyscallParameters::getThirdParameter() const
+{
+ return registers[2];
+}
+
+inline void SyscallParameters::setReturnValue(unsigned int ret)
+{
+ registers[0]=ret;
+}
+
+inline void portableSwitchToUserspace()
+{
+ asm volatile("movs r3, #1\n\t"
+ "svc 0"
+ :::"r3");
+}
+
+#endif //WITH_PROCESSES
+
+/**
+ * \}
+ */
+
+} //namespace miosix_private
+
+#endif //PORTABILITY_IMPL_H