30天自制操作系统-5

发布时间:2019-08-07 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了30天自制操作系统-5脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

我记得我以前学习的时候卡在了,这一章,有些时间。我也会尽量在作者之外描述出来,尽量易懂些。

还记得以前保存的屏幕分辨率信息,我们是存在了内存里面,而在昨天我们直接写320这样的数字,万一等到后来调分辨率,就尴尬了。所以我们来读取我们之前写的吧。

    binfo_scrnx = (short *) 0x0ff4;
    binfo_scrny = (short *) 0x0ff6;
    binfo_vram = (int *) 0x0ff8;
    xsize = *binfo_scrnx;
    ysize = *binfo_scrny;
    vram = (char *) *binfo_vram;

由于之前就是保存在这些地址的,主要是注意一下类型,是short类型的也就是一个word

结构体的导入

struct BOOTINFO {
    char cyls, leds, vmode, reserve;
    short scrnx, scrny;
    char *vram;
};

struct BOOTINFO *binfo;

inIT_palette();
binfo = (struct BOOTINFO *) 0x0ff0;
xsize = (*binfo).scrnx;
ysize = (*binfo).scrny;
vram = (*binfo).vram;

注意看一下我们定义的结构体,都是由一定顺序的,是因为我们在对这个结构体进行初始化的时候是按照0x0ff0来的,会依次向后读取内存数据来填充结构体变量值

指针玩儿法

init_screen(binfo->vram, binfo->scrnx, binfo->scrny);

因为会常常(*binfo).scrnx 这里给了一个语法糖,这样的情况下用->就好啦。

显示一个字符

之前显示过字符,但是是调用BIOS自带的功能来调用的。既然能填写像素的方式画出一个巨型,举一反三嘛,我们想画啥都可以,当然也可以画一个字出来。

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 &amp; 0x80) != 0) { p[0] = c; }
        if ((d & 0x40) != 0) { p[1] = c; }
        if ((d & 0x20) != 0) { p[2] = c; }
        if ((d & 0X10) != 0) { p[3] = 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;
}

来看下代码,首先遍历16此,是因为十六行。 然后d分别与0x80,0x40,0x20..等分别进行与操作,这些数这样看,看不出来,如果你写出二进制你就看的比较明白了 0x80->1000 000 0x40->0100 0000 可以发现其实是二进制挨着往右移动后的值。然后来说说怎么控制的坐标,首先vram是显卡地址开始,然后(y + i)控制的是每行的位置, * xsize的原因是一行又xsize度,x上之后则定位到具体某一行上,最后加x的原因就是,在该行,以x的位置开始显示字符。

读取字符库

当然像上面那样写,成功的显示了字符,通常讲,字符库会有很多很多,那么多艺设计,那么多种类的语言,需要别人帮助我们去设计,所以我们从外部来读取最好。所以接下来读取一个字符库会。

首先的是需要把这个txt文件编译到我们的操作系统中去,作者使用的是makefont工具,他解释道,其实就是定义了一个tag的感觉,叫做_hankanku 这个,然后这个TAG下定义了那4096个字节。来细看一下,makefile里面的文件,

30天自制操作系统-5

可以看到会先把我们的hankaku.txt制作成kankaku.obj,并且在48行,传入了一个参数_hankaku(这个参数就是拿来给我们在c语言中用的标记,当然你可以改成其他的名字,但是一定不能把 ‘_’ 去掉,因为这是链接的意思),有了这个hankaku.obj,我们会把他做成bootpack.bim。然后是bootpack.hrb,最后是haribote.Sys,再写入待haribote.img中去。
所以我们在C语言中可以名正言顺的来写这个变量啦。

    extern char hankaku[4096];
    putfont8(binfo->vram, binfo->scrnx,  8, 8, COL8_FFFFFF, hankaku + 'A' * 16);
    putfont8(binfo->vram, binfo->scrnx, 16, 8, COL8_FFFFFF, hankaku + 'B' * 16);
    putfont8(binfo->vram, binfo->scrnx, 24, 8, COL8_FFFFFF, hankaku + 'C' * 16);
    putfont8(binfo->vram, binfo->scrnx, 40, 8, COL8_FFFFFF, hankaku + '1' * 16);
    putfont8(binfo->vram, binfo->scrnx, 48, 8, COL8_FFFFFF, hankaku + '2' * 16);
    putfont8(binfo->vram, binfo->scrnx, 56, 8, COL8_FFFFFF, hankaku + '3' * 16);

拿到这个字符库变量后就好办啦,接下来就是对他进行读取,由于C语言中会把'A'解释位0x41所以作者直接就写成了 hankaku + 'A',最后X16的原因就是一个字符16个字节,第N个字符就是从 X16开始。
由于刚才那个还是有点麻烦,又继续简化了一下

void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s)
{
    extern char hankaku[4096];
    for (; *s != 0x00; s++) {
        putfont8(vram, xsize, x, y, c, hankaku + *s * 16);
        x += 8;
    }
    return;
}

其实比较好理解,原理就是在之前的putfont8函数之上封装了一个函数,负责解析成类似与刚才写了那么多重复的代码的功能。

打印调试

写程序过程中,最重要的就是看到某个值的变化情况,所以这里我们要做这样一个功能。sPRintf就是往指定内存中写数据,然后我们再利用我们刚写的putfonts8_asc来输出这个地址的值,就达到了输出的作用啦。

@H_973_360@显示鼠标

既然能显示出来一个字符,那么按照原理来显示一个鼠标箭头也就是理所应当啦。

void init_mouse_cursor8(char *mouse, char bc)
/* ƒ}ƒEƒXƒJ[ƒƒ‹‚ð€”õi16x16j */
{
    static char cursor[16][16] = {
        "**************..",
        "*OOOOOOOOOOO*...",
        "*OOOOOOOOOO*....",
        "*OOOOOOOOO*.....",
        "*OOOOOOOO*......",
        "*OOOOOOO*.......",
        "*OOOOOOO*.......",
        "*OOOOOOOO*......",
        "*OOOO**OOO*.....",
        "*OOO*..*OOO*....",
        "*OO*....*OOO*...",
        "*O*......*OOO*..",
        "**........*OOO*.",
        "*..........*OOO*",
        "............*OO*",
        ".............***"
    };
    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;
}

再根据刚才填好的颜色,放到显卡中去。

三四参数决定,这个鼠标的宽高,五六决定所在位置,mcursor:鼠标颜色形状。bxsize 鼠标宽度。


void init_gdtidt(void)
{
    struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) 0x00270000;
    struct GATE_DESCRIPTOR    *idt = (struct GATE_DESCRIPTOR    *) 0x0026f800;
    int i;

    // GDT的初始化
    for (i = 0; i < 8192; i++) {
        set_segmdesc(gdt + i, 0, 0, 0);
    }
    set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, 0x4092);
    set_segmdesc(gdt + 2, 0x0007ffff, 0x00280000, 0x409a);
    load_gdtr(0xffff, 0x00270000);

    // IDT的初始化
    for (i = 0; i < 256; i++) {
        set_gatedesc(idt + i, 0, 0, 0);
    }
    load_idtr(0x7ff, 0x0026f800);

    return;
}

void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)
{
    if (limit > 0xfffff) {
        ar |= 0x8000; /* G_bit = 1 */
        limit /= 0x1000;
    }
    sd->limit_low    = limit & 0xffff;
    sd->base_low     = base & 0xffff;
    sd->base_mid     = (base >> 16) & 0xff;
    sd->access_right = ar & 0xff;
    sd->limit_high   = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0);
    sd->base_high    = (base >> 24) & 0xff;
    return;
}

void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)
{
    if (limit > 0xfffff) {
        ar |= 0x8000; /* G_bit = 1 */   // 0x8000 => 1000 0000 0000 0000  让ar的第一个一定是1
        limit /= 0x1000;  
    }
    sd->limit_low    = limit & 0xffff;  // 只要limit低16位
    sd->base_low     = base & 0xffff; // 只要base低16位
    sd->base_mid     = (base >> 16) & 0xff;  // 首先右移16位,然后与ff按位于,得到接下来8位
    sd->access_right = ar & 0xff; // 取后8位
    sd->limit_high   = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0);    // ((limit >> 16) & 0x0f)  只要第五位(十六进制), 要ar中第四位  
    sd->base_high    = (base >> 24) & 0xff;  // 取第七八位(十六进制)
    return;
}

首先是初始化8192所有地址,然后让 1,2分别变为ffffffff和7ffff,然后就没啦。。。。位运算相关的都写在注释里了

脚本宝典总结

以上是脚本宝典为你收集整理的30天自制操作系统-5全部内容,希望文章能够帮你解决30天自制操作系统-5所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。