中断控制

描述

玄武OS将中断分为CPU中断与外设中断分别进行管理:

  • CPU总中断:当CPU关闭总中断开关后,所有外设发射到当前CPU的中断都会被屏蔽;
  • 外设中断:外设自己的中断,当关闭外设中断后,不会对其他中断产生影响。

用法

中断向量

中断向量通常位于vector.c文件中,此文件可以存放在

  • xwbd/电路板名称/bdl
  • xwbd/电路板名称/bm下的某个玄武模块

中断向量可以是只读的或可修改的,这与xwbd/电路板名称/cfg/soc.h中配置有关。

  • SOCCFG_RO_ISRTABLE 配置为1: 中断向量表位于code段,不可修改。
  • SOCCFG_RO_ISRTABLE 配置为0: 中断向量表位于data段,可在程序运行时修改,但会消耗额外的RAM。

CPU总中断

玄武OS可以对CPU的总中断开关进行操作:

  • 关闭:xwosal_cpuirq_disable_lc()
  • 开启:xwosal_cpuirq_enable_lc()
    • 关闭与开启这一组API需要确保不会发生嵌套,例如下面的嵌套代码就是错误的:
void func1(void)
{
        xwosal_cpuirq_disable_lc();
        /* ... 临界区 ... */
        xwosal_cpuirq_enable_lc();
}

void func0(void)
{
        xwosal_cpuirq_disable_lc();
        /* ... 临界区 ... */
        /* 错误!func1()会导致CPU中断开关被打开,
           导致后面的临界区处于未保护状态。 */
        func1();
        /* ... 临界区 ... */
        xwosal_cpuirq_enable_lc();
}
  • 保存当前开关状态后关闭:xwosal_cpuirq_save_lc()
  • 恢复之前保存的状态:xwosal_cpuirq_restore_lc()
    • 当关闭中断的代码发生嵌套时,应当使用保存与恢复这一组API,上面的例子可以更正为:
void func1(void)
{
        xwreg_t cpuirq;

        xwosal_cpuirq_save_lc(&cpuirq);
        /* ... 临界区 ... */
        xwosal_cpuirq_restore_lc(cpuirq);
}

void func0(void)
{
        xwreg_t cpuirq;

        xwosal_cpuirq_save_lc(&cpuirq);
        /* ... 临界区 ... */
        func1();
        /* ... 临界区 ... */
        xwosal_cpuirq_restore_lc(cpuirq);
}

外设中断

玄武OS可以对CPU的外设中断单独控制:

  • 申请中断:xwos_irq_request()
    • 此API用于安装中断处理函数及其参数,此API需要将中断向量表配置 为可读写的,参考 中断控制-配置
  • 释放中断:xwos_irq_release()
    • 此API用于释放已安装的中断处理函数以及其参数。
  • 开启中断:xwos_irq_enable()
  • 关闭中断:xwos_irq_disable()
  • 保存中断的开关标志,然后将其关闭:xwos_irq_save()
  • 恢复中断的开关标志:xwos_irq_restore()
  • 挂起中断标志:xwos_irq_pend()
    • 此API用于通过软件强制将一个外设中断挂起,这个操作并不是所有的架构都支持,已经 支持的架构:
      • ARMv6-m
      • ARMv7-m
      • PowerPC-e200z0
  • 清除中断标志:xwos_irq_clear()
    • 此API用于通过软件强制将一个外设中断清除,这个操作并不是所有的架构都支持,已经 支持的架构:
      • ARMv6-m
      • ARMv7-m
      • PowerPC-e200z0
  • 配置中断:xwos_irq_cfg()
    • 此API用于配置外设中断,其参数soc_irq_cfg是一个与架构相关的数据结构,不同 架构定义不同,需要参考xwcd文件夹,soc目录中的soc_irq.h文件,例如stm32h7x, 此文件位于xwcd/soc/arm/v7m/gcc/m7/stm32h7x/soc_irq.h
  • 获取中断的配置:xwos_irq_get_cfg()
    • 此API用于获取外设中断配置,其参数soc_irq_cfg是一个与架构相关的数据结构, 不通架构定义不同,需要参考xwcd文件夹,soc目录中的soc_irq.h文件,例如 stm32h7x,此文件位于xwcd/soc/arm/v7m/gcc/m7/stm32h7x/soc_irq.h
  • 获取中断的数据:xwos_irq_get_data()
    • 获取通过xwos_irq_request()安装的中断处理函数的参数。
  • 获取当前上下文的中断号:xwos_irq_get_id()
    • 此API可用于判断当前上下文:
      • 函数返回错误码-EINTHRD:表示当前上下文为线程
      • 函数返回错误码-EINBH:表示当前上下文为中断底半部
      • 函数返回错误码XWOK:表示当前上下文为中断,并且可从参数指定的 缓冲区中获取当前中断的中断号,但并不是所有架构都支持返回中断号, 已经支持的架构:
        • ARMv6-m
        • ARMv7-m
        • PowerPC-e200z0

示例

CPU总中断

  • 应用模块:xwam/example/lock/cpuirq
  • 用法:
    • 在配置文件xwbd/电路板名称/cfg/xwam.h中 定义宏XWAMCFG_example_lock_cpuirq1
    • 在初始化流程中(例如:xwos_main())调用 example_cpuirq_start()启动模块。

外设中断

可以参考ARMv7-m架构初始化切换上下文的中断:

/* xwcd/soc/arm/v7m/gcc/arch_sched.c */
__xwbsp_rodata const struct soc_irq_cfg cortex_m_swcx_irq_cfg = {
        .irqcfg = {
                .priority = ARCH_IRQ_SWCX_PRIO,
        },
};

__xwbsp_rodata const struct xwos_irq_resource cortex_m_swcx_irqrsc = {
        .irqn = ARCH_IRQ_PENDSV,
        .isr = arch_scheduler_isr_swcx,
        .cfg = &cortex_m_swcx_irq_cfg,
        .description = "rsc.irq.swcx.armv7m",
};

__xwbsp_code
xwer_t arch_scheduler_lib_init_pendsv(struct xwos_scheduler * xwsd)
{
        xwer_t rc;
        const struct xwos_irq_resource * irqrsc;

        UNUSED(xwsd);

        /* 申请中断 */
        irqrsc = &cortex_m_swcx_irqrsc;
        rc = xwos_irq_request(irqrsc->irqn, irqrsc->isr);
        BUG_ON(rc < 0);

        /* 配置中断 */
        rc = xwos_irq_cfg(irqrsc->irqn, irqrsc->cfg);
        BUG_ON(rc < 0);

        /* 开启中断 */
        rc = xwos_irq_enable(irqrsc->irqn);
        BUG_ON(rc < 0);

        return rc;
}

配置

/* <cfg/soc.h> */

#define SOCCFG_RO_ISRTABLE          1   // 是否启用只读中断向量表
                                        // 1:只读
                                        // 0:读写

API参考

CPU总中断

  • 头文件:xwos/osal/irq.h
  • 注释:见头文件

外设中断

  • 头文件:xwos/irq.h
  • 注释:见头文件