[笨叔点滴14] ARMv8里异常处理哪些蛇神牛鬼
“ 小明同学在一次计算机的实验课里,怎么也出不来实验结果。
小明:老师,老师,这个怎么老是404啊?
老师:你把这个配置文件的某某项填空就行
小明兴高采烈的修改配置文件。
过了一会,小明又嘟囔不行。
老师:你把配置文件发给我。
。。。
老师:小明同学,滚。。。,我让你填空就行,就怎么给我填了一个“空”字
”
昨天的笨叔点滴里和大家go through一下ARM v7手册和Linux内核代码里异常处理部分的哪些事儿。有小伙伴微信上和笨叔叔说,今晚能不能介绍一下ARMv8上的异常处理,我说好啊,这要看我家小笨笨今天晚上乖不乖了,乖的话,笨叔的空余时间就多一些。
话说ARM v8是和一个ARM v7完全不兼容的架构,但是又偏偏把 ARM v7融入了ARM v8里,说不出什么感觉,至少还没有让笨叔感觉到拍案称绝,但至少64位和32位可以比较完美的融合,也许是为了往后兼容吧,毕竟软件生态最重要。另外一点,ARMv8架构做的越来越成熟了,完全有大家闺秀的风范,完全有能力和其他的架构比一比,这一点从ARM v8的汇编代码可以窥探出来,简洁干练!
ARMv8的最新手册是V8.3版本,全程有6666页,大家一看6666估计都吓坏了,其实大家不用担心,且来听笨叔给你分析分析:
这6666页里有很多内容和ARMv7是重复的,第F和G章是讲ARM v7。另外,ARM的芯片手册是把所有的运行模式都揉在一块来描述,比如我做的系统不用虚拟化,不用secure monitor,那剩下的有用内容就不是很多了。若再把ARM v7和介绍指令集的章节去掉,那这6666页就没有这么恐怖了,对吧?
01
—
我们来翻开ARM v8手册第D.1章,第一页就告诉你ARM v8有哪些EL,EL是exception level的意思,翻译成中文也许叫异常等级,我们下文还是简称EL等级吧,和芯片手册和代码同步。ARM芯片手册通常使用ELn来表示第n个异常等级。
这里有4个EL,其中EL0是用户态,EL1是内核态也就是特权模式,EL2是虚拟化的hypevisor模式,EL3是安全monitor。是不是和x86的ring0~ring3很像呢?这是向x86前辈致敬吗?哈哈~~
在第D1.2.5章里,介绍了异常主要是分成2大类。一类是同步,另外一类是异步。
这里主要是说,同步异常是:
导致异常发生的原因是执行了某个指令
异常返回地址就指明了是因为执行了那个“圈套”指令导致的
这个异常发生是精确的。
这个异常的发生不是因为执行了某个指令而中的圈套
异常返回地址没法指明是中了哪条指令的圈套
这个异常发生是不精确的
那啥是异步异常呢:
如果笨叔再用自己的话来翻译一下就是,所谓的同步异常就是说中了指令的圈套,这样的,这些异常的发生是比较精准的。而异步异常是和运行的指令没有关系,因为它是被中圈套。如果用打猎来说的话,你在地里挖个陷阱来打猎,这是同步异常,任何猎物只要跑到这里就中圈套。如果你追着这猎物射箭,对于猎物来说,它什么时候被杀中,它是不知道的,它又不能说 NG重来:笨叔,我们重来,我在前面跑,你重新射我。
所以,我们在ARMv7里说的那些异常,比如data abort等,就很吻合这里说的同步异常,而IRQ和FIQ中断就很吻合异步异常,ARMv8里还有System Error也是属于异步异常。
在D1.10章里包含了很多和异常相关的内容。比如当一个异常发生了之后,ARM处理器做了那些事情?
上面这一大段都是描述异常发生了,ARM处理器做了那些事情。这好比之前那个打猎的例子,不管是守株待兔式的还是射箭式的,中了都要去处理现场吧,万一你的猎物被第三者偷走了,咋办? 上面的步骤,笨叔简单总结一下:
处理器的状态保存到对应(target)的异常等级的SPSR_ELx寄存器里
返回地址保存到对应的异常等级的ELR_ELx寄存器里
PSTATE寄存器里的DAIF域都设置为1。PSTATE寄存器是ARM v8里新增的寄存器。
如果是同步异常,那么究竟什么原因导致的呢?请君看ESR_ELx寄存器。
设置一下栈指针,指向对应异常等级里的栈。
迁移到对应的异常等级,然后跑到异常向量表里。
总的来说,这个过程和ARM v7的差不了太多。
接下来,我们看一下异常向量表,究竟和ARM v7的有啥不一样。
在第D1.10.2章里就描述异常向量表了。
这里第一句话是说,这个向量表会占用一大段连续的空间,这是什么鬼呢?我们稍后再解释。
第二段说,每个EL等级里都有一个对应的VBAR寄存器,用来指向异常向量表的基地址。那你一定会疑问,那怎么放呢?
第三段说,异常向量表里必须包含同步异常,Serror,IRQ和FIQ这种信息。
在第D.1.10.2章里有一个表D1-7,这个表,估计很多人看了直接晕倒,太晦涩难懂了。
啥是current EL with SP_EL0,啥是current EL with SP_ELx呢?笨叔刚开始看这个表,也晕,功力不够,之因太笨。呵呵,就像武侠小说里说的,功力不够看武功秘籍会头晕。
还好,ARM公司提供了另外一份比较厚道的文档,那就是《ARM Cortex-A Series Programmer‘s Guide for ARMv8-A》,这个文件相对简单易懂一些。在第10.4章里有描述这个异常向量表是怎么回事的。
她说:在ARM v7的异常向量表,每个表项只有4个字节,只能存放一条跳转指令,但是我们在ARM v8里升级啦,我们每个表项需要128个字节,这样我们可以存放32条指令。小伙伴注意啦,ARM v8指令集里一条指令的位宽是32bit的,而不是64bit,小明同学最近去面试就被面试官鄙视了。异常向量表里要包含4组,每一组包含4个表项。这怎么理解?
比如当前系统只运行Linux内核不包括虚拟化或者安全特性,那最高的EL等级是EL1,那么它就一定有EL0。所以上面说的Current EL就是说的当前系统最高的EL等级。那current EL with SP_EL0是啥意思呢,其实是说,当系统运行在EL1的时候,然后使用EL0的SP,貌似还没有这种场景。current EL with SP_EL1,这是说系统运行在EL1里,SP也是使用EL1,那就是在内核态里发生了异常,这个场景是有的。
第10.4章这个表,比较适合我们去理解上面说的那一大段废话。
举个栗子,当OS运行在内核态时发生了IRQ中断,这时候应该跳转到异常表里的0x280处。如果OS运行在用户态并且正在执行32bit的app,发生了IRQ中断,它应该跳转到哪里呢?
关于异常向量表,还有一个问题需要考虑,那就是异常向量表放在哪里?ARM v8里提供了VBAR(Vector Base address register)。这几个寄存器的描述是在第D10.2章里。
小明同学问:这里有三个相同的VBAR寄存器,我应该设置那个呢?
我们来看一下Linux内核代码(以runninglinux_4.0为例)。代码路径是在arch/arm64/kernel/entry.S文件里。
笨叔在图上圈了4组,就是我们刚才说的那4组。
但是小明同学由有疑问了,笨叔叔,你不是说,每个表项是128个字节吗,我怎么看每个表项好像是4个字节啊?
现在的小明同学已经变得聪明了。
猫腻隐藏在entry这个宏里。
注意这里的127行的align这个伪指令,它的威力很大。这里align 7表示按照2的7次方来对齐,2的7次方是128。
(未完待续,明天我们继续以 data abort异常处理为例,介绍ARM v8上异常处理的那些蛇神牛鬼)
第二季来啦
大家期待的第二季视频来了,我们这次是进程管理、锁机制以及中断管理三合一,加量不加价。旗舰篇还是原价1199,现在特价999。三合一初级篇特价299。
初级篇: 笨叔和大家彻底理清进程管理、锁机制以及中断管理相关的概念。比如说:
进程的生命周期
进程控制块
进程调度的本质
CFS调度器
进程切换是怎么玩
SMP负载均衡
大小核调度是怎么回事
为啥需要中断
中断发生了ARMv7和ARMv8处理器做了啥
中断底层汇编处理
中断上下半部
如何写好一个中断处理函数
软中断是怎么回事
tasklet和workqueue怎么玩
什么是中断上下文
为啥需要锁
什么是原子操作
ARMv7和ARMv8处理器怎么进行原子操作的
内存屏障是什么
spinlock怎么用
信号量和mutex该选谁
RCU怎么用
为啥这里要添加一个锁
...
旗舰篇包含初级篇内容,还包括如下内容:
额外增加核心代码的导读,真正做到自主可控。
综合创新实验,笨叔带领大家在树莓派上玩一个小OS。
面试宝典,那些年我们被虐过的面试题目。
现在第二季旗舰篇和初级篇正在火热接收预定,预计8月28号开始陆续发货。点击“阅读原文”进入订阅页面。
订阅旗舰篇优惠活动:
已经订阅第一季旗舰篇的小伙伴,订阅第二季旗舰篇可以返回100元现金。同时一起订阅第一季+第二季旗舰篇的小伙伴也是同样返回100元现金。(100元现金是微信返回)
订阅了第一季+第二季旗舰篇的小伙伴,参加转发笨叔点滴活动可以获得《奔跑吧Linux内核》入门篇签名新书,新书预计2018年双十一或者双十二出版。
[往期精彩]
[笨叔点滴12]面试必考:如果在中断处理函数里发生了缺页中断会怎样?为什么?
[笨叔点滴5] git rebase和git merge究竟有啥区别?
[笨叔点滴2] 为啥子ARM32体系结构中每个处理模式都有一个单独的栈?
[笨叔点滴1] 为什么do_page_fault函数里代码需要判断用户态还是内核态?
高级运维必杀技:如何图形化单步调试RHEL/Centos 7里的内核?