searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

GICv2 配置流程全解析:以 GIC - 400 寄存器为例

2025-04-03 10:19:52
12
0

一、GICv2 简介

GIC(Generic Interrupt Controller)是 ARM 架构中用于管理中断的控制器,GICv2 是其一个重要版本,广泛应用于 ARM Cortex - A 系列处理器。GIC - 400 是 GICv2 架构下的一款具体的中断控制器芯片,通过配置其相关寄存器,可实现中断的分发、优先级管理等功能。

二、关键寄存器作用及配置方法

(一)分发器(Distributor)寄存器

分发器负责接收所有中断源的中断请求,并将其分发到相应的 CPU 接口。以下是几个关键的分发器寄存器:
  1. GICD_CTLR(控制寄存器)
    • 作用:用于控制分发器的启用和禁用。
    • 配置方法:将其设置为 0 时关闭分发器,设置为 1 时打开分发器。

代码示例

volatile uint32_t *dist_base = (volatile uint32_t *)DIST_BASE_ADDR;
dist_base[GICD_CTLR / 4] = 0x0; // 关闭分发器
dist_base[GICD_CTLR / 4] = 0x1; // 打开分发器
  1. GICD_TYPER(类型寄存器)
    • 作用:用于获取 GIC 支持的最大中断数。
    • 选择方法:此寄存器用于获取全局信息,不依赖特定中断号进行选择。
    • 配置方法:读取该寄存器的值,通过计算得到最大中断数。
    • 代码示例
      uint32_t typer = dist_base[GICD_TYPER / 4];
      uint32_t it_lines = (typer & 0x1F) + 1;
      uint32_t max_irq = 32 * it_lines;
  1. GICD_ISENABLER(中断设置使能寄存器基址)和 GICD_ICENABLER(中断清除使能寄存器基址)
    • 作用:分别用于使能和禁用中断源。
    • 选择方法:每个寄存器组控制 32 个中断,根据中断号 irq_num 计算所在寄存器组偏移 irq_num / 32,以及在寄存器中的位偏移 irq_num % 32
    • 配置方法:向相应的寄存器位写入 1 来使能或禁用特定的中断。
    • 代码示例
      // 禁用所有中断源
      for (uint32_t i = 0; i < max_irq / 32; i++) {
          dist_base[(GICD_ICENABLER / 4) + i] = 0xFFFFFFFF;
      }
      // 使能特定中断
      volatile uint32_t *isenabler = (volatile uint32_t *)(DIST_BASE_ADDR + GICD_ISENABLER);
      isenabler[irq_num / 32] = 1 << (irq_num % 32);
  1. GICD_ICFGR(配置寄存器基址)
    • 作用:用于配置中断的触发模式,如电平触发或边沿触发。
    • 选择方法:每个寄存器控制 16 个中断,根据中断号 irq_num 计算所在寄存器索引 irq_num / 16,以及在寄存器中的位偏移 (irq_num % 16) * 2
    • 配置方法:通过设置相应的位来选择触发模式。
    • 代码示例
    • volatile uint32_t *icfgr = (volatile uint32_t *)(DIST_BASE_ADDR + GICD_ICFGR);
      uint32_t icfgr_idx = irq_num / 16;
      uint32_t icfgr_bit = (irq_num % 16) * 2;
      icfgr[icfgr_idx] = (icfgr[icfgr_idx] & ~(0x3 << icfgr_bit)) | (0x2 << icfgr_bit); // 配置为边沿触发
  2. GICD_ITARGETSR(处理器目标寄存器基址)
    • 作用:用于指定中断的目标 CPU。
    • 选择方法:每个中断对应 4 位,根据中断号 irq_num 计算所在字节偏移 irq_num & ~0x3,以及在字节中的偏移 irq_num % 4
    • 配置方法:设置相应的位来选择目标 CPU。
    • 代码示例
      volatile uint8_t *itargetsr = (volatile uint8_t *)(DIST_BASE_ADDR + GICD_ITARGETSR);
      itargetsr += (irq_num & ~0x3);
      itargetsr[irq_num % 4] = 0x01; // 配置中断路由到 CPU0
  3. GICD_IPRIORITYR(优先级寄存器基址)
    • 作用:用于设置中断的优先级。
    • 选择方法:每个中断对应一个字节,直接根据中断号 irq_num 定位寄存器偏移。
    • 配置方法:向相应的寄存器写入优先级值。
    • 代码示例
      volatile uint8_t *ipriority = (volatile uint8_t *)(DIST_BASE_ADDR + GICD_IPRIORITYR);
      ipriority[irq_num] = 0x80; // 设置中断优先级
  4. GICD_ISPENDR(中断 Set - Pending 寄存器组基址)
    • 作用:用于检查中断是否处于挂起状态。
    • 选择方法:每个寄存器组控制 32 个中断,根据中断号 irq_num 计算所在寄存器组偏移 irq_num / 32,以及在寄存器中的位偏移 irq_num % 32
    • 配置方法:读取相应的位来判断中断是否挂起。
    • 代码示例
      int is_irq_pending(uint32_t irq_num)
      {
          volatile uint32_t *dist_base = (volatile uint32_t *)DIST_BASE_ADDR;
          uint32_t reg_offset = GICD_ISPENDR + (irq_num / 32) * 4;
          uint32_t bit_offset = irq_num % 32;
      
          uint32_t pending_reg = dist_base[reg_offset / 4];
          return (pending_reg & (1 << bit_offset)) != 0;
      }
  5. GICD_SGIR(软件生成中断寄存器)
    • 作用:用于软件生成中断。
    • 选择方法:此寄存器用于全局软件中断生成,不依赖特定中断号选择,但需指定中断号 sgi_num 和目标 CPU target_cpu
    • 配置方法:写入相应的值来指定中断号和目标 CPU。

代码示例

void trigger_sgi(int sgi_num, int target_cpu)
{
    volatile uint32_t *dist_base = (volatile uint32_t *)DIST_BASE_ADDR;
    uint32_t sgi_value = (target_cpu << 16) | (sgi_num & 0xF);
    dist_base[GICD_SGIR / 4] = sgi_value;
}

(二)CPU 接口(CPU Interface)寄存器

CPU 接口负责将中断请求传递给 CPU 核心,并处理 CPU 对中断的响应。以下是几个关键的 CPU 接口寄存器:
  1. GICC_CTLR(控制寄存器)
    • 作用:用于控制 CPU 接口的启用和禁用。
    • 选择方法:此寄存器控制整个 CPU 接口,不依赖特定中断号进行选择。
    • 配置方法:设置为 1 时使能 CPU 接口。

代码示例

volatile uint32_t *cpu_base = (volatile uint32_t *)GICC_BASE_ADDR;
cpu_base[GICC_CTLR / 4] = 0x1; // 使能 CPU 接口

      2.GICC_PMR(优先级掩码寄存器)

    • 作用:用于设置允许的最低中断优先级。
    • 选择方法:此寄存器为全局配置,不依赖特定中断号进行选择。
    • 配置方法:写入相应的优先级值。

代码示例

cpu_base[GICC_PMR / 4] = 0xFF; // 允许所有优先级
  1. GICC_IAR(中断确认寄存器)
    • 作用:用于获取当前正在处理的中断号。
    • 选择方法:此寄存器返回当前中断信息,不依赖特定中断号进行选择。
    • 配置方法:读取该寄存器的值。

代码示例

uint32_t znic_interrupt_dispatcher(void)
{
    return ((volatile uint32_t *)GICC_BASE_ADDR)[GICC_IAR / 4] & 0x3FF;
}
  1. GICC_EOIR(中断结束寄存器)
    • 作用:用于通知 GIC 中断处理已完成。
    • 选择方法:根据当前处理的中断号写入该寄存器。
    • 配置方法:写入相应的中断号。
    • 代码示例
      volatile uint32_t *cpu_base = (volatile uint32_t *)GICC_BASE_ADDR;
      cpu_base[GICC_EOIR / 4] = 149; // 确认中断
0条评论
0 / 1000
c****g
1文章数
0粉丝数
c****g
1 文章 | 0 粉丝
c****g
1文章数
0粉丝数
c****g
1 文章 | 0 粉丝
原创

GICv2 配置流程全解析:以 GIC - 400 寄存器为例

2025-04-03 10:19:52
12
0

一、GICv2 简介

GIC(Generic Interrupt Controller)是 ARM 架构中用于管理中断的控制器,GICv2 是其一个重要版本,广泛应用于 ARM Cortex - A 系列处理器。GIC - 400 是 GICv2 架构下的一款具体的中断控制器芯片,通过配置其相关寄存器,可实现中断的分发、优先级管理等功能。

二、关键寄存器作用及配置方法

(一)分发器(Distributor)寄存器

分发器负责接收所有中断源的中断请求,并将其分发到相应的 CPU 接口。以下是几个关键的分发器寄存器:
  1. GICD_CTLR(控制寄存器)
    • 作用:用于控制分发器的启用和禁用。
    • 配置方法:将其设置为 0 时关闭分发器,设置为 1 时打开分发器。

代码示例

volatile uint32_t *dist_base = (volatile uint32_t *)DIST_BASE_ADDR;
dist_base[GICD_CTLR / 4] = 0x0; // 关闭分发器
dist_base[GICD_CTLR / 4] = 0x1; // 打开分发器
  1. GICD_TYPER(类型寄存器)
    • 作用:用于获取 GIC 支持的最大中断数。
    • 选择方法:此寄存器用于获取全局信息,不依赖特定中断号进行选择。
    • 配置方法:读取该寄存器的值,通过计算得到最大中断数。
    • 代码示例
      uint32_t typer = dist_base[GICD_TYPER / 4];
      uint32_t it_lines = (typer & 0x1F) + 1;
      uint32_t max_irq = 32 * it_lines;
  1. GICD_ISENABLER(中断设置使能寄存器基址)和 GICD_ICENABLER(中断清除使能寄存器基址)
    • 作用:分别用于使能和禁用中断源。
    • 选择方法:每个寄存器组控制 32 个中断,根据中断号 irq_num 计算所在寄存器组偏移 irq_num / 32,以及在寄存器中的位偏移 irq_num % 32
    • 配置方法:向相应的寄存器位写入 1 来使能或禁用特定的中断。
    • 代码示例
      // 禁用所有中断源
      for (uint32_t i = 0; i < max_irq / 32; i++) {
          dist_base[(GICD_ICENABLER / 4) + i] = 0xFFFFFFFF;
      }
      // 使能特定中断
      volatile uint32_t *isenabler = (volatile uint32_t *)(DIST_BASE_ADDR + GICD_ISENABLER);
      isenabler[irq_num / 32] = 1 << (irq_num % 32);
  1. GICD_ICFGR(配置寄存器基址)
    • 作用:用于配置中断的触发模式,如电平触发或边沿触发。
    • 选择方法:每个寄存器控制 16 个中断,根据中断号 irq_num 计算所在寄存器索引 irq_num / 16,以及在寄存器中的位偏移 (irq_num % 16) * 2
    • 配置方法:通过设置相应的位来选择触发模式。
    • 代码示例
    • volatile uint32_t *icfgr = (volatile uint32_t *)(DIST_BASE_ADDR + GICD_ICFGR);
      uint32_t icfgr_idx = irq_num / 16;
      uint32_t icfgr_bit = (irq_num % 16) * 2;
      icfgr[icfgr_idx] = (icfgr[icfgr_idx] & ~(0x3 << icfgr_bit)) | (0x2 << icfgr_bit); // 配置为边沿触发
  2. GICD_ITARGETSR(处理器目标寄存器基址)
    • 作用:用于指定中断的目标 CPU。
    • 选择方法:每个中断对应 4 位,根据中断号 irq_num 计算所在字节偏移 irq_num & ~0x3,以及在字节中的偏移 irq_num % 4
    • 配置方法:设置相应的位来选择目标 CPU。
    • 代码示例
      volatile uint8_t *itargetsr = (volatile uint8_t *)(DIST_BASE_ADDR + GICD_ITARGETSR);
      itargetsr += (irq_num & ~0x3);
      itargetsr[irq_num % 4] = 0x01; // 配置中断路由到 CPU0
  3. GICD_IPRIORITYR(优先级寄存器基址)
    • 作用:用于设置中断的优先级。
    • 选择方法:每个中断对应一个字节,直接根据中断号 irq_num 定位寄存器偏移。
    • 配置方法:向相应的寄存器写入优先级值。
    • 代码示例
      volatile uint8_t *ipriority = (volatile uint8_t *)(DIST_BASE_ADDR + GICD_IPRIORITYR);
      ipriority[irq_num] = 0x80; // 设置中断优先级
  4. GICD_ISPENDR(中断 Set - Pending 寄存器组基址)
    • 作用:用于检查中断是否处于挂起状态。
    • 选择方法:每个寄存器组控制 32 个中断,根据中断号 irq_num 计算所在寄存器组偏移 irq_num / 32,以及在寄存器中的位偏移 irq_num % 32
    • 配置方法:读取相应的位来判断中断是否挂起。
    • 代码示例
      int is_irq_pending(uint32_t irq_num)
      {
          volatile uint32_t *dist_base = (volatile uint32_t *)DIST_BASE_ADDR;
          uint32_t reg_offset = GICD_ISPENDR + (irq_num / 32) * 4;
          uint32_t bit_offset = irq_num % 32;
      
          uint32_t pending_reg = dist_base[reg_offset / 4];
          return (pending_reg & (1 << bit_offset)) != 0;
      }
  5. GICD_SGIR(软件生成中断寄存器)
    • 作用:用于软件生成中断。
    • 选择方法:此寄存器用于全局软件中断生成,不依赖特定中断号选择,但需指定中断号 sgi_num 和目标 CPU target_cpu
    • 配置方法:写入相应的值来指定中断号和目标 CPU。

代码示例

void trigger_sgi(int sgi_num, int target_cpu)
{
    volatile uint32_t *dist_base = (volatile uint32_t *)DIST_BASE_ADDR;
    uint32_t sgi_value = (target_cpu << 16) | (sgi_num & 0xF);
    dist_base[GICD_SGIR / 4] = sgi_value;
}

(二)CPU 接口(CPU Interface)寄存器

CPU 接口负责将中断请求传递给 CPU 核心,并处理 CPU 对中断的响应。以下是几个关键的 CPU 接口寄存器:
  1. GICC_CTLR(控制寄存器)
    • 作用:用于控制 CPU 接口的启用和禁用。
    • 选择方法:此寄存器控制整个 CPU 接口,不依赖特定中断号进行选择。
    • 配置方法:设置为 1 时使能 CPU 接口。

代码示例

volatile uint32_t *cpu_base = (volatile uint32_t *)GICC_BASE_ADDR;
cpu_base[GICC_CTLR / 4] = 0x1; // 使能 CPU 接口

      2.GICC_PMR(优先级掩码寄存器)

    • 作用:用于设置允许的最低中断优先级。
    • 选择方法:此寄存器为全局配置,不依赖特定中断号进行选择。
    • 配置方法:写入相应的优先级值。

代码示例

cpu_base[GICC_PMR / 4] = 0xFF; // 允许所有优先级
  1. GICC_IAR(中断确认寄存器)
    • 作用:用于获取当前正在处理的中断号。
    • 选择方法:此寄存器返回当前中断信息,不依赖特定中断号进行选择。
    • 配置方法:读取该寄存器的值。

代码示例

uint32_t znic_interrupt_dispatcher(void)
{
    return ((volatile uint32_t *)GICC_BASE_ADDR)[GICC_IAR / 4] & 0x3FF;
}
  1. GICC_EOIR(中断结束寄存器)
    • 作用:用于通知 GIC 中断处理已完成。
    • 选择方法:根据当前处理的中断号写入该寄存器。
    • 配置方法:写入相应的中断号。
    • 代码示例
      volatile uint32_t *cpu_base = (volatile uint32_t *)GICC_BASE_ADDR;
      cpu_base[GICC_EOIR / 4] = 149; // 确认中断
文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0