babyos (二)——使用BIOS以及直接写显存绘制图形

注:以下程序系由相应的Intel格式汇编改编而来,略有修改,若发现bug,欢迎指正。若有问题,欢迎交流。若能帮助一二访客,幸甚。


一年前仿照Skelix 写过一个简单的内核,并命名为BabyOS。当时代码大部分用的Skelix的,终究有些遗憾,所以想趁今年寒假--工作前最后一个假期,重新实现一下BabyOS,力求尽量用自己的代码实现。所以前几天学习了一下AT&T 汇编、内联汇编及C与汇编的相互调用。下一个问题就是显示,经过许多考虑,这次准备尝试一下图形界面的系统(因为看上去更有趣些),或许有点舍本求末的嫌疑,但我写个OS kernel主要是好玩,从未想有正式应用,所以怎么好玩就怎么来。

昨晚研究了下BIOS INT 0x10显示字符,今晚决定不管有用没有先学习一下BIOS INT 0x10及实模式下写显存来显示图形的知识。

1.绘制像素

-----------------------------------------------------------------------
						INT 0x10可识别的视频图形模式
--------------------------------------------------------------------
模式			分辨率(列*行,像素)	  颜色数
6					640x200					2
0DH					320x200					16
0EH					640x350					16
0FH					640x350					2
10H					640x200					16
11H					640x480					2
12H					640x480					16
13H					320x200					256
6AH					800x600					16
-----------------------------------------------------------------------
当视频控制器处于图形模式时,INT 0x10的功能0CH在屏幕上绘制一个像素点。(功能0CH执行的相当慢)

-----------------------------------------------------------------------
						INT 0x10 功能0CH
---------------------------------------------------------------
描述:
	写像素
接受参数:
	AH			0CH
	AL			像素值
	BH			视频页
	CX			X坐标
	DX			Y坐标
返回值:
	无
注意:
	视频显示必须处于图形模式下。像素值的范围和坐标范围与当前的图形模式有关。
	如果AL的位7置位,新的像素同当前像素的内容进行异或运算。
-------------------------------------------------------------------------

示例,画线程序:
# This program draws a straight line in graphics mode.
# 2012-12-24 20:42
# [email protected]

.section .text
.global _start
.code16

_start:
	jmp		main

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

main:
	movw	%cx,	%ax
	movw	%ax,	%ds
	movw	%ax,	%es

	call	clear_screen	# 清屏

	# 设置成图形模式,0x6a为800x600, 16种颜色
	movb	$0,		%ah		# 功能号0x0
	movb	$0x6a,	%al		# 显示模式
	int		$0x10

	# 画一条直线
	movb	$0x0,	%bh		# 视频页
	movw	$300,	%dx		# y坐标
	movw	$100,	%cx		# x坐标
	movb	$0x0c,	%ah		# 功能号
	movb	$9,		%al		# 像素值(颜色)
1:	
	int		$0x10
	incw	%cx				# 下一个像素
	cmpw	$700,	%cx		# 是否到了结束位置
	jne		1b

1:
	jmp		1b

	.org	0x1fe,	0x90
	.word	0xaa55

结果:


2.图形模式用功能0x13显示字符串

# This program draws text and a straight line in graphics mode.
# 2012-12-24 20:42
# [email protected]

.section .text
.global _start
.code16

_start:
	jmp		main

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

main:
	movw	%cx,	%ax
	movw	%ax,	%ds
	movw	%ax,	%es

	call	clear_screen	# 清屏

	# 设置成图形模式,0x6a为800x600, 16种颜色
	movb	$0,		%ah		# 功能号0x0
	movb	$0x6a,	%al		# 显示模式
	int		$0x10

	# 显示文字
	movw	$msgstr,%ax
	movw	%ax,	%bp
	movw	len,	%cx
	movb	$0x13,	%ah
	movb	$0,		%al
	movb	$0x04,	%bl
	movb	$0x0,	%bh
	movb	$0x02,	%dh
	movb	$0x04,	%dl
	int		$0x10

	# 画一条直线
	movb	$0x0,	%bh		# 视频页
	movw	$300,	%dx		# y坐标
	movw	$100,	%cx		# x坐标
	movb	$0x0c,	%ah		# 功能号
	movb	$9,		%al		# 像素值(颜色)
1:	
	int		$0x10
	incw	%cx				# 下一个像素
	cmpw	$700,	%cx		# 是否到了结束位置
	jne		1b

1:
	jmp		1b

msgstr:
	.asciz	"line: start(100, 300), end(700, 300)\n"
len:
	.int	. - msgstr

	.org	0x1fe,	0x90
	.word	0xaa55

结果:


3.内存映射图形

对于内存映射图形视频模式0x13最容易使用。这时屏幕像素映射为一个字节数组,每个像素一个字节。
共有320*200个像素,因为有256种颜色,所以每个像素一个字节。左上角像素对应地址0xa0000。
模式0x13中,每个整数色彩值表示调色板的色彩表的索引。调色板中每个项都由三个独立的整数(0~63)构成,称为RGB值。调色板的第0项控制着屏幕的背景色。
有两个输出端口用于控制视频调色板:送往端口0x3c8的值表示要修改的调色板表项,送往端口0x3c9的是要修改的颜色值。
示例:
# This program draws color pixels at mode 0x13
# 2012-12-24 21:31
# [email protected]

.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

#----------------------------------------------------------------
# 设置显示模式函数
set_video_mode:
	movb	$0,			%ah			# 功能号0x0
	movb	$MODE_0X13,	%al			# 显示模式
	int		$0x10
	ret

#---------------------------------------------------------------
# 显示一些文字函数:
#	使用INT 0x10中断0x13功能,显示计算机当前工作的显示模式
draw_some_text:
	movw	$msg_str,	%bp			# ES:BP为字符串地址
	movw	msg_len,	%cx			# 显示字符数
	movb	$0x13,		%ah			# 功能号
	movb	$0,			%al			# 显示模式
	movb	$TEXT_COLOR,%bl			# 属性值
	movb	$0,			%bh			# 视频页
	movb	$TEXT_ROW,	%dh			# 显示起始行
	movb	$TEXT_COL,	%dl			# 显示起始列
	int		$0x10

	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	$(PIXEL_ROW_ST*320 + PIXEL_COL_ST),	%di
	movb	$PA_INDEX_WHITE,		%al
	movw	$PIXEL_COUNT,			%cx

draw_a_pixel:
	stosb
	addw	$5,						%di
	loop	draw_a_pixel

	ret

main:
	movw	%cx,	%ax
	movw	%ax,	%ds
	movw	%ax,	%es

	call	clear_screen		# 清屏
	call	set_video_mode		# 设置显示模式
	call	set_screen_bk_color	# 设置背景颜色
	call	draw_some_text		# 绘制字符串
	call	draw_some_pixels	# 绘制像素

1:
	jmp		1b

# 常量定义:
	VIDEO_SEG_TEXT		= 0xb800
	VIDEO_SEG_GRAPHIC	= 0xa000

	VIDEO_PALLETE_PORT	= 0x3c8
	COLOR_SELECTION_PORT= 0x3c9
	
	MODE_0X13			= 0x13

	PA_INDEX_BACKGROUND	= 0x0
	PA_INDEX_WHITE		= 0x1

	TEXT_ROW			= 0x01
	TEXT_COL			= 0x00
	TEXT_COLOR			= 0x04

	PIXEL_ROW_ST		= 100
	PIXEL_COL_ST		= 160-5*10
	PIXEL_COUNT			= 20

msg_str:
msg_mode:
	.asciz	"video mode: 0x13"
	.org	msg_mode+40,		0
msg_scr_res:
	.asciz	"screen resolution:320x200"
	.org	msg_scr_res+40,		0
msg_color_num:
	.asciz	"color num:256"
	.org	msg_color_num+40*4,	0
msg_babyos:
	.asciz	"The new Baby OS will have a GUI,but now it can only draw some pixels, haha..And merry Christmas!"
msg_len:
	.int	. - msg_str - 1

	.org	0x1fe,	0x90
	.word	0xaa55

结果:


注释:

文字是用的BIOS INT 0x10显示的,VGA的0x13模式下显示的文字为40列x25行,字符框8x8,看上去有点丑,以后再研究下超级VGA(SVGA)吧~


你可能感兴趣的:(BabyOS,BIOS,bios,INT,0x10,os,汇编,直接写显存)