当前位置: 技术问答>linux和unix
关于x86任务切换的问题请教
来源: 互联网 发布时间:2016-08-22
本文导语: 在 Linux内核完全剖析 赵炯编著,第138页,有一个x86上的多任务程序示例,使用时钟中断控制两个任务的切换。 中断处理程序如下,如下代码有些地方不太明白: 既然无论是任务0还是任务1,进入到中断处理程序后...
在 Linux内核完全剖析 赵炯编著,第138页,有一个x86上的多任务程序示例,使用时钟中断控制两个任务的切换。
中断处理程序如下,如下代码有些地方不太明白:
既然无论是任务0还是任务1,进入到中断处理程序后,都会执行ljmp,那ljmp之后的代码会有机会执行吗?
即最后的出栈操作和中断返回指令,怎么会有机会执行?
如果不能执行,只进栈不出栈的话,岂不是导致栈溢出。
timer_interrupt:
push %ds
pushl %eax
movl $0x10,%eax #先让ds指向内核数据段
mov %ax, %ds
movb $0x20, %al
outb %al, $0x20 #立刻运行其他硬件中断,即向8259A发送EOI命令
movl $1, %eax
cmp %eax, current #如果当前是任务1,则转去执行任务0
je 1f
movl %eax, current #如果当前是任务0,则转去执行任务1
ljmp $TSS1_SEL, $0
jmp 2f
1: movl $0, current
ljmp $TSS0_SEL, $0
2: popl %eax
pop %ds
iret
中断处理程序如下,如下代码有些地方不太明白:
既然无论是任务0还是任务1,进入到中断处理程序后,都会执行ljmp,那ljmp之后的代码会有机会执行吗?
即最后的出栈操作和中断返回指令,怎么会有机会执行?
如果不能执行,只进栈不出栈的话,岂不是导致栈溢出。
timer_interrupt:
push %ds
pushl %eax
movl $0x10,%eax #先让ds指向内核数据段
mov %ax, %ds
movb $0x20, %al
outb %al, $0x20 #立刻运行其他硬件中断,即向8259A发送EOI命令
movl $1, %eax
cmp %eax, current #如果当前是任务1,则转去执行任务0
je 1f
movl %eax, current #如果当前是任务0,则转去执行任务1
ljmp $TSS1_SEL, $0
jmp 2f
1: movl $0, current
ljmp $TSS0_SEL, $0
2: popl %eax
pop %ds
iret
|
我的理解是这样的:
当执行ljmp时,切换到新任务运行,而原有任务的各寄存器被保存
注意这里保存的EIP保存的是ljmp $TSS0_SEL, $0或者ljmp $TSS1_SEL, $0后面的一条指令
当新任务又发生任务切换,又切换到现在的任务,注意现在加载的是内核态的SS0,那么以下的指令:
popl %eax
pop %ds
iret
将清楚内核态的堆栈,并iret跳转恢复eflag和用户态堆栈并跳转到保存用户态的下一条指令去执行。。
事实上看switch_to的asm汇编代码也可以看的出来:
#define switch_to(n) {
struct (long a,b;} __tmp;
__asm__("cmpl %%ecx,current nt"
"je 1fnt"
"xchgl %%ecx, currentnt"
"movw %%dx, %1nt"
"ljmp *%0nt"
"cmpl %%ecx, %2nt"
"jne 1fnt"
"cltsn"
"1:"
::"m" (*&__tmp.a), "m" (*&__tmp.b),
"m" (last_task_used_math),"d" _TSS(n), "c" ((long) task[n]));
}
当执行ljmp时,切换到新任务运行,而原有任务的各寄存器被保存
注意这里保存的EIP保存的是ljmp $TSS0_SEL, $0或者ljmp $TSS1_SEL, $0后面的一条指令
当新任务又发生任务切换,又切换到现在的任务,注意现在加载的是内核态的SS0,那么以下的指令:
popl %eax
pop %ds
iret
将清楚内核态的堆栈,并iret跳转恢复eflag和用户态堆栈并跳转到保存用户态的下一条指令去执行。。
事实上看switch_to的asm汇编代码也可以看的出来:
#define switch_to(n) {
struct (long a,b;} __tmp;
__asm__("cmpl %%ecx,current nt"
"je 1fnt"
"xchgl %%ecx, currentnt"
"movw %%dx, %1nt"
"ljmp *%0nt"
"cmpl %%ecx, %2nt"
"jne 1fnt"
"cltsn"
"1:"
::"m" (*&__tmp.a), "m" (*&__tmp.b),
"m" (last_task_used_math),"d" _TSS(n), "c" ((long) task[n]));
}
|