共计 2473 个字符,预计需要花费 7 分钟才能阅读完成。
“老师在讲 ARM 课程:小明,你来说说中断和缺页中断有啥区别?
小明:他们不是一个妈生的
老师:小明同学,滚。。。
”
昨天咱们和大家聊了一下中断处理函数里遇到缺页中断的那些事儿,咱们只探讨了 do_page_fault() 这条内核解决门路,基本上这条解决门路曾经蕴含了次要和最难了解的场景,当然对于简略的 do_translation_fault()/do_sect_fault() 这条门路咱们认为代码比较简单,很好了解,所以就疏忽了。
那咱们明天来重新认识一下 ARM v7 上的异样解决的那些事儿。要意识 ARM v7 上的异样解决,咱们天然离不开 ARM 官网的手册了。这个大家在 ARM 官网上下载就行,一共 2600 多页,不过不必放心,ARM v8 手册一共 6666 页,是不是有点恐怖?ARM v8 的,咱们当前有机会再和大家介绍吧。
01
打开 ARM v7 手册,在第 B1.8 章里就开始介绍异样解决了。一开始就给大家介绍异样向量表。
大家须要注意的是,ARM 的芯片手册的介绍是把几个模式都揉在一起介绍的,如 Hyp 模式,Monitor 模式,Secure 模式,non-secure 模式,这样会让初学者看起来有点凌乱,若把这几个模式独自章节兴许更好一些。假如咱们只关注 Linux kernel 运行的场景,那咱们关注 non-secure 模式就好了。这里显示异样解决次要有预取 abort,data abort 和 undefined abort。其实和缺页中断相干的是 data abort 和预取 abort。
还有一个向量表安放的问题,传统的向量表能够放在 0x0 或者 0xffff_0000 这两个地位,当然设置 SCTL 寄存器的 V 域,能够依照程序猿的要求来比拟随便的安放这个向量表的地位。
而后在第 B.1.8.3 章里介绍了如果一个异样产生了,ARM 处理器会做了那些事件。
上图让笨叔翻译一下的话就是这样的:
硬件啊,你首先要确定要触发那个异样?预取 abort 还是 data 还是 undefined,这个不应该是咱们程序媛来拍脑袋
保留产生异样那个现场的 CPSR 到 异样模式的 SPSR 寄存器
保留返回地址(return address)到 LR 寄存器
设置 CPSR.M 域到相应的模式,并切换到该模式。设置相应的 mask bits,避免异样嵌套
PC 指向向量表的对应的中央,而后 go
异样产生的时候是跑在异样模式的。ARM 很奇怪,每个模式都有本人的堆栈,和中断一样。通常硬件就帮你带到了异样模式里,然而异样模式的堆栈大小无限啊,没有方法保留所有的上下文,那怎么办?通常软件是在异样模式里晃了一下就跑到 SVC 模式去的。
上面笨叔以 runninglinuxkernel_4.0 这个 git tree 代码为例,比方当初 data abort 产生了,代码会跳转到异样向量表里的 vector_dabt 里。(arch/arm/kerne/entry-armv.S)
在下面代码中 1188 行代码,vector_stub 是一个宏。有的小伙伴会问了,为啥这个宏最初的一个参数是 8,而 vector_irq 是 4 呢?这个问题大家还是要依赖 ARM v7 手册啊,谁让它是咱们的衣食父母呢。在第 B1.8.3 章里有这么一个表,意思是说在每个异样产生的时候,LR 寄存器寄存的值是产生异样那个点的地址加上了一个 offset,因为流水线的起因。然而咱们 OS 里保留的 LR 须要减去这个 offset,咱们在 vector_stub 宏代码里能够看到。
vector_stub 宏代码如下:
笨叔大抵把它分成 4 局部来了解就简略多了。第一局部减掉方才说的 offset 失去真正的 LR 返回地址,第二局部保留异样产生时 LR 和 SPSR 寄存器到 异样的栈里,第三局部切换到 SVC 模式,第 4 局部判断异样产生是在用户态还是内核态,而后别离跳转到_dabt_svc 和_dabt_usr 外面。
vector_stub 这个宏的具体每一行代码的解释能够看《奔跑吧 linux 内核》第 621 页。
上面以_data_svc 为例。
svc_entry 和 svc_exit 都是宏,具体代码剖析见《奔跑吧 linux 内核》第 5.1.4 节内容。
对应 ARM v7 处理器,最初会跑到 v7_early_abort 这个汇编函数里,
第 16 和 17 行啥意思呢?
这外面波及到两个寄存器别离是 FSR 和 FAR,咱们先看芯片手册的第 B3.13.1 章,这里就介绍了当产生异样,咱们怎么能晓得发了啥事呢?因为硬件是能精确 get 到异样产生的起因和地址的,然而咱们程序猿不晓得,所以须要通过寄存器的形式来通知咱们,对吧?
这里巴拉巴拉的和你说了,有一个叫做 FSR 寄存器寄存了异样状态信息,还有一个叫做 FAR 寄存器寄存了异样产生的地址。这两个寄存器别离形容在哪里呢?能够看第 B4.1.51 和第 B4.1.52 节,外面有这两个寄存器详细描述。
其中最重要的是 FS 寄存器域,留神了,这里 FS 域是有两局部组成的,一个是 BIT [0~3] 和 BIT[10],是不是有点奇葩呢。代码是这样的。
至多咱们是对应上的。那读出来的 FS 域有啥用呢?大家看手册的第 B3.13.3 章,这里有一个表来形容 FS 域的用法。
这表里定义了好多种缺页异样的类型,比方有 translation fault,access fault,domain fault,permission fault 等。
do_DataAbort() 函数如下,大家能够重点看第 547 行,这里 fsr_fs() 方才提过了,fsr_info 定义成一个 table。
通过 FSR 寄存器的 FS 域来进行查表,而后跳转到对应的处理函数里。
大家能够对照代码和 FS 的表来看看什么状况下会跑到 do_translation_fault()/do_sect_fault(),而什么状况下跑到 do_page_fault。
ARM 外面还有一种异样,叫做预取 abort,代码门路和原理是相似的,小伙伴能够自行浏览 ARM v7 手册和相应的代码来。
奔跑吧 Linux 社区保持原创文章,原汁原味,绝不转载!喜爱的话,记得打赏和转发,谢谢!
预报:奔跑吧 Linux 社区第二季《过程、锁和中断三合一》,高级篇和旗舰篇很快要上线了,敬请关注!