实现BSP中断系统处理接口
这些接口都定义在bspLib.c中,需要BSP开发者根据实际平台去实现这些接口。全志R16使用的arm官方的GICv2版本中断控制器,关于这个控制器硬件上如何使用我们不会在这篇文章中讲解,请参考arm官方资料或者互联网上相关文章。我们这里关心的是bspLib.c中哪些接口是和中断系统相关的以及实现这些接口我们需要做哪些事。
1. bspIntInit
这个接口主要是初始化中断控制器,一般都是清除所有中断状态,关闭所有中断等操作:
VOID bspIntInit (VOID) { /* * TODO: 加入你的处理代码 * * 如果某中断为链式中断,请加入形如: * API_InterVectorSetFlag(LW_IRQ_4, LW_IRQ_FLAG_QUEUE); * 的代码. * * 如果某中断可用作初始化随机化种子,请加入形如: * API_InterVectorSetFlag(LW_IRQ_0, LW_IRQ_FLAG_SAMPLE_RAND); * 的代码. */ armGicInit(); armGicCpuInit(LW_FALSE, 255); }
2. bspIntHandle
中断处理接口,当cpu产生IRQ中断时,首先是从startup.S的中断向量表中找到IRQ中断入口也即是archIntEntry 这个函数,这个函数在处理过程中最终调用到BSP中的bspIntHandle 。这个接口首先需要读取中断控制器来获取当前是哪个中断号产生了中断,然后调用内核接口archIntHandle 来处理这个中断号对应的中断服务函数,当中断服务函数处理完毕之后可能还需要通知中断控制器:
VOID bspIntHandle (VOID) { /* * TODO: 通过读取硬件寄存器, 得到当前产生的中断向量号, 并赋给 uiVector 变量 */ REGISTER UINT32 uiAck = armGicIrqReadAck(); REGISTER UINT32 uiSourceCpu = (uiAck >> 10) & 0x7; REGISTER UINT32 uiVector = uiAck & 0x1FF; (VOID)uiSourceCpu; archIntHandle((ULONG)uiVector, LW_FALSE); armGicIrqWriteDone(uiAck); }
3. bspIntVectorEnable
这个接口使能相应中断号对应的中断,调用系统接口API_InterVectorEnable 最终就是调用BSP中的这个接口来使能中断的:
VOID bspIntVectorEnable (ULONG ulVector) { /* * TODO: 通过设置硬件寄存器, 使能指定的中断向量 */ armGicIntVecterEnable(ulVector, LW_FALSE, 127, 1 << 0); }
因为GICv2是支持多核的中断控制器,所以这里使能中断时我们将中断默认都在0核上处理。
4. bspIntVectorDisable
这个接口关闭相应中断号对应的中断,调用系统接口API_InterVectorDisable 最终就是调用BSP中的这个接口来关闭中断的:
VOID bspIntVectorDisable (ULONG ulVector) { /* * TODO: 通过设置硬件寄存器, 禁能指定的中断向量 */ armGicIntVecterDisable(ulVector); }
5. bspIntVectorIsEnable
这个接口用来检测某一个中断号对应的中断是否使能,调用系统接口API_InterVectorIsEnable 最终就是调用BSP中的这个接口来检测中断状态的:
BOOL bspIntVectorIsEnable (ULONG ulVector) { /* * TODO: 通过读取硬件寄存器, 检查指定的中断向量是否使能 */ return (armGicIrqIsEnable(ulVector) ? LW_TRUE : LW_FALSE); }
6. bspIntVectorSetPriority
某些中断控制器支持中断优先级设置,这个接口用来设置某个中断的优先级,调用系统接口API_InterVectorSetPriority 最终就是调用BSP中的这个接口来设置中断优先级的,在本次教程中我们不关心中断优先级,所以这个接口使用默认设置就好:
ULONG bspIntVectorSetPriority (ULONG ulVector, UINT uiPrio) { return (ERROR_NONE); }
7. bspIntVectorGetPriority
这个接口用来获取某个中断的优先级,调用系统接口API_InterVectorGetPriority 最终就是调用BSP中的这个接口来获取中断优先级的,在本次教程中我们不关心中断优先级,所以这个接口使用默认设置就好:
ULONG bspIntVectorGetPriority (ULONG ulVector, UINT *puiPrio) { *puiPrio = 0; return (ERROR_NONE); }
8. bspIntVectorSetTarget
这个接口用于设置某个中断可以被哪些cpu核处理,调用系统接口API_InterSetTarget 最终就是调用BSP中的这个接口来实现中断绑核功能,在本教程中我们让中断都在0核上处理,所以这个接口使用默认设置就好:
ULONG bspIntVectorSetTarget (ULONG ulVector, size_t stSize, const PLW_CLASS_CPUSET pcpuset) { return (ERROR_NONE); }
9. bspIntVectorGetTarget
这个接口用于获取某个中断可以被哪些cpu核处理,调用系统接口API_InterGetTarget 最终就是调用BSP中的这个接口来获取中断绑在哪个核上的,在本教程中我们让中断都在0核上处理,所以这个接口使用默认设置就好:
ULONG bspIntVectorGetTarget (ULONG ulVector, size_t stSize, PLW_CLASS_CPUSET pcpuset) { LW_CPU_ZERO(pcpuset); LW_CPU_SET(0, pcpuset); return (ERROR_NONE); }
到此为止我们就介绍完了bspLib.c中需要实现的核中断处理相关的接口,在实际BSP开发调试中,中断控制器的驱动一般都是从别的使用相同型号中断控制器的BSP中拷贝过来然后进行修改调试。如果是完全从头开发的话,需要参考芯片厂商提供的Linux源码,这部分工作也是重中之重,因为如果中断系统无法正常工作的话,SylixOS基本也就基本告别自行车了==
实现完上述接口之后还有最后一个步骤要做,我们需要将当前系统设置的中断向量表的基址告诉cpu,在armv7架构中我们可以通过cp15协处理器指令设置中断向量表的基址,在SylixOS内核中已经提供好接口armVectorBaseAddrSet ,只需要将基址传入即可。
注意:如果使能了MMU,这里需要设置的地址是虚拟地址,但是在SylixOS内核中,中断向量表是在内核代码段的,这段内存是对等映射的,所以直接将物理地址填入即可。
这个设置操作我们放在bspInit.c中的halModeInit 函数中,因为在之后的从核启动过程中也会使用这个接口:
static VOID halModeInit (VOID) { /* * TODO: 加入你的处理代码, 但建议不作处理 */ armHighVectorDisable(); armVectorBaseAddrSet(BSP_CFG_RAM_BASE); }
在arm架构中,为了安全考虑可以将中断向量表位置固定在0xffff0000这个地址,这个位置一般都是厂商BootRom所在的位置,但是我们现在要使用自己的中断向量表而不是BootRom中的,所以需要先将中断向量表定位在0xffff0000这个功能关闭掉,这是通过上面的armHighVectorDisable 接口来实现的。
在driver目录下新建gic目录,将中断控制器的驱动放在其中:
2021年12月13日 13:49 1F
打卡
2022年9月4日 23:25 2F
博主能发给我gic文件吗,初学bsp想参照下