Miosix: added support for ARM Cortex M7 devices

pull/313/head
Silvano Seva 2024-10-17 08:42:12 +02:00
rodzic 07c4ea6753
commit 04401c6eeb
5 zmienionych plików z 672 dodań i 1 usunięć

Wyświetl plik

@ -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' : ''}

Wyświetl plik

@ -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

Wyświetl plik

@ -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 <http://www.gnu.org/licenses/> *
***************************************************************************/
#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

Wyświetl plik

@ -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 <http://www.gnu.org/licenses/> *
***************************************************************************/
#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 <algorithm>
#include <cstdio>
#include <cstring>
#include <cassert>
/**
* \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<unsigned int*>(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;i<watermarkSize;i++)
{
if(miosix::cur->watermark[i]!=miosix::WATERMARK_FILL)
miosix::errorHandler(miosix::STACK_OVERFLOW);
}
if(miosix::cur->ctxsave[0] < reinterpret_cast<unsigned int>(
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<unsigned long>(
&miosix::Thread::threadLauncher); stackPtr--; //--> pc
*stackPtr=0xffffffff; stackPtr--; //--> lr
*stackPtr=0; stackPtr--; //--> r12
*stackPtr=0; stackPtr--; //--> r3
*stackPtr=0; stackPtr--; //--> r2
*stackPtr=reinterpret_cast<unsigned long >(argv); stackPtr--; //--> r1
*stackPtr=reinterpret_cast<unsigned long >(pc); //--> r0
ctxsave[0]=reinterpret_cast<unsigned long>(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<unsigned long>(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<unsigned long >(argv); //--> r0
ctxsave[0]=reinterpret_cast<unsigned long>(stackPtr); //--> psp
ctxsave[6]=reinterpret_cast<unsigned long>(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<int>(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<unsigned short>(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

Wyświetl plik

@ -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 <http://www.gnu.org/licenses/> *
***************************************************************************/
//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<br>
* 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<unsigned int*>(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