Linux 0.12 switch_to切换过程
switch_to源代码:
/*
* switch_to(n) should switch tasks to task nr n, first
* checking that n isn't the current task, in which case it does nothing.
* This also clears the TS-flag if the task we switched to has used
* tha math co-processor latest.
*/
#define switch_to(n) {\
struct {long a,b;} __tmp; \
__asm__("cmpl %%ecx,_current\n\t" \
"je 1f\n\t" \
"movw %%dx,%1\n\t" \
"xchgl %%ecx,_current\n\t" \
"ljmp %0\n\t" \
"cmpl %%ecx,_last_task_used_math\n\t" \
"jne 1f\n\t" \
"clts\n" \
"1:" \
::"m" (*&__tmp.a),"m" (*&__tmp.b), \
"d" (_TSS(n)),"c" ((long) task[n])); \
}
汇编知识:
这段汇编代码分为四个部分,以":"号加以分割,一般形式为:
指令部:输出部:输入部:损坏部
在指令部中,数字前面加上前缀%, 如%0, %1表示使用寄存器样板操作数,可以使用的此类操作数的总数取决于具体CPU中通用寄存器的数量。那么这里的数字具体代表那些寄存器呢?这里就要看输出部和输入部了
操作数的编号从输出部的第一个约束(序号为0)开始,顺序下来,每个约束计数一次,表示约束条件的字母很多,主要有:
"m","v","o" ——表示内存单元;
"r" ——表示任何寄存器;
"q" ——表示eax,ebx,ecs,edx 之一;
"i"和"h" ——表示直接操作数;
"E"和"F" ——表示浮点数;
"g" ——表示“任意”;
"a","b","c","d" ——表示使用寄存器eax,ebx,ecx,edx
"S"和"D" ——表示要求使用寄存器esi和edi
"I" ——表示常数(0至31)
实例如下:
__asm__ __volatile__ (
LOCK "addl %1, %0"
: "=m" (v->counter)
: "ir" (i), "m" (v->counter));
这段代码的输出部为v->counter,存储在内存单元中,对于的寄存器编号为%0,
输入部:直接操作数i对应于任何寄存器,对应的寄存器编号为%1, v->counter存储在内存单元中,对应的寄存器编号为%2
没有损坏部
这段代码的含义是:将v->counter的值加上i,并把最终的结果写回到v->counter中
那么对应到switch_to的这段代码中,由于没有输出部,所以输入部对应参数如下:
"m" (&__tmp.a) ===> %0, &tmp.a存储在内存中
"m" (*&tmp.b) ===> %1, *&__tmp.b存储在内存中
"d" (_TSS(n)) ===> %2, _TSS(n)存储在edx中
"c" ((long) task[n]) ===> %3, (long) task[n]存储在ecx中
下面对switch_to汇编代码进行详细分析
这段代码的主要意思是:首先判断需要切换到的进程是否是当