linux2.4之前的核心有程序最大數的限制,受限制的原因是,每一個程序都有自已的TSS和LDT,而TSS(任務描述符)和LDT(私有描述符)必須放在GDT中,GDT最大隻能存放8192個描述符,除掉系統用掉的12描述符之外,最大程序數=(8192-12)/2, 總共4090個程序。從Linux2.4以後,全部程序使用同一個TSS,準确的說是,每個CPU一個TSS,在同一個CPU上的程序使用同一個TSS。TSS的定義在asm-i386/processer.h中,定義如下:
extern struct tss_struct init_tss[NR_CPUS];
在start_kernel()->trap_init()->cpu_init()初始化并加載TSS:
void __init cpu_init (void){int nr = smp_processor_id(); //擷取目前cpu
struct tss_struct * t = &init_tss[nr]; //目前cpu使用的tss
t->esp0 = current->thread.esp0; //把TSS中esp0更新為目前程序的esp0set_tss_desc(nr,t);gdt_table[__TSS(nr)].b &= 0xfffffdff;load_TR(nr); //加載TSSload_LDT(&init_mm.context); //加載LDT
}
我們知道,任務切換(硬切換)需要用到TSS來儲存全部寄存器(2.4以前使用jmp來實作切換),
中斷發生時也需要從TSS中讀取ring0的esp0,那麼,程序使用相同的TSS,任務切換怎麼辦?
其實2.4以後不再使用硬切換,而是使用軟切換,寄存器不再儲存在TSS中了,而是儲存在
task->thread中,隻用TSS的esp0和IO許可位圖,是以,在程序切換過程中,隻需要更新TSS中
的esp0、io bitmap,代碼在sched.c中:
schedule()->switch_to()->__switch_to(),
void fastcall __switch_to(struct task_struct *prev_p, struct task_struct *next_p){struct thread_struct *prev = &prev_p->thread, *next = &next_p->thread;struct tss_struct *tss = init_tss + smp_processor_id(); //目前cpu的TSS
ttss->esp0 = next->esp0; //用下一個程序的esp0更新tss->esp0
//拷貝下一個程序的io_bitmap到tss->io_bitmap
if (prev->ioperm || next->ioperm) { if (next->ioperm) { memcpy(tss->io_bitmap, next->io_bitmap, IO_BITMAP_BYTES); tss->bitmap = IO_BITMAP_OFFSET; } else tss->bitmap = INVALID_IO_BITMAP_OFFSET;}}
====