GDT和IDT的初始化

內存管理時,不讓多進程的程序出現內存衝突的一解決方案是Segmentation4GB的內存可以任何分割,每塊的初始地址都是0。另外還有一種複雜的內存管理方案,既Paging,目前主流的操作系統都是採用這種方式。本文的OS爲了實現簡單,只採用Segmentation方案。

我們規定1Segmentation的信息有:

l         Size

l         初始地址

l         屬性(讀寫權限等)。

每個Segementation信息佔8Byte,既64bit。我們把所有的Segment編號,並把編號保存在CPU內的16segment register裏。Segment register可以處理08191segment,本來16位的register應該可以處理065535segment,但是因爲register的低3爲不能使用,所以最多隻到8191。爲了保存8192segment(每個8bytes),需要64KB的容量,CPU是無法保存這麼多數據的,因此需要內存的幫助。GDT[gobal (segment) descriptor table]的縮寫,它保存所有segment的信息。Segment的初始地址和有效設定個數保存在CPUGDTR寄存器內。另外一個IDT[interrupt descriptor table]的縮寫,用來處理一些內部或外部的中斷。例如鍵盤,鼠標,軟驅,硬盤,CDROM,網卡等。IDT可以處理0255編號的中斷,例如當123號中斷髮生時,調用XXX函數。IDT的信息和GDT相似,也是每個8bytes。本系統的GDT分配在內存的0x270000x27ffffIDT0x26f8000x26ffff,佔2KB

我們將Segment定義爲:

struct SEGMENT_DESCRIPTOR {

              short limit_low, base_low;

              char base_mid, access_right;

              char limit_high, base_high;

};

Segment信息的初始地址由32bit組成,成爲Base地址,分爲3個部分,low2byte),mid1byte),high1byte),如此分割是爲了兼容80286 CPU

Segment信息的大小成爲LimitLimit最大可以爲4GB,當然是在32位機。這樣就需要4Byte,和Base地址一共需要8byte,但這樣就沒有保存屬性的位置。爲了留給屬性空間,只能給Limit 20bit,最大能表示1MB,當然這樣是不能滿足目前主流的32bit機的。Intel爲了解決這個問題,規定了在屬性裏留有1位稱爲G bitG表示granularity,粒度),limit的單位不是Byte,而是PagePCCPU1Page表示4KB。這樣4KB*1MB=4GB。爲了能表示20bitLimit,我們使用2Byte。其中多出的4bit用來表示屬性。

Segment的屬性由Limit多出的4bit加上剩下的8bit表示,也稱訪問權限。訪問權限的構成:

XXXX0000XXXXXXXXX代表01

4bit386以後使用的擴張訪問屬性,由[GD00]構成,G表示上面提到的粒度,D表示Segment mode1表示32位機,0表示16位機。下8bit繼承80286時代的Segement屬性。8bit的屬性內容非常多,在這裏,我們常用的有如下幾個:

000000000x00):未使用的Descriptor table

100100100x92):系統專用,可讀寫,不能執行

100110100x9a):系統專用,可執行,可讀,不可寫

111100100xf2):應用程序使用,可讀寫,不可執行。

111110100xfa):應用程序可用,可執行,可讀,不可寫。

屬性規定了系統和應用程序使用的讀寫執行權限。系統模式稱爲Ring0,應用程序模式稱爲Ring3,中間的Ring1Ring2模式是系統服務。Ring0管理Ring3,例如,Ring3的應用程序在請求Load LGDT時,操作系統將否決該請求,以保證系統的安全性。下面是新增加的源代碼文件。

 

/*boot.h*/

#define AR_DATA32_RW  0x4092

#define AR_CODE32_ER 0x409a

#define ADR_BOTPAK                   0x00280000

#define LIMIT_BOTPAK  0x0007ffff

#define LIMIT_GDT                       0x0000ffff

 

#define ADR_IDT                                         0x0026f800

#define LIMIT_IDT                        0x000007ff

 

 

struct SEGMENT_DESCRIPTOR {

              short limit_low, base_low;

              char base_mid, access_right;

              char limit_high, base_high;

};

 

 

struct GATE_DESCRIPTOR {

              short offset_low, selector;

              char dw_count, access_right;

              short offset_high;

};

 

void init_gdtidt(void);

void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar);

void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar);

 

/*gldt.c*/

#include "boot.h"

 

void init_gdtidt(void)

{

              struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;

              struct GATE_DESCRIPTOR    *idt = (struct GATE_DESCRIPTOR    *) ADR_IDT;

              int i;

 

              /*GDT Init*/

              for (i = 0; i <= LIMIT_GDT / 8; i++) {

                            set_segmdesc(gdt + i, 0, 0, 0);

              }

             

              /*set all memory into data segement*/

              set_segmdesc(gdt + 1, 0xffffffff,   0x00000000, AR_DATA32_RW);

             

              /*set this segemnt to code segment that can be executed by system*/

              set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);

             

              load_gdtr(LIMIT_GDT, ADR_GDT);

 

              /*IDT Init*/

              for (i = 0; i <= LIMIT_IDT / 8; i++) {

                            set_gatedesc(idt + i, 0, 0, 0);

              }

              /*implemented in func.s*/

              load_idtr(LIMIT_IDT, ADR_IDT);

 

              return;

}

 

void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)

{

              if (limit > 0xfffff) {

                            ar |= 0x8000; /* G_bit = 1 */

                            limit /= 0x1000;

              }

              sd->limit_low    = limit & 0xffff;

              sd->base_low     = base & 0xffff;

              sd->base_mid     = (base >> 16) & 0xff;

              sd->access_right = ar & 0xff;

              sd->limit_high   = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0);

              sd->base_high    = (base >> 24) & 0xff;

              return;

}

 

void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar)

{

              gd->offset_low   = offset & 0xffff;

              gd->selector     = selector;

              gd->dw_count     = (ar >> 8) & 0xff;

              gd->access_right = ar & 0xff;

              gd->offset_high  = (offset >> 16) & 0xffff;

              return;

}

 

;func.s

;Colimas Simple OS

 

[BITS 32]        

                            GLOBAL             _io_hlt, _io_cli, _io_sti, io_stihlt

                            GLOBAL             _io_in8,  _io_in16,  _io_in32

                            GLOBAL             _io_out8, _io_out16, _io_out32

                            GLOBAL             _io_load_eflags, _io_store_eflags

                            GLOBAL             _load_gdtr, _load_idtr                    

segment .text

 

 

_io_hlt:  ; void io_hlt(void);

                            HLT

                            RET

 

_io_cli:   ; void io_cli(void);

                            CLI

                            RET

 

_io_sti:   ; void io_sti(void);

                            STI

                            RET

 

_io_stihlt:             ; void io_stihlt(void);

                            STI

                            HLT

                            RET

 

_io_in8:  ; int io_in8(int port);

                            MOV                    EDX,[ESP+4]                    ; port

                            MOV                    EAX,0

                            IN                        AL,DX

                            RET

 

_io_in16:              ; int io_in16(int port);

                            MOV                    EDX,[ESP+4]                    ; port

                            MOV                    EAX,0

                            IN                        AX,DX

                            RET

 

_io_in32:              ; int io_in32(int port);

                            MOV                    EDX,[ESP+4]                    ; port

                            IN                        EAX,DX

                            RET

 

_io_out8:              ; void io_out8(int port, int data);

                            MOV                    EDX,[ESP+4]                    ; port

                            MOV                    AL,[ESP+8]                       ; data

                            OUT                    DX,AL

                            RET

 

_io_out16:            ; void io_out16(int port, int data);

                            MOV                    EDX,[ESP+4]                    ; port

                            MOV                    EAX,[ESP+8]                    ; data

                            OUT                    DX,AX

                            RET

 

_io_out32:            ; void io_out32(int port, int data);

                            MOV                    EDX,[ESP+4]                    ; port

                            MOV                    EAX,[ESP+8]                    ; data

                            OUT                    DX,EAX

                            RET

 

_io_load_eflags:   ; int io_load_eflags(void);

                            PUSHFD                           ; PUSH EFLAGS

                            POP                     EAX

                            RET

 

_io_store_eflags:  ; void io_store_eflags(int eflags);

                            MOV                    EAX,[ESP+4]

                            PUSH    EAX

                            POPFD                ; POP EFLAGS

                            RET

 

;09/03

 

_load_gdtr:                        ; void load_gdtr(int limit, int addr);

                            MOV                    AX,[ESP+4]                       ; limit

                            MOV                    [ESP+6],AX

                            LGDT    [ESP+6]

                            RET

 

_load_idtr:                         ; void load_idtr(int limit, int addr);

                            MOV                    AX,[ESP+4]                       ; limit

                            MOV                    [ESP+6],AX

                            LIDT     [ESP+6]

                            RET

_load_gdtr函數的參數是LimitBase地址,GDTR48位寄存器,不能直接使用Mov指令,這個寄存器的後16bit,也就是內存的最初2byte表示Limit,剩下的4byte表示Base地址。[ESP+4]表示limit[ESP+8]表示base地址。因爲我們不需要Limit[ESP+4][ESP+6]的值,只需要將[ESP+6]代入LGDT_load_idtr_load_gdtr相同。
發佈了0 篇原創文章 · 獲贊 8 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章