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的标志。
linux 2.6源代码情景分析笔记之进程9
最新推荐文章于 2025-04-29 14:26:00 发布
