1. 分割源文件
- 由于原先的bootpack.c 太过冗长, 将他分割成几个部分
- 同时为了节省声明所占空间, 使用 头文件
2. 整理Makefile
- 将多个类似的编译规则, 使用一般规则进行合并, 简化书写
- 一般而言, 普通规则的优先级比一般规则要高 (类似于 C++ 模板 和 偏特化情形)
4. 意犹未尽
4.1 load_gdtr
_load_gdtr: ; void load_gdtr(int limit, int addr);
MOV AX,[ESP+4] ; limit
MOV [ESP+6],AX
LGDT [ESP+6]
RET
- 这里本质上涉及到 GDTR 寄存器的使用方式, 知道了他的使用方式就可以理解这段汇编代码的意思了
- GDTR 寄存器是 48bit 的, 他不能直接使用mov 操作, 如果需要对他进行赋值, 可以指定一个内存地址, 然后从这个地址中读取 6 个字节(48bit), 赋值给 GDTR 寄存器, 使用 LGDT 指令。
- 该寄存器低 16 bit (即 内存的最初的 2 个字节)为 段上限, 它等于 “GDT 的有效字节数 - 1”。剩下的高32 bit (剩余 4 个字节), 代表GDT 的开始地址。
- 由于我们的平台是 i386 平台, 所以采用的是小端字节序 http://blog.csdn.net/sky453589103/article/details/50595287
4.2 set_segmdesc
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;
}
- 这段代码实际上是用来设置 gdt 表的
- 我们首先来看一下 i386 平台中对 段寄存器的定义 http://blog.csdn.net/zhyh1435589631/article/details/50989569
- 由于历史遗留因素, base 地址 和 limit 字段被拆成了多个部分, limit字段 高位是段属性的设置
5. 初始化 PIC
- PIC 亦即 可编程中断控制器
init_pic
void init_pic(void) /* PICの初期化 */ { io_out8(PIC0_IMR, 0xff ); /* 全ての割り込みを受け付けない */ io_out8(PIC1_IMR, 0xff ); /* 全ての割り込みを受け付けない */ io_out8(PIC0_ICW1, 0x11 ); /* エッジトリガモード */ io_out8(PIC0_ICW2, 0x20 ); /* IRQ0-7は、INT20-27で受ける */ io_out8(PIC0_ICW3, 1 << 2); /* PIC1はIRQ2にて接続 */ io_out8(PIC0_ICW4, 0x01 ); /* ノンバッファモード */ io_out8(PIC1_ICW1, 0x11 ); /* エッジトリガモード */ io_out8(PIC1_ICW2, 0x28 ); /* IRQ8-15は、INT28-2fで受ける */ io_out8(PIC1_ICW3, 2 ); /* PIC1はIRQ2にて接続 */ io_out8(PIC1_ICW4, 0x01 ); /* ノンバッファモード */ io_out8(PIC0_IMR, 0xfb ); /* 11111011 PIC1以外は全て禁止 */ io_out8(PIC1_IMR, 0xff ); /* 11111111 全ての割り込みを受け付けない */ return; }
- 其中 IMR 是 中断屏蔽寄存器, ICW 是初始化控制数据, ICW3 设定主从连接(确定是使用哪个IRQ 来通知CPU), ICW2 确定 使用哪一号中断。
6. 中断处理程序制作
- 首先编写 中断处理程序, 然后将程序注册到 IDT 表中, 即可
- 需要注意的是这里 鼠标使用 IRQ12, 键盘使用 IRQ1
- 相应调用代码:
void HariMain(void)
{
struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
char s[40], mcursor[256];
int mx, my;
init_gdtidt();
init_pic();
io_sti(); /* IDT/PICの初期化が終わったのでCPUの割り込み禁止を解除 */
init_palette();
init_screen8(binfo->vram, binfo->scrnx, binfo->scrny);
mx = (binfo->scrnx - 16) / 2; /* 画面中央になるように座標計算 */
my = (binfo->scrny - 28 - 16) / 2;
init_mouse_cursor8(mcursor, COL8_008484);
putblock8_8(binfo->vram, binfo->scrnx, 16, 16, mx, my, mcursor, 16);
sprintf(s, "(%d, %d)", mx, my);
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, s);
io_out8(PIC0_IMR, 0xf9); /* PIC1とキーボードを許可(11111001) */
io_out8(PIC1_IMR, 0xef); /* マウスを許可(11101111) */
for (;;) {
io_hlt();
}
}