[读书笔记]30 天自制操作系统 day6 分割编译与中断处理

来源:互联网 发布:宿州煤电集团知乎 编辑:程序博客网 时间:2024/05/20 20:48

1. 分割源文件

  1. 由于原先的bootpack.c 太过冗长, 将他分割成几个部分
    这里写图片描述
  2. 同时为了节省声明所占空间, 使用 头文件

2. 整理Makefile

  1. 将多个类似的编译规则, 使用一般规则进行合并, 简化书写
  2. 一般而言, 普通规则的优先级比一般规则要高 (类似于 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
  1. 这里本质上涉及到 GDTR 寄存器的使用方式, 知道了他的使用方式就可以理解这段汇编代码的意思了
  2. GDTR 寄存器是 48bit 的, 他不能直接使用mov 操作, 如果需要对他进行赋值, 可以指定一个内存地址, 然后从这个地址中读取 6 个字节(48bit), 赋值给 GDTR 寄存器, 使用 LGDT 指令。
  3. 该寄存器低 16 bit (即 内存的最初的 2 个字节)为 段上限, 它等于 “GDT 的有效字节数 - 1”。剩下的高32 bit (剩余 4 个字节), 代表GDT 的开始地址。
  4. 由于我们的平台是 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;}
  1. 这段代码实际上是用来设置 gdt 表的
  2. 我们首先来看一下 i386 平台中对 段寄存器的定义 http://blog.csdn.net/zhyh1435589631/article/details/50989569

  3. 由于历史遗留因素, base 地址 和 limit 字段被拆成了多个部分, limit字段 高位是段属性的设置

5. 初始化 PIC

  1. PIC 亦即 可编程中断控制器
    这里写图片描述
  2. 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;}
  3. 其中 IMR 是 中断屏蔽寄存器, ICW 是初始化控制数据, ICW3 设定主从连接(确定是使用哪个IRQ 来通知CPU), ICW2 确定 使用哪一号中断。

6. 中断处理程序制作

  1. 首先编写 中断处理程序, 然后将程序注册到 IDT 表中, 即可
  2. 需要注意的是这里 鼠标使用 IRQ12, 键盘使用 IRQ1
  3. 相应调用代码:
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();    }}
0 0
原创粉丝点击