linux 2.6源代码情景分析笔记之进程9

本文介绍Intel MMX指令集及其对多媒体程序性能的提升。深入探讨80x86微处理器如何管理FPU、MMX及XMM寄存器,包括硬件支持机制、寄存器状态保存与恢复的方法,以及Linux内核如何处理这些寄存器的状态。

intel在他的微处理器中引入一个新的汇编指令集,叫做MMX指令,用来加速多媒体应用程序的执行。mmx指令作用于fpu的浮点寄存器。
80x86微处理器并不在tss中自动保存fpu,mmx,xmm寄存器。他们包含某种硬件支持,能在需要时保存这些寄存器的数值,硬件支持由cr0寄存器中的一个ts标志组成。遵循以下规则:
每当执行硬件上下文切换时,设置ts标志。
每当ts标志被设置时执行ESCAPE,MMX,SSE,SSE2指令,控制单元就产生一个device not available异常。

为处理fpu,mmx,xmm寄存器的选择性装入而引入的数据结构。它们存放在进程描述符的thread.i387子字段中,其格式由i387_union联合体描述:

union i387_union {
        struct i387_fsave_struct        fsave;由具有数学协处理器、也可能有mmx单元的cpu模型使用。
        struct i387_fxsave_struct       fxsave;由具有see,sse2扩展功能的cpu模型使用。
        struct i387_soft_struct        soft;由无数学协处理器的cpu模型使用;linux内核通过软件模拟协处理器来支持这些老式芯片。
};

进程描述符包含两个附加的标志:
包含在thread_info描述符的status字段中的TS_USEDFPU标志。它表示进程在当前执行过程中是否使用过fpu,mmx,xmm寄存器。
包含在task_struct描述符的flags字段中的PF_USED_MATH标志。这个标志表示thread.i387子字段的内容是否有意义。该标志在两种情况下被清0.
当进程调用execve()系统调用开始执行一个新程序时,因为控制权将不再返回到前一个程序,所以当前存放在thread.i387中的数据也不再使用。
当在用户态下执行一个程序的进程开始执行一个信号处理程序时。因为信号处理程序与程序的执行流是异步的,因此,浮点寄存器对信号处理程序来说可能是毫无意义的。不过,内核开始执行信号处理程序之前在thread.i387中保存浮点寄存器,处理程序结束后恢复它们。因此信号处理程序可以使用数学协处理器。

struct i387_fsave_struct {
        long    cwd;
        long    swd;
        long    twd;
        long    fip;
        long    fcs;
        long    foo;
        long    fos;
        long    st_space[20];   /* 8*10 bytes for each FP-reg = 80 bytes */
        long    status;         /* software status information */
};

struct i387_fxsave_struct {
        unsigned short  cwd;
        unsigned short  swd;
        unsigned short  twd;
        unsigned short  fop;
        long    fip;
        long    fcs;
        long    foo;
        long    fos;
        long    mxcsr;
        long    mxcsr_mask;
        long    st_space[32];   /* 8*16 bytes for each FP-reg = 128 bytes */
        long    xmm_space[32];  /* 8*16 bytes for each XMM-reg = 128 bytes */
        long    padding[56];
} __attribute__ ((aligned (16)));

struct i387_soft_struct {
        long    cwd;
        long    swd;
        long    twd;
        long    fip;
        long    fcs;
        long    foo;
        long    fos;
        long    st_space[20];   /* 8*10 bytes for each FP-reg = 80 bytes */
        unsigned char   ftop, changed, lookahead, no_update, rm, alimit;
        struct info     *info;
        unsigned long   entry_eip;
};

#define __unlazy_fpu( tsk ) do { /
        if ((tsk)->thread_info->status & TS_USEDFPU) /
                save_init_fpu( tsk ); /
} while (0)

此宏检查prev的TS_USEDFPU标志值。如果被设置,说明prev在这次执行中使用了fpu,mmx,sse,sse2指令。因此内核必须保存上下文。

static inline void save_init_fpu( struct task_struct *tsk )
{
        preempt_disable();
        __save_init_fpu(tsk);
        stts();
        preempt_enable();
}

static inline void __save_init_fpu( struct task_struct *tsk )
{
        if ( cpu_has_fxsr ) {
                asm volatile( "fxsave %0 ; fnclex" : "=m" (tsk->thread.i387.fxsave) );
        } else {
                asm volatile( "fnsave %0 ; fwait" : "=m" (tsk->thread.i387.fsave) );
        }
        tsk->thread_info->status &= ~TS_USEDFPU;
}

把fpu寄存器的内容转储到prev进程描述符中,然后重新初始化fpu.如果cpu使用sse/sse2扩展,则还应该转储xmm寄存器的内容,并重新初始化sse/sse2单元。一对功能强大的嵌入式汇编语言指令处理每件事情,如果cpu使用sse/sse2扩展。
充值prev的TS_USEDFPU标志。

#define stts() write_cr0(8 | read_cr0())
#define write_cr0(x) /
        __asm__("movl %0,%%cr0": :"r" (x));

设置cr0的TS的标志。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值