第四天:操作系统界面绘制
OUT:让cpu给设备发送电信号.
IN:让cpu从设备获取电信号.
为了区别不同的设备,要使用设备号码,用port表示.
pushad: 将所有的32位通用寄存器压入堆栈
pusha:将所有的16位通用寄存器压入堆栈
pushfd:然后将32位标志寄存器EFLAGS压入堆栈
pushf::将的16位标志寄存器EFLAGS压入堆栈
popad:将所有的32位通用寄存器取出堆栈
popa:将所有的16位通用寄存器取出堆栈
popfd:将32位标志寄存器EFLAGS取出堆栈
popf:将16位标志寄存器EFLAGS取出堆栈
今天比较简单是在第三天基础上扩充c语言进行画图的.
1.对内存写入数据
改写bootpack.c代码如下:
VRAM:保存的是0xa0000,指的是显卡内存.这块内存可以像一般的内存一样存储数据,也可以保存画面上的像素.利用这一点可以在画面上显示不同的图像.
void io_hlt(void);
void HariMain(void)
{
int i; /*i为DWORD4个字节*/
char *p; /* p用于byte类型地址 */
p = (char *) 0xa0000; /* */
for (i = 0; i <= 0xffff; i++) {
*(p + i) = i & 0x0f; //这样对内存进行赋值以后就会显示出图案了.
}
for (;;) {
io_hlt();
}
}
显示如下:
2.色号设定
rgb表示一个像素颜色时需要6位十六进制数,也就是24位来指定颜色. 而我们显示这个虚拟显示屏只有320*200的8位颜色模式.也就是只能使用0-255的数.
这个8位彩色模式,是由程序员随意指定0-255的数字所对应的颜色的,比如25号颜色对应#ffffff,26号颜色对应#123456等,这种方式就叫做调色板.
目前需要这16种颜色就够了.
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:暗灰*/
};
这个调色模式在上一节中已经说明,调用bios函数切换显示模式,
int 0x10 ,
ah=0x00 设置显卡模式,
al=模式,
0x03:16色字符模式,80×25(最基础)
0x12: VGA图形模式,640×480×4位彩色模式,独特的4面存储模式.
0x13:VGA图形模式,320×200×8位彩色模式,调色板模式.
0x6a: 扩展vga图形模式,800x600x4位彩色模式,独特的4面存储模式.
返回值:无
本系统采用0x13。8位彩色模式,就是有程序员随意指定0~255的数字所对应的颜色。如25号颜色对应#ffffff,26号对应#123456,这种方式叫做调色板palette。
调色板的访问步骤:
(1)首先在一连串的访问中屏蔽中断(比如CLI)。
(2)将想要设定的调色板号码写入0x03c8端口,紧接着,按RGB的顺序写入0x03c9。若还想继续设定下个调色板,就省略调色板的号码,再按RGB的顺序写入0x03c9就行了。
(3)若想读出当前调色板的状态,首先要将调色板的号码写入0x03c7,再从0x03c9中读取3次,顺序为RGB。若要继续读下一个,则省略调色板号码设定,继续按RGB读出。
(4)若开始执行了CLI,则最后执行STI。
调色板设置代码如下:
void set_palette(int start, int end, unsigned char *rgb)
{
int i, eflags;
eflags = io_load_eflags(); /* 保存EFLAGS寄存器的值 */
io_cli(); /*禁止中断*/
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); /* 恢复EFLAGS寄存器的值 */
return;
}
c程序中调用的汇编函数如下:
_io_out8: ; void io_out8(int port, int data);
MOV EDX,[ESP+4] ; port DX寄存器通常被称为数据寄存器。常用来存放双字长数据的高16位,或存放外设端口地址。
MOV AL,[ESP+8] ; data
OUT DX,AL
RET
_io_hlt: ; void io_hlt(void);
HLT
RET
_io_cli: ; void io_cli(void);
CLI ;禁止中断发生
RET
_io_sti: ; void io_sti(void);
STI ;允许中断发生
RET
_io_load_eflags: ; int io_load_eflags(void);
PUSHFD ; PUSH EFLAGS
POP EAX
RET
_io_store_eflags: ; void io_store_eflags(int eflags);
MOV EAX,[ESP+4]
PUSH EAX
POPFD ; POP EFLAGS
RET
3.绘制矩形
颜色配好了,现在开始画,在画面模式中,画面上有320x200=64000个像素,假设坐上角坐标是(0,0),右下角坐标是(319x199),(书里为什么是319x319不明白),那么像素坐标(x,y)对应的VRAM地址应该是
0xa0000+x+y*320
画矩形框函数如下:
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;
}
4.画出系统界面的大概轮廓
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();
}
}
执行效果如下: