Linux抢占是如何发生的(3)?

参考博客:

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的中断向量表中中断处理的主要脉络

1. 中断返回内核态时的抢占

本文想说明红框处的执行过程

Linux抢占是如何发生的(3)?_第1张图片

红框处具体的过程是由汇编代码给出的,在arch/arm64/kernel/entry.S中,在中断上下文结束后(637行开始),执行上下文开始返回内核的进程上下文,考虑到抢占因素,是返回到被中断的进程进程上下文呢,还是返回到抢占进程上下文,就由下面这段代码来决定

Linux抢占是如何发生的(3)?_第2张图片

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:抢占结束后,需要恢复被中断进程的寄存器状态,然后返回被中断进程上下文

2. line637行的问题

line637:结束中断上下文,返回进程上下文(这里返回的是被中断进程的进程上下文,为什么?)

我们来看line636行的实现,实质上line418~line424是中断处理的过程,我们主要关注上下文的切换

Linux抢占是如何发生的(3)?_第3张图片

line420:将sp保存到x0寄存器,这里的sp是被中断进程的sp

line421:进入中段栈(在ARM64中,中断的处理在中断栈中)之前保存sp到x19

line423:结束中断栈中的处理之后恢复x19中的sp

Linux抢占是如何发生的(3)?_第4张图片

所以我们看到,在中断的执行完成后,sp从中断栈又指回了被中断的进程的进程栈,实际上这个时候程序已经处于内核进程上下文了,只是具体返回到哪个进程还没有被决定下来而已 

 3. 中断向量表

先只考虑el1的irq

Linux抢占是如何发生的(3)?_第5张图片

 kernel_ventry是一个宏,精简后的宏如下所示:所以kernel_ventry 1,irq就会跳转到el1_irq处

Linux抢占是如何发生的(3)?_第6张图片

精简后的el1_irq看起来像这个样子:

Linux抢占是如何发生的(3)?_第7张图片

 这就和下面这张脉络图大概对应了起来

Linux抢占是如何发生的(3)?_第8张图片

 4. el0和el1是什么?

el0和el1是ARM V8异常相关的概念

el0_irq对应用户态运行时产生的中断,el1_irq对应内核态运行期间产生的中断(理解不完善)

5. 疑惑点

在irq_handler前的sp中存的究竟是什么?

sp我们知道是栈指针,同时我们也知道ARM64中每个内核进程有自己的内核栈,中断处理在中断栈中进行,那么irq_handler之前的sp的值是不是被中断内核进程的栈顶?或者是不是代表了被中断内核进程的某一部分?

去掉抢占部分的el1_irq如下所示:

Linux抢占是如何发生的(3)?_第9张图片

首先在kernel_ventry 1,irq将sp减了#S_FRAME_SIZE,也就是sizeof(struct pt_regs),用来保存寄存器组

Linux抢占是如何发生的(3)?_第10张图片

接下来在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也被恢复了

所以根据以上猜测并辅以代码中的证据,我猜测到:

  • 进入中断向量表中的sp是被中断内核进程的堆栈指针
  • 在kernel_ventry中将其修改,预留了sizeof(struct pt_regs)用于保存寄存器信息
  • 实际保存工作在kernel_entry 1中
  • 在正式处理中断前又将sp指向了专门的中断栈,并于中断结束后恢复到先前的sp
  • 在kernel_exit中利用sp恢复了被中断进程的寄存器信息,然后sp也被恢复到了被中断内核进程的栈顶位置

以上有猜测部分,错误之处待日后更正

 

 

 

你可能感兴趣的:(Linux基础,linux,arm开发,运维)