1. 程式人生 > >《80X86匯編語言程序設計教程》十九 操作系統類指令與輸入輸出保護

《80X86匯編語言程序設計教程》十九 操作系統類指令與輸入輸出保護

.html 影響 輸出 lsp use com 之間 自己的 操作數

1、 通常只在操作系統代碼中使用,80386支持4個特權等級,操作系統指令也可分3種:實模式和任何特權級下可執行指令、實模式及特權級0下可執行的指令和僅在保護模式下執行的指令。

  1) 實模式和任何特權級下可執行的指令

    a)存儲全局和中斷描述符表寄存器指令

      GDT與IDT整個系統各只有一張,它們的定位信息分別保存在GDTR與IDTR中,這兩個寄存器的值可以被保存。須註意,LDT表示任務私有,存儲LDTR值的指令不屬於這一類。

      i)存儲全局描述符表寄存器指令:SGDT DST

        DST是48位(6字節)存儲器操作數,執行後GDTR的16位界限值存入DST低字,而GDTR中32位基地址存入DST高雙字。對標誌位無影響。

      ii)存儲中斷描述符表寄存器指令:SIDT DST

        與“SGDT DST”類似。

    b)存儲機器狀態字指令:SMSW DST

      DST可以是16位通用寄存器或存儲單元。對標誌位無影響。

      說明:為了兼容80286指令集(386的CR0低字節等同於286機器狀態字),在386中,存儲機器字應該使用存儲CR0寄存器指令。

  2) 實模式及特權級0下可執行的指令

    關鍵寄存器的設置指令等,在保護模式下CPL不為0的指令執行它們將引發錯誤碼為0的通用保護故障。虛擬8086模式下(CPL = 3)同樣如此。

    a)清任務切換標誌指令:CLTS

      任務切換時,CR0的TS位(任務切換標誌位)自動被置1(參考“《80X86匯編語言程序設計教程》十二 任務狀態段、控制門和控制轉移”),該指令功能是把TS標誌位清0。不影響其它標誌位。

    b)暫停指令:HLT

      該指令使處理器暫停執行,只有在接受一個已經啟用的中斷,或者讓系統復位,才重新啟動。對標誌位沒有影響。

    c)裝載全局描述符表寄存器指令:LGDT SRC

      SRC是48位(6字節)存儲器操作數,執行後偽描述符SRC(PDESC結構)的低字送GDTR低字(段界限),高雙字送GDTR高雙字(段基址)。對標誌位無影響。

    d)裝載中斷描述符表寄存器指令:LIDT SRC

      與“LGDTR”類似。

    e)裝載機器狀態字指令:LMSW SRC

      SRC可以是16位通用寄存器或存儲單元。該指令將SRC裝入機器狀態字(CR0的低16位),不影響標誌位。同樣,是為了兼容286,386不應該用它。

    f)控制寄存器數據傳送指令:MOV DST,SRC

      實現386控制寄存器和32位通用寄存器之間的數據傳送。所以,DST和SRC可以是3個控制寄存器(CR0、CR2、CR3---參考“《80X86匯編語言程序設計教程》八 80386程序設計基礎”)和任一32位通用寄存器,但不能同時為控制寄存器。對標誌位門影響。

    g)調試寄存器數據傳送指令

      規則同上。調試寄存器為DR0~DR7(參考“《80X86匯編語言程序設計教程》八 80386程序設計基礎”)。

    h)測試寄存器數據傳送指令

      規則同上。測試寄存器為TR6和TR7(參考“《80X86匯編語言程序設計教程》八 80386程序設計基礎”)。

  3) 只能在保護模式下執行的指令

    只能在保護模式下執行,在實模式下執行將引起非法操作碼故障(向量號6)。

    a)裝載局部描述符表寄存器指令:LLDT SRC

      SRC可以為16位通用寄存器或存儲單元(代表的選擇子必須指示GDT中類型為LDT的描述符,為0則表示空選擇子,及不使用LDT),不影響標誌位。CPL不為0時(錯誤碼為0)、選擇子不指示GDT中描述符或描述符類型不是LDT時( 錯誤碼由該選擇子構成),執行它將產生通用保護故障。

    b)存儲局部描述符表寄存器指令:SLDT DST

      規則同上。

    c)裝載和存儲任務寄存器指令

      任務寄存器TR指示當前任務狀態段TSS(參考“《80X86匯編語言程序設計教程》十二 任務狀態段、控制門和控制轉移”)。隨著任務的切換而切換,如果任務嵌套,那麽TR原值作為鏈接字保存在新任務TSS中。

      i) 裝載任務寄存器指令:LTR SRC

        SRC為16位通用寄存器或存儲單元。SRC指示的選擇子不能為空,必須索引位於GDT中的描述符,且類型為TSS。該指令不影響標誌位。CPL不為0時(錯誤碼為0)、選擇子不指示GDT中描述符或描述符類型不是LDT時(錯誤碼由該選擇子構成),執行它將產生通用保護故障。

      ii)存儲任務寄存器指令:STR DST

        DST規則同上,不影響標誌位。

    d)調整申請特權級指令:ARPL OPRD1,OPRD2

      OPRD1為16位通用寄存器或存儲單元,OPRD2為16位通用寄存器。該指令用選擇子OPRD2的申請特權級(RPL)去檢查選擇子OPRD1的RPL,如果OPRD1.RPL < OPRD2.RPL,那麽ZF = 1,OPRD1.RPL = OPRD2.RPL;否則ZF = 0。二者都可為空,不影響其它標誌位。

    e)裝載存取權指令:LAR OPRD1,OPRD2

      兩操作數都可以為16位或32位通用寄存器,OPRD2還可以是存儲單元,但它們尺寸必須一樣。如果選擇子OPRD2(32位則使用低16位)所指示描述符滿足下述條件,那麽ZF = 1,並把描述符屬性字段裝入OPRD1;否則ZF = 0,OPRD1不變。

      i)在描述符表範圍內

      ii)為存儲段描述符或系統段描述符,或任務門、調用門描述符

      iii)CPL和OPRD2.RPL都不大於OPRD2.DPL

      描述符參考“《80X86匯編語言程序設計教程》九 分段管理機制及純DOS環境搭建”與“《80X86匯編語言程序設計教程》十二 任務狀態段、控制門和控制轉移”。結果是高4字節與00FFXFF00相與的結果,X表示未定義,如果OPRD1為16位,那麽只取結果低2字節(無G位、AVL位)。除ZF不影響其它標誌位。

    f)裝載段界限指令:LSL OPRD1,OPRD2

      規則同上,區別在於轉載的是段界限字段且條件第二點限制更加嚴格,不能為門描述符。在滿足條件下,裝載到OPRD1的OPRD2所指示描述符的界限字段值以字節為單位。如果描述符中界限字段以4K為單位(G = 1),那麽裝入到OPRD1時左移12位,空出的位全部填1。如果使用16位操作數,只有段界限低16位被裝載到OPRD1。除ZF不影響其它標誌位。

    g)讀寫檢驗指令

      檢查在當前特權級上指定的段是否能讀寫,從而避免不必要的異常。

      i)讀檢驗指令:VERR OPRD

        OPRD可以是16位或32位通用寄存器和存儲單元。如果為32位則使用低16位,功能是判斷OPRD選擇子指示的段在當前CPL是否可讀,如果選擇子合法,且在當前CPL可讀,那麽ZF置1,否則ZF清0。除ZF不影響其它標誌位。

      ii)寫檢驗指令:VERW OPRD

        規則同上,只不過檢查的屬性是是否可寫。

  4) 特權指令

    保護模式下只有CPL = 0才能執行的指令,否則引發通用保護異常。特權指令在構造完善保護機制上起重要作用。總結如下:

指令

功能

指令

功能

CLTS

清除CR0的TS位

LTR

裝入TR

HLT

停機

MOV CRn,reg

裝入控制寄存器

LGDT

裝入GDTR

MOV reg,CRn

保存控制寄存器

LIDT

裝入IDTR

MOV DRn,reg

裝入測試寄存器

LLDT

裝入LDTR

MOV reg,DRn

保存測試寄存器

LMSW

裝入MSW(CR0低16位)

    可見,設置GDTR、IDTR和LDTR是特權指令,而存儲它們不是。而設置和存儲控制和測試寄存器都是特權指令。

2、 輸入/輸出保護

  1) 輸入/輸出保護

    a)I/O敏感指令

      輸入/輸出特權級(I/O Privilege Level)規定可執行I/O有關指令和訪問I/O空間地址的最外層特權級(在標誌寄存器EFLAGS中,參考“《80X86匯編語言程序設計教程》八 80386程序設計基礎”)。I/O許可位圖(在TSS中)規定I/O空間哪些地址可以在任何特權級執行的代碼訪問。I/O敏感指令如下:

指令

功能

保護模式下執行條件

CLI

清除EFLAGS中IF位

CPL <= IOPL

STI

設置EFLAGS中IF位

CPL <= IOPL

IN

從I/O地址讀出數據

CPL <= IOPL或I/O位圖允許

INS

從I/O地址讀出字符串

CPL <= IOPL或I/O位圖允許

OUT

從I/O地址寫入數據

CPL <= IOPL或I/O位圖允許

OUTS

從I/O地址寫入字符串

CPL <= IOPL或I/O位圖允許

      如果權限不夠,則引發通用保護異常。每個任務有自己的EFLAGS與TSS,所以各個任務IOPL可以有不同,並且可定義不同的I/O許可位圖。註意:實模式下全部可執行。

    b)I/O許可位圖

      由二進制位串組成,每一位對應一個I/O地址,如果m位為0,那麽I/O地址m可由本任何特權等級代碼的程序訪問,否則只能在IOPL特權級或更內層特權級執行的程序訪問,不然引發通用保護異常。 一條I/O指令最多涉及4個I/O地址(如IN EAX,71H),只有涉及到的全部I/O許可位為0才能順利訪問。386支持I/O地址空間大小64K,所以I/O許可位有效部分最大為8KB。當前任務使用的I/O許可位圖在TSS低端64K(用16位偏移,最大為64K)字節內,位串以字節為存儲單位,所以要存儲整個I/O許可位圖時,偏移盡量保證低於64K – 8K = 56K。

    c)I/O訪問許可檢查細節

      步驟如下:

      i)CPL <= IOPL是否成立,成立則直接跳轉到第8步直接進行I/O訪問

      ii)取得位圖開始偏移(TSS的I/O許可位圖I偏移字段---TSS內偏移66H字節單元)

      iii)計算字節偏移(I/O地址值右移3位---即除以8)

      iv)計算位偏移以形成屏蔽碼值(I/O地址右移出來的3位放字單元)

      v)字節是否越界,是則引發通用保護異常(位圖偏移+字節偏移+1<=段界限)

      vi)從位圖中讀出兩個字節(讀寫最快)

      vii)進行位檢查,不通過則引發通用保護異常

      ix)進行I/O訪問

      在讀取時,總是讀取兩個字節,由於I/O訪問最多同時訪問4個連續端口,最多也是分布在連續2個字節之內,所以在判斷是否越界時要也僅要加1處理,為了在判斷I/O許可位圖最高字節上述流程同樣適用,必須在I/O許可位圖最後添加一個全1字節0ffh。I/O許可位圖開始偏移加上8K所得值與TSS界限值二者較小者決定I/O許可位圖有效末端偏移。當許可位圖開始偏移大於56K時,將有部分位越過位圖界限,從而無法因無法訪問而觸發通用保護異常(那部分位被認為是全1)。利用這個特點,可以大大減小I/O許可位圖占用的存儲單元,從而大大減小TSS。如:

1 ;演示任務任務狀態段(TSS)
2 DemoTSSSeg    segment    para    use16
3     DTSS    TASKSS<>                      ;TSS低端部分
4             db    100h/8 dup(0ffh)        ;對應I/O端口00H~0FFH
5             db    100h/8 dup(0)           ;對應I/O端口100H~1FFH
6             db    0ffh                    ;IO許可位結束標誌
7     DemoTSSLen = $ - DemoTSSSeg
8 DemoTSSSeg    

      上面的TSS只含有許可位圖最初的200H位,對應端口0~1FFH,而其它位都被認為是1。之前實例中使用的格式,高度區只帶IO許可位結束標誌表示所有的位都為1。

  2) 重要標誌保護

    386對EFLAGS標誌中的IOPL、IF和VM這3個字段的處理比較特殊,只有較高權限等級的代碼才能通過IRET、POPF、CLI和STI等指令來改變它們。下面是不同特權等級下對3個字段的處理情況:

特權等級

標誌字段

VM

IOPL

IF

CPL = 0

可變(除POPF指令外)

可變

可變

0 < CPL <= IOPL

不變

不變

可變

CPL > IOPL

不變

不變

不變

    可見,只有CPL = 0的情況下才能修改VM和IOPL,必須在IOPL同級或者更內層才能修改IF。須註意,在特權級不滿足的條件下,其中IRET和POPF指令試圖更改這3個字段並不引發異常,只是試圖的修改操作並不會被成功執行。此外,POPF總是不能改變VM位,而PUSHF指令總是把0壓入到VM位。

《80X86匯編語言程序設計教程》十九 操作系統類指令與輸入輸出保護