导读:
  保护模式中不依赖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() */ 
 
  pokeb(0xB800, 0, '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 
 
   /* _farpokeb() */ 
  
  #include 
  
    /* _dos_ds */ 
   
  _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() */ 
       
  movedata(0xB800, 80 * 2, 
       
  0xB800, 0, 
       
  80 * (25 - 1) * 2); 
       
  DJGPP 代码 scroll 80x25 display up one line (color emulation): 
       
  #include 
       
         /* movedata() */ 
        
  #include 
        
          /* _dos_ds */ 
         
  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 crtc_adr = 0x3D4; /* 0x3B4 for monochrome */ 
           
  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 
           
             /* outportb() */ 
            
  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 
            
              /* atoi() */ 
             
  #include 
             
               /* printf() */ 
              
  //#include "../port.c" /* inportb(), peekw() */ 
              
  /********************************* TURBO C **********************************/ 
              
  #if defined(__TURBOC__) 
              
  #include 
              
                /* inportb(), peek() */ 
               
  #define peekw(S,O) peek(S,O) 
               
  /********************************* DJGPP ************************************/ 
               
  #elif defined(__DJGPP__) 
               
  #include 
               
                 /* _CRT0_FLAG_LOCK_MEMORY */ 
                
  #include 
                
                  /* inportb() */ 
                 
  //#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 
                 
                   /* __djgpp_conventional_base, __djgpp_nearptr_enable() */ 
                  
  #include 
                  
                    /* printf() */ 
                   
  #include 
                   
                     /* _CRT0_FLAG_NEARPTR, _crt0_startup_flags */ 
                    
  #define peekw(S,O) *(unsigned short *)(16uL * (S) + (O) + / 
                    
  __djgpp_conventional_base) 
                    
  /* far pointers */ 
                    
  #else 
                    
  #include 
                    
                      /* _farpeekw() */ 
                     
  #include 
                     
                       /* _dos_ds */ 
                      
  #define peekw(S,O) _farpeekw(_dos_ds, 16uL * (S) + (O)) 
                      
  #endif 
                      
  /******************************** WATCOM C **********************************/ 
                      
  #elif defined(__WATCOMC__) 
                      
  #include 
                      
                        /* inp() */ 
                       
  #if defined(__386__) 
                       
  /* CauseWay DOS extender only */ 
                       
  #define peekw(S,O) *(unsigned short *)(16uL * (S) + (O)) 
                       
  #else 
                       
  #include 
                       
                         /* MK_FP() */ 
                        
  #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, 2, 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; 
                        
  }