30天自制操作系统-4

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

首先啊,今天的内容比较多,但大家可以直接看书最后面,一想到做完后就能看到这个界面上有我们画上去的东西就开心纳,朝着这个尽头,开始吧。

首先就是用c语言写内存,如果用汇编写的话,就是用[]这种来进行内存读写,其实我们就是要在汇编里封装一些函数让C去调用。这里突然想起了,做手游,为了热更新,也是这个套路。

    _wrITe_mem8:    ; void write_mem8(int addr, int data);
    MOV        ECX,[ESP+4]        ; [ESP+4]‚中存放的是地址,将其读入ECX
    MOV        AL,[ESP+8]        ; [ESP+8]‚中存放的是数据,将其读入AL
    MOV        [ECX],AL
    RET

首先,写了个函数叫write_mem8,其意是向内存地址中写入8个字节,所以用的是AL。
函数本身也很简单,作者在这里做了说明,只能用EAX,ECX,EDX,因为用于记忆C语言编译后的机器语言中。
[INSTRSET "i486p"] ; 486‚指定用于486,当然也不是说其他的就不能用。

int i;

for (i = 0xa0000; i <= 0xaffff; i++) {
    write_mem8(i, i &amp; 0x0f);
}

for (;;) {
    io_hlt();
}

注释也省略了,因为我觉得到了C语言,应该没有什么语法看不懂的了,主要是思维。昨天已经介绍过0xa00000-0xaffff是使用这个模式,对这部分内存操作就是对最终屏幕绘制出来的内容密切相关。

条纹图案

这里巧妙的运用了AND运算符,由于每次遍历出来一个字节,8位,与0x0f与运算,也就是0x0f有低四位但是高四位是0。由于i、每隔16进一次位,所以每隔16次反复进行此运算,而这16此每一次的计算,保留低4位,因为f的存在,高四位变成0因为0x0f中0的存在。

指针
理所当然C语言的指针就是拿来玩儿内存的,可能是读者为了让我们更了解原理,然后写了之前的read_mem8这个函数。如果直接对i进行取地址,那他当然不知道这个地址是个什么类型,当然也就不知道赋值多少位过去,所以写了个char *p
指针在专栏里作者讲了一大堆,如果能看懂,哦,作者讲的确实对。但我觉得对于初学者,去学一些C语言的书,多看些打印的值,更直观些。说个我也会忘的知识吧 a[1] 1[a]是一样的意思

void io_hlt(void);
void io_cli(void);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_Store_eflags(int eflags);

// 就算写在同一个文件里,在使用之前必须声明一下,如果函数在前面则不用

void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);

void HariMain(void)
{

int i; // 声明变量,这里的变量i是32位整型
char *p; // 变量p是Byte[...]用的地址

init_palette(); // 设定调色板

p = (char *) 0xa0000; // 指定地址

for (i = 0; i <= 0xffff; i++) {
    p[i] = i & 0x0f;
}

for (;;) {
    io_hlt();
}

}

void init_palette(void)
{

static unsigned char table_rgb[16 * 3] = {
    0x00, 0x00, 0x00,    
    0xff, 0x00, 0x00,    
    0x00, 0xff, 0x00,    
    0xff, 0xff, 0x00,    
    0x00, 0x00, 0xff,    
    0xff, 0x00, 0xff,    
    0x00, 0xff, 0xff,    
    0xff, 0xff, 0xff,    
    0xc6, 0xc6, 0xc6,    
    0x84, 0x00, 0x00,    
    0x00, 0x84, 0x00,    
    0x84, 0x84, 0x00,    
    0x00, 0x00, 0x84,    
    0x84, 0x00, 0x84,    
    0x00, 0x84, 0x84,    
    0x84, 0x84, 0x84    
};
set_palette(0, 15, table_rgb);
return;

// C语言中的static char语句只能用于数据,相当于汇编中的DB指令

}

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;

}

代码有点长,不过声明就占了好些行数。记得不管以前是学C还是其他高级语言对于静态变量的说法都是,静态存储区,特有的存储区。具有全局性等,但现在如果从汇编的角度来看,好像会对他产生全新的认识。记住static就相当于在汇编使用DB一样。作者说这个方式a[0] = 1;占三个字节的原因可能是赋值语句转换位汇编是mov ....可能是这样导致的,所以改成static就能避免很多这样的操作。
我们初始我们想要的颜色后,现在要设定到调色板里去。虽然作者说让我们先不理解io_out这个函数,但我觉得有点奇怪,一直往一个地址里面写值,不久把之前的覆盖了吗?还是我写一个,就会有相应的东西把值取走,然后保存下来?
有两个函数CLI与STL这两个配合起来意思是我在做这段代码的过程中不许任何人打搅,感觉有点像高级语言的线程锁。

前面几个函数相对简单,我直接来搞后两个新函数。如果之前知道push和pop的来理解也就不难,PUSHFD先把eflags的值存在栈里面,然后又放到EAX里面去(不知道为什么作者没讲,要想返回函数的值,放到EAX里面就好了,所以在C语言我们可以接收到一个返回值)。由于这个值到C那边跑了一圈,又传回来了,所以我们再入栈,在POPFD又回到了EFLAGS里边儿。

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;

}

看到这里更带劲儿了,因为画出了个正方形,来看看这个函数,思想也比较简答, 就是块数组,指定区域用指定值,然后对应的就是指定屏幕变成指定颜色。像这种常值的值,定义成define就好。

void HariMain(void)
{

char *vram;
int xsize, ysize;

init_palette();
vram = (char *) 0xa0000;
xsize = 320;
ysize = 200;

boxfill8(vram, xsize, COL8_008484,  0,         0,          xsize -  1, ysize - 29);
boxfill8(vram, xsize, COL8_C6C6C6,  0,         ysize - 28, xsize -  1, ysize - 28);
boxfill8(vram, xsize, COL8_FFFFFF,  0,         ysize - 27, xsize -  1, ysize - 27);
boxfill8(vram, xsize, COL8_C6C6C6,  0,         ysize - 26, xsize -  1, ysize -  1);

boxfill8(vram, xsize, COL8_FFFFFF,  3,         ysize - 24, 59,         ysize - 24);
boxfill8(vram, xsize, COL8_FFFFFF,  2,         ysize - 24,  2,         ysize -  4);
boxfill8(vram, xsize, COL8_848484,  3,         ysize -  4, 59,         ysize -  4);
boxfill8(vram, xsize, COL8_848484, 59,         ysize - 23, 59,         ysize -  5);
boxfill8(vram, xsize, COL8_000000,  2,         ysize -  3, 59,         ysize -  3);
boxfill8(vram, xsize, COL8_000000, 60,         ysize - 24, 60,         ysize -  3);

boxfill8(vram, xsize, COL8_848484, xsize - 47, ysize - 24, xsize -  4, ysize - 24);
boxfill8(vram, xsize, COL8_848484, xsize - 47, ysize - 23, xsize - 47, ysize -  4);
boxfill8(vram, xsize, COL8_FFFFFF, xsize - 47, ysize -  3, xsize -  4, ysize -  3);
boxfill8(vram, xsize, COL8_FFFFFF, xsize -  3, ysize - 24, xsize -  3, ysize -  3);

for (;;) {
    io_hlt();
}

}

这段代码运行后,简直是太棒啦,感觉有点想我们的桌面了,但其实还是前面的知识,只是巧妙的利用了boxfill8这个函数。

大概解释一下吧,第一个boxfill8是绘制桌面的感觉,一张蓝绿色的低,从左上角到离右下角y29,x1的位置,至于为什么作者在x方向少了一个1不太理解,可能是留出边缘吧。第二个是绘制一个桌面与状态栏的灰色分割线。然后是蓝色分割线,以此。。。还有一个办法看每一行到底做了哪些东西,可以一句代码一句代码的注释,然后看效果。实话说这个操作系统是真的小,像我做exe,apk,ipa什么的随便弄个空项目出来就好几百K,甚至用游戏引擎的话,随随便便就是几MB,简直不敢想象,那个在我们看来是个空项目,内部到底有多少代码。

写在最后我记得我在编译这一天代码的时候出现过一个问题, 不过最后也找到了,就是路径问题,请大家注意一下,tolsetz_toolsharibote这个路径下的haribote.rul文件内容的路径一定也要修改,不然make run会报错。

脚本宝典总结

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

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

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