關於段及相關概念的一些自己的闡述

來源:互聯網
上載者:User

1.
void sched_init(void)
{...
00392    

set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));

00393    

set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
...}
gdt:全域描述符,一共定義256個描述符,GDT本身不是一個段而是線形空間

的一個資料結構。GDT的基地址和長度需要載入進GDTR寄存器。GDT的基地

址要以8個位元組對齊獲得最佳的運行效率。因為GDT描述符號以8位元組為單位


2.結構相關解釋
typedef struct desc_struct {
     unsigned long a,b;
 } desc_table;
這裡使用兩個標準long四位元組的存放gdt和ldt。
首先程式運行在虛擬位址上的(實際程式都如此在保護模式下)虛擬位址是

由兩部分組成 段選擇符號(16)+偏梁量(有效地址32位);通過段選擇符號來

訪問相應的段描述符號,由段描述符中提供的段基地址,限長,屬性及虛擬地

址另外的位移來構造線形地址。
a.段選擇符:是虛擬位址組成部分見上面描述。其中前16位是段的唯一標誌

,並且提供了段描述符表GDT中的一個欄位的位移量。具體的組成如下面表

示:
|15-3描述符索引index|2是TI|1-0是RPL|
index:索引值用於尋找對應的描述符表中的具體段
TI: 表示是GDT還是LDT
RPL:類似許可權的東西
Remark:段選擇符總共提供6個,CS DS SS ES FS GS,其實段描述符資訊在訪

問的時候由cpu自動通過對16位段選擇符的解碼來載入到一個所謂的影子寄

存器中,這樣速度會非常快。可以直接使用當然對於我們使用者可能是看不到

這個寄存器的存在和操作。
b.段描述符表,如同gdt上面的也屬於段描述符表的一種,用於提供段選擇符

號的最終訪問獲得儲存的段資訊。
c:最終的線形地址確立是由段描述符中提供的段基址+虛擬位址的段位移。

然後再根據分頁的方法獲得最終的物理地址。

3.描述格式
//這個兩個低層調用及最後一個實現宏用於調用設定TSS,LDT段描述孵內容


//n:為描述符的地址,即後面會往n開始到n+7位置中寫入一個完整的8個字

節的段描述符。
//add:基地址,即段資訊中所儲存的段基址
//0x8X是屬性描述表示是何種類型的段TSS or LDT or the other
#define  set_tss_desc(n, addr)   _set_tssldt_desc(((char *)

(n)),((int)(addr)),"0x89")
#define  set_ldt_desc(n, addr)   _set_tssldt_desc(((char *)

(n)),((int)(addr)),"0x82")
段描述符的格式
高32位中
|31-24:基地址

31..24|23:G|22:D/B|21:0|20:AVL|19-16:Limit19..16|15:P|14-13:DPL|1

2:S|11-8:TYPE|7-0:基地址23..16|
低32位中
|31-16:base address 15..0|15-0:Segment Limit|

4.
//看具體實現載入段描述符的過程
#define _set_tssldt_desc  (  n,  addr,  type)
//104是段限長,TSS最長104個位元組放到低2個位元組 15-0:Segment Limit
__asm__ ("movw $104,%1/n/t" /
//ax段基地址的低16位放入 31-16:base address 15..0
    "movw %%ax,%2/n/t" /
//右移16位 ax中變成高16位地址
    "rorl $16,%%eax/n/t" /
//將高16位地址中的低8位放入 7-0:基地址23..16
    "movb %%al,%3/n/t" /
//將type放入|15:P|14-13:DPL|12:S|11-8:TYPE
    "movb $" type ",%4/n/t" /
//|23:G|22:D/B|21:0|20:AVL|19-16:Limit19..16|全部置零
    "movb $0x00,%5/n/t" /
//高基地址8位放入最高位
    "movb %%ah,%6/n/t" /
    "rorl $16,%%eax" /
    //輸入規則%0指定eax存放addr段基址,%1~%6均為指定m記憶體位址分別

為n,n+2,n+4...地址內容
    ::"a" (addr), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), /
     "m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) /
    )
5.載入任務TSS,LDT等段選擇符和段描述符載入到任務寄存器中的實現
n:第n號任務或局部表的段位移
//ltr或者lldt命令載入%%ax的段選擇符,此段選擇可以看到是由低層的一

個宏_TSS和_LDT來返回來實現。
#define ltr  (n)     __asm__("ltr %%ax"::"a" (_TSS(n)))
#define lldt (n)     __asm__("lldt %%ax"::"a" (_LDT(n)))
//_TSS _LDT將返回一個當前任務資訊或者局部描述符的對應段位移是相對

於GDT中的位移,這裡使用一個簡單的計算公式 n*(8+8)+起始位移數目*8,

這裡我們要看下這些TSS和LDT在GDT中位置。
#define _TSS  (n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
#define _LDT  (n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
6.GDT具體分布
0 |NULL   |  不可以使用的GDT(0)
1 |系統程式碼片段CS |  作業系統的自己使用
2 |系統資料區段DS |  作業系統的資料區段
3 |系統調用 |  一些調用的資訊符
4 |TSS0  |  這裡很容易看到FIRST_TSS_ENTRY=4
5 |LDT0  |  這裡很容易看到FIRST_LDT_ENTRY=5
....
每個域都是8個位元組所以第n個TSS地址 = TSS0的基址+ (n*LSSi-LSSi-1)
= FIRST_TSS_ENTRY*8 + n*(8+8)
= FIRST_TSS_ENTRY<<3+n<<4
同理可以推匯出LDT的地址進行載入

至此基本清楚段選擇符 描述符 段一些關係和如何設定的操作
#define str  (n)  
__asm__("str %%ax/n/t" /
    "subl %2,%%eax/n/t" /
    "shrl $4,%%eax" /
    :"=a" (n) /
    :"a" (0),"i" (FIRST_TSS_ENTRY<<3))

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.