您的当前位置:首页正文

操作系统(七)深入理解Linux内核进程上下文切换

来源:华佗健康网

1.进程上下文的概念

2.上下文切换详细过程

__schedule   // kernel/sched/core.c
->context_switch
  ->switch_mm_irqs_off   //进程地址空间切换
  ->switch_to //处理器状态切换

2.1 进程地址空间切换

context_switch  // kernel/sched/core.c
->switch_mm_irqs_off
  ->switch_mm
  ->__switch_mm
    ->check_and_switch_context
    ->cpu_switch_mm
      ->cpu_do_switch_mm(virt_to_phys(pgd),mm) //arch/arm64/include/asm/mmu_context.h
    
arch/arm64/mm/proc.S
158 /*
159  *      cpu_do_switch_mm(pgd_phys, tsk)
160  *
161  *      Set the translation table base pointer to be pgd_phys.
162  *
163  *      - pgd_phys - physical address of new TTB
164  */
165 ENTRY(cpu_do_switch_mm)
166         mrs     x2, ttbr1_el1
167         mmid    x1, x1                          // get mm->context.id
168         phys_to_ttbr x3, x0
169
170 alternative_if ARM64_HAS_CNP
171         cbz     x1, 1f                          // skip CNP for reserved ASID
172         orr     x3, x3, #TTBR_CNP_BIT
173 1:
174 alternative_else_nop_endif
175 #ifdef CONFIG_ARM64_SW_TTBR0_PAN
176         bfi     x3, x1, #48, #16                // set the ASID field in TTBR0
177 #endif
178         bfi     x2, x1, #48, #16                // set the ASID
179         msr     ttbr1_el1, x2                   // in TTBR1 (since TCR.A1 is set)
180         isb
181         msr     ttbr0_el1, x3                   // now update TTBR0
182         isb
183         b       post_ttbr_update_workaround     // Back to C code...
184 ENDPROC(cpu_do_switch_mm)

2.2 处理器状态(硬件上下文)切换

switch_to
->__switch_to
  ... //浮点寄存器等的切换
  ->cpu_switch_to(prev, next)

arch/arm64/kernel/entry.S1032 /*
1033  * Register switch for AArch64. The callee-saved registers need to be saved
1034  * and restored. On entry:
1035  *   x0 = previous task_struct (must be preserved across the switch)
1036  *   x1 = next task_struct
1037  * Previous and next are guaranteed not to be the same.
1038  *
1039  */
1040 ENTRY(cpu_switch_to)
1041         mov     x10, #THREAD_CPU_CONTEXT
1042         add     x8, x0, x10
1043         mov     x9, sp
1044         stp     x19, x20, [x8], #16             // store callee-saved registers
1045         stp     x21, x22, [x8], #16
1046         stp     x23, x24, [x8], #16
1047         stp     x25, x26, [x8], #16
1048         stp     x27, x28, [x8], #16
1049         stp     x29, x9, [x8], #16
1050         str     lr, [x8]
1051         add     x8, x1, x10
1052         ldp     x19, x20, [x8], #16             // restore callee-saved registers
1053         ldp     x21, x22, [x8], #16
1054         ldp     x23, x24, [x8], #16
1055         ldp     x25, x26, [x8], #16
1056         ldp     x27, x28, [x8], #16
1057         ldp     x29, x9, [x8], #16
1058         ldr     lr, [x8]
1059         mov     sp, x9
1060         msr     sp_el0, x1
1061         ret
1062 ENDPROC(cpu_switch_to)

3.ASID机制

4. 普通用户进程、普通用户线程、内核线程切换的差别

5. 进程切换全景视图

我们以下场景为例: A,B两个进程都是普通的用户进程,从进程A切换到进程B,简单起见我们在这里不考虑其他的抢占时机,我们假设A,B进程只是循环进行一些基本的运算操作,从来不调用任何系统调用,只考虑被时钟中断,返回用户空间之前被抢占的情况。
下面给出进程切换的全景视图:

6. 总结

因篇幅问题不能全部显示,请点此查看更多更全内容