ARM64的中断属于异常模式的一种,对中断的处理流程跟上节的异常处理类似,走其中的一个分支;

树莓派4b的中断控制器分两种:传统的中断方式legacy interruptGIC(BCM2711支持GIC-400)

一个典型的ARM64中断处理流程:

树莓派4b上的硬件资源:

1.中断控制器:

GIC-400(默认)
传统的中断控制器(legacy interrupt controller)

2.树莓派4b支持多种中断源:

ARM Core N: ARM Core本身的中断源,例如Core里的generic timer;
ARMC: 可以被VPU和CPU访问的中断源,例如mailbox;
ARM_LOCAL: 只能被CPU访问的中断源,例如本地timer等;

3.树莓派4b的legacy中断控制器

实例:以ARM Core的generic timer产生中断信号

3.1 Cortex-A72支持4个ARM Core的generic timer


这里采用Nonsecure EL1 Physical Timer,演示中断处理过程;
查看ARMv8手册,第一个是EL1 TIMER的控制寄存器CNTP_CTL_EL0;

计数器寄存器CNTP_TVAL_EL0

Timer支持两种触发方式,参考armv8_D11.2.4;

3.2 ARM_LOCAL寄存器有:

4个IRQ_SOURCE寄存器,每个CPU一个,表示IRQ中断源状态;
4个FIQ_SOURCE寄存器,每个CPU一个,表示FIQ中断源状态;
4个TIMER_CNTRL寄存器,每个CPU一个,用来使能对应中断源;

1.查看BCM2711手册可知,ARM_LOCAL基地址为0x4c000000或0xff800000

对于IRQ_SOURCE寄存器,可以读取对应中断源状态

TIMER_CNTRL寄存器用来使能中断响应

3.3 EL1的Nonsecure generic timer中断处理流程

初始化

1.初始化timer,设置cntp_ctl_el0寄存器的enable域使能;
2.给timer的TimeValue一个初值,设置cntp_tval_el0寄存器;
3.打开树莓派b4中断控制器中和timer相关的中断,设置TIMER_CNTRL0寄存器的CNT_PNS_IRQ为1;
4.打开PSTATE寄存器中的IRQ中断总开关;

异常中断处理

5.Timer中断发生;
6.跳转到异常向量表的el1_irq1函数;
7.保存中断上下文(kernel_entry宏);
8.跳转到中断处理函数;
9.读取ARM_LOCAL中断状态寄存器IRQ_SOURCE0;
10.判断中断源,是否为CNT_PNS_IRQ中断;
11.如果是CNT_PNS_IRQ,重置TimerValue;

返回现场

12.返回到el1_irq函数;
13.恢复中断上下文;
14.返回中断现场

中断源的判断:

以一个稍微复杂的中断源为例,根据树莓派4b BCM2711手册:

由上图可知,最多分三级:
1.读SOURCEn中断寄存器;
2.若SOURCEn[8]置位,继续读取PENDING2寄存器;
3.若PENDING2[24]置位,则读PENDING0寄存器;
4.若PENDING2[25]置位,则读PENDING1寄存器;

可见当中断源数量增加到一定程度,中断处理程序将会变得十分繁杂,GIC控制器就是为解决这个问题而生,下篇将详细介绍;

3.4 中断现场(上下文)

3.4.1 中断上下文内容

中断发生瞬间,CPU状态包括:
PSTATE寄存器
PC值
SP值
X0~X30寄存器

Linux使用一个栈框数据结构来描述需要保存的中断现场;

3.4.2 保存中断现场

中断发生时,中断上下文保存到当前进程的内核栈里;

代码实现:

.macro kernel_entrysub sp, sp, #S_FRAME_SIZE/*保存通用寄存器x0~x29到栈框里pt_regs->x0~x29*/stp x0, x1, [sp, #16 *0]stp x2, x3, [sp, #16 *1]stp x4, x5, [sp, #16 *2]stp x6, x7, [sp, #16 *3]stp x8, x9, [sp, #16 *4]stp x10, x11, [sp, #16 *5]stp x12, x13, [sp, #16 *6]stp x14, x15, [sp, #16 *7]stp x16, x17, [sp, #16 *8]stp x18, x19, [sp, #16 *9]stp x20, x21, [sp, #16 *10]stp x22, x23, [sp, #16 *11]stp x24, x25, [sp, #16 *12]stp x26, x27, [sp, #16 *13]stp x28, x29, [sp, #16 *14]/* x21: 栈顶 的位置*/add     x21, sp, #S_FRAME_SIZEmrs     x22, elr_el1mrs     x23, spsr_el1/* 把lr保存到pt_regs->lr, 把sp保存到pt_regs->sp位置*/stp     lr, x21, [sp, #S_LR]/* 把elr_el1保存到pt_regs->pc中把spsr_elr保存到pt_regs->pstate中*/stp     x22, x23, [sp, #S_PC].endm

3.4.3 恢复中断现场

中断处理完成后,从内核栈中恢复中断现场;

代码实现:

.macro kernel_exit/* 从pt_regs->pc中恢复elr_el1,从pt_regs->pstate中恢复spsr_el1*/ldp     x21, x22, [sp, #S_PC]           // load ELR, SPSRmsr     elr_el1, x21                    // set up the return datamsr     spsr_el1, x22ldp     x0, x1, [sp, #16 * 0]ldp     x2, x3, [sp, #16 * 1]ldp     x4, x5, [sp, #16 * 2]ldp     x6, x7, [sp, #16 * 3]ldp     x8, x9, [sp, #16 * 4]ldp     x10, x11, [sp, #16 * 5]ldp     x12, x13, [sp, #16 * 6]ldp     x14, x15, [sp, #16 * 7]ldp     x16, x17, [sp, #16 * 8]ldp     x18, x19, [sp, #16 * 9]ldp     x20, x21, [sp, #16 * 10]ldp     x22, x23, [sp, #16 * 11]ldp     x24, x25, [sp, #16 * 12]ldp     x26, x27, [sp, #16 * 13]ldp     x28, x29, [sp, #16 * 14]/* 从pt_regs->lr中恢复lr*/ldr     lr, [sp, #S_LR]add     sp, sp, #S_FRAME_SIZE           // restore speret.endm

3.5 实例代码:

在树莓派上实现generic timer, 关键代码
timer初始化

#include <asm/timer.h>
#include <asm/irq.h>
#include <io.h>
#include <asm/arm_local_reg.h>
#include <timer.h>#define HZ 250
#define NSEC_PER_SEC    6000000000Lstatic unsigned int val = NSEC_PER_SEC / HZ;static int generic_timer_init(void)
{asm volatile("mov x0, #1\n""msr cntp_ctl_el0, x0"::: "memory");return 0;
}static int generic_timer_reset(unsigned int val)
{asm volatile("msr cntp_tval_el0, %x[timer_val]":: [timer_val] "r" (val): "memory");return 0;
}static void enable_timer_interrupt(void)
{writel(CNT_PNS_IRQ, TIMER_CNTRL0);
}void timer_init(void)
{generic_timer_init();generic_timer_reset(val);enable_timer_interrupt();
}void handle_timer_irq(void)
{generic_timer_reset(val);printk("Core0 Timer interrupt received\r\n");
}

中断服务程序:

#include <asm/irq.h>
#include <io.h>
#include <asm/arm_local_reg.h>void irq_handle(void)
{unsigned int irq = readl(ARM_LOCAL_IRQ_SOURCE0);switch (irq) {case (CNT_PNS_IRQ):handle_timer_irq();break;default:printk("Unknown pending irq: %x\r\n", irq);}
}

主应用程序:

void kernel_main(void)
{uart_init();init_printk_done();uart_send_string("Welcome BenOS!\r\n");printk("printk init done\n");//my_ldr_test();my_data_process();//my_cmp_test();//other_test();print_func_name(0x800880);//unsigned long val1 = 0,val2=0;//val1 = macro_test1(3,5);//val2 = macro_test2(3,5);print_memmap();my_memcpy_asm_test(0x80000, 0x100000, 32);my_memset_16bytes_asm(0x600000,0xaabbccdd,4096);//test_asm_goto(1);//trigger_alignment();printk("init done\n");timer_init(); //初始化timerraw_local_irq_enable();//启动timermy_ops_test();test_sysregs();int count=0;while (1) {//uart_send(uart_recv());printk("printk while...%ds\n",count++);delay_s(1);}
}

3.6在qemu上模拟结果如下:

ARM64基础13:ARM64的异常处理之中断处理(以树莓派4采用的BCM2711芯片为例)相关推荐

  1. [.net 面向对象编程基础] (13) 面向对象三大特性——多态

    [.net 面向对象编程基础] (13) 面向对象三大特性--多态 前面两节,我们了解了面向对象的的封装和继承特性,面向对象还有一大特性就是多态.比起前面的封装和继承,多态这个概念不是那么好理解.我们 ...

  2. 命名空间_python基础 13 类命名空间于对象、实例的命名空间,组合方法

    python基础 13 类命名空间于对象.实例的命名空间,组合方法 1.类命名空间于对象.实例的命名空间 创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性 而类有两 ...

  3. Java基础13:反射与注解详解

    Java基础13:反射与注解详解 什么是反射? 反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性. Orac ...

  4. 作业1 OO基础1-3、 设计一个教师类Teacher(属于cn.net.sdkd包)

    作业1 OO基础1-3. 设计一个教师类Teacher(属于cn.net.sdkd包) 要求: 1)属性有编号(int no).姓名(String name).年龄(int age).所属学院(Str ...

  5. 【Grasshopper基础13】创建可在画布上自由传递的自定义类型数据(上)—— IGH_Goo接口的重要性及其实现

    接下来的两章,我们来介绍一下在之前章节尚未介绍到的,但却在Grasshopper中占据极其重要地位的另一批我们早就虎视眈眈但却还没想到理由要去触碰的电池们(左侧红色框指示): 是的,就是这一些带黑底的 ...

  6. ARM64基础0:ARM64架构简介

    如题,一些ARM64通用的架构知识 1.ARMv8特色: (1) 超大的物理地址空间(Large Physical Address),提供超过4GB物理内存的访问: (2) 64位宽的虚拟地址空间(6 ...

  7. ARM64基础7:A64的比较和跳转指令

    pstate的nzcv标志位 条件标志位 描述 N 负数标志(上次运算结果为负值,则N=1,否则N=0) Z 上次运算结果为0 C 对于加法运算,无符号溢出,C=1, 其他不变 V 有符号溢出 条件码 ...

  8. 判断三角形java代码_java基础编程题之异常处理

    以下是刚开始学习java的基础编程题,每天持续更新java每个知识点的题目,持续练习,不断提高java基本功,培养编程能力.今天的练习的十八题是java的异常处理的使用. 1.检测年龄不能为负数和大于 ...

  9. linux arm64 宏定义,ARM64 芯片的 Jiffies 更新流程

    最近在调试 arm64 机器时遇到了一个比较蛋疼的时钟问题,这个时钟问题会导致在部分机器类型上导致无法启动,为了深入了解并解决掉这个问题,特定决定研究一下整个 jiffies 的更新逻辑过程,本篇文章 ...

最新文章

  1. java程序ssh置顶_使用shell脚本启动远程(SSH)Java应用程序不会返回本地提示
  2. appium+python自动化测试教程_Python+Appium实现自动化测试
  3. 复习04统计学习方法(朴素贝叶斯算法Naive Bayes)---图片版
  4. javascript操作dom的一些函数
  5. <meta name=“robots“ content=“index,follow“>的解释
  6. 万事开头难 - 介绍IMX6ULL启动方式
  7. mysql都有哪些数据库日志_MySQL数据库之MySQL都有哪些日志?分别都代表什么
  8. ORACLE利用scn赚钱,在Oracle中增进SCN及案例介绍
  9. Window部分软件图标显示不正常
  10. vue html if,vue中v-if使用方法详解
  11. 两张ID卡,完美消除互相干扰合二为一,实现“一卡”正反两用。
  12. Delphi Exif
  13. Predicting Ship T rajectory Based on Neural Networks UsingAIS Data
  14. Go语言如何高效的进行字符串拼接(6种方式进行对比分析)
  15. 十五款固态硬盘收获季节展示
  16. 第9章第24节:制作商业计划书的盈利模式幻灯片 [PowerPoint精美幻灯片实战教程]
  17. 关于python使用pip install 安装包,Geany无法找到包的问题
  18. 系统默认环境变量PATH设置
  19. html怎么让一行文字有滚动的效果,网页HTML代码:滚动文字的制作
  20. Deblurring by Realistic Blurring 图像去模糊论文解读

热门文章

  1. REDIS实践之在线人数统计几种方案分析
  2. Centos7篇---Centos7 卸载nvidia驱动和CUDA toolkit
  3. 北航计算机学院的含金量课程,北京航空航天大学在职研究生课程含金量怎么样?...
  4. 怎么把扫描文件转换成word
  5. adb 最大连接_如何通过雷电模拟器的 adb.exe 做QQ好友/微信匹配
  6. STM32的“外部中断”和“事件”区别和理解
  7. python线程异常中断_中断线程
  8. (附源码)计算机毕业设计SSM基于Java的健身房管理系统
  9. JavaScript __ 对象小记
  10. python画旋转六边形_使用python中的元素进行六边形绘制