“ 老师在讲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社区第二季《过程、锁和中断三合一》,高级篇和旗舰篇很快要上线了,敬请关注!