《30天自制操作系統》筆記(11)——高分辨率
進度回顧
上一篇介紹了定時器的初始化和使用方法。接下來就該實現多任務了。不過原作者在這之前寫了關於提高分辨率的章節,本篇也總結一下設置顯示器高分辨率的方法好了。本篇內容過於簡單,算是小小的休息一下。
啟用高分辨率的思路:檢測顯卡是否支持某種分辨率;如果支持,則通過INT 0x10指令啟用之;否則使用任意顯卡都支持的低分辨率。
VBE
歷史上秦始皇掃平中原一統六國,其歷史功績之一便是在這之后統一了度量衡,從此全國人民在計算度量買賣的時候都有統一的標准了。秦始皇能夠強制廢除六國的貨幣、度量標准,但是顯卡公司里沒有一個能夠成為秦始皇,也就造成了設置顯示器分辨率的各種麻煩。
然而天下大勢分久必合,顯卡公司雖然無法合並為一,但市場不接受各自為政的混亂標准,因此多家顯卡公司協商成立了VBE(Video Electronics Standards Association)即視頻電子標准協會。VBE制作了專用的BIOS,基本上可以兼容所有的顯卡分辨率設置。這個BIOS就稱為"VESA BIOS extension"(VBE)。可以說VBE就是顯卡公司之間統一的度量衡。
設置低分辨率
設置320*200這樣的低分辨率時,使用"AH=0; AL=畫面模式號碼;INT 0x10;"就行了。
設置高分辨率
設置640*480等高分辨率時,要使用"AX=0x4f02;BX=畫面模式號碼;INT 0x10;"。
VBE的畫面模式號如下。
-
0x101……640*480*8bit彩色
-
0x103……800*600*8bit彩色
-
0x105……1024*768*8bit彩色
-
0x107……1280*1024*8bit彩色
還有一些其它的模式,原作者省略了,我也就懶得知道了。
另外,QEMU中不能使用0x107。原因不明。
實際使用的時候,要把畫面模式號加上0x4000,再賦值到BX中。
首先要判斷計算機使用的是什么顯卡。如果不能使用VBE,就只能用低分辨率了。
1 MOV AX, 0x9000 2 MOV ES, AX 3 MOV DI, 0 4 MOV AX, 0x4f00 5 INT 0x10 6 CMP AX, 0x004f 7 JNE scrn320
在這里,我們給ES賦值為0x9000,DI賦值為0,AX賦值為0x4f00,再執行INT 0x10。如果VBE存在,AX就會變成0x004f,否則就只能使用320*200的分辨率了。
顯卡能利用的VBE信息,會寫入內存中ES:DI指定的地址開始的512字節,所以這樣要設置ES和DI。
然后要判斷VBE版本。原作者的OS只支持VBE2.0以上的顯卡。
1 MOV AX, [ES:DI + 4] 2 CMP AX, 0x0200 3 JB scrn320 ; if (AX < 0x0200) goto scrn320
即使VBE版本是2.0以上,也不能保證所有的畫面模式都能用。現在我們要通過VBE來查看一下畫面模式0x105能不能用。
1 MOV CX, VBEMODE ; VBEMODE EQU 0x105 2 MOV AX, 0x4f01 3 INT 0x10 4 CMP AX, 0x004f 5 JNE scrn320
如果AX是0x004f以外的值,那么所指定的畫面模式就不能用。
此次取得的畫面模式信息也被寫入DS:DI開始的512字節處(即覆蓋了之前檢查VBE是否存在的結果)。
畫面模式信息中重要的有如下幾個。
-
WORD [ES:DI + 0x00] ; 模式屬性……bit7不是1就不好辦
-
WORD [ES:DI + 0x12] ; X的分辨率
-
WORD [ES:DI + 0x14] ; Y的分辨率
-
WORD [ES:DI + 0x19] ; 顏色數……必須為8
-
WORD [ES:DI + 0x1b] ; 顏色的指定方法……必須為4(即調色板模式)
-
WORD [ES:DI + 0x28] ; VRAM的地址
我們來確認如下三項內容:
-
顏色數是否為8
-
是否為調色板模式
-
畫面模式號碼可否加上0x4000再進行指定
1 CMP BYTE [ES:DI + 0x19], 8 2 3 JNE scrn320 4 5 CMP BYTE [ES:DI + 0x1b], 4 6 7 JNE scrn320 8 9 MOV AX, [ES:DI + 0x00] 10 11 AND AX, 0x0080 12 13 JZ scrn320 ; 模式屬性的bit7是0,所以放棄
如果上述步驟中沒有跳入scrn320,那么就可以使用高分辨率。
1 MOV BX, VBEMODE+0x4000 2 MOV AX, 0x4f02 3 INT 0x10 4 MOV BYTE [VMODE], 8 ; 記下畫面模式(參考C語言) 5 MOV AX, [ES:DI + 0x12] 6 MOV [SCRNX], AX 7 MOV AX, [ES:DI + 0x14] 8 MOV [SCRNY], AX 9 MOV EAX, [ES:DI + 0x28] 10 JMP keystatus
最后的JMP指令,用來讓程序跳過后面的scrn320,直接進入在BIOS中查詢鍵盤狀態的地方。
下面就剩下scrn320這一小段了。
1 scrn320: 2 MOV AL, 0x13 ; VGA圖,320*200*8bit彩色 3 MOV AH, 0x00 4 INT 0x10 5 MOV BYTE [VMODE], 8 ; 記下畫面模式(參考C語言) 6 MOV WORD [SCRNX], 320 7 MOV WORD [SCRNY], 200 8 MOV DWORD [VRAM], 0x000a0000
我用VMware分別試驗了640*480*8bit彩色、800*600*8bit彩色、1024*768*8bit彩色、1280*1024*8bit彩色這幾種情況,發現均可以支持。另外,如原作者所說,QEMU不支持1280*1024*8bit彩色。這也是VMware比QEMU更強一些的一個證據。
截圖如下。
下面是600*400分辨率的。
下面是1024*768分辨率的。
下面是1280*1024分辨率的。我的顯示器不夠顯示這么大,所以截了2個圖。
總結
啟用高分辨率的思路:檢測顯卡是否支持某種分辨率;如果支持,則通過INT 0x10指令啟用之;否則使用任意顯卡都支持的低分辨率。
本篇算是個美化工作,下一篇就是期待已久的"多任務"了。