操作系统-内核中的屏幕打印(上)

操作系统-内核中的屏幕打印(上)

一.屏幕的打印-使用C语言设计一组打印函数,为后续进一步开发内核功能做准备

内核中的屏幕打印模块
操作系统-内核中的屏幕打印(上)
这里有三个不同的入口,在screen.模块中是提供保护模式下在屏幕下打印文本的功能,该模块的具体实现是
操作系统-内核中的屏幕打印(上)
如图所示有7个接口需要设计,最重要的一个函数为void PrintChar(char c)-打印字符串的函数,由此总结了以上七个函数接口的关系,如下图所示
操作系统-内核中的屏幕打印(上)
如图所示中心函数就为上文所说的函数,由此可以得出上图的关系

二.void PrintChar(char c)函数的实现

可以得出最重要的函数为void PrintChar(char c),所以来实现该函数
1.功能定义:在屏幕上打印一个字符
2.实现原理:直接在显存对应的位置写入数据
操作系统-内核中的屏幕打印(上)
由上图可知,写入数据的部分可以用四行汇编的语言来实现,但是通过之前的学习,应该是C语言来实现内核开发的,原因是在屏幕打印字符串使用汇编语言较简单,同时汇编的指令有时是必须由汇编语言来实现,之后在C语言调用。
三.语言中的内嵌汇编-内嵌汇编的语法格式
操作系统-内核中的屏幕打印(上)
代码示例
操作系统-内核中的屏幕打印(上)
从代码示例可以看到该函数是C语言来编写的,但是通过asm volatile关键字来实现汇编语言的内嵌,在这里需要注意的是因为使用GCC编译器,所以在内嵌汇编时使用的时AT&T汇编格式(与nasm汇编格式不同)

三.屏幕打印的实现

1.首先创建screen.c与screen.h的文件,同时在makefile中进行改动,同时在编译后需要将编译之后的文件保存在后面,所以改代的地方如下
操作系统-内核中的屏幕打印(上)操作系统-内核中的屏幕打印(上)
2.screen.h头文件的实现


#ifndef SCREEN_H
#define SCREEN_H

#define SCREEN_WIDTH    80//定义的宽与高-横坐标与纵坐标
#define SCREEN_HEIGHT   25

typedef enum//颜色枚举类型的定义
{
    SCREEN_GRAY   = 0x07,
    SCREEN_BLUE   = 0x09,
    SCREEN_GREEN  = 0x0A,
    SCREEN_RED    = 0x0C,
    SCREEN_YELLOW = 0x0E,
    SCREEN_WHITE  = 0x0F
} PrintColor;
//接口的声明
void ClearScreen();
int  SetPrintPos(short w, short h);
void SetPrintColor(PrintColor c);
int PrintChar(char c);
int PrintString(const char* s);
int PrintIntDec(int n);
int PrintIntHex(unsigned int n);

#endif

3.screen.c的实现-int SetPrintPos与void SetPrintColor

static int  gPosW = 0;
static int  gPosH = 0;//全局变量的定义
static char gColor = SCREEN_WHITE;

int SetPrintPos(short w, short h)
{
    int ret = 0;

    if( ret = ((0 <= w) && (w <= SCREEN_WIDTH) && (0 <= h) && (h <= SCREEN_HEIGHT)) )
    {
        unsigned short bx = SCREEN_WIDTH * h + w;

        gPosW = w;
        gPosH = h;

        asm volatile(
            "movw %0,      %%bx\n"
            "movw $0x03D4, %%dx\n"
            "movb $0x0E,   %%al\n"
            "outb %%al,    %%dx\n"
            "movw $0x03D5, %%dx\n"
            "movb %%bh,    %%al\n"
            "outb %%al,    %%dx\n"
            "movw $0x03D4, %%dx\n"
            "movb $0x0F,   %%al\n"
            "outb %%al,    %%dx\n"
            "movw $0x03D5, %%dx\n"
            "movb %%bl,    %%al\n"
            "outb %%al,    %%dx\n"
            :
            : "r"(bx)
            : "ax", "bx", "dx"
        );
    }

    return ret;
}

void SetPrintColor(PrintColor c)
{
    gColor = c;
}

4.PrintChar函数的实现

int PrintChar(char c)
{
    int ret = 0;

    if( (c == '\n') || (c == '\r') )//需要注意这两个字符,当出现这俩个时换行,不进行打印
    {
        ret = SetPrintPos(0, gPosH + 1);//重新换行
    } 
    else
    {
        int pw = gPosW;
        int ph = gPosH;

        if( (0 <= pw) && (pw <= SCREEN_WIDTH) && (0 <= ph) && (ph <= SCREEN_HEIGHT) )
        {
            int edi = (SCREEN_WIDTH * ph + pw) * 2;//位置的确定
            char ah = gColor;//颜色的确定
            char al = c;//具体打印的字符
            //汇编的嵌入 l四个字节,b为一个字节,w为俩个字节
            asm volatile(
               "movl %0,   %%edi\n"
               "movb %1,   %%ah\n"
               "movb %2,   %%al\n"
               "movw %%ax, %%gs:(%%edi)"
               "\n"
               :
               : "r"(edi), "r"(ah), "r"(al)
               : "ax", "edi"
            );

            pw++;

            if( pw == SCREEN_WIDTH )
            {
                pw = 0;
                ph = ph + 1;
            }

            ret = 1;
        }

        SetPrintPos(pw, ph);
    }

    return ret;
}

5.需要将loader.asm进行设置,因为是在32位的保护模式下运行的,选择子也需要改动
操作系统-内核中的屏幕打印(上)操作系统-内核中的屏幕打印(上)
6.PrintString的实现
实现方式-循环调用PrintChar直到遇到0结束符
int PrintIntHex的实现
实现方式-将参数n转换为对应的16进制数字字符串,调用PrintString打印转换得到的字符串

猜你喜欢

转载自blog.51cto.com/13475106/2551064