tss的作用舉例:儲存不同特權級别下任務所使用的寄存器,特别重要的是esp,因為比如中斷後,涉及特權級切換時(一個任務切換),首先要切換棧,這個棧顯然是核心棧,那麼如何找到該棧的位址呢,這需要從tss段中得到,這樣後續的執行才有所依托(在x86機器上,c語言的函數調用是通過棧實作的)。隻要涉及地特權環到高特權環的任務切換,都需要找到高特權環對應的棧,是以需要esp2,esp1,esp0起碼三個esp,然而linux隻使用esp0。
tss是什麼:tss是一個段,段是x86的概念,在保護模式下,段選擇符參與尋址,段選擇符在段寄存器中,而tss段則在tr寄存器中。
intel的建議:為每一個程序準備一個獨立的tss段,程序切換的時候切換tr寄存器使之指向該程序對應的tss段,然後在任務切換時(比如涉及特權級切換的中斷)使用該段保留所有的寄存器。
linux的做法:
1.linux沒有為每一個程序都準備一個tss段,而是每一個cpu使用一個tss段,tr寄存器儲存該段。程序切換時,隻更新唯一tss段中的esp0字段到新程序的核心棧。
2.linux的tss段中隻使用esp0和iomap等字段,不用它來儲存寄存器,在一個使用者程序被中斷進入ring0的時候,tss中取出esp0,然後切到esp0,其它的寄存器則儲存在esp0訓示的核心棧上而不儲存在tss中。
3.結果,linux中每一個cpu隻有一個tss段,tr寄存器永遠指向它。符合x86處理器的使用規範,但不遵循intel的建議,這樣的後果是開銷更小了,因為不必切換tr寄存器了。
linux的實作:
1.定義tss:
struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS };(arch/i386/kernel/init_task.c)
INIT_TSS定義為:
#define INIT_TSS { /
.esp0 = sizeof(init_stack) + (long)&init_stack, /
.ss0 = __KERNEL_DS, /
.esp1 = sizeof(init_tss[0]) + (long)&init_tss[0], /
.ss1 = __KERNEL_CS, /
.ldt = GDT_ENTRY_LDT, /
.io_bitmap_base = INVALID_IO_BITMAP_OFFSET, /
.io_bitmap = { [ 0 ... IO_BITMAP_LONGS] = ~0 }, /
}
2.初始化tss:
struct tss_struct * t = init_tss + cpu;
...
load_esp0(t, thread);
set_tss_desc(cpu,t);
cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff;
load_TR_desc();
相關函數或者宏為:
#define load_TR_desc() __asm__ __volatile__("ltr %%ax"::"a" (GDT_ENTRY_TSS*8))
static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, void *addr)
{
_set_tssldt_desc(&cpu_gdt_table[cpu][entry], (int)addr,
offsetof(struct tss_struct, __cacheline_filler) - 1, 0x89);
}
#define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr)
經過上述的初始化,tr永遠指向唯一的tss段,然而tss段中的esp0以及iomap卻是不斷随着程序切換而變化的。
3.程序切換時切換全局唯一tss段中的esp0以及iomap即可:
在__switch_to中:
struct tss_struct *tss = init_tss + cpu;
...
load_esp0(tss, next);
進而改變了tss的esp0。
此時如果程序在使用者态被中斷,機器切到ring0,從tr中取出唯一的tss段,找到它的esp0,将堆棧切過去即可,然後把所有的其它寄存器都儲存在tss目前的esp0訓示的核心也就是ring0的堆棧上。
再分享一下我老師大神的人工智能教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智能的隊伍中來!https://blog.csdn.net/jiangjunshow
标簽:__,x86,寄存器,cpu,tss,切換,linux,esp0,TSS
來源: https://www.cnblogs.com/ksiwnhiwhs/p/10390327.html