注:以下程序系原创,若有bug欢迎指正,若有问题欢迎交流,转载请注明出处。若能有益于一二访客,幸甚。
1.VGA
VGA(Video Graphics Array)即视频图形阵列,是IBM在1987年随PS/2机推出的。VGA主要由七大块组成:图形控制器、显示存储器、定序器、CRT控制器、数据串行发生器、属性控制器和数模转换器DAC。
2.VBE
IBM的VGA标准是显示卡发展史上的一块丰碑。但后来无法满足人们的需要,于是市场上出现了TVGA、S3系列、Cirrus Logic、ET等为首的一批显示卡,提供了比VGA分辨率更高,颜色更丰富的显示模式,又兼容VGA显示卡,它们被统称为Super VGA(SVGA)。各种不同的SVGA之间的显示控制各不相同,带来软件兼容性问题,为此视频电子学标准协会VESA(Video Electronics Standards Association)提出了一组附加的BIOS功能调用借口——VBE(VESA BIOS EXTENSION)标准,从而在软件接口层次上实现了各种SVGA显示卡之间的兼容性。时至今日,所有的显示卡OEM厂商都提供了符合VESA SUPER标准的扩展BIOS。通过一组INT 10H中断调用(AH=4FH),可以方便地使用VESA SVGA的扩展功能而不必了解各种显示卡的硬件细节。
Super VGA的扩充显示能力关键取决于对较大显示存储器的寻址能力。
各Super VGA 卡提供的分辨率远高于VGA,VESA VBE均赋予一个标准的16位模式号(实际上是9位,其他各位为标志位或留给以后扩充)。
3.VBE功能调用和返回值
VBE功能调用的共同点:1)AH必须等于4FH,表明是VBE标准;
2)AL等于VBE功能号,0<= AL <= 0BH;
3)BL等于子功能号,也可以没有子功能;
4)调用INT 10H;
5)返回值
VBE返回值一般在AX中:
1)AL=4FH:支持该功能
2)AL!=4FH:不支持该功能;
3)AH=00H:调用成功;
4)AH=01H:调用失败;
5)AH=02H:当前硬件配置不支持该功能;
6)AH=03H:当前的显示模式不支持该功能;
4.VBE 功能
-----------------------------------------------------------
功能0x00:返回VBE信息
------------------------------------------------------
入口:
AX 0x4F00
ES:DI 指向VBE信息块的指针
出口:
AX VBE返回值
------------------------------------------------------------
-----------------------------------------------------------
功能0x01:返回VBE特定模式信息
------------------------------------------------------
入口:
AX 0x4F01
CX 模式号
ES:DI 指向VBE特定模式信息块的指针
出口:
AX VBE返回值
------------------------------------------------------------
-----------------------------------------------------------
功能0x02:设置VESA VBE 模式
------------------------------------------------------
入口:
AX 0x4F02
BX 模式号
出口:
AX VBE返回值
------------------------------------------------------------
当设置模式失败时,返回错误代码,一般返回AH=01H
VESA 2.0以上增加了BX中D14,D15的位定义,完整定义如下:
BX = 模式号
D0~D8:9位模式号
D9~D13:保留,必须为0
D14 = 0:使用普通的窗口页面缓存模式,用VBE功能05H切换显示页面
= 1:使用大的线性缓存区,其地址可从VBE功能01H的返回信息ModeInfo获得
D15 = 0:清除显示内存
= 1:不清除显示内存
------------------------------------------------------------
5.示例
检查VBE可否使用、版本、模式0x103,并切换到模式0x103(800*600, 256色):
# 本程序测试VBE(VESA BIOS EXTENSION)显示模式,然后切换到1024*768 256色模式,
# 并通过软盘读取Baby OS 的简单LOGO,显示在屏幕上
# 2012-12-28 21:03
# guzhoudiaoke@126.com
.section .text
.global _start
.code16
_start:
jmp main
#--------------------------------------------------------------
# 清屏函数:
# 设置屏幕背景色,调色板的索引0指代的颜色为背景色
clear_screen: # 清屏函数
movb $0x06, %ah # 功能号0x06
movb $0, %al # 上卷全部行,即清屏
movb $0, %ch # 左上角行
movb $0, %ch # 左上角列
movb $24, %dh # 右下角行
movb $79, %dl # 右下角列
movb $0x07, %bh # 空白区域属性
int $0x10
ret
#----------------------------------------------------------------
# 设置VGA 0x13显示模式函数
set_video_mode_0x13:
movb $0, %ah # 功能号0x0
movb $MODE_0x13, %al # 显示模式
int $0x10
movw $0x13, video_mode
movw $320, screen_x
movw $200, screen_y
movl $0xb8000, video_ram
ret
#----------------------------------------------------------------
# 设置VBE 0x103显示模式
# 因第一次写此类程序,只考虑了可读性,未考虑效率,比如al、ah分开赋值等
set_video_mode_vbe_0x103:
# 确认VBE是否存在
movw $BUFFER_SEG, %ax
movw %ax, %es
movw %ax, %ds
xorw %di, %di
# 下面检查是否支持VBE及VBE版本
movb $0x4f, %ah # VBE标准
movb $0x00, %al # 功能号
int $0x10
cmp $0x004f, %ax # 若有VBE,AX应该为0x004f
jne 1f
movw 0x04(%di), %ax
cmp $0x0200, %ax # 若VBE版本不是2.0以上,不能使用髙分辨率
jb 1f
# 下面检查MODE_VBE_0x13的参数
movw $MODE_VBE_0x103, %cx
movb $0x4f, %ah # 表明VBE标准
movb $0x01, %al # 子功能号
int $0x10
cmpb $0x00, %ah # 是否调用成功
jne 1f
cmpb $0x4f, %al # 是否支持该模式
jne 1f
cmpb $8, 0x19(%di) # 颜色是否占8bit
jne 1f
cmpb $4, 0x1b(%si) # 颜色的指定方法是否为4,即调色板方式
jne 1f
movw (%di), %ax
andw $0x0080, %ax
jz 1f # AX第7个比特是否为1,该位表示线性帧缓存是否有效
# 下面设置模式
movw $MODE_VBE_0x103, %bx
addw $0x4000, %bx # BX第14个比特表示是否使用大的线性缓存区,故置位
movb $0x4f, %ah # 表示使用VBE标准
movb $0x02, %al # 功能号,表示设置模式
int $0x10
# 下面记录切换到的模式的一些参数信息
movw $MODE_VBE_0x103, video_mode
movw 0x12(%di), %ax
movw %ax, screen_x
movw 0x02(%di), %ax
movw %ax, screen_y
movl 0x28(%di), %eax
movl %eax, video_ram
movw $1, %ax
ret
1:
movw $0, %ax
ret
#----------------------------------------------------------------
# 设置背景颜色为深蓝色
set_screen_bk_color:
movw $VIDEO_PALLETE_PORT, %dx
movb $PA_INDEX_BACKGROUND, %al
outb %al, %dx
movw $COLOR_SELECTION_PORT, %dx
movb $0, %al # 红
outb %al, %dx
movb $0, %al # 绿
outb %al, %dx
movb $18, %al # 蓝(亮度18/63)
outb %al, %dx
ret
#----------------------------------------------------------------
# 通过写显存绘制一些像素点:
# 首先设置调色板索引1处的颜色为白色
# 然后通过写显存的方式,向ES:DI写入数据(PA_INDEX_WHITE)
draw_some_pixels:
# 把索引1处的颜色改为白色(63,63,63)
movw $VIDEO_PALLETE_PORT, %dx
movb $PA_INDEX_WHITE, %al
outb %al, %dx
movw $COLOR_SELECTION_PORT, %dx
movb $63, %al # 红
outb %al, %dx
movb $63, %al # 绿
outb %al, %dx
movb $63, %al # 蓝
outb %al, %dx
# 设置ES的值
movw $VIDEO_SEG_GRAPHIC, %ax
movw %ax, %es
# 设置要显示的像素位置的显存地址(目的地址)
movw $(800*5), %di # 从第五行像素开始开始
movb $PA_INDEX_WHITE, %al
movw $800, %cx # 画800个连续像素即一条直线
draw_a_pixel:
stosb
#addl $799, %edi
loop draw_a_pixel
ret
main:
movw %cx, %ax
movw %ax, %ds
movw %ax, %es
call clear_screen # 清屏
call set_video_mode_vbe_0x103 # 设置显示模式
cmpw $0, %ax
jne 1f
call set_video_mode_0x13
1:
call set_screen_bk_color # 设置背景颜色
call draw_some_pixels # 绘制像素
1:
jmp 1b
# 常量定义:
VIDEO_SEG_TEXT = 0x0e00
VIDEO_SEG_GRAPHIC = 0xa000
BUFFER_SEG = 0x800
VIDEO_PALLETE_PORT = 0x3c8
COLOR_SELECTION_PORT= 0x3c9
MODE_0x13 = 0x13
MODE_VBE_0x105 = 0x0105
MODE_VBE_0x103 = 0x0103
PA_INDEX_BACKGROUND = 0x0
PA_INDEX_WHITE = 0x1
video_mode:
.short 0
screen_x:
.short 0
screen_y:
.short 0
video_ram:
.long 0
.org 0x1fe, 0x90
.word 0xaa55
