SylixOS下的GIC中断实现(基于T3)

SylixOS下的GIC中断实现(基于T3)

GIC常用寄存器介绍

GICD_CTLR

GICv2控制器将中断分为两组。配置对应寄存器可以控制这两组中断的使能与禁能。

GICD_ISENABLERn

中断向量使能寄存器,写入1使能对应的中断向量号,写0没有影响。读取数据表示对应中断向量号的使能状态。每32个中断向量使用一个寄存器位,后续中断向量放在接下来的寄存器地址上。

GICD_ICENABLERn

中断使能清除寄存器。写入1禁能对应中断向量号,写0没有影响。读取数据表示对应中断向量号的使能状态。每32个中断向量使用一个寄存器位,后续中断向量放在接下来的寄存器地址上。

GICD_ISPENDRn

中断阻塞寄存器。读取为0表示中断不会再任何处理器上挂起,读取为1表示中断挂起在相应的处理器上。写入0没有影响,写入1将原来的非活动中断改为挂起状态或者将活动状态改为活动和挂起状态。

GICD_ICPENDRn

中断清除阻塞寄存器。读取为0表示中断不会再任何处理器上挂起,读取为1表示中断挂起在相应的处理器上。写入0没有影响,写入1挂起状态改为非活动态,将原来的活动和挂起状态改为活动状态。

GICD_ISACTIVERn

中断活动寄存器。读0表示中断非活动状态,读1表示中断活动。写入0没有影响,写入1激活对应的中断为活动状态。

GICD_ICACTIVERn

中断清除活动寄存器。读0表示中断非活动状态,读1表示中断活动。写入0没有影响,写入1清除中断的激活状态。

GICD_IPRIORITYRn

中断优先级寄存器。每个中断向量有8位来表示中断的优先级。中断优先级数字越低表示优先级越高。

GICD_ITARGETSRn

中断处理器目标寄存器。每个中断向量有8位配置中断向量发送到哪个或者哪些处理器上。配置的一个字节的每一个位表示一个处理器目标。

GICD_ICFGRn

中断配置寄存器。每个中断向量有两位的配置位,其中高位写1表示中断电平触发,写0表示中断边沿触发。低位是兼容旧版本GIC实现留下的保留位。

GICD_SGIR

TargetListFilter 选择软中断的目标处理器,自主选择触发哪些CPU中断,发送给除自己以外所有处理器或者发送给自己软终端。CPUTargetList 表示软中断触发哪些处理器。SIGIINTID 配置触发的软中断的中断向量号。

软件中断触发寄存器。

GICC_CTLR

CPU处理器接口控制寄存器。

控制GICC_EOIR和GICC_DIR寄存器的功能

控制中断的旁路中断的工作状态。

CBPR控制 GIC_BPR寄存器的工作状态。 FIQEn寄存器控制中断向量组0发出IRQ信号还是FIQ信号。

最低两位控制两个中断向量组的使能。

GICC_PMR

中断优先级掩码寄存器。CPU只接受中断优先级高于掩码优先级的中断响应,并且根据中断优先级的数量配置对应的位数为0。

GICC_BPR

中断优先级划分寄存器。根据配置的参数将中断优先级分为组优先级和次优先级。

GICC_IAR

中断应答寄存器。对于软终端 CPUID 标识出中断请求来源的CPU号。InterruptID表示触发的中断向量号。

GICC_EOIR

中断结束寄存器。CPUID表示软中断从GICC_IAR读取的软件中断请求来源。EIOINTID表示中断结束的中断向量号。

GICC_IIDR

GIC处理器接口识别寄存器。存放了GIC的版本信息和JEP106代码。GIC版本信息应该是0x2,JEP106代码应该是0x43B

中断控制器初始化

中断初始化

/*********************************************************************************************************
** 函数名称: bspIntInit
** 功能描述: 中断系统初始化
** 输 入 : NONE
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID  bspIntInit (VOID)
{
#define ALLWINNERT3_GIC_REDIST_BA   (0x1c82000)
#define ALLWINNERT3_GIC_DIST_BA     (0x1c81000)
#if defined(BSP_MODE_SMP)
   ULONG           ulCPUId = LW_CPU_GET_CUR_ID();
#endif
   ARM_GIC         armGic;
   ARM_GIC_REDIST  armGicRedist[4];

   armGicRedist[0].AGICRD_ulRedistBase = ALLWINNERT3_GIC_REDIST_BA;
   armGicRedist[1].AGICRD_ulRedistBase = ALLWINNERT3_GIC_REDIST_BA;
   armGicRedist[2].AGICRD_ulRedistBase = ALLWINNERT3_GIC_REDIST_BA;
   armGicRedist[3].AGICRD_ulRedistBase = ALLWINNERT3_GIC_REDIST_BA;

   armGic.AGIC_ulDistBase  = ALLWINNERT3_GIC_DIST_BA;
   armGic.AGIC_uiRedistNum = 4;
   armGic.AGIC_pRedist     = armGicRedist;

   armGicPrimaryInit(ARM_GIC_V2, &armGic);

#if defined(BSP_MODE_SMP)
   API_InterVectorIpi(ulCPUId, ulCPUId);                               /* 安装 CPU 0 IPI 向量         */
#endif

#if defined(BSP_MODE_AMP_CPU0)
   API_InterVectorSetFlag(SPI_PIO, LW_IRQ_FLAG_QUEUE);
   API_InterVectorSetPriority(SPI_PIO, 10);
#endif
}

中断初始化中,给定 GIC 控制器的基地址,初始化 GICv2 版本的中断控制器。如果系统是 SMP 模式,设置CPU的核间中断(软终端)。如果系统工作在 AMP 模式,将 IO 外部中断配置为一个中断向量对应多个中断服务函数的处理模式。

GICv2 版本初始化

GICv2 版本初始化其实调用的还是v1版本初始化的代码,内部功能兼容。

/*********************************************************************************************************
** 函数名称: armGicV1Init
** 功能描述: 初始化 GIC V1 版本中断控制器
** 输 入 : pcGicName       中断控制器名称
**           parmGic         中断控制器结构指针
**           parmGicOp       中断控制器操作集
** 输 出 : ERROR_CODE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
INT  armGicV1Init (CPCHAR  pcGicName, PARM_GIC  parmGic, PARM_GIC_OP  parmGicOp)
{
   PARM_GIC_CPU_INF  parmGicInf;
   ULONG             ulDistBase;
   UINT              uiInfNum;
   UINT              uiIrqNum;
   INT               i;

   uiInfNum    = parmGic->AGIC_ulCpuInfNum;
   ulDistBase  = parmGic->AGIC_ulDistBase;
   uiIrqNum    = GICD_TYPER_IRQS(read32(ulDistBase + GICD_TYPER));      /* 获取支持的中断数           */
   if (uiIrqNum > 1020) {
       uiIrqNum = 1020;
  }

   parmGicInf = __SHEAP_ZALLOC(uiInfNum * sizeof(ARM_GIC_CPU_INF));
   if (!parmGicInf) {
       _ErrorHandle(ENOMEM);
       return (PX_ERROR);
  }

   for (i = 0; i < uiInfNum; i++) {
       parmGicInf[i].AGICRD_ulCpuInfBase = parmGic->AGIC_pCpuInf[i].AGICRD_ulCpuInfBase;
  }

   _G_armGicV1Data.AGICD_pCpuInf    = parmGicInf;
   _G_armGicV1Data.AGICD_ulDistBase = ulDistBase;
   _G_armGicV1Data.AGICD_uiIrqNum   = uiIrqNum;

#if defined(BSP_MODE_SMP) || defined(BSP_MODE_AMP_CPU0)
   armGicV1DistInit();                                                 /* 初始化 GIC 发布器           */
#endif
   armGicV1CpuInit();                                                  /* 初始化 CPU 部分             */

   parmGicOp->AGIC_pfuncIrqEnable      = armGicV1IrqEnable;
   parmGicOp->AGIC_pfuncIrqDisable     = armGicV1IrqDisable;
   parmGicOp->AGIC_pfuncIrqIsEnable    = armGicV1IrqIsEnable;
   parmGicOp->AGIC_pfuncRaiseSoftIrq   = armGicV1RaiseSoftIrq;
   parmGicOp->AGIC_pfuncIrqHandle      = armGicV1IrqHandle;
   parmGicOp->AGIC_pfuncIrqPrioritySet = armGicV1IrqPrioritySet;
   parmGicOp->AGIC_pfuncIrqPriorityGet = armGicV1IrqPriorityGet;
   parmGicOp->AGIC_pfuncIrqAffinitySet = armGicV1IrqAffinitySet;
   parmGicOp->AGIC_pfuncIrqAffinityGet = armGicV1IrqAffinityGet;
   parmGicOp->AGIC_pfuncIrqTypeSet     = armGicV1IrqTypeSet;

   return (ERROR_NONE);
}

获取 GIC 控制器支持的中断向量数量,初始化GIC结构体。分别初始化GIC发布器和GIC处理器,并安装了对应的GIC控制函数。

初始化GIC 发布器

/*********************************************************************************************************
** 函数名称: armGicV1CpuMaskGet
** 功能描述: 获取 GIC V1 的 CPU 掩码
** 输 入 : ulDistBase   Distributor 基址
** 输 出 : CPU 掩码
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static UINT8  armGicV1CpuMaskGet (ULONG  ulDistBase)
{
   UINT32  uiMask;
   INT     i;

   for (i = 0; i < 32; i += 4) {
       uiMask  = read32(ulDistBase + GICD_ITARGETSR + i);
       uiMask |= uiMask >> 16;
       uiMask |= uiMask >> 8;
       if (uiMask) {
           break;
      }
  }

   return ((UINT8)uiMask);
}
/*********************************************************************************************************
** 函数名称: armGicDistConfig
** 功能描述: GIC Distributor 配置
** 输 入 : ulDistBase   Distributor 基址
**           uiIrqNum     中断数量
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID  armGicDistConfig (ULONG  ulDistBase, UINT  uiIrqNum)
{
   INT  i;
//GICD_INT_ACTLOW_LVLTRIG == 0x00
   //配置所有的外围设备中断为低电平触发
   for (i = 32; i < uiIrqNum; i += 16) {                               /* SPI 中断默认为低电平触发   */
       write32(GICD_INT_ACTLOW_LVLTRIG, ulDistBase + GICD_ICFGR + i / 4);
  }
//GICD_INT_DEF_PRI_X4 = 0xa0a0a0a0
   //配置所有的外围设备中断优先级为0xa0
   for (i = 32; i < uiIrqNum; i += 4) {                                /* SPI 中断默认的中断优先级   */
       write32(GICD_INT_DEF_PRI_X4, ulDistBase + GICD_IPRIORITYR + i);
  }
//GICD_INT_EN_CLR_X32 == 0xffffffff
   //清除所有外围设备中断的状态
   for (i = 32; i < uiIrqNum; i += 32) {
       write32(GICD_INT_EN_CLR_X32,
              ulDistBase + GICD_ICACTIVER + i / 8);                    /* 失效所有的 SPI 中断         */
       write32(GICD_INT_EN_CLR_X32,
              ulDistBase + GICD_ICENABLER + i / 8);                    /* 禁用所有的 SPI 中断         */
       write32(GICD_INT_EN_CLR_X32,
              ulDistBase + GICD_ICPENDR + i / 8);                      /* 清除所有的 SPI 中断         */
  }
}
/*********************************************************************************************************
** 函数名称: armGicV1DistInit
** 功能描述: 初始化 GIC V1 Distributor
** 输 入 : NONE
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static VOID  armGicV1DistInit (VOID)
{
   UINT32  uiMask;
   ULONG   ulDistBase;
   UINT    uiIrqNum;
   UINT    i;

   ulDistBase = GIC_DIST_BASE_GET();
   uiIrqNum   = GIC_IRQ_NUM_GET();
//关闭两个GIC分组的中断
   write32(0, ulDistBase + GICD_CTLR);                                 /* 禁用发布器                 */
//这里找到前32个中断向量号的CPU目标的设置,默认配置到所有的中断向量上
   uiMask  = armGicV1CpuMaskGet(ulDistBase);                           /* 默认路由到 BOOT CPU         */
   uiMask |= uiMask << 8;
   uiMask |= uiMask << 16;
   for (i = 32; i < uiIrqNum; i += 4) {
       write32(uiMask, ulDistBase + GICD_ITARGETSR + i * 4 / 4);
  }

   armGicDistConfig(ulDistBase, uiIrqNum);                             /* SPI 默认状态设置           */
//打开第0组的中断使能
   //SylixOS下没有特地把中断分组,所有的中断reset之后默认都存在0组中
   write32(1, ulDistBase + GICD_CTLR);                                 /* 使能发布器                 */
}
#endif

初始化GIC处理器接口

/*********************************************************************************************************
** 函数名称: armGicCpuConfig
** 功能描述: GIC CPU 端配置
** 输 入 : ulCpuIfBase   CPU 端基址
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID  armGicCpuConfig (ULONG  ulCpuIfBase)
{
   INT  i;
//GICD_INT_EN_CLR_X32 == 0xffffffff
   //清除前32个中断向量的激活状态
   write32(GICD_INT_EN_CLR_X32, ulCpuIfBase + GICD_ICACTIVER);
   //GICD_INT_EN_CLR_PPI == 0xffff0000
   //禁能16~31号中断,这一部分表示私有外设中断
   write32(GICD_INT_EN_CLR_PPI, ulCpuIfBase + GICD_ICENABLER);
   //GICD_INT_EN_SET_SGI == 0x0000ffff
   //使能0~15号中断,这一部分表示软终端,用于核间中断
   write32(GICD_INT_EN_SET_SGI, ulCpuIfBase + GICD_ISENABLER);
//GICD_INT_DEF_PRI_X4 = 0xa0a0a0a0
   //配置前32个中断的默认中断优先级
   for (i = 0; i < 32; i += 4) {
       write32(GICD_INT_DEF_PRI_X4,
              ulCpuIfBase + GICD_IPRIORITYR + i * 4 / 4);              /* 设置 PPI 和 SGI 优先级     */
  }
}
/*********************************************************************************************************
** 函数名称: armGicV2CpuInfCheck
** 功能描述: 判断是否是 GIC V2 的 CPU Interface
** 输 入 : ulBase   CPU Interface 基址
** 输 出 : LW_TRUE 为 GIC V2,LW_FALSE 不是 GIC V2
** 全局变量:
** 调用模块:
*********************************************************************************************************/
BOOL  armGicV2CpuInfCheck (ULONG  ulBase)
{
   UINT32  uiVal;
//读取GIC的ID寄存器,判断GIC控制器的版本
   uiVal = read32(ulBase + GICC_IIDR);

   return ((uiVal & 0xff0fff) == 0x02043b);
}
/*********************************************************************************************************
** 函数名称: armGicV1CpuInit
** 功能描述: 初始化 GIC V1 CPU 部分
** 输 入 : NONE
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID  armGicV1CpuInit (VOID)
{
   ULONG   ulCpuInfBase;
   UINT32  uiBypass;
   INT     i;

   ulCpuInfBase = GIC_CUR_CPU_INF_BASE_GET();

   armGicCpuConfig(ulCpuInfBase);
//GICC_INT_PRI_THRESHOLD == 0xff
   //配置CPU接受的中断优先级掩码为最低优先级,CPU可以响应所有的优先级的中断
   write32(GICC_INT_PRI_THRESHOLD, ulCpuInfBase + GICC_PMR);
   //配置中断优先级的主优先级和次优先级划分,具体见下图
   write32(0x0,                    ulCpuInfBase + GICC_BPR);

   if (armGicV2CpuInfCheck(ulCpuInfBase)) {
       for (i = 0; i < 4; i++) {
            write32(0, ulCpuInfBase + GICC_APR + i * 4);
      }
  }

   uiBypass  = read32(ulCpuInfBase + GICC_CTRL);
   //关闭中断旁路功能
   uiBypass &= GICC_DIS_BYPASS_MASK;
   //GICC_ENABLE == 0x1
   //打开中断向量组0的使能位
   write32(uiBypass | GICC_ENABLE, ulCpuInfBase + GICC_CTRL);
}

中断驱动函数

中断向量使能

/*********************************************************************************************************
** 函数名称: armGicV1IrqEnable
** 功能描述: GIC V1 设置中断使能
** 输 入 : ulVector   中断号
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static VOID  armGicV1IrqEnable (ULONG  ulVector)
{
   UINT32  uiMask;
   ULONG   ulBase;

   uiMask = 1 << (ulVector % 32);
   ulBase = GIC_DIST_BASE_GET();

   write32(uiMask, ulBase + GICD_ISENABLER + (ulVector / 32) * 4);
}

中断向量禁能

/*********************************************************************************************************
** 函数名称: armGicV1IrqDisable
** 功能描述: GIC V1 设置中断禁能
** 输 入 : ulVector   中断号
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static VOID  armGicV1IrqDisable (ULONG  ulVector)
{
   UINT32  uiMask;
   ULONG   ulBase;

   uiMask = 1 << (ulVector % 32);
   ulBase = GIC_DIST_BASE_GET();

   write32(uiMask, ulBase + GICD_ICENABLER + (ulVector / 32) * 4);
}

中断向量是否使能

/*********************************************************************************************************
** 函数名称: armGicV1IrqIsEnable
** 功能描述: 判断 GIC V1 中断是否使能
** 输 入 : ulVector   中断号
** 输 出 : LW_TRUE 中断使能,LW_FALSE 中断禁能
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static BOOL  armGicV1IrqIsEnable (ULONG  ulVector)
{
   UINT32  uiMask;
   UINT32  uiReg;
   ULONG   ulBase;

   uiMask = 1 << (ulVector % 32);
   ulBase = GIC_DIST_BASE_GET();
   uiReg  = read32(ulBase + GICD_ICENABLER + (ulVector / 32) * 4);

   return ((uiReg & uiMask) ? (LW_TRUE) : (LW_FALSE));
}

发送软中断

/*********************************************************************************************************
** 函数名称: armGicV1RaiseSoftIrq
** 功能描述: GIC V1 发送软中断
** 输 入 : ullCpuId   目标 CPU
**           ulVector   中断号
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static VOID  armGicV1RaiseSoftIrq (UINT64  ullCpuId, ULONG  ulVector)
{
   ULONG   ulBase;
   UINT32  uiVal;

   ulBase = GIC_DIST_BASE_GET();

#if defined(BSP_MODE_SMP)
   //工作在SMP的模式下,当SMP的系统号为1的时候,软中断发送给本身的CPU上
   if (LW_NCPUS == 1) {
       write32(2 << 24 | ulVector, ulBase + GICD_SGIR);
       return;
  }
#endif

   KN_SMP_WMB();
//(0 << 24)表示发送软中断到指定的CPU上
   //((1 << ullCpuId) << 16)表示软终端发送到ullCpuId对应的CPU上
   //ulVector表示触发的中断向量号
   uiVal = (0 << 24) | (UINT32)((1 << ullCpuId) << 16) | (UINT32)ulVector;
   write32(uiVal, ulBase + GICD_SGIR);
}

中断优先级配置

/*********************************************************************************************************
** 函数名称: armGicV1IrqPrioritySet
** 功能描述: GIC V1 中断优先级设置
** 输 入 : ulVector   中断号
**           uiPriority 优先级
** 输 出 : ERROR_CODE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static INT   armGicV1IrqPrioritySet (ULONG  ulVector, UINT32  uiPriority)
{
   ULONG   ulBase;
   UINT32  uiVal;

   ulBase = GIC_DIST_BASE_GET();
   uiVal  = read32(ulBase + GICD_IPRIORITYR + ulVector / 4 * 4);
   uiVal &= ~(0xff << (ulVector % 4 * 8));
   //配置中断优先级为新的优先级
   uiVal |= (uiPriority & 0xff) << (ulVector % 4 * 8);
   write32(uiVal, ulBase + GICD_IPRIORITYR + ulVector / 4 * 4);

   return (ERROR_NONE);
}

中断优先级获取

/*********************************************************************************************************
** 函数名称: armGicV1IrqPriorityGet
** 功能描述: GIC V1 中断优先级获取
** 输 入 : ulVector     中断号
**           puiPriority 优先级
** 输 出 : ERROR_CODE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static INT   armGicV1IrqPriorityGet (ULONG  ulVector, UINT32  *puiPriority)
{
   ULONG   ulBase;
   UINT32  uiVal;

   ulBase = GIC_DIST_BASE_GET();
   uiVal  = read32(ulBase + GICD_IPRIORITYR + ulVector / 4 * 4);
//读取目标中断优先级
   *puiPriority = (uiVal >> (ulVector % 4 * 8)) & 0xff;

   return (ERROR_NONE);
}

中断亲和性设置

/*********************************************************************************************************
** 函数名称: armGicV1IrqAffinitySet
** 功能描述: GIC V1 中断亲和设置
** 输 入 : ulVector   中断号
**           ullCPUId   目标 CPU
**           bForce     是否强制设置
** 输 出 : ERROR_CODE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static INT   armGicV1IrqAffinitySet (ULONG  ulVector, UINT64  ullCPUId, BOOL  bForce)
{
   ULONG   ulBase;
   UINT32  uiVal;

   ulBase = GIC_DIST_BASE_GET();
   uiVal  = read32(ulBase + GICD_ITARGETSR + ulVector / 4 * 4);
   uiVal &= ~(0xff << (ulVector % 4 * 8));
   //配置对应中断向量的中断目标CPU
   uiVal |= (1 << ullCPUId) << (ulVector % 4 * 8);

   write32(uiVal, ulBase + GICD_ITARGETSR + ulVector / 4 * 4);

   return (ERROR_NONE);
}

中断亲和性获取

/*********************************************************************************************************
** 函数名称: armGicV1IrqAffinityGet
** 功能描述: GIC V1 中断亲和获取
** 输 入 : ulVector   中断号
**           pullCPUId   目标 CPU
** 输 出 : ERROR_CODE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static INT   armGicV1IrqAffinityGet (ULONG  ulVector, UINT64  *pullCPUId)
{
   ULONG   ulBase;
   UINT32  uiVal;
   INT     i;

   ulBase  = GIC_DIST_BASE_GET();
   uiVal   = read32(ulBase + GICD_ITARGETSR + ulVector / 4 * 4);
   uiVal   = (uiVal >> (ulVector % 4 * 8)) & 0xff;

#if defined(BSP_MODE_SMP)
   //SMP模式下,中断目标只设定在CPU0上
   for (i = 0; i < LW_NCPUS; i++) {
#else
   for (i = 0; i < 4; i++) {
#endif
       //检查CPU0~CPU3,对应中断绑定在哪一个CPU上
       if (uiVal & (1 << i)) {
           *pullCPUId = i;
           break;
      }
  }

   return (ERROR_NONE);
}

中断触发方式配置

/*********************************************************************************************************
** 函数名称: armGicV1IrqTypeSet
** 功能描述: GIC V1 设置中断触发方式
** 输 入 : ulVector   中断号
**           uiType     中断触发方式
** 输 出 : ERROR_CODE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static INT   armGicV1IrqTypeSet (ULONG  ulVector, UINT  uiType)
{
   ULONG   ulBase;
   UINT32  uiEnableMask;
   UINT32  uiEnableOff;
   UINT32  uiConfigMask;
   UINT32  uiConfigOff;
   UINT32  uiVal;
   UINT32  uiOldVal;
   BOOL    bEnabled;
   INT     iRet = ERROR_NONE;

   if (ulVector < 16) {                                                /* SGI 中断不能设置触发类型   */
       _ErrorHandle(EINVAL);
       return (PX_ERROR);
  }

   if ((ulVector >= 32) &&
      (uiType != IRQ_TYPE_LEVEL_HIGH) &&
      (uiType != IRQ_TYPE_EDGE_RISING)) {                             /* SPI 中断有指定的触发范围   */
       _ErrorHandle(EINVAL);
       return (PX_ERROR);
  }

   ulBase = GIC_DIST_BASE_GET();

   uiEnableMask = 1 << (ulVector % 32);
   uiEnableOff  = (ulVector / 32) * 4;
   uiConfigMask = 0x2 << ((ulVector % 16) * 2);
   uiConfigOff  = (ulVector / 16) * 4;
   bEnabled     = LW_FALSE;

   uiVal = uiOldVal = read32(ulBase + GICD_ICFGR + uiConfigOff);
   //根据uiType判断是电平触发还是边沿触发配置相应的触发方式
   if (uiType & IRQ_TYPE_LEVEL_MASK) {
       uiVal &= ~uiConfigMask;
  } else if (uiType & IRQ_TYPE_EDGE_BOTH) {
       uiVal |= uiConfigMask;
  }

   if (read32(ulBase + GICD_ISENABLER + uiEnableOff) & uiEnableMask) {
       //在改变触发方式之前,先使能对应中断向量
       write32(uiEnableMask, ulBase + GICD_ICENABLER + uiEnableOff);
       bEnabled = LW_TRUE;
  }

   write32(uiVal, ulBase + GICD_ICFGR + uiConfigOff);
   if ((read32(ulBase + GICD_ICFGR + uiConfigOff) != uiVal) &&
      (uiVal != uiOldVal)) {
       _ErrorHandle(EIO);
       iRet = PX_ERROR;
  }

   if (bEnabled) {
       //改变触发方式之后,重新使能中断你向量
       write32(uiEnableMask, ulBase + GICD_ISENABLER + uiEnableOff);
  }

   return (iRet);
}

中断处理函数

/*********************************************************************************************************
** 函数名称: armGicV1IrqHandle
** 功能描述: GIC V1 中断服务程序
** 输 入 : bPreemptive   是否可抢占
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static VOID  armGicV1IrqHandle (BOOL  bPreemptive)
{
   REGISTER UINT32  uiAck;
   REGISTER UINT32  uiVector;
   REGISTER ULONG   ulBase;

   ulBase   = GIC_CUR_CPU_INF_BASE_GET();
   //读取中断应答寄存器,获得中断请求来源和中断向量号
   uiAck    = read32(ulBase + GICC_IAR);
   uiVector = uiAck & 0x1ff;

#if defined(BSP_MODE_AMP_SYS0) || defined(BSP_MODE_AMP_SYS1)

extern VOID         t3GpioClearIrq(PLW_GPIO_CHIP  pGpioChip, UINT  uiNum);
extern irqreturn_t  t3GpioSvrIrq(PLW_GPIO_CHIP  pGpioChip, UINT  uiNum);
extern INT          bspBoardGpioEINTGet(INT  iIdx);
extern INT          bspBoardGpioEINTNumGet(VOID);

   INT i;

   /*
    * [SPI_PIO=60] shared by all cores
    * [0x1FF] means INT occur but GicIrqAck read by other core.
    */
   if (uiVector == SPI_PIO || uiVector == 0x1FF) {
       //外部中断需要单独处理,一个中断向量对应了多个中断服务函数
       for (i = 0; i < bspBoardGpioEINTNumGet(); i++) {
           if (t3GpioSvrIrq(LW_NULL, bspBoardGpioEINTGet(i)) != LW_IRQ_NONE) {
               //处理对应中断向量的中断处理函数
               archIntHandle((ULONG)SPI_PIO, bPreemptive);             /* handle interrupt             */
          }
      }

       if (uiVector == SPI_PIO) {                                      /* clear interrupt SPI_PIO     */
           //中断结束,触发中断结束寄存器
           write32(uiAck, ulBase + GICC_EOIR);
      }

       return;
  }
#endif
   
//处理对应中断向量的中断处理函数
   archIntHandle((ULONG)uiVector, bPreemptive);
   //中断结束,触发中断结束寄存器
   write32(uiAck, ulBase + GICC_EOIR);
}

中断驱动函数转化为bsp接口

以API_InterVectorEnable为例,其他的驱动函数的实现方式相似。

base端接口形式

#define __ARCH_INT_VECTOR_ENABLE    bspIntVectorEnable
/*********************************************************************************************************
** 函数名称: API_InterVectorEnable
** 功能描述: 使能指定向量的中断
** 输 入 : ulVector                     中断向量号
** 输 出 : ERROR
** 全局变量:
** 调用模块:
                                          API 函数
*********************************************************************************************************/
LW_API  
ULONG  API_InterVectorEnable (ULONG  ulVector)
{
   INTREG  iregInterLevel;

   if (_Inter_Vector_Invalid(ulVector)) {
       _ErrorHandle(ERROR_KERNEL_VECTOR_NULL);
       return (ERROR_KERNEL_VECTOR_NULL);
  }

   LW_SPIN_LOCK_QUICK(&_K_slcaVectorTable.SLCA_sl, &iregInterLevel);
   //宏定义函数入口
   __ARCH_INT_VECTOR_ENABLE(ulVector);
   LW_SPIN_UNLOCK_QUICK(&_K_slcaVectorTable.SLCA_sl, iregInterLevel);
   
   MONITOR_EVT_LONG1(MONITOR_EVENT_ID_INT, MONITOR_EVENT_INT_VECT_EN, ulVector, LW_NULL);
   
   return (ERROR_NONE);
}

bsp端接口形式

/*********************************************************************************************************
** 函数名称: armGicIrqEnable
** 功能描述: GIC 中断使能
** 输 入 : ulVector   中断号
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID  armGicIrqEnable (ULONG  ulVector)
{
   if (_G_armGicOp.AGIC_pfuncIrqEnable) {
       //本质上调用了中断初始化的时候注册的函数
       _G_armGicOp.AGIC_pfuncIrqEnable(ulVector);
  }
}
/*********************************************************************************************************
** 函数名称: bspIntVectorEnable
** 功能描述: 使能指定的中断向量
** 输 入 : ulVector     中断向量
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID  bspIntVectorEnable (ULONG  ulVector)
{
#if defined(BSP_MODE_AMP_SYS0) || defined(BSP_MODE_AMP_SYS1)
   ULONG   ulCpuIdStart;
   ULONG   ulCpuIdEnd;
   ULONG   ulCpuId;
   UINT64  ullMprId;
   /*
    * 外部中断特殊处理 (AMP 架构中需要将外部中断分发到各个系统中)
    */
extern INT   armGicV1IrqAffinityMoreSet(ULONG  ulVector, UINT64  ullTarget, BOOL  bForce);
   if (ulVector == SPI_PIO) {
       armGicV1IrqAffinityMoreSet(SPI_PIO, 0x3, LW_TRUE);
       armGicIrqEnable(SPI_PIO);
       return;
  }
   /*
    * 调整中断绑核,判断当前系统的核范围
    */
#if defined(BSP_MODE_AMP_SYS0)
   ulCpuIdStart = BSP_CFG_SYS0_CPU;
   ulCpuIdEnd   = ulCpuIdStart + BSP_CFG_SYS0_CPU_NUM - 1;
#elif defined(BSP_MODE_AMP_SYS1)
   ulCpuIdStart = BSP_CFG_SYS1_CPU;
   ulCpuIdEnd   = ulCpuIdStart + BSP_CFG_SYS1_CPU_NUM - 1;
#endif
   /*
    * 若当前中断绑核不在当前系统核号范围内,则绑核到当前系统的起始核
    */
   armGicIrqAffinityGet(ulVector, &ullMprId);
   ulCpuId = (ULONG)ullMprId;
   if (ulCpuId < ulCpuIdStart || ulCpuIdStart > ulCpuIdEnd) {
       armGicIrqAffinitySet(ulVector, ulCpuIdStart, LW_TRUE);
  }
#endif
   //实际的入口
   armGicIrqEnable(ulVector);
}

配置一个中断(以外部中断为例)

/*********************************************************************************************************
** 函数名称: __GpioInit
** 功能描述: 初始化 Gpio 相关配置
** 输 入 : GpioDev         GPIO 设备结构体
** 输 出 : NONE
** 返 回 : ERROR_CODE
*********************************************************************************************************/
static INT  __GpioInit (Gpio_DEV  GpioDev)
{
   INT iRet = 0;
//请求一个 GPIO 的使用
   iRet = API_GpioRequestOne(GpioDev->Gpio_Cfg.uiGpioIrq, LW_GPIOF_DIR_IN, LW_NULL);
   if (iRet < 0) {
       GPIO_ERR("request gpio err, ret = %d!\n", iRet);
       __GpioGpioDeInit(GpioDev);

       return (PX_ERROR);
  } else {
       GpioDev->Gpio_uGpioIrqPinUseFlag = FLAG_IN_USE;
  }
//配置一个GPIO的外部中断
   GpioDev->Gpio_irqn = API_GpioSetupIrq(GpioDev->Gpio_Cfg.uiGpioIrq,
                                         GpioDev->Gpio_Cfg.bIsIrqLevel,
                                         GpioDev->Gpio_Cfg.uiIrqType);
   if (GpioDev->Gpio_irqn ==  LW_VECTOR_INVALID) {
       GPIO_ERR("gpio setup irq error, irqn = %d!\n", GpioDev->Gpio_irqn);
       __GpioGpioDeInit(GpioDev);

       return (PX_ERROR);
  }
   //配置标志位,GPIO中断为一个中断向量对应多个中断服务函数
   API_InterVectorSetFlag(GpioDev->Gpio_irqn, LW_IRQ_FLAG_QUEUE);
   API_InterVectorDisable(GpioDev->Gpio_irqn);
   //注册中断服务函数
   if (API_InterVectorConnect(GpioDev->Gpio_irqn,
                            (PINT_SVR_ROUTINE)__GpioGpioIsr,    /* 触发采集的中断入口         */
                            (PVOID)GpioDev,
                             "gpio_isr") != ERROR_NONE) {
       GPIO_ERR("API_InterVectorConnect fail\r\n");
       __GpioGpioDeInit(GpioDev);

       return (PX_ERROR);
  } else {
       GpioDev->Gpio_uGpioVectorUseFlag = FLAG_IN_USE;
  }
   //配置中断优先级
   API_InterVectorSetPriority(GpioDev->Gpio_irqn, 10);
   //中断使能
   API_InterVectorEnable(GpioDev->Gpio_irqn);

   return  iRet;
}

配置GPIO中断

/*********************************************************************************************************
** 函数名称: __t3GpioSetupIrq
** 功能描述: 设置指定 GPIO 为外部中断输入管脚
** 输 入 : pGpioChip   GPIO 芯片
**           uiNum       GPIO 在系统中的编号
**           bIsLevel   是否为电平触发, 1 表示电平触发,0 表示边沿触发
**           uiType     如果为电平触发, 1 表示高电平触发, 0 表示低电平触发
**                       如果为边沿触发, 1 表示上升沿触发, 0 表示下降沿触发, 2 双边沿触发
** 输 出 : IRQ 向量号 -1:错误
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static ULONG  __t3GpioSetupIrq (PLW_GPIO_CHIP  pGpioChip, UINT  uiNum, BOOL  bIsLevel, UINT  uiType)
{
   addr_t  ulAddr;
   UINT32  uiValue;
   UINT32  uiCfg;
   INT     iIRQn;
   UINT32  uiIntN;
   INT32   iOffset = gpioOffset(uiNum);

   if (PX_ERROR == iOffset) {
       return (PX_ERROR);
  }

   if (iOffset >= GPIO_NUM(GPIO_PORT_H, GPIO_PIN_00) &&
       iOffset <= GPIO_NUM(GPIO_PORT_H, GPIO_PIN_21)) {
       uiIntN = iOffset - GPIO_NUM(GPIO_PORT_H, GPIO_PIN_00);          /* 中断EINT0-21               */
  } else if (iOffset >= GPIO_NUM(GPIO_PORT_I, GPIO_PIN_10) &&
              iOffset <= GPIO_NUM(GPIO_PORT_I, GPIO_PIN_19)) {
       uiIntN = iOffset - GPIO_NUM(GPIO_PORT_I, GPIO_PIN_10) + 22;     /* 中断EINT22-31               */
  } else {
       return (PX_ERROR);                                              /* 该端口没有中断功能         */
  }

   /*
    * 设置中断时钟源
    */
   ulAddr   = GPIO_INT_DEB + GPIO_A_I_BASE;
   API_SpinLock(&gpioSpinlock);
   uiValue  = readl(ulAddr);
   uiValue |= (1 << 0);                                                /* HOSC 24MHz                 */
   //配置中断时钟源
   writel(uiValue, ulAddr);
   API_SpinUnlock(&gpioSpinlock);

   ulAddr = (uiIntN / 8 * 4) + GPIO_INT_CFG + GPIO_A_I_BASE;
   //配置中断向量号SPI_PIO,对于所有的外部中断共用这一个中断向量号
   iIRQn  = SPI_PIO;

   /*
    * 设置中断触发类型
    */
   if (bIsLevel) {                                                     /* 如果是电平触发中断         */
       if (uiType) {
           uiCfg = EINT_MODE_HIGH_LEVEL;                               /* 高电平触发                 */
      } else {
           uiCfg = EINT_MODE_LOW_LEVEL;                                /* 低电平触发                 */
      }
  } else {
       if (uiType == 0) {                                              /* 下降沿触发                 */
           uiCfg = EINT_MODE_NEGATIVE_EDGE;
      } else if (uiType == 1) {                                       /* 上升沿触发                 */
           uiCfg = EINT_MODE_POSITIVE_EDGE;
      } else {                                                        /* 双边沿触发                 */
           uiCfg = EINT_MODE_DOUBLE_EDGE;
      }
  }

   API_SpinLock(&gpioSpinlock);
   uiValue  = readl(ulAddr);
   uiValue &= ~(0x0f << ((uiIntN % 8) * 4));
   uiValue |= (uiCfg << ((uiIntN % 8) * 4));
   //配置外部中断的触发方式
   writel(uiValue, ulAddr);
   API_SpinUnlock(&gpioSpinlock);

   /*
    * 设置引脚为中断输入功能
    */
   gpioPinmuxSet(uiNum, GPIO_EINT);

   /*
    * 使能引脚中断响应
    */
   ulAddr = GPIO_INT_CTL + GPIO_A_I_BASE;

   API_SpinLock(&gpioSpinlock);
   uiValue = readl(ulAddr);
   uiValue |= 1 << uiIntN;
   //使能对应的外部中断
   writel(uiValue, ulAddr);
   API_SpinUnlock(&gpioSpinlock);

   return (iIRQn);
}
/*********************************************************************************************************
** 函数名称: API_GpioSetupIrq
** 功能描述: 根据指定 GPIO 号设置相应的外部中断, 并返回对应的 IRQ 号
** 输 入 : uiGpio       GPIO 号
**           bIsLevel     是否为电平触发
**           uiType       如果为电平触发, 1 表示高电平触发, 0 表示低电平触发
**                         如果为边沿触发, 1 表示上升沿触发, 0 表示下降沿触发, 2 表示双边沿触发
** 输 出 : IRQ 号, 错误返回 LW_VECTOR_INVALID
** 全局变量:
** 调用模块:
                                          API 函数
*********************************************************************************************************/
LW_API  
ULONG  API_GpioSetupIrq (UINT uiGpio, BOOL bIsLevel, UINT uiType)
{
   ULONG           ulVector;
   PLW_GPIO_DESC   pgdesc;
   PLW_GPIO_CHIP   pgchip;

   pgdesc = __gpioGetDesc(uiGpio, LW_TRUE);
   if (!pgdesc) {
       _ErrorHandle(EINVAL);
       return (LW_VECTOR_INVALID);
  }
   
   pgchip = pgdesc->GD_pgcChip;
   
   if (pgchip->GC_pfuncSetupIrq) {
       ulVector = pgchip->GC_pfuncSetupIrq(pgchip, GPIO_CHIP_HWGPIO(pgdesc), bIsLevel, uiType);
       if (ulVector != LW_VECTOR_INVALID) {                            /* 外部中断设置成功           */
           if (bIsLevel) {
               pgdesc->GD_ulFlags |= LW_GPIODF_TRIG_LEVEL;
          }
           if (uiType == 0) {
               pgdesc->GD_ulFlags |= LW_GPIODF_TRIG_FALL;
           
          } else if (uiType == 1) {
               pgdesc->GD_ulFlags |= LW_GPIODF_TRIG_RISE;
               
          } else if (uiType == 2) {
               pgdesc->GD_ulFlags |= (LW_GPIODF_TRIG_FALL | LW_GPIODF_TRIG_RISE);
          }
      }
       return (ulVector);
   
  } else {
       _ErrorHandle(ENXIO);
       return (LW_VECTOR_INVALID);
  }
}

配置GPIO中断标志位

/*********************************************************************************************************
** 函数名称: API_InterVectorSetFlag
** 功能描述: 设置指定中断向量的特性.
** 输 入 : ulVector                     中断向量号
**           ulFlag                       特性
** 输 出 : ERROR CODE
** 全局变量:
** 调用模块:
** 注 意 : LW_IRQ_FLAG_QUEUE 必须在安装任何一个驱动前设置, 且设置后不再能取消.
            最好放在 bspIntInit() 函数中完成设置.
                                          API 函数
*********************************************************************************************************/
LW_API
ULONG  API_InterVectorSetFlag (ULONG  ulVector, ULONG  ulFlag)
{
   INTREG              iregInterLevel;
   PLW_CLASS_INTDESC   pidesc;

   if (_Inter_Vector_Invalid(ulVector)) {
       _ErrorHandle(ERROR_KERNEL_VECTOR_NULL);
       return (ERROR_KERNEL_VECTOR_NULL);
  }
   
   pidesc = LW_IVEC_GET_IDESC(ulVector);
   
   LW_SPIN_LOCK_QUICK(&pidesc->IDESC_slLock, &iregInterLevel);         /* 关闭中断同时锁住 spinlock   */
   
   if (LW_IVEC_GET_FLAG(ulVector) & LW_IRQ_FLAG_QUEUE) {               /* 已经是 QUEUE 类型中断向量   */
       LW_IVEC_SET_FLAG(ulVector, ulFlag | LW_IRQ_FLAG_QUEUE);
   
  } else {
       LW_IVEC_SET_FLAG(ulVector, ulFlag);
  }
   
   LW_SPIN_UNLOCK_QUICK(&pidesc->IDESC_slLock, iregInterLevel);        /* 打开中断, 同时打开 spinlock */
   
   return (ERROR_NONE);
}

关闭外部中断

最终调用到对应的中断向量禁能的函数接口

注册中断服务函数

/*********************************************************************************************************
** 函数名称: API_InterVectorConnect
** 功能描述: 设置系统指定向量中断服务
** 输 入 : ulVector                     中断向量号
**           pfuncIsr                     服务函数
**           pvArg                         服务函数参数
**           pcName                       中断服务名称
** 输 出 : ERROR CODE
** 全局变量:
** 调用模块:
                                          API 函数
*********************************************************************************************************/
LW_API
ULONG  API_InterVectorConnect (ULONG            ulVector,
                              PINT_SVR_ROUTINE pfuncIsr,
                              PVOID            pvArg,
                              CPCHAR           pcName)
{
   return (API_InterVectorConnectEx(ulVector, pfuncIsr, LW_NULL, pvArg, pcName));
}
/*********************************************************************************************************
** 函数名称: API_InterVectorConnectEx
** 功能描述: 设置系统指定向量中断服务
** 输 入 : ulVector                     中断向量号
**           pfuncIsr                     服务函数
**           pfuncClear                   附加中断清除函数(可为 NULL)
**           pvArg                         服务函数参数
**           pcName                       中断服务名称
** 输 出 : ERROR CODE
** 全局变量:
** 调用模块:
                                          API 函数
*********************************************************************************************************/
LW_API
ULONG  API_InterVectorConnectEx (ULONG              ulVector,
                                PINT_SVR_ROUTINE   pfuncIsr,
                                VOIDFUNCPTR        pfuncClear,
                                PVOID              pvArg,
                                CPCHAR             pcName)
{
   INTREG              iregInterLevel;
   BOOL                bNeedFree;
   
   PLW_LIST_LINE       plineTemp;
   PLW_CLASS_INTACT    piactionOld;
   PLW_CLASS_INTACT    piaction;
   PLW_CLASS_INTDESC   pidesc;
   
   if (LW_CPU_GET_CUR_NESTING()) {                                     /* 不能在中断中调用           */
       _DebugHandle(__ERRORMESSAGE_LEVEL, "called from ISR.\r\n");
       _ErrorHandle(ERROR_KERNEL_IN_ISR);
       return (ERROR_KERNEL_IN_ISR);
  }
   
   INTER_SHOWLOCK_CREATE();

   if (_Object_Name_Invalid(pcName)) {                                 /* 检查名字有效性             */
       _DebugHandle(__ERRORMESSAGE_LEVEL, "name too long.\r\n");
       _ErrorHandle(ERROR_KERNEL_PNAME_TOO_LONG);
       return (ERROR_KERNEL_PNAME_TOO_LONG);
  }
   
   if (_Inter_Vector_Invalid(ulVector)) {
       _ErrorHandle(ERROR_KERNEL_VECTOR_NULL);
       return (ERROR_KERNEL_VECTOR_NULL);
  }
   
   if (pfuncIsr == LW_NULL) {
       _ErrorHandle(ERROR_KERNEL_VECTOR_NULL);
       return (ERROR_KERNEL_VECTOR_NULL);
  }
   
   piaction = (PLW_CLASS_INTACT)__KHEAP_ALLOC(sizeof(LW_CLASS_INTACT));
   if (piaction == LW_NULL) {
       _DebugHandle(__ERRORMESSAGE_LEVEL, "kernel low memory.\r\n");
       _ErrorHandle(ERROR_KERNEL_LOW_MEMORY);
       return (ERROR_KERNEL_LOW_MEMORY);
  }
   lib_bzero(piaction, sizeof(LW_CLASS_INTACT));
   
   //将服务函数的参数填写到action结构体中
   piaction->IACT_pfuncIsr   = pfuncIsr;
   piaction->IACT_pfuncClear = pfuncClear;
   piaction->IACT_pvArg      = pvArg;
   if (pcName) {
       lib_strcpy(piaction->IACT_cInterName, pcName);
  } else {
       piaction->IACT_cInterName[0] = PX_EOS;
  }
   
   pidesc = LW_IVEC_GET_IDESC(ulVector);
   
   LW_SPIN_LOCK_QUICK(&pidesc->IDESC_slLock, &iregInterLevel);         /* 关闭中断同时锁住 spinlock   */

   if (LW_IVEC_GET_FLAG(ulVector) & LW_IRQ_FLAG_QUEUE) {               /* 队列服务类型向量           */
       //GPIO中断属于队列服务类型向量
       for (plineTemp  = pidesc->IDESC_plineAction;
            plineTemp != LW_NULL;
            plineTemp  = _list_line_get_next(plineTemp)) {
            //获取链表中的中断服务函数结构体
           piactionOld = _LIST_ENTRY(plineTemp, LW_CLASS_INTACT, IACT_plineManage);
           if ((piactionOld->IACT_pfuncIsr == pfuncIsr) &&
              (piactionOld->IACT_pvArg    == pvArg)) {                /* 中断处理函数是否被重复安装 */
               break;
          }
      }
       
       if (plineTemp) {                                                /* 此中断被重复安装           */
           bNeedFree = LW_TRUE;
       
      } else {
           //将中断服务函数安装到线性链表中
           _List_Line_Add_Ahead(&piaction->IACT_plineManage,
                                &pidesc->IDESC_plineAction);
           bNeedFree = LW_FALSE;
      }
   
  } else {                                                            /* 非队列服务式中断向量       */
       if (pidesc->IDESC_plineAction) {
           piactionOld = _LIST_ENTRY(pidesc->IDESC_plineAction,
                                     LW_CLASS_INTACT,
                                     IACT_plineManage);
           piactionOld->IACT_pfuncIsr   = piaction->IACT_pfuncIsr;
           piactionOld->IACT_pfuncClear = piaction->IACT_pfuncClear;
           piactionOld->IACT_pvArg      = piaction->IACT_pvArg;
           lib_strcpy(piactionOld->IACT_cInterName, piaction->IACT_cInterName);
           bNeedFree = LW_TRUE;
       
      } else {
           _List_Line_Add_Ahead(&piaction->IACT_plineManage,
                                &pidesc->IDESC_plineAction);
           bNeedFree = LW_FALSE;
      }
  }
   
   LW_SPIN_UNLOCK_QUICK(&pidesc->IDESC_slLock, iregInterLevel);        /* 打开中断, 同时打开 spinlock */
   
   if (bNeedFree) {
       __KHEAP_FREE(piaction);
  }
   
   _DebugFormat(__LOGMESSAGE_LEVEL, "IRQ %d : %s connect : %p\r\n",
                (INT)ulVector, (pcName ? pcName : ""), (PVOID)pfuncIsr);

   return (ERROR_NONE);
}

配置中断优先级

最终调用到对应的中断优先级设置的函数接口

外部中断使能

/*********************************************************************************************************
** 函数名称: bspIntVectorEnable
** 功能描述: 使能指定的中断向量
** 输 入 : ulVector     中断向量
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID  bspIntVectorEnable (ULONG  ulVector)
{
#if defined(BSP_MODE_AMP_SYS0) || defined(BSP_MODE_AMP_SYS1)
   ULONG   ulCpuIdStart;
   ULONG   ulCpuIdEnd;
   ULONG   ulCpuId;
   UINT64  ullMprId;
   /*
    * 外部中断特殊处理 (AMP 架构中需要将外部中断分发到各个系统中)
    */
extern INT   armGicV1IrqAffinityMoreSet(ULONG  ulVector, UINT64  ullTarget, BOOL  bForce);
   if (ulVector == SPI_PIO) {
       //配置外部中断发往的CPU编号
       armGicV1IrqAffinityMoreSet(SPI_PIO, 0x3, LW_TRUE);
       armGicIrqEnable(SPI_PIO);
       return;
  }
   /*
    * 调整中断绑核,判断当前系统的核范围
    */
#if defined(BSP_MODE_AMP_SYS0)
   ulCpuIdStart = BSP_CFG_SYS0_CPU;
   ulCpuIdEnd   = ulCpuIdStart + BSP_CFG_SYS0_CPU_NUM - 1;
#elif defined(BSP_MODE_AMP_SYS1)
   ulCpuIdStart = BSP_CFG_SYS1_CPU;
   ulCpuIdEnd   = ulCpuIdStart + BSP_CFG_SYS1_CPU_NUM - 1;
#endif
   /*
    * 若当前中断绑核不在当前系统核号范围内,则绑核到当前系统的起始核
    */
   armGicIrqAffinityGet(ulVector, &ullMprId);
   ulCpuId = (ULONG)ullMprId;
   if (ulCpuId < ulCpuIdStart || ulCpuIdStart > ulCpuIdEnd) {
       //其他的中断向量,绑定到对应系统编号下对应的起始CPU
       armGicIrqAffinitySet(ulVector, ulCpuIdStart, LW_TRUE);
  }
#endif
   armGicIrqEnable(ulVector);
}

中断处理函数流程(以外部中断为例)

中断向量入口

中断会触发中断异常,进入startup.S处理中断异常。archIntEntry进入不同架构下对应的中断处理函数。

FUNC_DEF(vector)
  B       reset
  LDR     PC, undefineEntry
  LDR     PC, swiEntry
  LDR     PC, prefetchEntry
  LDR     PC, abortEntry
  LDR     PC, reserveEntry
  LDR     PC, irqEntry
  LDR     PC, fiqEntry
  FUNC_END()
   
  FUNC_LABEL(irqEntry)
  .word   archIntEntry

中断汇编函数

进入到Arm架构下的中断处理函数

;/*********************************************************************************************************
; 中断入口
;*********************************************************************************************************/

FUNC_DEF(archIntEntry)
  ;/*
   ; * 保存 REG 到 IRQ 模式栈空间(这里做了个必须成立的假设, 之前必须工作在 SYS 或 USR 模式)
   ; */
   SUB     LR , LR, #4                                                 ;/* 调整用于中断返回的 PC 值   */
   STMFD   SP!, {LR}                                                   ;/* 保存返回地址               */
   STMFD   SP!, {R0-R12}                                               ;/* 保存寄存器                 */
   MOV     R1 , SP
   MSR     CPSR_c, #(DIS_INT | SYS32_MODE)                             ;/* 回到 SYS 模式               */
   STMFD   R1!, {SP}                                                   ;/* 保存 SP_sys                 */
   STMFD   R1 , {LR}                                                   ;/* 保存 LR_sys                 */
   MSR     CPSR_c, #(DIS_INT | IRQ32_MODE)                             ;/* 回到 IRQ 模式               */
   SUB     SP , SP , #(2 * 4)                                         ;/* 调整 SP_irq                 */
   MRS     R2 , SPSR
   STMFD   SP!, {R2}                                                   ;/* 保存 CPSR_sys               */
   
  ;/*
   ; * API_InterEnter(SP_irq), 如果是第一次中断, 会将 IRQ 模式栈空间的 ARCH_REG_CTX
   ; * 拷贝到当前任务 TCB 的 ARCH_REG_CTX 里
   ; */
   MOV     R0 , SP
   LDR     R1 , =API_InterEnter
   MOV     LR , PC
   BX      R1

  ;/*
   ; * 如果不是第一次进入中断, 那么上一次中断(工作在 SYS 模式)已经设置 SP_sys, 只需要回到 SYS 模式
   ; */
   CMP     R0 , #1
   BNE     1f

  ;/*
   ; * 第一次进入中断: 因为已经将 IRQ 模式栈空间的 ARCH_REG_CTX 拷贝到当前任务 TCB 的 ARCH_REG_CTX 里
   ; * 调整 SP_irq
   ; */
   ADD     SP , SP , #(ARCH_REG_CTX_SIZE)

  ;/*
   ; * 第一次进入中断: 获得当前 CPU 中断堆栈栈顶, 并回到 SYS 模式, 并设置 SP_sys
   ; */
   LDR     R0 , =API_InterStackBaseGet
   MOV     LR , PC
   BX      R0

   MSR     CPSR_c, #(DIS_INT | SYS32_MODE)                             ;/* 回到 SYS 模式               */
   MOV     SP , R0                                                     ;/* 设置 SP_sys                 */

1:
   MSR     CPSR_c, #(DIS_INT | SYS32_MODE)                             ;/* 回到 SYS 模式(不是多余的)   */

  ;/*
   ; * bspIntHandle()
   ; */
   LDR     R1 , =bspIntHandle
   MOV     LR , PC
   BX      R1
   
  ;/*
   ; * API_InterExit()
   ; * 如果没有发生中断嵌套, 则 API_InterExit 会调用 archIntCtxLoad 函数, SP_irq 在上面已经调整好
   ; */
   LDR     R1 , =API_InterExit
   MOV     LR , PC
   BX      R1
   
  ;/*
   ; * 来到这里, 说明发生了中断嵌套
   ; */
   MSR     CPSR_c, #(DIS_INT | IRQ32_MODE)                             ;/* 回到 IRQ 模式               */

   MOV     R0 , SP
   LDMIA   R0!, {R2-R4}                                               ;/* 读取 CPSR LR SP             */
   ADD     SP , SP , #(ARCH_REG_CTX_SIZE)                             ;/* 调整 SP_irq                 */

   MSR     CPSR_c, #(DIS_INT | SYS32_MODE)                             ;/* 回到 SYS 模式               */

   MOV     SP , R4                                                     ;/* 恢复 SP_sys                 */
   MOV     LR , R3                                                     ;/* 恢复 LR_sys                 */

   MSR     CPSR_c, #(DIS_INT | IRQ32_MODE)                             ;/* 回到 IRQ 模式               */
   MSR     SPSR_cxsf , R2
   LDMIA   R0 , {R0-R12, PC}^                                         ;/* 恢复包括 PC 的所有寄存器,   */
                                                                      ;/* 同时更新 CPSR               */
   FUNC_END()

回到bsp中断接口

进入中断处理函数bspIntHandle

/*********************************************************************************************************
** 函数名称: armGicIrqHandle
** 功能描述: GIC 中断服务函数
** 输 入 : bPreemptive   是否可抢占
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID  armGicIrqHandle (BOOL  bPreemptive)
{
   if (_G_armGicOp.AGIC_pfuncIrqHandle) {
       _G_armGicOp.AGIC_pfuncIrqHandle(bPreemptive);
  }
}
/*********************************************************************************************************
** 函数名称: bspIntHandle
** 功能描述: 中断入口
** 输 入 : NONE
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID  bspIntHandle (VOID)
{
   armGicIrqHandle(LW_FALSE);
}

GIC中断处理函数

进入中断处理函数

/*********************************************************************************************************
** 函数名称: bspBoardGpioEINTGet
** 功能描述: 获取此核需要触发的外部中断引脚
** 输 入 : NONE
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
INT  bspBoardGpioEINTGet (INT  iIdx)
{
   return _G_iGpioEINTSourceTable[iIdx];
}
/*********************************************************************************************************
** 函数名称: bspBoardGpioEINTNumGet
** 功能描述: 获取此核需要触发的外部中断引脚总数
** 输 入 : NONE
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
INT  bspBoardGpioEINTNumGet (VOID)
{
   return (sizeof(_G_iGpioEINTSourceTable) / sizeof(INT));
}
/*********************************************************************************************************
** 函数名称: __t3GpioSvrIrq
** 功能描述: 判断 GPIO 中断标志
** 输 入 : pGpioChip   GPIO 芯片
**           uiNum       GPIO 在系统中的编号
** 输 出 : 中断返回值
** 全局变量:
** 调用模块:
*********************************************************************************************************/
irqreturn_t  t3GpioSvrIrq (PLW_GPIO_CHIP  pGpioChip, UINT  uiNum)
{
   addr_t  ulAddr;
   UINT32  uiRegister;
   UINT32  uiIntN;
   INT32   iOffset = gpioOffset(uiNum);

   if (PX_ERROR == iOffset) {
       return (PX_ERROR);
  }

   if (iOffset >= GPIO_NUM(GPIO_PORT_H, GPIO_PIN_00) &&
       iOffset <= GPIO_NUM(GPIO_PORT_H, GPIO_PIN_21)) {
       uiIntN = iOffset - GPIO_NUM(GPIO_PORT_H, GPIO_PIN_00);          /* 中断EINT0-21               */
  } else if (iOffset >= GPIO_NUM(GPIO_PORT_I, GPIO_PIN_10) &&
              iOffset <= GPIO_NUM(GPIO_PORT_I, GPIO_PIN_19)) {
       uiIntN = iOffset - GPIO_NUM(GPIO_PORT_I, GPIO_PIN_10) + 22;     /* 中断EINT22-31               */
  } else {
       return (PX_ERROR);                                              /* 该端口没有中断功能         */
  }

   ulAddr = GPIO_INT_STA + GPIO_A_I_BASE;

   uiRegister = readl(ulAddr);
   //判断外部中断状态位,判断是否是当前中断管脚触发了外部中断
   if (uiRegister & (1 << uiIntN)) {
       return (LW_IRQ_HANDLED_CONT);
  } else {
       return (LW_IRQ_NONE);
  }
}
/*********************************************************************************************************
** 函数名称: armGicV1IrqHandle
** 功能描述: GIC V1 中断服务程序
** 输 入 : bPreemptive   是否可抢占
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static VOID  armGicV1IrqHandle (BOOL  bPreemptive)
{
   REGISTER UINT32  uiAck;
   REGISTER UINT32  uiVector;
   REGISTER ULONG   ulBase;

   ulBase   = GIC_CUR_CPU_INF_BASE_GET();
   //读取中断应答寄存器,获得中断请求来源和中断向量号
   uiAck    = read32(ulBase + GICC_IAR);
   uiVector = uiAck & 0x1ff;

#if defined(BSP_MODE_AMP_SYS0) || defined(BSP_MODE_AMP_SYS1)

extern VOID         t3GpioClearIrq(PLW_GPIO_CHIP  pGpioChip, UINT  uiNum);
extern irqreturn_t  t3GpioSvrIrq(PLW_GPIO_CHIP  pGpioChip, UINT  uiNum);
extern INT          bspBoardGpioEINTGet(INT  iIdx);
extern INT          bspBoardGpioEINTNumGet(VOID);

   INT i;

   /*
    * [SPI_PIO=60] shared by all cores
    * [0x1FF] means INT occur but GicIrqAck read by other core.
    */
   if (uiVector == SPI_PIO || uiVector == 0x1FF) {
       //外部中断需要单独处理,一个中断向量对应了多个中断服务函数
       //bspBoardGpioEINTNumGet()获取了一个系统对应的外部中断管脚配置的个数
       for (i = 0; i < bspBoardGpioEINTNumGet(); i++) {
           //t3GpioSvrIrq()便利系统中所有的外部中断管脚,查询哪一个中断管脚被触发了
           if (t3GpioSvrIrq(LW_NULL, bspBoardGpioEINTGet(i)) != LW_IRQ_NONE) {
               //处理对应中断向量的中断处理函数
               archIntHandle((ULONG)SPI_PIO, bPreemptive);             /* handle interrupt             */
          }
      }

       if (uiVector == SPI_PIO) {                                      /* clear interrupt SPI_PIO     */
           //中断结束,触发中断结束寄存器
           write32(uiAck, ulBase + GICC_EOIR);
      }

       return;
  }
#endif
   
//处理对应中断向量的中断处理函数
   archIntHandle((ULONG)uiVector, bPreemptive);
   //中断结束,触发中断结束寄存器
   write32(uiAck, ulBase + GICC_EOIR);
}

不同架构对应的中断处理C函数

archIntHandle调用对应架构下的中断处理函数,这里进入Arm的中断处理函数

;/*********************************************************************************************************
; ARM 关闭总中断
;*********************************************************************************************************/

FUNC_DEF(archIntDisable)
   MRS     R0 , CPSR
   ORR     R1 , R0, #0x80
   MSR     CPSR_c, R1
   MRS     R2 , CPSR
   AND     R2 , R2, #0x80
   CMP     R2 , #0x80
   BNE     archIntDisable
   BX      LR
   FUNC_END()
   
FUNC_DEF(archIntEnable)
   MSR     CPSR_c, R0
   BX      LR
   FUNC_END()
   
FUNC_DEF(archIntEnableForce)
   MRS     R0 , CPSR
   BIC     R0 , R0, #0x80
   MSR     CPSR_c, R0
   BX      LR
   FUNC_END()
/*********************************************************************************************************
 ARM 处理器标准底层库
*********************************************************************************************************/
#define KN_INT_DISABLE()           archIntDisable()
#define KN_INT_ENABLE(intLevel)     archIntEnable(intLevel)
#define KN_INT_ENABLE_FORCE()       archIntEnableForce()
/*********************************************************************************************************
** 函数名称: archIntHandle
** 功能描述: bspIntHandle 需要调用此函数处理中断 (关闭中断情况被调用)
** 输 入 : ulVector         中断向量
**           bPreemptive     中断是否可抢占
** 输 出 : NONE
** 全局变量:
** 调用模块:
** 注 意 : 此函数退出时必须为中断关闭状态.
*********************************************************************************************************/
LW_WEAK VOID  archIntHandle (ULONG  ulVector, BOOL  bPreemptive)
{
   REGISTER irqreturn_t irqret;

   if (_Inter_Vector_Invalid(ulVector)) {
       return;                                                         /* 向量号不正确               */
  }
//判断对应中断是否配置了中断抢占标志位
   if (LW_IVEC_GET_FLAG(ulVector) & LW_IRQ_FLAG_PREEMPTIVE) {
       bPreemptive = LW_TRUE;
  }
//如果中断可抢占,这里关闭本Vector对应中断,强制开启中断
   if (bPreemptive) {
       VECTOR_OP_LOCK();
       __ARCH_INT_VECTOR_DISABLE(ulVector);                            /* 屏蔽 vector 中断           */
       VECTOR_OP_UNLOCK();
       KN_INT_ENABLE_FORCE();                                          /* 允许中断                   */
  }

   irqret = API_InterVectorIsr(ulVector);                              /* 调用中断服务程序           */
   
   KN_INT_DISABLE();                                                   /* 禁能中断                   */
   
   if (bPreemptive) {
       if (irqret != LW_IRQ_HANDLED_DISV) {
           VECTOR_OP_LOCK();
           __ARCH_INT_VECTOR_ENABLE(ulVector);                         /* 允许 vector 中断           */
           VECTOR_OP_UNLOCK();
      }
   
  } else if (irqret == LW_IRQ_HANDLED_DISV) {
       VECTOR_OP_LOCK();
       __ARCH_INT_VECTOR_DISABLE(ulVector);                            /* 屏蔽 vector 中断           */
       VECTOR_OP_UNLOCK();
  }
}

向量中断总服务

/*********************************************************************************************************
 系统中断返回值
*********************************************************************************************************/
#define LW_IRQ_NONE         0                                           /* 不是本设备中断             */
#define LW_IRQ_HANDLED     1                                           /* 中断已被正确处理           */
#define LW_IRQ_HANDLED_DISV 2                                           /* 中断处理结束并且屏蔽本中断 */
#define LW_IRQ_HANDLED_CONT 3                                           /* 中断已被处理, 但需要继续循环*/

#define LW_IRQ_RETVAL(x)   ((x) != 0)
#define LW_IRQ_RETBREAK(x) ((x) != LW_IRQ_HANDLED_CONT)
/*********************************************************************************************************
 中断服务
*********************************************************************************************************/
#define INTER_VECTOR_MEASURE_ENTER(a, b, c, d)
#define INTER_VECTOR_MEASURE_EXIT(a, b, c, d)

#define INTER_VECTOR_SVC_HANDLE()                                                                   \
//这里真正调用Connect的中断服务函数
   irqret = piaction->IACT_pfuncIsr(piaction->IACT_pvArg, ulVector);

#define INTER_VECTOR_SVC(BREAK)                                                                     \
{                                                                                                   \
   INTER_VECTOR_MEASURE_ENTER(&tv, ulVector, LW_CPU_GET_ID(pcpu), piaction->IACT_cInterName);     \
   INTER_VECTOR_SVC_HANDLE();                                                                     \
   if (LW_IRQ_RETVAL(irqret)) {                                                                   \
       INTER_VECTOR_MEASURE_EXIT(&tv, ulVector, LW_CPU_GET_ID(pcpu), piaction->IACT_cInterName);   \
       //函数正常处理之后,中断触发计数++
       piaction->IACT_iIntCnt[LW_CPU_GET_ID(pcpu)]++;                                              \
       if (piaction->IACT_pfuncClear) {                                                            \
           piaction->IACT_pfuncClear(piaction->IACT_pvArg, ulVector);                              \
      }                                                                                           \
       //如果不是需要继续循环的中断处理函数,就可以break退出了
       //线性队列类型的中断将会循环处理所有挂载的中断服务函数
       if (LW_IRQ_RETBREAK(irqret)) {                                                              \
           BREAK                                                                                   \
      }                                                                                           \
  }                                                                                               \
}
/*********************************************************************************************************
** 函数名称: API_InterVectorIsr
** 功能描述: 向量中断总服务
** 输 入 : ulVector                     中断向量号 (arch 层函数需要保证此参数正确)
** 输 出 : 中断返回值
** 全局变量:
** 调用模块:
** 注 意 : 这里并不处理中断嵌套, 他需要 arch 层移植函数支持.
                                          API 函数
*********************************************************************************************************/
LW_API
irqreturn_t  API_InterVectorIsr (ULONG  ulVector)
{
   PLW_CLASS_CPU       pcpu;
   PLW_LIST_LINE       plineTemp;
   PLW_CLASS_INTDESC   pidesc;
   PLW_CLASS_INTACT    piaction;
   irqreturn_t         irqret = LW_IRQ_NONE;
   
#if LW_CFG_INTER_MEASURE_HOOK_EN > 0
   struct timespec     tv;
#endif
         
   pcpu = LW_CPU_GET_CUR();                                            /* 中断处理程序中, 不会改变 CPU*/
   
#if LW_CFG_CPU_INT_HOOK_EN > 0
   //中断前的hook函数
   __LW_CPU_INT_ENTER_HOOK(ulVector, pcpu->CPU_ulInterNesting);
#endif                                                                  /* LW_CFG_CPU_INT_HOOK_EN > 0 */
   
#if LW_CFG_SMP_EN > 0
   //核间中断的处理
   if (pcpu->CPU_ulIPIVector == ulVector) {                            /* 核间中断                   */
       _SmpProcIpi(pcpu);
       if (pcpu->CPU_pfuncIPIClear) {
           pcpu->CPU_pfuncIPIClear(pcpu->CPU_pvIPIArg, ulVector);      /* 清除核间中断               */
      }
  } else
#endif                                                                  /* LW_CFG_SMP_EN               */
  {
       pidesc = LW_IVEC_GET_IDESC(ulVector);
       //如果中断类型是线性队列中断,例如外部中断
       if (pidesc->IDESC_ulFlag & LW_IRQ_FLAG_QUEUE) {
#if LW_CFG_SMP_EN > 0
           LW_SPIN_LOCK(&pidesc->IDESC_slLock);                        /* 锁住 spinlock               */
#endif                                                                  /* LW_CFG_SMP_EN > 0           */
           for (plineTemp  = pidesc->IDESC_plineAction;
                plineTemp != LW_NULL;
                plineTemp  = _list_line_get_next(plineTemp)) {
               //遍历运行所有在链表中的中断服务函数
               piaction = (PLW_CLASS_INTACT)plineTemp;
               INTER_VECTOR_SVC(break;);
          }

#if LW_CFG_SMP_EN > 0
           LW_SPIN_UNLOCK(&pidesc->IDESC_slLock);                      /* 解锁 spinlock               */
#endif                                                                  /* LW_CFG_SMP_EN > 0           */
      } else {
           //一般情况下直接找到中断向量对应的中断服务结构体,运行中断服务函数
           piaction = (PLW_CLASS_INTACT)pidesc->IDESC_plineAction;
           if (piaction) {
               INTER_VECTOR_SVC(;);
           
          } else {
               _DebugFormat(__ERRORMESSAGE_LEVEL, "interrupt vector: %ld no service.\r\n", ulVector);
          }
      }
  }
   
#if LW_CFG_CPU_INT_HOOK_EN > 0
   //中断服务之后的钩子函数
   __LW_CPU_INT_EXIT_HOOK(ulVector, pcpu->CPU_ulInterNesting);
#endif                                                                  /* LW_CFG_CPU_INT_HOOK_EN > 0 */
                     
   return (irqret);
}

    • Related Articles

    • SylixOS 串口中断

      问:SylixOS 的串口在收到几个字节后就能给出中断?如,串口收到一个字符,这个时候会立即给出中断吗还是像龙芯手册中写的,得等4个空闲周期后再给出中断? 答:这个和处理器及中断控制器相关, 默认1字节就会触发中断; 这个要看CPU的串口是怎么处理的, 龙芯芯片手册说的要等空闲周期那就是要等空闲时间 。
    • 用户 GPIO 中断实现

      Q:用户 GPIO 中断实现应用 1. 应用场景 经常有用户会提到这样的使用方式:定义一个周期性的 GPIO 中断,应用层收到该中断信号后做出相应的动作,按照目前的情况来看,这种使用方式不外乎两种,一是直接使用片内或者外扩的具备中断功能的 GPIO 去实现该项功能,二是 GPIO 这一侧的功能使用 FPGA 来实现,定期的去发送某个电平或者上升沿/下降沿,某些用户更习惯将这种方式称之为“秒脉冲”或者“同步中断”。 2. 问题 ...
    • SylixOS 中是否支持中断底半部,如何使用?

      1. 适用范围       本文档适用于对中断底半部有了解需求的开发人员。  2. 原理概述       在发生中断时,内核会记录哪个中断产生并把中断相应的处理函数加入一个处理队列里, 直到把所有同一时间发生的中断全部记录好后, 处理队列里的函数才会逐一得到调用。所以当一个中断处理函数处理过久时,就有可能影响它后面的中断处函数的执行时机。我们用的中断处 理函数是可以被中断信号打断的。   ...
    • SylixOS 下如何测量中断服务耗时

      功能概要 SylixOS 下可以测量中断服务耗时,分析各中断服务耗时对分析系统实时性和驱动故障等有很大帮助。 操作步骤 1、该功能通过中断中执行钩子函数来实现,会略微增加中断执行时间,所以默认是关闭的。需要使用时,编译前需修改base文件,主要修改为将 /libsylixos/SylixOS/config/ kernel/kernel_cfg.h 中 LW_CFG_INTER_MEASURE_HOOK_EN 宏使能(即置为1) ...
    • 缺页中断后系统被任务 Kill ?

      Q:缺页中断后系统被任务 Kill ? SylixOS 系统发生缺页中断后,打印了一些调试后系统就重启或者任务被杀死了 由于 SylixOS 操作系统为了保持硬实时操作系统的特性,所以内核与应用程序没有严格的隔离。 缺页中断如果发生在内核被锁定或者中断中,则操作系统不能正确处理,这里需要应用程序员与驱动开发人员注意。