zoukankan      html  css  js  c++  java
  • 自制操作系统Antz(9)——实现内核 (下) 实现图形化界面

    Antz系统更新地址: https://www.cnblogs.com/LexMoon/category/1262287.html

    Linux内核源码分析地址:https://www.cnblogs.com/LexMoon/category/1267413.html

    Github项目地址:https://github.com/CasterWx/AntzOS

      在前几天的任务中,我们已经简单实现了MBR,直接操作显示器和硬盘操作来加载其他扇区的程序,如今已经可以进入保护模式了,并且编写了我们自己的内核程序,接下来我们要完成界面的图形化,在显示屏中显示鼠标字符桌面,并显示一个终端界面。

      效果如下:

      

      现在我们已经简单实现了半终端半桌面的显示,虽然说非常Low,但也是Antz的一大步了。


    1.  封装函数

      在前几天我们已经说明了屏幕显示的原理,也就是在显存固定位置写入数据,这对于显卡来说就是像素点。

      如果屏幕显示原理不清楚的可以参考第三天的:http://www.cnblogs.com/LexMoon/p/antz03.html

      为了方便实现图像化,我将显卡写入的代码使用C语言封装成了函数,颜色定义为数组。

     1     static unsigned char table_rgb[16 * 3] = {
     2         0x00, 0x00, 0x00,    /*  0:黑 */
     3         0xff, 0x00, 0x00,    /*  1:梁红 */
     4       ....
     5         0x84, 0x00, 0x84,    /* 13:暗紫 */
     6         0x00, 0x84, 0x84,    /* 14:浅暗蓝 */
     7         0x84, 0x84, 0x84    /* 15:暗灰 */
     8     };
    View Code

       这个数组对应了我们要显示的颜色RGB值,将数组下标定义对应的枚举值,可以更加方便使用。

      要在显示器显示字体,可以使用putfont8_asc ()函数,它调用了putfont8()函数:   

     1 void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s)
     2 {
     3     extern char hankaku[4096];
     4     /* C语言中,字符串都是以0x00结尾 */
     5     for (; *s != 0x00; s++) {
     6         putfont8(vram, xsize, x, y, c, hankaku + *s * 16);
     7         x += 8;
     8     }
     9     return;
    10 }
    View Code

      鼠标指针实现是将其呈图形化的写入,函数init_mouse_cursor8():

     1 void init_mouse_cursor8(char *mouse, char bc)
     2 
     3 {
     4     static char cursor[16][16] = {
     5      
     6     };
     7     int x, y;
     8 
     9     for (y = 0; y < 16; y++) {
    10         for (x = 0; x < 16; x++) {
    11             if (cursor[y][x] == '*') {
    12                 mouse[y * 16 + x] = COL8_000000;
    13             }
    14             if (cursor[y][x] == 'O') {
    15                 mouse[y * 16 + x] = COL8_FFFFFF;
    16             }
    17             if (cursor[y][x] == '.') {
    18                 mouse[y * 16 + x] = bc;
    19             }
    20         }
    21     }
    22     return;
    23 }
    View Code

      


    2 . GDT与lDT

      GDT是在32位时16位寻址模式的改造,在学习汇编时,我们所说的 段:偏移量(段x16+偏移量)寻址方式已经不能使用了,所以厂商们使用了GDT,在不改变段寄存器位数的情况下,完成了32位段寻址,就是利用GDT。

    (1)全局描述符表GDT(Global Descriptor Table)

      在整个系统中,全局描述符表GDT只有一张(一个处理器对应一个GDT),GDT可以被放在内存的任何位置,但CPU必须知道GDT的入口,也就是基地址放在哪里,Intel的设计者门提供了一个寄存器GDTR用来存放GDT的入口地址,程序员将GDT设定在内存中某个位置之后,可以通过LGDT指令将GDT的入口地址装入此寄存器,从此以后,CPU就根据此寄存器中的内容作为GDT的入口来访问GDT了。GDTR中存放的是GDT在内存中的基地址和其表长界限。

      基地址指定GDT表中字节0在线性地址空间中的地址,表长度指明GDT表的字节长度值。指令LGDT和SGDT分别用于加载和保存GDTR寄存器的内容。在机器刚加电或处理器复位后,基地址被默认地设置为0,而长度值被设置成0xFFFF。在保护模式初始化过程中必须给GDTR加载一个新值。

    (2)段选择子(Selector)

      由GDTR访问全局描述符表是通过“段选择子”(实模式下的段寄存器)来完成的。段选择子是一个16位的寄存器(同实模式下的段寄存器相同)

      段选择子包括三部分:描述符索引(index)、TI、请求特权级(RPL)。他的index(描述符索引)部分表示所需要的段的描述符在描述符表的位置,由这个位置再根据在GDTR中存储的描述符表基址就可以找到相应的描述符。然后用描述符表中的段基址加上逻辑地址(SEL:OFFSET)的OFFSET就可以转换成线性地址,段选择子中的TI值只有一位0或1,0代表选择子是在GDT选择,1代表选择子是在LDT选择。请求特权级(RPL)则代表选择子的特权级,共有4个特权级(0级、1级、2级、3级)。

      关于特权级的说明:任务中的每一个段都有一个特定的级别。每当一个程序试图访问某一个段时,就将该程序所拥有的特权级与要访问的特权级进行比较,以决定能否访问该段。系统约定,CPU只能访问同一特权级或级别较低特权级的段。

      例如给出逻辑地址:21h:12345678h转换为线性地址

      a. 选择子SEL=21h=0000000000100 0 01b 他代表的意思是:选择子的index=4即100b选择GDT中的第4个描述符;TI=0代表选择子是在GDT选择;左后的01b代表特权级RPL=1

      b. OFFSET=12345678h若此时GDT第四个描述符中描述的段基址(Base)为11111111h,则线性地址=11111111h+12345678h=23456789h

    (3)局部描述符表LDT(Local Descriptor Table)

      局部描述符表可以有若干张,每个任务可以有一张。我们可以这样理解GDT和LDT:GDT为一级描述符表,LDT为二级描述符表。

        

      关于GDT于IDT初始化的代码,它们可以实现鼠标的移动,现在我还没有去写它,此次的任务只是显示。

      最新的Antz系统镜像和代码已经上传到我的github了,这里只列举出剩余的主要代码。

    #include <stdio.h>
    struct BOOTINFO {
        char cyls, leds, vmode, reserve;
        short scrnx, scrny;
        char *vram;
    };
    
    struct SEGMENT_DESCRIPTOR {
        short limit_low, base_low;
        char base_mid, access_right;
        char limit_high, base_high;
    };
    
    struct GATE_DESCRIPTOR {
        short offset_low, selector;
        char dw_count, access_right;
        short offset_high;
    };
    
    void init_gdtidt(void);
    void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar);
    void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar);
    void load_gdtr(int limit, int addr);
    void load_idtr(int limit, int addr);
    
    void HariMain(void)
    {
        struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;
        char s[40], mcursor[256];
        int mx, my;
    
        init_palette();
        init_screen(binfo->vram, binfo->scrnx, binfo->scrny);
    
    
        mx = (binfo->scrnx - 16) / 2; /* 计算画面的中心坐标*/
        my = (binfo->scrny - 28 - 16) / 2;
        init_mouse_cursor8(mcursor, COL8_00FFFF);
        putblock8_8(binfo->vram, binfo->scrnx, 16, 16, mx+20, my, mcursor, 16);
        for (;;) {
            io_hlt();
        }
    }
    
    void set_palette(int start, int end, unsigned char *rgb)
    {
        int i, eflags;
        eflags = io_load_eflags();    /* 记录中断许可标志的值 */
        io_cli();                     /* 将中断许可标志置为0,禁止中断 */
        io_out8(0x03c8, start);
        for (i = start; i <= end; i++) {
            io_out8(0x03c9, rgb[0] / 4);
            io_out8(0x03c9, rgb[1] / 4);
            io_out8(0x03c9, rgb[2] / 4);
            rgb += 3;
        }
        io_store_eflags(eflags);    /* 复原中断许可标志 */
        return;
    }
    
    void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
    {
        int x, y;
        for (y = y0; y <= y1; y++) {
            for (x = x0; x <= x1; x++)
                vram[y * xsize + x] = c;
        }
        return;
    }
    
    void init_screen(char *vram, int x, int y)
    {
        boxfill8(vram, x, COL8_00FFFF,  0,     0,      x,         y);
        boxfill8(vram, x, COL8_C6C6C6,  0,     0,     x/2,   y);
        boxfill8(vram, x, COL8_000000,  3,     15,     x/2-3, y-3);
    
        boxfill8(vram, x, COL8_008400,  165    ,     30,     215,     40);
        boxfill8(vram, x, COL8_008400,  265    ,     30,     315,     40);
    
        boxfill8(vram, x, COL8_008400,  190    ,     60,     200,     70);
        boxfill8(vram, x, COL8_008400,  280    ,     60,     290,     70);
    
        boxfill8(vram, x, COL8_008400,  235    ,     65,     245,     100);
    
        boxfill8(vram, x, COL8_008400,  235-15    ,     65+40,     245-15,     85+30);
        boxfill8(vram, x, COL8_008400,  235    ,     65+40,     245,     85+30);
        boxfill8(vram, x, COL8_008400,  235+15    ,     65+40,     245+15,     85+30);
    
        boxfill8(vram, x, COL8_008400,  200    ,     130,     280,     140);
        boxfill8(vram, x, COL8_008400,  200    ,     130,     210,     160);
        boxfill8(vram, x, COL8_008400,  270    ,     130,     280,     160);
        boxfill8(vram, x, COL8_008400,  200    ,     150,     280,     160);
    
        return;
    }
    
    void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
    {
        int i;
        char *p, d /* data */;
        for (i = 0; i < 16; i++) {
            p = vram + (y + i) * xsize + x;
            d = font[i];
            if ((d & 0x80) != 0) { p[0] = c; }
            if ((d & 0x40) != 0) { p[1] = c; }
            if ((d & 0x10) != 0) { p[3] = c; }
            if ((d & 0x20) != 0) { p[2] = c; }
            if ((d & 0x08) != 0) { p[4] = c; }
            if ((d & 0x04) != 0) { p[5] = c; }
            if ((d & 0x02) != 0) { p[6] = c; }
            if ((d & 0x01) != 0) { p[7] = c; }
        }
        return;
    }
    
    void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s)
    {
        extern char hankaku[4096];
        /* C语言中,字符串都是以0x00结尾 */
        for (; *s != 0x00; s++) {
            putfont8(vram, xsize, x, y, c, hankaku + *s * 16);
            x += 8;
        }
        return;
    }
    
    void init_mouse_cursor8(char *mouse, char bc)
    /* マウスカーソルを準備(16x16) */
    {
        static char cursor[16][16] = {
        //鼠标图形
        };
        int x, y;
    
        for (y = 0; y < 16; y++) {
            for (x = 0; x < 16; x++) {
                if (cursor[y][x] == '*') {
                    mouse[y * 16 + x] = COL8_000000;
                }
                if (cursor[y][x] == 'O') {
                    mouse[y * 16 + x] = COL8_FFFFFF;
                }
                if (cursor[y][x] == '.') {
                    mouse[y * 16 + x] = bc;
                }
            }
        }
        return;
    }
    
    void putblock8_8(char *vram, int vxsize, int pxsize,
        int pysize, int px0, int py0, char *buf, int bxsize)
    {
        int x, y;
        for (y = 0; y < pysize; y++) {
            for (x = 0; x < pxsize; x++) {
                vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x];
            }
        }
        return;
    }
  • 相关阅读:
    The formatter threw an exception while trying to deserialize the message in WCF
    通过Web Deploy方式部署WCF
    The Managed Metadata Service or Connection is currently not available
    How to create Managed Metadata Column
    冒泡算法
    asp.net core 实战项目(一)——ef core的使用
    Vue学习笔记入门篇——安装及常用指令介绍
    Vue学习笔记入门篇——数据及DOM
    Vue学习笔记目录
    Chart.js在Laravel项目中的应用
  • 原文地址:https://www.cnblogs.com/LexMoon/p/antz09.html
Copyright © 2011-2022 走看看