linux 进程管理---硬件上下文切换

本文详细介绍了Linux系统中硬件上下文切换的过程,包括struct cpu_context和struct thread_struct的数据结构,以及switch_to、__switch_to、tls_thread_switch和cpu_switch_to等关键函数的功能。通过这些函数,系统实现了对进程的fpsimd状态、线程局部存储和寄存器的保存与恢复,确保进程切换的顺利进行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

struct cpu_context {
        unsigned long x19;
        unsigned long x20;
        unsigned long x21;
        unsigned long x22;
        unsigned long x23;
        unsigned long x24;
        unsigned long x25;
        unsigned long x26;
        unsigned long x27;
        unsigned long x28;
        unsigned long fp;
        unsigned long sp;
        unsigned long pc;
};

struct thread_struct {
        struct cpu_context      cpu_context;   //保存非通用寄存器的值
        unsigned long           tp_value;        //指向线程私有的内存区域
#ifdef CONFIG_COMPAT
        unsigned long           tp2_value;
#endif
        struct fpsimd_state     fpsimd_state; 
        unsigned long           fault_address;  /* fault info */
        unsigned long           fault_code;     /* ESR_EL1 value */
        struct debug_info       debug;          /* debugging */
};

arm switch_to定义如下:

#define switch_to(prev,next,last)                                       \
do {                                                                    \
        __complete_pending_tlbi();      //暂时不去深究                                \
        last = __switch_to(prev,task_thread_info(prev), task_thread_info(next));        \
} while (0)

__switch_to 函数定义

struct task_struct *__switch_to(struct task_struct *prev,
                                struct task_struct *next)
{
        struct task_struct *last;

        fpsimd_thread_switch(next); //保存fpsimd状态 task>thread.fpsimd_state,根据新的进程的状态设置cpu
        tls_thread_switch(next); //线程局部变量地址切换
        hw_breakpoint_thread_switch(next);
        contextidr_thread_switch(next); //这两个是跟硬件跟踪相关,这里不深究

        /*
         * Complete any pending TLB or cache maintenance on this CPU in case
         * the thread migrates to a different CPU.
         */
        dsb(ish);  //插入屏障

        /* the actual thread switch */
        last = cpu_switch_to(prev, next);  //进行正在的切换动作,注意这里返回之后则是运行到了next进程的switch_to函数剩余部分,则是执行next进程,保存的pc地址也就是这里的return指令地址。

        return last;
}

tls_thread_switch函数:

static void tls_thread_switch(struct task_struct *next)
{
        unsigned long tpidr, tpidrro;

        asm("mrs %0, tpidr_el0" : "=r" (tpidr));  //内联汇编,将tpidr_el0寄存器加载到tpidr变量中。
        *task_user_tls(current) = tpidr;   //这里是将上一步获取的tpidr_el0值保存到current->thread.tp_value

        tpidr = *task_user_tls(next);  //读取新的进程的next->thread.tp_value 到tpidr中
        tpidrro = is_compat_thread(task_thread_info(next)) ?
                  next->thread.tp_value : 0;   //这个是先判断是否存在TIF_32BIT标志,存在则将next->thread.tp_value也赋值到tpidrro变量

        asm(
        "       msr     tpidr_el0, %0\n"  //这三句则是将上面读取到的tpidr、tpidrro里去。
        "       msr     tpidrro_el0, %1"
        : : "r" (tpidr), "r" (tpidrro));    
}  

tls_thread_switch函数则是保存旧的current->thread.tp_value加载新的next->thread.tp_value

cpu_switch_to函数:

ENTRY(cpu_switch_to)

//DEFINE(THREAD_CPU_CONTEXT, offsetof(struct task_struct, thread.cpu_context));
        mov     x10, #THREAD_CPU_CONTEXT //从上述定义可以看出是thread.cpu_context相对于task的偏移
        add     x8, x0, x10  //这句汇编等价于x8=prev->thread.cpu_context
        mov     x9, sp  //将sp保存到x9
        stp     x19, x20, [x8], #16             // 将x19 x20寄存器保存到prev->thread.cpu_context.x19  x18中
        stp     x21, x22, [x8], #16 //类似上述指令
        stp     x23, x24, [x8], #16
        stp     x25, x26, [x8], #16
        stp     x27, x28, [x8], #16
        stp     x29, x9, [x8], #16 //保存x29和sp
        str     lr, [x8]   // 将lr寄存器保存到prev->thread.cpu_context.pc中
        add     x8, x1, x10 //这里x8=next->thread.cpu_context
        ldp     x19, x20, [x8], #16             // restore callee-saved registers
        ldp     x21, x22, [x8], #16
        ldp     x23, x24, [x8], #16
        ldp     x25, x26, [x8], #16
        ldp     x27, x28, [x8], #16
        ldp     x29, x9, [x8], #16
        ldr     lr, [x8]
        mov     sp, x9
        ret //arm返回值都是保存在x0中所以这里返回的task地址还是prev的 
ENDPROC(cpu_switch_to)

1、上述汇编指令将lr保存为pc值,是因为lr是switch_to函数的return指令,正常恢复执行流的函数都会执行到这里。

2、注意函数返回的task_struct结构体是prev指向的地址

3、上述可以看到switch_to只是做了硬件切换没有进行内存地址等的切换

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值