使用IOPL設置一個特權級的用戶程序對全部端口的訪問權限,使用I/O位圖對一個特權級的用戶程序設置個性化的端口訪問權限(能訪問部分端口、不能訪問另外的端口)。設計
用戶程序的CPL<IOPL,用戶程序能訪問全部端口。不然,從I/O位圖中查找用戶程序對端口的訪問權限。code
IOPL存儲在eflags中,只能在0特權級的下經過popf
、iretd
修改。進程
I/O位圖存儲在TSS中。資源
I/O操做也能夠看做一種特權資源,也有「訪問門檻」。代碼段和數據段的訪問「門檻」是DPL
,存儲在段描述符中。it
I/O操做的訪問門檻存儲在eflags
的IOPL
位。可是否具備I/O操做
的權限,還受I/O位圖
影響。io
敏感指令是指這些指令:in、ins、out、outs、pof、iretd
。class
數值上,CPL <= IOPL,權限上,當前代碼段的特權級高於或等於IOPL中存儲的特權等級,當前代碼段才能執行I/O
操做。cli
CPL = 0,用戶程序才能執行敏感指令。擴展
eflags
是flags
的32位擴展寄存器,保護許多標誌位,例如cf、zf
等。IOPL
也存儲在eflags中,佔用2個bit,正好能表示四個特權級:00、0一、十、11
。配置
沒有能直接更新eflags
的指令,只能間接修改eflags
從而修改IOPL
。方法是使用兩個指令:popf
和iretd
。
只有特權級是0的用戶程序才能成功修改eflags
中的IOPL
。特權不是0的用戶程序也能執行popf
和iretd
來修改IOPL
,只不過修改無效,也就是說,能執行、無效果、不報錯。
popf
的示意代碼以下:
pushf ; 把eflags中的值入棧 mov [esp], 要更新到eflags中的值 popf ; 把棧中的值存儲到eflags
popf
除了能修改IOPL
,還能修改IF
。這不難理解。由於popf
是把棧中的整個符合eflags
結構的數據更新到eflags
中,只需把那個結構的IF
位修改成目標值就能修改eflags
中的IF
位。
popf
用來修改IF
位的時候,和sti、cli
同樣是敏感指令,須要知足特權級檢查規則:CPL <= IOPL。
popf
用來修改IOPL
位的時候,須要知足特權級檢查規則:CPL = 0。
同一個指令,修改的內容不一樣,需知足的特權級檢查規則不一樣,這種設計,很差。若我來設計,我會設計成兩個指令,每一個指令完成各自的功能。
中斷髮生時,eflags
會入棧中斷例程的堆棧。修改這個堆棧中的eflags
的值,而後再使用iretd
就能把棧中的新eflags
值更新到eflags
中。
IOPL
對一個特權級的全部用戶程序的I/O權限
作「一刀切」的限制,要麼這個特權級的全部用戶程序擁有全部端口的I/O
權限,要麼擁有0個端口的I/O
權限。IO位圖容許對每一個用戶程序在I/O端口限制上作個性化配置。
若是用戶進程的CPL <= IOPL,那麼,IO位圖的值是多少不影響用戶進程的I/O權限。若是用戶進程的CPL > IOPL,那麼,IO位圖的值決定了用戶進程能讀寫哪些I/O端口。
位圖,又叫bitmap
。一個bit能表示兩種值,0或1。1kb的空間擁有1024個bit,1Mb的空間擁有1024*1024
個bit。
假如咱們的硬件一共有65536個I/O端口,只須要8Kb的空間就能標識出這麼多端口的權限狀態。給8kb空間中的65536個bit依次編號,若第0號I/O端口在能被當前用戶進程讀寫,將此bit設置爲1,不然設置爲0;剩餘的第1到第65535個bit依次按對應的I/O端口依次設置值。
若是用戶程序存在I/O位圖,它將出如今用戶程序的TSS的頂端。正由於如此,TSS的尺寸是不固定的。若是不包含I/O位圖,TSS的尺寸是104字節。若是包含I/O位圖,TSS的尺寸是「I/O位圖地址 + 8192字節 + 1字節」。
包含/IO位圖,TSS的尺寸爲何不是「104字節 + 8192字節 + 1字節」?
由於I/O位圖有可能不是緊挨着保存"I/O位圖地址"的那個 字節,兩者之間可能有空白空間。I/O位圖地址是I/O位圖在TSS中的偏移量,注意,I/O位圖在TSS中,它與TSS中的其餘元素都在TSS中。也就是說,從TSS的初始位置開始到I/O位圖地址,也許包含部分沒有存儲數據的空間,都是TSS的一部分。TSS的空間被I/O位圖地址分割爲兩個部分,前一部分的大小是I/O位圖地址,後一部分是8192個字節(65536個端口須要65536個bit)+1字節(位圖的結束標誌必須是0xff)。
說得簡單點,就是,I/O位圖和TSS中的其餘元素可能不是牢牢挨着。
位圖爲何要用0xff
做爲結束標誌?我沒有弄明白。
不知道TSS中的保留位是什麼,更不知道怎麼在代碼中表示保留位。這裏的代碼只保證正確表示I/O位圖。
怎麼寫代碼?
0xff
結尾就行。[SECTION .tss3] LABEL_TSS3: ;TSS中的其餘元素 ; 最糾結的語句。$ - LABEL_TSS3是當前行在TSS中的偏移量。 ; 本語句佔用2個字節,2個字節以後是I/O位圖。 dw $ - LABEL_TSS3 + 2 times 12 db 0ffh ; 12個字節,96個bit,都設置爲1,表示當前用戶程序有端口0到端口95的讀寫權限。 ; 端口96到102只有端口97對當前用戶程序開放了讀寫權限。從右到左編號,因此第2個0表示97號端口。 db 1111101b ; I/O位圖的結束標誌 db 0xff TSS3_LEN equ $$ - LABEL_TSS3