代码仓库地址:https://github.com/freedom-xiao007/operating-system
在上篇中我们成功的加载跳转执行了C语言的代码,本篇中将跟随书籍,初步展示了一个系统页面的初步界面,看到桌面那刻还是有点意思的
不多啰嗦,这里先直接展示结果,最终的运行界面如下:
可以看到有点模样了,令人激动啊。当最终到这一步的时候,心里开心极了,哈哈
本篇中的代码修改基本上是抄《30天自制操作系统》中的,但可能是nask和nasm的区别问题,我们需要单独修改的地方也不少,下面我们详细说明下需要修改的地方
这个文件需要添加界面相关的参数设置,我们将其插入到start的下面,如下:
start:; 画面モードを設定MOV AL,0x13 ; VGA显卡,320x200x8bitMOV AH,0x00INT 0x10MOV BYTE [VMODE],8 ; 屏幕的模式(参考C语言的引用)MOV WORD [SCRNX],320MOV WORD [SCRNY],200MOV DWORD [VRAM],0x000a0000
这次新增了比较多的函数,但不复杂,也不多,这个文件的内容如下:
[BITS 32] ; 制作32位模式用的机器语言GLOBAL _io_hlt, _io_cli, _io_sti, io_stihltGLOBAL _io_in8, _io_in16, _io_in32GLOBAL _io_out8, _io_out16, _io_out32GLOBAL _io_load_eflags, _io_store_eflags
[SECTION .text]
_io_hlt: ; void io_hlt(void);HLTRET
_io_cli: ; void io_cli(void);CLIRET
_io_sti: ; void io_sti(void);STIRET
_io_stihlt: ; void io_stihlt(void);STIHLTRET
_io_in8: ; int io_in8(int port);MOV EDX, [ESP+4] ; portMOV EAX,0IN AL, DXRET
_io_in16: ; int io_in16(int port);MOV EDX, [ESP+4] ; portMOV EAX,0IN AX, DXRET
_io_in32: ; int io_in32(int port);MOV EDX, [ESP+4] ; portIN EAX, DXRET
_io_out8: ; void io_out8(int port, int data);MOV EDX, [ESP+4] ; portMOV AL, [ESP+8] ; dataOUT DX, ALRET
_io_out16: ; void io_out16(int port, int data);MOV EDX, [ESP+4] ; portMOV EAX, [ESP+8] ; dataOUT DX, AXRET
_io_out32: ; void io_out32(int port, int data);MOV EDX, [ESP+4] ; portMOV EAX, [ESP+8] ; dataOUT DX, EAXRET
_io_load_eflags: ; int io_load_eflags(void);PUSHFD ; 指PUSH EFLAGSPOP EAXRET
_io_store_eflags: ; void io_store_eflags(int eflags);MOV EAX, [ESP+4]PUSH EAXPOPFD ; 指POP EFLAGSRET
本次直接使用书中的C相关代码,但有几处不适配,需要我们单独进行修改
需要将其修改下,替换为先循环x再循环y(不断地尝试后发现的,但没有搞懂为啥会这样)
这里就需要修改下传入boxfill8的y0和y1的差值最小为3
经过修改后,文件的所有内容如下:
#define COL8_000000 0
#define COL8_FF0000 1
#define COL8_00FF00 2
#define COL8_FFFF00 3
#define COL8_0000FF 4
#define COL8_FF00FF 5
#define COL8_00FFFF 6
#define COL8_FFFFFF 7
#define COL8_C6C6C6 8
#define COL8_840000 9
#define COL8_008400 10
#define COL8_848400 11
#define COL8_000084 12
#define COL8_840084 13
#define COL8_008484 14
#define COL8_848484 15/*就算写在同一个源文件里,如果想在定义前使用,还是必须事先声明一下。*/
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 boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);void start(void)
{init_palette(); /* 设定调色板 */char *vram; /* 变量p是BYTE [...]用的地址 */vram = (char *) 0xa0000; /* 指定地址 */int xsize = 320;int ysize = 200;boxfill8(vram, xsize, COL8_008484, 0, 0, xsize, ysize - 29);boxfill8(vram, xsize, COL8_C6C6C6, 0, ysize - 28, xsize, ysize - 28);boxfill8(vram, xsize, COL8_FFFFFF, 0, ysize - 27, xsize, ysize - 27);boxfill8(vram, xsize, COL8_C6C6C6, 0, ysize - 26, xsize, ysize - 1);// y距离有时候需要大于3boxfill8(vram, xsize, COL8_FFFFFF, 3, ysize - 24, 59, ysize - 21);boxfill8(vram, xsize, COL8_FFFFFF, 2, ysize - 24, 2, ysize - 4);boxfill8(vram, xsize, COL8_848484, 3, ysize - 4, 59, ysize - 1);boxfill8(vram, xsize, COL8_848484, 59, ysize - 23, 59, ysize - 5);boxfill8(vram, xsize, COL8_000000, 2, ysize - 3, 59, ysize - 0);boxfill8(vram, xsize, COL8_000000, 60, ysize - 24, 60, ysize - 3);boxfill8(vram, xsize, COL8_848484, xsize - 47, ysize - 24, xsize - 4, ysize - 21);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 - 0);boxfill8(vram, xsize, COL8_FFFFFF, xsize - 3, ysize - 24, xsize - 3, ysize - 3);for (; ; ) {io_hlt();}
}void init_palette(void)
{static unsigned char table_rgb[16 * 3] = {0x00, 0x00, 0x00, /* 0:黑 */0xff, 0x00, 0x00, /* 1:亮红 */0x00, 0xff, 0x00, /* 2:亮绿 */0xff, 0xff, 0x00, /* 3:亮黄 */0x00, 0x00, 0xff, /* 4:亮蓝 */0xff, 0x00, 0xff, /* 5:亮紫 */0x00, 0xff, 0xff, /* 6:浅亮蓝 */0xff, 0xff, 0xff, /* 7:白 */0xc6, 0xc6, 0xc6, /* 8:亮灰 */0x84, 0x00, 0x00, /* 9:暗红 */0x00, 0x84, 0x00, /* 10:暗绿 */0x84, 0x84, 0x00, /* 11:暗黄 */0x00, 0x00, 0x84, /* 12:暗青 */0x84, 0x00, 0x84, /* 13:暗紫 */0x00, 0x84, 0x84, /* 14:浅暗蓝 */0x84, 0x84, 0x84 /* 15:暗灰 */};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;
}void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{int x, y;for (x = x0; x <= x1; x++) {for (y = y0; y <= y1; y++) {vram[y * xsize + x] = c;}}return;
}
脚本还是使用原来的,本篇中没有变化,一键运行后,出现文章开头令人激动的画面
在书中开始时介绍了不同手段实现同一个效果:给内存赋值
第一个方式是使用wirte_mem8时的编译nasm代码:使用写汇编函数的方式,根据传入的值,写到相应的内存中
void write_mem8(int addr, int data);
void start(void) {int i;for (i = 0xa0000; i < 0xaffff; i++) {write_mem8(i, i & 0x0f);}
}
ALIGN 8
?_001: mov eax, ebx ; 0018 _ 89. D8mov dword [esp], ebx ; 001A _ 89. 1C 24add ebx, 1 ; 001D _ 83. C3, 01and eax, 0FH ; 0020 _ 83. E0, 0Fmov dword [esp+4H], eax ; 0023 _ 89. 44 24, 04call _write_mem8 ; 0027 _ E8, 00000000(rel)cmp ebx, 720895 ; 002C _ 81. FB, 000AFFFFjnz ?_001 ; 0032 _ 75, E4_write_mem8: ; void write_mem8(int addr, int data);MOV ECX, [ESP+4] ; [ESP + 4]中存放的是地址,将其读入ECXMOV AL, [ESP+8] ; [ESP + 8]中存放的是数据,将其读入ALMOV [ECX], ALRET
第二个是指针,使用char*时的编译nasm代码:突然有种回到以前学习C的感觉,想到初期使用指针时的痛苦
void start(void) {int i;char *p;for (i = 0xa0000; i < 0xaffff; i++) {p = (char *) i;*p = i & 0x0f;}/* 或者下面这样写,生成的汇编码也一样 */char *p;p = (char *) 0xa0000; /*将地址赋值进去*/for (i = 0; i <= 0xffff; i++) {p[i] = i & 0x0f;}
}
?_001: mov edx, eax ; 0018 _ 89. C2add eax, 1 ; 001A _ 83. C0, 01and edx, 0FH ; 001D _ 83. E2, 0Fmov byte [eax-1H], dl ; 0020 _ 88. 50, FFcmp eax, 720895 ; 0023 _ 3D, 000AFFFFjnz ?_001 ; 0028 _ 75, EE
可以看到两种不同的实现方式,对C的指针有了更深的理解,了解底层确实是有一定帮助的
本文相对而言还是比较顺利的,虽然有一点坎坷,但在不断的调试中,顺利解决了
还进一步理解了C的指针
但关于书中的控制屏幕显示部分,目前还不是很通透,很需要再刷刷
上一篇:企业 SDLC 安全生命周期管理
下一篇:谢谢你的失败。你怎么能处理这件事