》小明在上计算机实验课,实验结果上不去。小明:老师,老师,为什么是thisalways404?师:把这个配置文件填空就行了。小明高兴地修改配置文件。过了一会,小明嘀咕说他不能再做了。师:把配置文件发给我……老师:小明同学,滚出去……,我让你填空,就填一个“空”字给我。昨天傻大叔跟大家一起把ARMv7手册和Linux内核代码的异常处理部分都翻了一遍。有小伙伴在微信上问笨叔,今晚能介绍一下ARMv8上的异常处理吗?多一点。据说ARMv8是一个完全不兼容ARMv7的架构,但是它把ARMv7集成到了ARMv8中。比特能完美融合,或许是为了向后兼容,毕竟软件生态才是最重要的。还有一点就是ARMv8架构越来越成熟了。具有贵妇风范,完全有能力与其他建筑相媲美。这从ARMv8的汇编代码就可以看出,简洁干练!最新的ARMv8手册是V8.3版本,整个过程有6666页。大家看到6666可能会被吓到,其实不用着急,听笨叔叔给你分析一下:6666这几个页面里面有很多内容和ARMv7类似。重复,F章和G章是关于ARMv7的。另外,ARM的芯片手册把所有的操作模式都描述在一起了。比如我做的系统,没有使用虚拟化,没有安全监控,所以有用的内容就没有了。如果去掉ARMv7和介绍指令集的章节,那么6666页就不会那么吓人了吧?01让我们打开ARMv8手册的D.1章。第一页将告诉您ARMv8中有哪些EL可用。EL表示异常级别。翻译成中文可能会被称为例外级别。下面简称为EL级,芯片手册和代码是同步的。ARM芯片手册通常使用ELn表示第n个异常级别。这里有4个EL,其中EL0是用户态,EL1是内核态或者特权模式,EL2是虚拟化hypervisor模式,EL3是安全监视器。是不是类似于x86的ring0~ring3?这是在向x86的前辈们致敬吗?哈哈~~在D1.2.5章节中介绍了异常主要分为两类。一个是同步的,另一个是异步的。这里最主要的是,同步异常是:异常的原因是某条指令的执行,异常返回地址表示异常是执行“trap”指令是准确的。那么什么是异步异常:这种异常的发生并不是因为执行了某条指令的陷阱。异常的返回地址不能指示捕获到的是哪条指令。翻译一下,所谓同步异常就是说已经陷入了指令的陷阱。这样,这些异常的发生就更加精确了。异步异常与正在运行的指令无关,因为它被捕获在陷阱中。如果用打猎来说,你在地下挖个陷阱打猎,这是同步异常,任何猎物只要跑到这里都会落入陷阱。如果你追着猎物射箭,对于猎物来说,它不知道什么时候被杀死的,也不能说NG重新开始:笨叔叔,我们重新开始吧,我跑在前面,你再射我.所以我们在ARMv7中提到的异常,比如dataabort,和这里说的同步异常是非常一致的,而IRQ和FIQ中断和异步异常是非常一致的,而ARMv8中的SystemError也是异步异常。D1.10章包含了很多异常相关的内容。例如,当发生异常时,ARM处理器怎么办?上面一段是描述异常的发生,ARM处理器做了那些事。这就像前面打猎的例子。不管是观望还是射箭,中了就得处理场面。如果你的猎物被第三方偷走了怎么办?以上步骤,本叔简单总结一下:处理器的状态保存在对应(目标)异常级别的SPSR_ELx寄存器中,返回地址保存在对应异常级别的ELR_ELx寄存器中。PSTATE寄存器中的DAIF字段设置为1。PSTATE寄存器是ARMv8中的新寄存器。如果是同步异常,原因是什么?请查看ESR_ELx寄存器。设置栈指针指向对应异常级别的栈。迁移到对应的异常级别,然后运行到异常向量表。总的来说,这个过程和ARMv7没有太大区别。接下来我们看一下异常向量表,和ARMv7有什么区别。异常向量表在D1.10.2章中描述。这里第一句话就是这个向量表会占据很大的连续空间,这是什么鬼?我们稍后会解释。第二段说在每一层EL中都有一个对应的VBAR寄存器,用来指向异常向量表的基地址。那么你一定在想,如何放下它?第三段说异常向量表必须包含同步异常、Serror、IRQ、FIQ等信息。在D.1.10.2章中,有一个表D1-7。这张表,估计很多人看了都直接晕过去了,太晦涩了。SP_EL0的当前EL是什么,SP_ELx的当前EL是什么?笨大叔刚开始看这块表,也是头晕目眩,因为他的功力不够,因为他太笨了。呵呵,就像武侠小说里说的,功夫不够,看了武侠秘籍会头晕的。好在ARM提供了另一种文档,就是《ARM Cortex-A Series Programmer‘s Guide for ARMv8-A》,这个文档比较简单易懂。在第10.4章中,描述了这个异常向量表是怎么回事。她说:在ARMv7的异常向量表中,每个表项只有4个字节,只能存储一条跳转指令,但是我们在ARMv8中升级了,每个表项需要128个字节,所以我们可以存储32条指示。朋友们注意了,ARMv8指令集中一条指令的位宽是32bit,不是64bit。小明最近去面试的时候被面试官嫌弃了。异常向量表应该包含4个组,每个组包含4个表项。你怎么理解这个?例如,如果当前系统只运行Linux内核,不包含虚拟化或安全特性,那么最高的EL级别是EL1,那么它必须有EL0。所以上面说的CurrentEL指的是当前系统最高的EL级别。带有SP_EL0的当前EL是什么意思?其实就是说,当系统运行在EL1上,然后再使用EL0的SP时,好像就没有这种场景了。当前的EL带SP_EL1,也就是说系统运行在EL1,SP也用EL1,也就是内核态出现异常,存在这种场景。10.4章的表格更适合我们理解上面说的废话。例如,当操作系统运行在内核模式时发生IRQ中断,它应该跳转到异常表中的0x280。如果OS运行在用户态,正在执行一个32位的app,出现IRQ中断,应该跳转到哪里呢?关于异常向量表,还有一个问题需要考虑,那就是异常向量表放在哪里?ARMv8提供了VBAR(VectorBaseaddressregister)。这些寄存器的描述在D10.2章中。小明问:这里有3个相同的VBAR寄存器,应该设置哪一个?我们来看看Linux内核代码(以runninglinux_4.0为例)。代码路径在arch/arm64/kernel/entry.S文件中。笨叔叔在图上圈出了4组,也就是我们刚才说的4组。但是小明同学就有疑惑了,傻大叔,你不是说每个表项都是128字节吗,我怎么看每个表项好像是4个字节?现在的小明同学变聪明了。技巧隐藏在入口宏中。注意这里127行的align伪指令,非常强大。这里align7的意思是按照2的7次方来对齐,2的7次方就是128。(未完待续,明天继续以dataabort异常处理为例介绍那些处理的蛇神牛ARMv8上的例外)第二季就在这里。大家期待的第二季视频来了。这次我们是进程管理、锁机制和中断管理三合一,加量不加价。旗舰篇还是原价1199,现在特价999。三合一初级篇特价299。初级:笨叔和大家彻底理清了进程管理、锁机制和中断相关的概念管理。例如:一个进程的生命周期进程控制块进程调度的本质CFSscheduler进程切换如何打SMP负载均衡大小和核心调度是怎么回事如何处理上下半部分中断如何写一个中断处理函数什么是软中断?如何使用tasklet和工作队列?什么是中断上下文?如何使用信号量和互斥量,谁应该选择RCU,如何使用RCU,这里为什么要加锁……旗舰篇包含了初级篇的内容,还包括以下内容:对RCU的补充介绍核心代码,真正实现自主可控。在综合创新实验中,本叔带领大家在树莓派上玩起了小OS。面试书,那些年我们被虐的面试题。
