1. 接收启动信息
- 采用结构体, 将各个独立的变量联系起来, 让程序有更好的可读性
原始未使用 结构体的代码:
void HariMain(void)
{
char *vram;
int xsize, ysize;
short *binfo_scrnx, *binfo_scrny;
int *binfo_vram;
init_palette();
binfo_scrnx = (short *) 0x0ff4;
binfo_scrny = (short *) 0x0ff6;
binfo_vram = (int *) 0x0ff8;
xsize = *binfo_scrnx;
ysize = *binfo_scrny;
vram = (char *) *binfo_vram;
init_screen(vram, xsize, ysize);
for (;;) {
io_hlt();
}
}
使用了结构体之后的代码
明显代码的可读性提高了好多
struct BOOTINFO {
char cyls, leds, vmode, reserve;
short scrnx, scrny;
char *vram;
};
void HariMain(void)
{
struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;
init_palette();
init_screen(binfo->vram, binfo->scrnx, binfo->scrny);
for (;;) {
io_hlt();
}
}
4. 显示字符
- 之前显示字符使用的是 BIOS 中断, 现在cpu 处于 32 bit 模式, 需要手工绘制图形
通过将指定字符数据写入 VRAM 空间中, 实现字符的显示
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 & 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; }
字体数据
static char font_A[16] = {
0x00, 0x18, 0x18, 0x18, 0x18, 0x24, 0x24, 0x24,
0x24, 0x7e, 0x42, 0x42, 0x42, 0xe7, 0x00, 0x00
};
5. 增加字体
这里采用的是OSASK 字体, 并通过在 MAKEFILE 中使用 makefont 编译字体文件得到字体数据
封装字符串
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; }
- 实现效果
6. 显示变量值
- 通过sprintf 函数将变量值写入到字符串中
8. 显示鼠标
- 本质上就是读入鼠标cursor 的字符数组, 根据其中的字符将相应的vram 中的某个内存的数据设置成调色板中的某个标号, 来显示相应的字符。
9. GDT 和 IDT 的初始化
- 这里采用分段内存管理, 段寄存器表示 段的起始地址
- 段需要有以下信息
- 段的大小
- 段的起始地址
- 段的管理属性
- 但是, cpu的段寄存器只有16bit, 那么可以模仿调色板的做法, 建立段寄存器与段号之间的一种映射关系, 由于段寄存器德尔低三位表示权限, 可以使用的只有13bit, 因而, 可以处理 0 ~ 8191 的区域 (64KB)这个就是我们的 GDT(全局段号记录表)
- IDT 是中断记录表
- 为了处理外设的各种事件, 一般可以采用轮询方式, 不过轮询的频率不好控制, 太慢, 外设得不到响应, 太快, cpu做无意义处理, 因而, 一般采用 中断方式
- 本质上相当于, 将监控外设的任务委托给了第三方对象, 让第三方对象负责处理监控事件, 然后cpu专心处理手头的任务, 也可以理解成 cpu 请了一个小蜜