06day 分割编译与中断处理

来源:互联网 发布:爱拍录像软件 编辑:程序博客网 时间:2024/05/10 08:06

分割编译:
1.将不同功能的实现写到不同的c文件中
2.修Makefile普通规则为一般规则

  %.gas : %.c Makefile    $(CC1) -o $*.gas $*.c%.nas : %.gas Makefile    $(GAS2NASK) $*.gas $*.nas%.obj : %.nas Makefile    $(NASK) $*.nas $*.obj $*.lst

3.提取声明部分到.h文件中,减少冗余代码。


接下来说历史遗留问题:

_load_gdtr:     ; void load_gdtr(int limit, int addr);        MOV     AX,[ESP+4]      ; limit        MOV     [ESP+6],AX        LGDT    [ESP+6]        RET

这个函数将指定的 段上限和地址值 赋给名为GDTR的48位寄存器。
>
limit 0x0000ffff
esp+4 FF
esp+5 FF
esp+6 00
esp+7 00
addr 0x00270000
esp+8 00
esp+9 00
esp+0a 27
esp+0b 00

栈的格式如上,我们把FFFF拷贝到 ESP+6 处 然后把 ESP+6~~ESP+0B 处的数据作为GDTR,所以GDTR前16位是段限,后32位是地址。

IDTR也是同理的。

_load_idtr:     ; void load_idtr(int limit, int addr);        MOV     AX,[ESP+4]      ; limit        MOV     [ESP+6],AX        LIDT    [ESP+6]        RET

struct SEGMENT_DESCRIPTOR {    short limit_low, base_low;// 2 + 2    char base_mid, access_right;// 1 + 1    char limit_high, base_high;// 1 + 1 };//正好8字节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;}

接下来说说是如何用8个字节64位来表示段的属性的。段的属性有 大小,起始地址,管理属性(写入,执行,系统专用?)

段的地址,用base_low ,base_mid,base_high ,正好32位来表示。将地址分段是为了与80286兼容。
在剩下32位中,段上限只能使用20位,那么如何用20位的长度来表示32位的地址空间呢(也就是4GB空间),在段的属性里设置了一个标志位Gbit,如果标示位为1的时候,limit的单位解释为页,一页指4KB, 所以 1M*4KB=4GB。
而limit由limit_low和limit_high组成,一共有24位,其实我们要把段的属性写入limit_high的上4位中,所以段上限还是20位.

12位段属性中,高4位放在limit_high的高4位里,所以我们可以把ar当做16位处理 xxxx0000xxxxxxxx
高4位成为扩展访问权,这4位在80286的时代还不存在,386之后可以使用,这4位是GD00 G就是Gbit ,D是指段的模式,D=1表示32位,D=0表示16位模式。 这里的16位模式只能运行286的程序 不能调用BIOS。 我们通常使用D=1 32模式

ar的低8位:

value hex mean 0x00 00000000 未使用的记录表 0x92 10010010 系统专用 可读写 不可执行 0x9a 10011010 系统专用 可执行 可读不可写 0xf2 11110010 应用程序用 可读写 不可执行 0xfa 11111010 应用程序用 可执行 可读不可写

接着说中断处理就要说PIC的寄存器。
IMR寄存器 interrupt mask register 中断屏蔽寄存器,8位,如果某一位是1,对应的IRQ信号被屏蔽。
ICW寄存器 initial control word 初始化控制寄存器
ICW寄存器有4个 ICW1 ICW2 ICW3 ICW4
ICW3是有关主从连接的设定,对应某位置为1表示驱动该位的从PIC,这里我们设置为 00000100 表示驱动2号位从PIC。

#include "bootpack.h"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;}

这次我们以INT 0X20~0X2F接受中断信号 IRQ0~15

接下来制作我们的中断处理程序

void inthandler21(int *esp)/* 来自PS/2键盘的中断 */{    struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;    boxfill8(binfo->vram, binfo->scrnx, COL8_000000, 0, 0, 32 * 8 - 1, 15);    putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, "INT 21 (IRQ-1) : PS/2 keyboard");    for (;;) {        io_hlt();    }}void inthandler2c(int *esp)/* PS/2鼠标 */{    struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;    boxfill8(binfo->vram, binfo->scrnx, COL8_000000, 0, 0, 32 * 8 - 1, 15);    putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, "INT 2C (IRQ-12) : PS/2 mouse");    for (;;) {        io_hlt();    }}

中断程序写好之后 我们要注册中断程序,

    set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);    set_gatedesc(idt + 0x27, (int) asm_inthandler27, 2 * 8, AR_INTGATE32);
void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar){    gd->offset_low   = offset & 0xffff;    gd->selector     = selector;    gd->dw_count     = (ar >> 8) & 0xff;    gd->access_right = ar & 0xff;    gd->offset_high  = (offset >> 16) & 0xffff;    return;}

make run运行后 我们发现可以成功相应键盘中断,但是却不能响应鼠标中断。

0 0
原创粉丝点击