保护模式中不依赖bios才是重点.
原理: 显示到屏幕上的字母和符号统统存在于一段叫做 framebuffer 的显存中. 至于其出现于内存的物理地址,要看VGA板的工作模式. VGA
的两种模式是: monochrome (单色?) emulation,或者color emulation.
emulation---|--framebuffer linear address--|--framebuffer real-mode address--|--I/O address of CRTC
color-------|--B8000h----------------------|--B800h:0000 --------------------|--3D4h
monochrome--|--B0000h----------------------|--B000h:0000 --------------------|--3B4h
CRTC 是VGA的一个功能单元,待会再讨论有关CRTC的东东. 一般来说,应该是 color emulation,记得大一的时候我们的实验室倒是有几台386
上有 monochrome 的古董.
备注1 的c代码可以检测VGA是处于那种工作模式.
如果能够看懂,拿来用用应该不成问题.
不会弄代码的格式,大家拷贝后自己整理吧.
这里给一个简单的.
/* video card mono/colour detection by Dark Fiber
* returns 0=mono,1=colour
*/
int detect_video_type(void)
{
int rc;
char c=(*(USHORT*)0x410&0x30
/* C can be 0x00 or 0x20 for colour,0x30 for mono
if(c==0x30)
rc=0; // mono
else
rc=1; // colour
return rc;
}
字符及属性
在framebuffer中的每个字符都占用两个字节: ASCII 码值在地址 N 的话,N+1 就是他的属性字节.
属性字节的各个位的含义如下.
b7 ----- 闪烁
b6:b4 -- 背景色(0-7)
b3:b0 -- 前景色(0-15)
color value -- color -- color value -- color
0 ------------ 黑色------ 8 ---------- 暗灰
1 ------------ 蓝色------ 9 ---------- 亮蓝
2 ------------ green ---- 10 --------- bright green
3 ------------ cyan ----- 11 --------- bright cyan
4 ------------ red ------ 12 --------- pink
5 ------------ magenta -- 13 --------- bright magenta
6 ------------ brown ---- 14 --------- yellow
7 ------------ white ---- 15 --------- bright white
假定使用color模式:
Turbo C 代码的例子(cpu 工作于 16-bit real mode),把白色的 'H' 以蓝色背景放到屏幕左上角.
#include
pokeb(0xB800,'H');
pokeb(0xB800,1,0x1F);
NASM 汇编中这么写(16-bit real mode):
mov bx,0B800h
mov es,bx
mov byte [es:0],'H'
mov byte [es:1],1Fh
DJGPP 代码(32-bit pmode),有所不同. 把黄的 'H' 以红色背景放到屏幕右上角.因为处于保护模式,我们使用far指针.
#include
#include
_farpokeb(_dos_ds,0xB8000 + 79 * 2 + 0,'*');
_farpokeb(_dos_ds,0xB8000 + 79 * 2 + 1,0x4E);
非得用 near 指针?
#include
#include
#include
unsigned char *fb;
if(!(_crt0_startup_flags &_CRT0_FLAG_NEARPTR))
{ if(!__djgpp_nearptr_enable())
{ printf("Could not enable nearptr access/n");
return -1; } } /* probably Windows NT DOS Box */
fb = (unsigned char *)0xB8000 + __djgpp_conventional_base;
fb[79 * 2 + 0] = '*';
fb[79 * 2 + 1] = 0x4E;
Scrolling(滚屏)
BIOS 滚屏就算了吧?!
如果使用 movedata(),也算简单. 与memcpy() 不同的地方在于movedata对于源和目的都使用 far指针.
Turbo C 代码: 在 80x25 的方式下上滚一行(color emulation):
#include
movedata(0xB800,80 * 2,
0xB800,
80 * (25 - 1) * 2);
DJGPP 代码 scroll 80x25 display up one line (color emulation):
#include
#include
movedata(_dos_ds,0xB8000L + 80 * 2,
_dos_ds,0xB8000L,
80 * (25 - 1) * 2);
使用 movedata() 的的话,如果 src
hardware scrolling
硬件来做滚动就比较快了. 把VGA配置成使用不同地址的framebuffer 就可以实现快速滚屏. CRTC 寄存器 12 号13号 分别包含framebuffer
相对于B0000h,B8000h,or A0000h 之偏移(offset) 的MSB 与 LSB .
/* scroll up one line */
#include
unsigned short offset = 80;
/* the CRTC index is at crtc_adr + 0
select register 12 */
outportb(crtc_adr + 0,12);
/* the selected CRTC register appears at crtc_adr + 1 */
outportb(crtc_adr + 1,offset >>8);
outportb(crtc_adr + 0,13);
outportb(crtc_adr + 1,offset &0xFF);
硬件滚屏的缺陷在于不能够持续无限的滚动. 因为最终 framebuffer 会超过 video memory 的上(下)限.
可以用作 framebuffer 的那段内存可以分成几个虚拟控制台(virtual consoles (VCs)). 32K 的 video memory 可以被分成8 个80x25的VCs.
console 译作控制台我认为不妥,这里的console无非就是虚拟的几个屏幕.上面的代码就可以选择把那个虚拟屏呈现给用户. (Linux 的 VCs
使用了不同的管理方法,我不知道.)
Moving the cursor
CRTC 寄存器14号和 15 号,包含光标位置的 MSB LSB . 光标的位置用相对B8000h 或 B0000h的偏移来表示.
#include
unsigned short crtc_adr = 0x3D4; /* 0x3B4 for monochrome */
unsigned short offset;
unsigned short x = 20,y = 3;
offset = x + y * 80; /* 80 characters per line */
outportb(crtc_adr + 0,14); /* MSB of offset to CRTC reg 14 */
outportb(crtc_adr + 1,offset >>8);
outportb(crtc_adr + 0,15); /* LSB of offset to CRTC reg 15 */
outportb(crtc_adr + 1,offset);
[i] 不要告诉我,你不知道outportb 那里去找! [/i]
推荐网站
pc-hardware
VGADOC
一个vag包
execpc的控制台代码
备注1
/*****************************************************************************
Determines if VGA board is set for monochrome or color emulation.
Uses 3 different algorithms.
This code is public domain (no copyright).
You can do whatever you want with it.
*****************************************************************************/
#include
#include
//#include "../port.c" /* inportb(),peekw() */
/********************************* TURBO C **********************************/
#if defined(__TURBOC__)
#include
#define peekw(S,O) peek(S,O)
/********************************* DJGPP ************************************/
#elif defined(__DJGPP__)
#include
#include
//#define NEARPTR 1
/* near pointers; not supported in Windows NT/2k/XP DOS Box
Must call __djgpp_nearptr_enable() before using these functions */
#if defined(NEARPTR)
#include
#include
#include
#define peekw(S,O) *(unsigned short *)(16uL * (S) + (O) + /
__djgpp_conventional_base)
/* far pointers */
#else
#include
#include
#define peekw(S,O) _farpeekw(_dos_ds,16uL * (S) + (O))
#endif
/******************************** WATCOM C **********************************/
#elif defined(__WATCOMC__)
#include
#if defined(__386__)
/* CauseWay DOS extender only */
#define peekw(S,O) *(unsigned short *)(16uL * (S) + (O))
#else
#include
#define peekw(S,O) *(unsigned short far *)MK_FP(S,O)
#endif
#define inportb(P) inp(P)
#else
#error Not Turbo C,not DJGPP,not Watcom C. Sorry.
#endif
static unsigned short g_crtc_base_adr;
/*****************************************************************************
Pentium 486 Bochs
method color color (color) mono
------ ------- ----- ------- -------
1 pass pass pass UNTESTED
2 pass pass pass UNTESTED
3 pass pass pass UNTESTED
*****************************************************************************/
int main(int arg_c,char *arg_v[])
{
int method;
#if defined(__DJGPP__)&&defined(NEARPTR)
if(!(_crt0_startup_flags &_CRT0_FLAG_NEARPTR))
{
if(!__djgpp_nearptr_enable())
{
printf("Could not enable nearptr access "
"(Windows NT/2k/XP?)/nUn-define NEARPTR "
"in source code and re-compile/n");
return 1;
}
}
#endif
if(arg_c <2)
{
printf("attempt to detect monochrome/color VGA emulation "
"using one of three methods/n"
"specify 1,2,or 3 on the command line/n");
return 1;
}
method = atoi(arg_v[1]);
switch(method)
{
case 1:
/* this method cobbled from info in Finn Thoegersen's VGADOC4 */
#define VGA_MISC_READ 0x3CC
if((inportb(VGA_MISC_READ) &0x01) == 0)
g_crtc_base_adr = 0x3B4; /* mono */
else
g_crtc_base_adr = 0x3D4; /* color */
break;
case 2:
/* I forgot where this came from:
"The word at low memory address 0040:0063 (or 0000:0463) contains the
I/O address of the CRTC which can be used to determine whether the video
system is colour or monochrome. A value of 3B4 hex indicates monochrome."
(I presume 3D4 hex means color; my Pentium system has that value at 0463.) */
g_crtc_base_adr = peekw(0x40,0x63);
break;
case 3:
/* Dark Fiber's method,from the OS FAQ
[url=www.mega-tokyo.com/os]http://www.mega-tokyo.com/os[/url]
from MEMORY.LST of Ralf Brown's Interrupt List
0040:0010 is Installed Hardware word,b5:b4 indicate video hardware:
00 EGA,VGA,PGA,or other with on-board video BIOS
01 40x25 CGA color
10 80x25 CGA color
11 80x25 mono text
whoa,this won't work with DJGPP -- OK,I will make a slight change here
if((*(unsigned short *)0x410 &30) == 0x30) */
if((peekw(0x40,0x10) &30) == 0x30)
g_crtc_base_adr = 0x3B4; /* mono */
else
g_crtc_base_adr = 0x3D4; /* color */
break;
default:
printf("didn't find 1,or 3 on the command line,sorry/n");
return 1;
}
/* what've we got? */
if(g_crtc_base_adr <0x3C0)
printf("MONOCHROME emulation detected/n");
else
printf("color emulation detected/n");
return 0;
}
本文转自
http://www.cnblogs.com/huqingyu/archive/2005/02/17/105365.html