执行进程间切换

1 进程切换之前的工作


由于每个进程共享CPU寄存器(咱们就当是单CPU吧),因此在恢复一个进程之前,内核必须确保每个寄存器装入挂起进程时的值,他们就叫“硬件上下文”。在Linux中,进程硬件上下文得一部分放在TSS段,主要用于对内核态堆栈进行寻址,而剩余部分放在内核态堆栈中。

我们再回忆一下硬件中TSS段的内容:
struct tss_struct {
    unsigned short    back_link,__blh;
    unsigned long    esp0;        /*当前进程的内核栈栈顶地址偏移 */
    unsigned short    ss0,__ss0h;   /* 内核栈段描述符值,系统初始化后整个运行期间不被改变 */
    unsigned long    esp1;
    unsigned short    ss1,__ss1h;    /* ss1 is used to cache MSR_IA32_SYSENTER_CS */
    unsigned long    esp2;
    unsigned short    ss2,__ss2h;
    unsigned long    __cr3;
    unsigned long    eip;
    unsigned long    eflags;
    unsigned long    eax,ecx,edx,ebx;
    unsigned long    esp;          /*当前进程用户态堆栈栈顶地址偏移 */
    unsigned long    ebp;
    unsigned long    esi;
    unsigned long    edi;
    unsigned short    es, __esh;
    unsigned short    cs, __csh;
    unsigned short    ss, __ssh;
    unsigned short    ds, __dsh;
    unsigned short    fs, __fsh;
    unsigned short    gs, __gsh;
    unsigned short    ldt, __ldth;
    unsigned short    trace, io_bitmap_base;

    unsigned long    io_bitmap[IO_BITMAP_LONGS + 1];

    unsigned long io_bitmap_max;
    struct thread_struct *io_bitmap_owner;

    unsigned long __cacheline_filler[35];

    unsigned long stack[64];
} __attribute__((packed));

为了方便起见,我们设prev为切换出的进程描述符,next为切换进得进程描述符,那么进程切换则定义为:保存prev硬件上下文,用next硬件上下文代替(我们在后面的博文会看到prev和next是调度函数schedule()的局部变量)。内核2.6以前是直接利用80x86的far jmp指令跳到next进程的TSS描述符的选择符来执行进程切换,而2.6则使用软件执行进程切换。

 

进程切换只发生在内核态。在执行切换之前,即通过中断的方式执行系统调用由用户态进入内核态时,linux从用户态转移到内核态有三个途径,系统调用,中断,异常,对应的代码在/arch/i386/kernel/entry.S中。用户进程使用的所有寄存器内容都已被SAVE_ALL汇编指令压入内核态堆栈:
#define SAVE_ALL /
    cld; /
    pushl %es; /
    pushl %ds; /
    pushl %eax; /
    pushl %ebp; /
    pushl %edi; /
    pushl %esi; /
    pushl %edx; /
    pushl %ecx; /
    pushl %ebx; /
    movl $(__USER_DS), %edx; /
    movl %edx, %ds; /
    movl %edx, %es;


注意倒数三行这里一个问题,为啥进入内核态后,却要把用户态的数据段选择符__USER_DS装载到ds和es寄存器中呢?这岂不是胡闹吗?回忆一下,linux之所以设置什么ds,cs段选择符也是例行公事,完全没有必要,要明白为什么这里将ds设置成__USER_DS,还要先回忆ds是干什么用的,ds是数据段寄存器,cs是代码段寄存器,ds的保护作用是:如果你访问的段,要求的访问级别高于当前进程的代码段级别的话,访问会导致GP异常。现在进入了内核,当前代码段的访问级别为0,处于最高级别,它访问任何段都不会出错,再者,linux为了减少复杂性,只用了2个级别,那么就没有任何问题了,如果要

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值