《30天自制操作系统》笔记(11)——高分辨率
《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指令启用之;否则使用任意显卡都支持的低分辨率。
本篇算是个美化工作,下一篇就是期待已久的"多任务"了。
微信扫码,自愿捐赠。天涯同道,共谱新篇。
微信捐赠不显示捐赠者个人信息,如需要,请注明联系方式。 |