zoukankan      html  css  js  c++  java
  • [ExpOS]开发经验(2)保护模式中不依赖bios

    保护模式中不依赖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 <dos.h> /* 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 <sys/farptr.h> /* _farpokeb() */
    #include <go32.h> /* _dos_ds */
    _farpokeb(_dos_ds, 0xB8000 + 79 * 2 + 0, '*');
    _farpokeb(_dos_ds, 0xB8000 + 79 * 2 + 1, 0x4E);


    非得用 near 指针?

    #include <sys/nearptr.h>
    #include <crt0.h>
    #include <stdio.h>

    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 <string.h> /* movedata() */
    movedata(0xB800, 80 * 2,
    0xB800, 0,
    80 * (25 - 1) * 2);


    DJGPP 代码 scroll 80x25 display up one line (color emulation):

    #include <string.h> /* movedata() */
    #include <go32.h> /* _dos_ds */
    movedata(_dos_ds, 0xB8000L + 80 * 2,
    _dos_ds, 0xB8000L,
    80 * (25 - 1) * 2);


    使用 movedata() 的的话,如果 src < dst, 比如下滚, 可能不正确. 使用near 指针最好了, memmove() 保证任何滚动都能正确的工

    作.


    hardware scrolling

    硬件来做滚动就比较快了. 把VGA配置成使用不同地址的framebuffer 就可以实现快速滚屏. CRTC 寄存器 12 号13号 分别包含framebuffer

    相对于B0000h, B8000h, or A0000h 之偏移(offset) 的MSB 与 LSB .


    /* scroll up one line */
    #include <dos.h> /* outportb() */
    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 <dos.h> /* 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 <stdlib.h> /* atoi() */
    #include <stdio.h> /* printf() */
    //#include "../port.c" /* inportb(), peekw() */

    /********************************* TURBO C **********************************/
    #if defined(__TURBOC__)
    #include <dos.h> /* inportb(), peek() */

    #define peekw(S,O) peek(S,O)

    /********************************* DJGPP ************************************/
    #elif defined(__DJGPP__)
    #include <crt0.h> /* _CRT0_FLAG_LOCK_MEMORY */
    #include <dos.h> /* 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 <sys/nearptr.h> /* __djgpp_conventional_base, __djgpp_nearptr_enable() */
    #include <stdio.h> /* printf() */
    #include <crt0.h> /* _CRT0_FLAG_NEARPTR, _crt0_startup_flags */

    #define peekw(S,O) *(unsigned short *)(16uL * (S) + (O) + \
    __djgpp_conventional_base)
    /* far pointers */
    #else
    #include <sys/farptr.h> /* _farpeekw() */
    #include <go32.h> /* _dos_ds */

    #define peekw(S,O) _farpeekw(_dos_ds, 16uL * (S) + (O))
    #endif

    /******************************** WATCOM C **********************************/
    #elif defined(__WATCOMC__)
    #include <conio.h> /* inp() */

    #if defined(__386__)
    /* CauseWay DOS extender only */
    #define peekw(S,O) *(unsigned short *)(16uL * (S) + (O))
    #else
    #include <dos.h> /* 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;
    }
  • 相关阅读:
    虚拟机调用本机数据库发生错误
    VS2010添加虚拟机发布的WebService引用
    IIS发布错误及解决
    JSON.parse()与JSON.stringify()的区别
    数组去重
    React性能优化 PureComponent
    JS逻辑题 技术点: 1). 变量提升 2). 函数提升 3). 预处理 4). 调用顺序
    React组件间信息传递方式
    css/css3实现未知宽高元素的垂直居中和水平居中
    关于setTimeout的一个逻辑题
  • 原文地址:https://www.cnblogs.com/huqingyu/p/105365.html
Copyright © 2011-2022 走看看