nuttx/arch/mips/include/mips32/irq.h

589 lines
17 KiB
C

/****************************************************************************
* arch/mips/include/mips32/irq.h
*
* Copyright (C) 2011, 2013, 2015, 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/* This file should never be included directed but, rather, only indirectly
* through nuttx/irq.h
*/
#ifndef __ARCH_MIPS_INCLUDE_MIPS32_IRQ_H
#define __ARCH_MIPS_INCLUDE_MIPS32_IRQ_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <arch/types.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
/* The global pointer (GP) does not need to be saved in the "normal," flat
* NuttX build. However, it would be necessary to save the GP if this is
* a KERNEL build or if NXFLAT is supported.
*/
#undef MIPS32_SAVE_GP
#if defined(CONFIG_BUILD_KERNEL) || defined(CONFIG_NXFLAT)
# define MIPS32_SAVE_GP 1
#endif
/* If this is a kernel build, how many nested system calls should we support? */
#ifndef CONFIG_SYS_NNEST
# define CONFIG_SYS_NNEST 2
#endif
/* Register save state structure ********************************************/
/* Co processor registers */
#define REG_MFLO_NDX 0
#define REG_MFHI_NDX 1
#define REG_EPC_NDX 2
#define REG_STATUS_NDX 3
/* General pupose registers */
/* $0: Zero register does not need to be saved */
/* $1: at_reg, assembler temporary */
#define REG_R1_NDX 4
/* $2-$3 = v0-v1: Return value registers */
#define REG_R2_NDX 5
#define REG_R3_NDX 6
/* $4-$7 = a0-a3: Argument registers */
#define REG_R4_NDX 7
#define REG_R5_NDX 8
#define REG_R6_NDX 9
#define REG_R7_NDX 10
/* $8-$15 = t0-t7: Volatile registers */
#define REG_R8_NDX 11
#define REG_R9_NDX 12
#define REG_R10_NDX 13
#define REG_R11_NDX 14
#define REG_R12_NDX 15
#define REG_R13_NDX 16
#define REG_R14_NDX 17
#define REG_R15_NDX 18
/* $16-$23 = s0-s7: Static registers */
#define REG_R16_NDX 19
#define REG_R17_NDX 20
#define REG_R18_NDX 21
#define REG_R19_NDX 22
#define REG_R20_NDX 23
#define REG_R21_NDX 24
#define REG_R22_NDX 25
#define REG_R23_NDX 26
/* $24-25 = t8-t9: More Volatile registers */
#define REG_R24_NDX 27
#define REG_R25_NDX 28
/* $26-$27 = ko-k1: Reserved for use in exeption handers. These do not need
* to be saved.
*/
/* $28 = gp: Only needs to be saved under conditions where there are
* multiple, per-thread values for the GP.
*/
#ifdef MIPS32_SAVE_GP
# define REG_R28_NDX 29
/* $29 = sp: The value of the stack pointer on return from the exception */
# define REG_R29_NDX 30
/* $30 = either s8 or fp: Depends if a frame pointer is used or not */
# define REG_R30_NDX 31
/* $31 = ra: Return address */
# define REG_R31_NDX 32
# define XCPTCONTEXT_REGS 33
#else
/* $29 = sp: The value of the stack pointer on return from the exception */
# define REG_R29_NDX 29
/* $30 = either s8 or fp: Depends if a frame pointer is used or not */
# define REG_R30_NDX 30
/* $31 = ra: Return address */
# define REG_R31_NDX 31
# define XCPTCONTEXT_REGS 32
#endif
#define XCPTCONTEXT_SIZE (4 * XCPTCONTEXT_REGS)
/* In assembly language, values have to be referenced as byte address
* offsets. But in C, it is more convenient to reference registers as
* register save table offsets.
*/
#ifdef __ASSEMBLY__
# define REG_MFLO (4*REG_MFLO_NDX)
# define REG_MFHI (4*REG_MFHI_NDX)
# define REG_EPC (4*REG_EPC_NDX)
# define REG_STATUS (4*REG_STATUS_NDX)
# define REG_R1 (4*REG_R1_NDX)
# define REG_R2 (4*REG_R2_NDX)
# define REG_R3 (4*REG_R3_NDX)
# define REG_R4 (4*REG_R4_NDX)
# define REG_R5 (4*REG_R5_NDX)
# define REG_R6 (4*REG_R6_NDX)
# define REG_R7 (4*REG_R7_NDX)
# define REG_R8 (4*REG_R8_NDX)
# define REG_R9 (4*REG_R9_NDX)
# define REG_R10 (4*REG_R10_NDX)
# define REG_R11 (4*REG_R11_NDX)
# define REG_R12 (4*REG_R12_NDX)
# define REG_R13 (4*REG_R13_NDX)
# define REG_R14 (4*REG_R14_NDX)
# define REG_R15 (4*REG_R15_NDX)
# define REG_R16 (4*REG_R16_NDX)
# define REG_R17 (4*REG_R17_NDX)
# define REG_R18 (4*REG_R18_NDX)
# define REG_R19 (4*REG_R19_NDX)
# define REG_R20 (4*REG_R20_NDX)
# define REG_R21 (4*REG_R21_NDX)
# define REG_R22 (4*REG_R22_NDX)
# define REG_R23 (4*REG_R23_NDX)
# define REG_R24 (4*REG_R24_NDX)
# define REG_R25 (4*REG_R25_NDX)
# ifdef MIPS32_SAVE_GP
# define REG_R28 (4*REG_R28_NDX)
# endif
# define REG_R29 (4*REG_R29_NDX)
# define REG_R30 (4*REG_R30_NDX)
# define REG_R31 (4*REG_R31_NDX)
#else
# define REG_MFLO REG_MFLO_NDX
# define REG_MFHI REG_MFHI_NDX
# define REG_EPC REG_EPC_NDX
# define REG_STATUS REG_STATUS_NDX
# define REG_R1 REG_R1_NDX
# define REG_R2 REG_R2_NDX
# define REG_R3 REG_R3_NDX
# define REG_R4 REG_R4_NDX
# define REG_R5 REG_R5_NDX
# define REG_R6 REG_R6_NDX
# define REG_R7 REG_R7_NDX
# define REG_R8 REG_R8_NDX
# define REG_R9 REG_R9_NDX
# define REG_R10 REG_R10_NDX
# define REG_R11 REG_R11_NDX
# define REG_R12 REG_R12_NDX
# define REG_R13 REG_R13_NDX
# define REG_R14 REG_R14_NDX
# define REG_R15 REG_R15_NDX
# define REG_R16 REG_R16_NDX
# define REG_R17 REG_R17_NDX
# define REG_R18 REG_R18_NDX
# define REG_R19 REG_R19_NDX
# define REG_R20 REG_R20_NDX
# define REG_R21 REG_R21_NDX
# define REG_R22 REG_R22_NDX
# define REG_R23 REG_R23_NDX
# define REG_R24 REG_R24_NDX
# define REG_R25 REG_R25_NDX
# ifdef MIPS32_SAVE_GP
# define REG_R28 REG_R28_NDX
# endif
# define REG_R29 REG_R29_NDX
# define REG_R30 REG_R30_NDX
# define REG_R31 REG_R31_NDX
#endif
/* Now define more user friendly alternative name that can be used either
* in assembly or C contexts.
*/
/* $1: at_reg, assembler temporary */
#define REG_AT REG_R1
/* $2-$3 = v0-v1: Return value registers */
#define REG_V0 REG_R2
#define REG_V1 REG_R3
/* $4-$7 = a0-a3: Argument registers */
#define REG_A0 REG_R4
#define REG_A1 REG_R5
#define REG_A2 REG_R6
#define REG_A3 REG_R7
/* $8-$15 = t0-t7: Volatile registers */
#define REG_T0 REG_R8
#define REG_T1 REG_R9
#define REG_T2 REG_R10
#define REG_T3 REG_R11
#define REG_T4 REG_R12
#define REG_T5 REG_R13
#define REG_T6 REG_R14
#define REG_T7 REG_R15
/* $16-$23 = s0-s7: Static registers */
#define REG_S0 REG_R16
#define REG_S1 REG_R17
#define REG_S2 REG_R18
#define REG_S3 REG_R19
#define REG_S4 REG_R20
#define REG_S5 REG_R21
#define REG_S6 REG_R22
#define REG_S7 REG_R23
/* $24-25 = t8-t9: More Volatile registers */
#define REG_T8 REG_R24
#define REG_T9 REG_R25
/* $28 = gp: Only needs to be saved under conditions where there are
* multiple, per-thread values for the GP.
*/
#ifdef MIPS32_SAVE_GP
# define REG_GP REG_R28
#endif
/* $29 = sp: The value of the stack pointer on return from the exception */
#define REG_SP REG_R29
/* $30 = either s8 or fp: Depends if a frame pointer is used or not */
#define REG_S8 REG_R30
#define REG_FP REG_R30
/* $31 = ra: Return address */
#define REG_RA REG_R31
/****************************************************************************
* Public Types
****************************************************************************/
#ifndef __ASSEMBLY__
/* This structure represents the return state from a system call */
#ifdef CONFIG_BUILD_KERNEL
struct xcpt_syscall_s
{
uint32_t sysreturn; /* The return PC */
};
#endif
/* The following structure is included in the TCB and defines the complete
* state of the thread.
*/
struct xcptcontext
{
#ifndef CONFIG_DISABLE_SIGNALS
/* The following function pointer is non-NULL if there are pending signals
* to be processed.
*/
void *sigdeliver; /* Actual type is sig_deliver_t */
/* These additional register save locations are used to implement the
* signal delivery trampoline.
*
* REVISIT: Because there is only one copy of these save areas,
* only a single signal handler can be active. This precludes
* queuing of signal actions. As a result, signals received while
* another signal handler is executing will be ignored!
*/
uint32_t saved_epc; /* Trampoline PC */
uint32_t saved_status; /* Status with interrupts disabled. */
# ifdef CONFIG_BUILD_KERNEL
/* This is the saved address to use when returning from a user-space
* signal handler.
*/
uint32_t sigreturn;
# endif
#endif
#ifdef CONFIG_BUILD_KERNEL
/* The following array holds information needed to return from each nested
* system call.
*/
uint8_t nsyscalls;
struct xcpt_syscall_s syscall[CONFIG_SYS_NNEST];
#endif
/* Register save area */
uint32_t regs[XCPTCONTEXT_REGS];
};
/****************************************************************************
* Inline functions
****************************************************************************/
/****************************************************************************
* Name: cp0_getstatus
*
* Description:
* Read the CP0 STATUS register
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static inline irqstate_t cp0_getstatus(void)
{
register irqstate_t status;
__asm__ __volatile__
(
"\t.set push\n"
"\t.set noat\n"
"\t mfc0 %0, $12, 0\n" /* Get CP0 status register */
"\t.set pop\n"
: "=r" (status)
:
: "memory"
);
return status;
}
/****************************************************************************
* Name: cp0_putstatus
*
* Description:
* Write the CP0 STATUS register
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static inline void cp0_putstatus(irqstate_t status)
{
__asm__ __volatile__
(
"\t.set push\n"
"\t.set noat\n"
"\t.set noreorder\n"
"\tmtc0 %0, $12, 0\n" /* Set the status to the provided value */
"\tnop\n" /* MTC0 status hazard: */
"\tnop\n" /* Recommended spacing: 3 */
"\tnop\n"
"\tnop\n" /* Plus one for good measure */
"\t.set pop\n"
:
: "r" (status)
: "memory"
);
}
/****************************************************************************
* Name: cp0_getcause
*
* Description:
* Get the CP0 CAUSE register
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static inline uint32_t cp0_getcause(void)
{
register uint32_t cause;
__asm__ __volatile__
(
"\t.set push\n"
"\t.set noat\n"
"\t mfc0 %0, $13, 0\n" /* Get CP0 cause register */
"\t.set pop\n"
: "=r" (cause)
:
: "memory"
);
return cause;
}
/****************************************************************************
* Name: cp0_putcause
*
* Description:
* Write the CP0 CAUSE register
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static inline void cp0_putcause(uint32_t cause)
{
__asm__ __volatile__
(
"\t.set push\n"
"\t.set noat\n"
"\t.set noreorder\n"
"\tmtc0 %0, $13, 0\n" /* Set the cause to the provided value */
"\t.set pop\n"
:
: "r" (cause)
: "memory"
);
}
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Name: up_irq_save
*
* Description:
* Save the current interrupt state and disable interrupts.
*
* NOTE: This function should never be called from application code and,
* as a general rule unless you really know what you are doing, this
* function should not be called directly from operation system code either:
* Typically, the wrapper functions, enter_critical_section() is probably
* what you really want.
*
* Input Parameters:
* None
*
* Returned Value:
* Interrupt state prior to disabling interrupts.
*
****************************************************************************/
irqstate_t up_irq_save(void);
/****************************************************************************
* Name: up_irq_restore
*
* Description:
* Restore the previous interrupt state (i.e., the one previously returned
* by up_irq_save())
*
* NOTE: This function should never be called from application code and,
* as a general rule unless you really know what you are doing, this
* function should not be called directly from operation system code either:
* Typically, the wrapper functions, leave_critical_section() is probably
* what you really want.
*
* Input Parameters:
* state - The interrupt state to be restored.
*
* Returned Value:
* None
*
****************************************************************************/
void up_irq_restore(irqstate_t irqtate);
/****************************************************************************
* Name: up_irq_enable
*
* Description:
* Enable interrupts
*
* Input Parameters:
* None.
*
* Returned Value:
* None
*
****************************************************************************/
void up_irq_enable(void);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* __ASSEMBLY */
#endif /* __ARCH_MIPS_INCLUDE_MIPS32_IRQ_H */