参考博客:
ARM V8指令集
https://news.eda365.com/tech/cxsheji/12008119151469.htmlhttps://news.eda365.com/tech/cxsheji/12008119151469.html
ARM V8异常
Linux ARMv8 异常向量表-BugMan-ChinaUnix博客本章接着《http://blog.chinaunix.net/uid-69947851-id-5830546.html[注]本文主要紧接上一篇文章,主要想说明中断返回时的抢占部分以及整个ARM V8的中断向量表中中断处理的主要脉络
本文想说明红框处的执行过程
红框处具体的过程是由汇编代码给出的,在arch/arm64/kernel/entry.S中,在中断上下文结束后(637行开始),执行上下文开始返回内核的进程上下文,考虑到抢占因素,是返回到被中断的进程进程上下文呢,还是返回到抢占进程上下文,就由下面这段代码来决定
line637:结束中断上下文,返回进程上下文(这里返回的是被中断进程的进程上下文,为什么?)
line638:假设配置的系统允许抢占,CONFIG_PREEMPT=y
line639:获取当前进程的preempt_count(联系line637,这里获取的一定是被中断进程的preempt_count)放到w24寄存器中
line640:如果w24寄存器的值不为0,跳转到line644行处(1f==>0x1),cbnz(compare and branch not zero),也就是说preempt_count不为0的话代表被中断的进程不能被抢占(关抢占),则跳转到644行处,准备返回被中断的进程上下文;如果preempt_count为0的话,代表被中断的进程可以被抢占,继续执行641行
line641:获取当前进程的thread_info->flags(联系line637,这里获取的一定是被中断进程的thread_info->flags)到x0寄存器
line642:如果x0 & TIF_NEED_RESCHED == 0,跳转到644行处,tbz(test and branch zero),也就是说如果被中断的进程没有被其他进程触发抢占,那么跳转到644行处准备返回被中断的进程上下文;如果被中断的进程TIF_NEED_RESCHED置位,那么说明它被其它进程触发了抢占,继续执行643行
line643:跳转到el1_preempt执行抢占,到这里有三个条件必须满足(CONFIG_PREEMPT=y;preempt_count == 0;flags & TIF_NEED_RESCHED != 0)
line652~line659就是执行抢占的过程,实质上是通过执行__schedule()函数,将当前进程从处理器运行队列中移除,然后重选一个进程来运行的过程,对应到时序图中来说,此时在T4时刻,就执行了黄色的高优先级任务,从而低优先级任务被抢占,但是,高优先级任务执行完毕后,低优先级任务还是要继续处理的
line644~line649:抢占结束后,需要恢复被中断进程的寄存器状态,然后返回被中断进程上下文
line637:结束中断上下文,返回进程上下文(这里返回的是被中断进程的进程上下文,为什么?)
我们来看line636行的实现,实质上line418~line424是中断处理的过程,我们主要关注上下文的切换
line420:将sp保存到x0寄存器,这里的sp是被中断进程的sp
line421:进入中段栈(在ARM64中,中断的处理在中断栈中)之前保存sp到x19
line423:结束中断栈中的处理之后恢复x19中的sp
所以我们看到,在中断的执行完成后,sp从中断栈又指回了被中断的进程的进程栈,实际上这个时候程序已经处于内核进程上下文了,只是具体返回到哪个进程还没有被决定下来而已
先只考虑el1的irq
kernel_ventry是一个宏,精简后的宏如下所示:所以kernel_ventry 1,irq就会跳转到el1_irq处
精简后的el1_irq看起来像这个样子:
这就和下面这张脉络图大概对应了起来
el0和el1是ARM V8异常相关的概念
el0_irq对应用户态运行时产生的中断,el1_irq对应内核态运行期间产生的中断(理解不完善)
在irq_handler前的sp中存的究竟是什么?
sp我们知道是栈指针,同时我们也知道ARM64中每个内核进程有自己的内核栈,中断处理在中断栈中进行,那么irq_handler之前的sp的值是不是被中断内核进程的栈顶?或者是不是代表了被中断内核进程的某一部分?
去掉抢占部分的el1_irq如下所示:
首先在kernel_ventry 1,irq将sp减了#S_FRAME_SIZE,也就是sizeof(struct pt_regs),用来保存寄存器组
接下来在kernel_entry 1中用新的sp保存堆栈
再接下来进入中断处理irq_handler,在irq_stack_entry中将新的sp保存在了x19寄存器中,然后将中断栈指针赋给sp,有明确的这样一段注释(task stack?)
中断处理完成后在irq_stack_exit中将x19寄存器恢复到sp,所以这时sp又指向了之前的struct pt_regs
不考虑抢占的情况下执行kernel_exit 1进行被中断内核进程的恢复,我们看到了sp也被恢复了
所以根据以上猜测并辅以代码中的证据,我猜测到:
以上有猜测部分,错误之处待日后更正