![]() |
#2
chengstone2010-05-17 10:52
|
因为一时间也想不出更好的处理方案,所以就照搬《自己动手写操作系统》里的那一套方法用着先

具体的初始化流程为:
kernel -> init_prot()
//在 init_prot() 调用init_8259A(),对8259A进行初始化,与以前的代码一样的,只是换成了c形式了。
//调用init_8259A()后 就是重复init_idt_desc()函数对ide表进行初始化话,前十多个是异常处理,后16个是外部中断处理,最后是自定义中断
//值得注意的是为外部中断处理函数建立了一个函数处理表,如此可以在之后灵活的设置修改中断的最终处理函数。
建立中断异常处理机制后(尽管是最简单的),就可以对其进行简单测试。
在kernel.c的main函数里,分别取消以下三个异常测试项的注释符,就可以看到异常信息显示在屏幕上。
//测试异常
//int 3 //测试调试断点异常
//jmp 0x40:0 //测试常规保护错误异常
//ud2 //测试无效操作码异常
//int 3 //测试调试断点异常
//jmp 0x40:0 //测试常规保护错误异常
//ud2 //测试无效操作码异常
对外部中断的测试:
//测试外部中断
//enable_irq(KEYBOARD_IRQ); //开键盘中断
//enable_irq(CLOCK_IRQ); //开时钟中断
//enable_irq(KEYBOARD_IRQ); //开键盘中断
//enable_irq(CLOCK_IRQ); //开时钟中断
注意:因为一下子添加了很多代码,超出了最初在boot.c里设定加载内核4个扇区大小的限制,因此需要将加载的扇区数调大一些。
code:kernel.c(改)

//文件:kernel.c
//功能:内核程序,目前功能为测试print.c里的几个输出函数
//运行:run.exe自动会编译boot.c与生成img并调用Bochs运行此程序。
//作者:miao
//时间:2010-5-17
#define YCBIT 32 //告诉编译器,以32位格式编译程序
#define YCORG 0x0 //此值会对在编译时对变量函数等产生地址基址偏移量,简单起便,设置为0
#include "global.h"
#include "kernel.h"
#include "print.h"
#include "klib.h"
#include "i8259.h"
void init();
//内核入口点
asm void main()
{
lgdt cs:GdtPtr //加载新的GDTR
mov eax, SelectorVideo
mov gs, ax //视频段选择子(目的)
mov eax, SelectorData32 //令32位代码段的变量(printPlace)可以读写
mov ds, ax
call init //初始化函数
//测试异常
//int 3 //测试调试断点异常
//jmp 0x40:0 //测试常规保护错误异常
//ud2 //测试无效操作码异常
sti //开中断
jmp kernel_main
}
void init()
{
disp_str("================ init start =================\n");
disp_str(" init idt -------------------------------- ");
init_prot(); //初始化IDT
disp_str("ok\n");
disp_str("================ init end ===================\n");
}
int kernel_main()
{
//测试外部中断
//enable_irq(KEYBOARD_IRQ); //开键盘中断
//enable_irq(CLOCK_IRQ); //开时钟中断
while(1);
return 0;
}
#include "print.c"
#include "klib.c"
#include "i8259.c"
//功能:内核程序,目前功能为测试print.c里的几个输出函数
//运行:run.exe自动会编译boot.c与生成img并调用Bochs运行此程序。
//作者:miao
//时间:2010-5-17
#define YCBIT 32 //告诉编译器,以32位格式编译程序
#define YCORG 0x0 //此值会对在编译时对变量函数等产生地址基址偏移量,简单起便,设置为0
#include "global.h"
#include "kernel.h"
#include "print.h"
#include "klib.h"
#include "i8259.h"
void init();
//内核入口点
asm void main()
{
lgdt cs:GdtPtr //加载新的GDTR
mov eax, SelectorVideo
mov gs, ax //视频段选择子(目的)
mov eax, SelectorData32 //令32位代码段的变量(printPlace)可以读写
mov ds, ax
call init //初始化函数
//测试异常
//int 3 //测试调试断点异常
//jmp 0x40:0 //测试常规保护错误异常
//ud2 //测试无效操作码异常
sti //开中断
jmp kernel_main
}
void init()
{
disp_str("================ init start =================\n");
disp_str(" init idt -------------------------------- ");
init_prot(); //初始化IDT
disp_str("ok\n");
disp_str("================ init end ===================\n");
}
int kernel_main()
{
//测试外部中断
//enable_irq(KEYBOARD_IRQ); //开键盘中断
//enable_irq(CLOCK_IRQ); //开时钟中断
while(1);
return 0;
}
#include "print.c"
#include "klib.c"
#include "i8259.c"
code:klib.h(新)

//文件:klib.h
//功能:klib头文件,内核需要用到的公共函数的声明等
//作者:miao
//时间:2010-5-16
//向指定端口写入数据
asm void out_byte(t_port port, t_8 value);
//从指定端口读取数据
asm t_8 in_byte(t_port port);
//功能:klib头文件,内核需要用到的公共函数的声明等
//作者:miao
//时间:2010-5-16
//向指定端口写入数据
asm void out_byte(t_port port, t_8 value);
//从指定端口读取数据
asm t_8 in_byte(t_port port);
code:klib.c(新)

//文件:klib.c
//功能:定义内核需要用到的公共函数
//作者:miao
//时间:2010-5-16
//向指定端口写入数据
asm void out_byte(t_port port, t_8 value)
{
mov edx, [esp + 4] //port
mov al, [esp + 4 + 4] //value
out dx, al
nop //一点延迟
nop
ret
}
//从指定端口读取数据
asm t_8 in_byte(t_port port)
{
mov edx, [esp + 4] //port
xor eax, eax
in al, dx
nop //一点延迟
nop
ret
}
code:i8259.h(新)//功能:定义内核需要用到的公共函数
//作者:miao
//时间:2010-5-16
//向指定端口写入数据
asm void out_byte(t_port port, t_8 value)
{
mov edx, [esp + 4] //port
mov al, [esp + 4 + 4] //value
out dx, al
nop //一点延迟
nop
ret
}
//从指定端口读取数据
asm t_8 in_byte(t_port port)
{
mov edx, [esp + 4] //port
xor eax, eax
in al, dx
nop //一点延迟
nop
ret
}

//文件:i8259.h
//功能:i8259头文件,放置初始化8259A、以及设置中断需要用到的宏、数据结构定义、全局变量以及函数的声明等
//作者:miao
//时间:2010-5-16
//8259A 中断控制端口
#define INT_M_CTL 0x20 //主:中断控制器输入输出端口
#define INT_M_CTLMASK 0x21 //主:通过此端口禁止指定的中断号
#define INT_S_CTL 0xA0 //从:次级中断控制器输入输出端口
#define INT_S_CTLMASK 0xA1 //从:通过此端口禁止指定的中断号
//中断(异常)向量号 从0到255,共256个,前面0~13已定义,20~31Intel保留未使用,32~255用户自定义
#define INT_VECTOR_DIVIDE 0x0 //除法错
#define INT_VECTOR_DEBUG 0x1 //调试异常
#define INT_VECTOR_NMI 0x2 //非屏蔽中断
#define INT_VECTOR_BREAKPOINT 0x3 //调试断点
#define INT_VECTOR_OVERFLOW 0x4 //溢出
#define INT_VECTOR_BOUNDS 0x5 //越界
#define INT_VECTOR_INVAL_OP 0x6 //无效操作码
#define INT_VECTOR_COPROC_NOT 0x7 //设备不可用
#define INT_VECTOR_DOUBLE_FAULT 0x8 //双重错误
#define INT_VECTOR_COPROC_SEG 0x9 //协处理器段越界
#define INT_VECTOR_INVAL_TSS 0xA //无效TSS
#define INT_VECTOR_SEG_NOT 0xB //段不存在
#define INT_VECTOR_STACK_FAULT 0xC //堆栈段错误
#define INT_VECTOR_PROTECTION 0xD //常规保护错误
#define INT_VECTOR_PAGE_FAULT 0xE //页错误
// 0xF //Intel保留
#define INT_VECTOR_COPROC_ERR 0x10 //浮点错
// 0x14~0x1F //Intel保留未使用
//0x20~0x2F,作为8259A的16个外部中断用
#define INT_VECTOR_IRQ0 0x20 //主:0x20~0x27
#define INT_VECTOR_IRQ8 0x28 //从:0x28~0x2F
// 0x30~0xFF //暂时不是用
//硬件中断向量(打开或禁用某个外部中断时用)
#define CLOCK_IRQ 0
#define KEYBOARD_IRQ 1
//386中断门类型值
#define DA_386IGate 0x8E
//中断(异常)所具有的权限
#define PRIVILEGE_KRNL 0
#define PRIVILEGE_USER 3
//8259A,主8个,从8个,一共有16个硬件中断
#define NR_IRQ 16
typedef void (*t_pf_irq_handler)(int irq); //定义中断请求处理函数类型
typedef void (*t_pf_int_handler)(); //定义硬件中断处理函数类型
//为16个硬件中断创建一个函数指针表,每个硬件中断发生时调用对应的处理函数
t_pf_irq_handler irq_table[NR_IRQ];
//门描述符
struct GATE
{
t_16 offset_low;//Offset Low
t_16 selector; //Selector
t_8 dcount; //该字段只在调用门描述符中有效。
//如果在利用调用门调用子程序时引起特权级的转换和堆栈的改变,
//需要将外层堆栈中的参数复制到内层堆栈。
//该双字计数字段就是用于说明这种情况发生时,要复制的双字参数的数量。
t_8 attr; //P(1) DPL(2) DT(1) TYPE(4)
t_16 offset_high;//Offset High
};
#define IDT_SIZE 64
GATE idt[IDT_SIZE];//中断描述符表,最多可以定义256个,目前暂时申请64个
t_8 idt_ptr[6]; //共6个字节0~15:Limit,16~47:Base 用作sidt以及lidt的参数
//发生异常时,显示对应的异常错误信息
char err_description[][64] =
{
"#DE Divide Error",
"#DB RESERVED",
"— NMI Interrupt",
"#BP Breakpoint",
"#OF Overflow",
"#BR BOUND Range Exceeded",
"#UD Invalid Opcode (Undefined Opcode)",
"#NM Device Not Available (No Math Coprocessor)",
"#DF Double Fault",
" Coprocessor Segment Overrun (reserved)",
"#TS Invalid TSS",
"#NP Segment Not Present",
"#SS Stack-Segment Fault",
"#GP General Protection",
"#PF Page Fault",
"— (Intel reserved. Do not use.)",
"#MF x87 FPU Floating-Point Error (Math Fault)",
"#AC Alignment Check",
"#MC Machine Check",
"#XF SIMD Floating-Point Exception"
};
void init_prot(); //初始化IDT函数
asm void disable_irq(int irq); //关闭特定的中断
asm void enable_irq(int irq); //打开特定的中断
void put_irq_handler(int irq, t_pf_irq_handler handler);//向特定的中断注册处理函数
//功能:i8259头文件,放置初始化8259A、以及设置中断需要用到的宏、数据结构定义、全局变量以及函数的声明等
//作者:miao
//时间:2010-5-16
//8259A 中断控制端口
#define INT_M_CTL 0x20 //主:中断控制器输入输出端口
#define INT_M_CTLMASK 0x21 //主:通过此端口禁止指定的中断号
#define INT_S_CTL 0xA0 //从:次级中断控制器输入输出端口
#define INT_S_CTLMASK 0xA1 //从:通过此端口禁止指定的中断号
//中断(异常)向量号 从0到255,共256个,前面0~13已定义,20~31Intel保留未使用,32~255用户自定义
#define INT_VECTOR_DIVIDE 0x0 //除法错
#define INT_VECTOR_DEBUG 0x1 //调试异常
#define INT_VECTOR_NMI 0x2 //非屏蔽中断
#define INT_VECTOR_BREAKPOINT 0x3 //调试断点
#define INT_VECTOR_OVERFLOW 0x4 //溢出
#define INT_VECTOR_BOUNDS 0x5 //越界
#define INT_VECTOR_INVAL_OP 0x6 //无效操作码
#define INT_VECTOR_COPROC_NOT 0x7 //设备不可用
#define INT_VECTOR_DOUBLE_FAULT 0x8 //双重错误
#define INT_VECTOR_COPROC_SEG 0x9 //协处理器段越界
#define INT_VECTOR_INVAL_TSS 0xA //无效TSS
#define INT_VECTOR_SEG_NOT 0xB //段不存在
#define INT_VECTOR_STACK_FAULT 0xC //堆栈段错误
#define INT_VECTOR_PROTECTION 0xD //常规保护错误
#define INT_VECTOR_PAGE_FAULT 0xE //页错误
// 0xF //Intel保留
#define INT_VECTOR_COPROC_ERR 0x10 //浮点错
// 0x14~0x1F //Intel保留未使用
//0x20~0x2F,作为8259A的16个外部中断用
#define INT_VECTOR_IRQ0 0x20 //主:0x20~0x27
#define INT_VECTOR_IRQ8 0x28 //从:0x28~0x2F
// 0x30~0xFF //暂时不是用
//硬件中断向量(打开或禁用某个外部中断时用)
#define CLOCK_IRQ 0
#define KEYBOARD_IRQ 1
//386中断门类型值
#define DA_386IGate 0x8E
//中断(异常)所具有的权限
#define PRIVILEGE_KRNL 0
#define PRIVILEGE_USER 3
//8259A,主8个,从8个,一共有16个硬件中断
#define NR_IRQ 16
typedef void (*t_pf_irq_handler)(int irq); //定义中断请求处理函数类型
typedef void (*t_pf_int_handler)(); //定义硬件中断处理函数类型
//为16个硬件中断创建一个函数指针表,每个硬件中断发生时调用对应的处理函数
t_pf_irq_handler irq_table[NR_IRQ];
//门描述符
struct GATE
{
t_16 offset_low;//Offset Low
t_16 selector; //Selector
t_8 dcount; //该字段只在调用门描述符中有效。
//如果在利用调用门调用子程序时引起特权级的转换和堆栈的改变,
//需要将外层堆栈中的参数复制到内层堆栈。
//该双字计数字段就是用于说明这种情况发生时,要复制的双字参数的数量。
t_8 attr; //P(1) DPL(2) DT(1) TYPE(4)
t_16 offset_high;//Offset High
};
#define IDT_SIZE 64
GATE idt[IDT_SIZE];//中断描述符表,最多可以定义256个,目前暂时申请64个
t_8 idt_ptr[6]; //共6个字节0~15:Limit,16~47:Base 用作sidt以及lidt的参数
//发生异常时,显示对应的异常错误信息
char err_description[][64] =
{
"#DE Divide Error",
"#DB RESERVED",
"— NMI Interrupt",
"#BP Breakpoint",
"#OF Overflow",
"#BR BOUND Range Exceeded",
"#UD Invalid Opcode (Undefined Opcode)",
"#NM Device Not Available (No Math Coprocessor)",
"#DF Double Fault",
" Coprocessor Segment Overrun (reserved)",
"#TS Invalid TSS",
"#NP Segment Not Present",
"#SS Stack-Segment Fault",
"#GP General Protection",
"#PF Page Fault",
"— (Intel reserved. Do not use.)",
"#MF x87 FPU Floating-Point Error (Math Fault)",
"#AC Alignment Check",
"#MC Machine Check",
"#XF SIMD Floating-Point Exception"
};
void init_prot(); //初始化IDT函数
asm void disable_irq(int irq); //关闭特定的中断
asm void enable_irq(int irq); //打开特定的中断
void put_irq_handler(int irq, t_pf_irq_handler handler);//向特定的中断注册处理函数
code:i8259.c(新)

//文件:i8259.c
//功能:初始化8259A、以及设置中断相关的函数
//作者:miao
//时间:2010-5-16
//外部中断默认调用的函数
void spurious_irq(int irq)
{
disp_str("spurious_irq: ");
disp_int(irq);
disp_str("\n");
}
void init_8259A()
{
out_byte(INT_M_CTL, 0x11); // 主 8259, ICW1
out_byte(INT_S_CTL, 0x11); // 从 8259, ICW1
out_byte(INT_M_CTLMASK, INT_VECTOR_IRQ0); //主8259,ICW2.设置'主8259'的中断入口地址为 0x20
out_byte(INT_S_CTLMASK, INT_VECTOR_IRQ8); //从8259,ICW2.设置'从8259'的中断入口地址为 0x28
out_byte(INT_M_CTLMASK, 0x4); // 主 8259, ICW3. IR2 对应 '从8259'
out_byte(INT_S_CTLMASK, 0x2); // 从 8259, ICW3. 对应 '主8259' 的 IR2
out_byte(INT_M_CTLMASK, 0x1); // 主 8259, ICW4
out_byte(INT_S_CTLMASK, 0x1); // 从 8259, ICW4
//默认一开始屏蔽掉所有外部中断
out_byte(INT_M_CTLMASK, 0xFF); // 主 8259, OCW1
out_byte(INT_S_CTLMASK, 0xFF); // 从 8259, OCW1
int i;
for(i=0;i<NR_IRQ;i++)
irq_table[i] = spurious_irq; //为16个硬件中断处理函数指针表初始化一个默认的调用函数
}
//初始化386中断门
void init_idt_desc(unsigned char vector, t_8 desc_type, t_pf_int_handler handler, unsigned char privilege)
{
GATE *p_gate = &idt[vector];
t_32 base = (t_32)handler;
p_gate->offset_low = base & 0xFFFF;
p_gate->selector = SelectorCode32;
p_gate->dcount = 0;
p_gate->attr = desc_type | (privilege << 5);
p_gate->offset_high = (base >> 16) & 0xFFFF;
}
//异常处理函数,显示错误信息
void exception_handler(int vec_no, int err_code, int eip, int cs, int eflags)
{
int i;
int text_color = 0xA0;
disp_pos = 0; //从顶格开始显示错误信息
disp_color_str("Exception! --> ", text_color);
disp_color_str(err_description[vec_no], text_color);
disp_color_str("\nEFLAGS:", text_color);
disp_int(eflags);
disp_color_str(" CS:", text_color);
disp_int(cs);
disp_color_str(" EIP:", text_color);
disp_int(eip);
if(err_code != 0xFFFFFFFF)
{
disp_color_str("Error code:", text_color);
disp_int(err_code);
}
}
asm void exception()
{
call exception_handler //显示错误信息
add esp, 4*2 //让栈顶指向 EIP,堆栈中从顶向下依次是:EIP、CS、EFLAGS
hlt
}
//中断和异常 -- 异常,设置错误代码和中断号
asm void divide_error()
{
push 0xFFFFFFFF //没有错误代码
push 0 //vector_no = 0
jmp exception
}
asm void single_step_exception()
{
push 0xFFFFFFFF //没有错误代码
push 1 //vector_no = 1
jmp exception
}
asm void nmi()
{
push 0xFFFFFFFF //没有错误代码
push 2 //vector_no = 2
jmp exception
}
asm void breakpoint_exception()
{
push 0xFFFFFFFF //没有错误代码
push 3 //vector_no = 3
jmp exception
}
asm void overflow()
{
push 0xFFFFFFFF //没有错误代码
push 4 //vector_no = 4
jmp exception
}
asm void bounds_check()
{
push 0xFFFFFFFF //没有错误代码
push 5 //vector_no = 5
jmp exception
}
asm void inval_opcode()
{
push 0xFFFFFFFF //没有错误代码
push 6 //vector_no = 6
jmp exception
}
asm void copr_not_available()
{
push 0xFFFFFFFF //没有错误代码
push 7 //vector_no = 7
jmp exception
}
asm void double_fault()
{
push 8 //vector_no = 8
jmp exception
}
asm void copr_seg_overrun()
{
push 0xFFFFFFFF //没有错误代码
push 9 //vector_no = 9
jmp exception
}
asm void inval_tss()
{
push 10 //vector_no = A
jmp exception
}
asm void segment_not_present()
{
push 11 //vector_no = B
jmp exception
}
asm void stack_exception()
{
push 12 //vector_no = C
jmp exception
}
asm void general_protection()
{
push 13 //vector_no = D
jmp exception
}
asm void page_fault()
{
push 14 //vector_no = E
jmp exception
}
asm void copr_error()
{
push 0xFFFFFFFF //没有错误代码
push 16 //vector_no = 10h
jmp exception
}
#define EOI 0x20
//中断和异常 -- 硬件中断
#define hwint_master(irq_No) \
in al, INT_M_CTLMASK /* ┓ */ \
or al, (1 << irq_No) /* ┣ 屏蔽当前中断 */ \
out INT_M_CTLMASK, al /* ┛ */ \
mov al, EOI /* ┓置EOI位 */ \
out INT_M_CTL, al /* ┛ */ \
sti /* CPU在响应中断的过程中会自动关中断,这句之后就允许响应新的中断*/ \
push irq_No /* ┓ */ \
call dword [&irq_table + 4 * irq_No] /* ┣ 中断处理程序 */ \
pop ecx /* ┛ */ \
cli \
in al, INT_M_CTLMASK /* ┓ */ \
and al, ~(1 << irq_No) /* ┣ 恢复接受当前中断 */ \
out INT_M_CTLMASK, al /* ┛ */ \
iretd \
ret \
#pragma align(16)
asm void hwint00() //Interrupt routine for irq 0 (the clock).
{
hwint_master(0)
}
#pragma align(16)
asm void hwint01() //Interrupt routine for irq 1 (keyboard)
{
hwint_master(1)
}
#pragma align(16)
asm void hwint02() //Interrupt routine for irq 2 (cascade!)
{
hwint_master(2)
}
#pragma align(16)
asm void hwint03() //Interrupt routine for irq 3 (second serial)
{
hwint_master(3)
}
#pragma align(16)
asm void hwint04() //Interrupt routine for irq 4 (first serial)
{
hwint_master(4)
}
#pragma align(16)
asm void hwint05() //Interrupt routine for irq 5 (XT winchester)
{
hwint_master(5)
}
#pragma align(16)
asm void hwint06() //Interrupt routine for irq 6 (floppy)
{
hwint_master(6)
}
#pragma align(16)
asm void hwint07() //Interrupt routine for irq 7 (printer)
{
hwint_master(7)
}
#define hwint_slave(irq_No) \
push irq_No \
call spurious_irq \
add esp, 4 \
hlt \
#pragma align(16)
asm void hwint08() //Interrupt routine for irq 8 (realtime clock).
{
hwint_slave(8)
}
#pragma align(16)
asm void hwint09() //Interrupt routine for irq 9 (irq 2 redirected)
{
hwint_slave(9)
}
#pragma align(16)
asm void hwint10() //Interrupt routine for irq 10
{
hwint_slave(10)
}
#pragma align(16)
asm void hwint11() //Interrupt routine for irq 11
{
hwint_slave(11)
}
#pragma align(16)
asm void hwint12() //Interrupt routine for irq 12
{
hwint_slave(12)
}
#pragma align(16)
asm void hwint13() //Interrupt routine for irq 13 (FPU exception)
{
hwint_slave(13)
}
#pragma align(16)
asm void hwint14() //Interrupt routine for irq 14 (AT winchester)
{
hwint_slave(14)
}
#pragma align(16)
asm void hwint15() //Interrupt routine for irq 15
{
hwint_slave(15)
}
//初始化IDT
void init_prot()
{
init_8259A();
// 全部初始化成中断门(没有陷阱门)
// 中断向量 中断门类型值 处理函数 权限
//异常
init_idt_desc(INT_VECTOR_DIVIDE, DA_386IGate, divide_error, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_DEBUG, DA_386IGate, single_step_exception,PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_NMI, DA_386IGate, nmi, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_BREAKPOINT, DA_386IGate, breakpoint_exception, PRIVILEGE_USER);
init_idt_desc(INT_VECTOR_OVERFLOW, DA_386IGate, overflow, PRIVILEGE_USER);
init_idt_desc(INT_VECTOR_BOUNDS, DA_386IGate, bounds_check, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_INVAL_OP, DA_386IGate, inval_opcode, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_COPROC_NOT, DA_386IGate, copr_not_available, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_DOUBLE_FAULT,DA_386IGate, double_fault, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_COPROC_SEG, DA_386IGate, copr_seg_overrun, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_INVAL_TSS, DA_386IGate, inval_tss, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_SEG_NOT, DA_386IGate, segment_not_present, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_STACK_FAULT, DA_386IGate, stack_exception, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_PROTECTION, DA_386IGate, general_protection, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_PAGE_FAULT, DA_386IGate, page_fault, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_COPROC_ERR, DA_386IGate, copr_error, PRIVILEGE_KRNL);
//外部中断
init_idt_desc(INT_VECTOR_IRQ0 + 0, DA_386IGate, hwint00, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_IRQ0 + 1, DA_386IGate, hwint01, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ0 + 2, DA_386IGate, hwint02, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ0 + 3, DA_386IGate, hwint03, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ0 + 4, DA_386IGate, hwint04, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ0 + 5, DA_386IGate, hwint05, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ0 + 6, DA_386IGate, hwint06, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ0 + 7, DA_386IGate, hwint07, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ8 + 0, DA_386IGate, hwint08, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ8 + 1, DA_386IGate, hwint09, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ8 + 2, DA_386IGate, hwint10, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ8 + 3, DA_386IGate, hwint11, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ8 + 4, DA_386IGate, hwint12, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ8 + 5, DA_386IGate, hwint13, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ8 + 6, DA_386IGate, hwint14, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ8 + 7, DA_386IGate, hwint15, PRIVILEGE_KRNL);
//自定义中断
//init_idt_desc(INT_VECTOR_SYS_CALL, DA_386IGate, sys_call, PRIVILEGE_USER);
*(t_16*)(&idt_ptr[0]) = IDT_SIZE * sizeof(GATE);
*(t_32*)(&idt_ptr[2]) = (t_32)&idt + ProtecAddr;
asm{lidt idt_ptr} //加载idt
}
//关闭特定的中断
asm void disable_irq(int irq)
{
mov ecx, [esp + 4] //irq
pushf
cli
mov ah, 1
rol ah, cl //ah = (1 << (irq % 8))
cmp cl, 8
jae disable_8 //disable irq >= 8 at the slave 8259
disable_0:
in al, INT_M_CTLMASK
test al, ah
jnz dis_already //already disabled?
or al, ah
out INT_M_CTLMASK, al //set bit at master 8259
popf
mov eax, 1 //disabled by this function
ret
disable_8:
in al, INT_S_CTLMASK
test al, ah
jnz dis_already //already disabled?
or al, ah
out INT_S_CTLMASK, al //set bit at slave 8259
popf
mov eax, 1 //disabled by this function
ret
dis_already:
popf
xor eax, eax //already disabled
ret
}
//打开特定的中断
asm void enable_irq(int irq)
{
mov ecx, [esp + 4] ; irq
pushf
cli
mov ah, ~1
rol ah, cl //ah = ~(1 << (irq % 8))
cmp cl, 8
jae enable_8 //enable irq >= 8 at the slave 8259
enable_0:
in al, INT_M_CTLMASK
and al, ah
out INT_M_CTLMASK, al //clear bit at master 8259
popf
ret
enable_8:
in al, INT_S_CTLMASK
and al, ah
out INT_S_CTLMASK, al //clear bit at slave 8259
popf
ret
}
//向特定的中断注册处理函数
void put_irq_handler(int irq, t_pf_irq_handler handler)
{
disable_irq(irq);
irq_table[irq] = handler;
}
//功能:初始化8259A、以及设置中断相关的函数
//作者:miao
//时间:2010-5-16
//外部中断默认调用的函数
void spurious_irq(int irq)
{
disp_str("spurious_irq: ");
disp_int(irq);
disp_str("\n");
}
void init_8259A()
{
out_byte(INT_M_CTL, 0x11); // 主 8259, ICW1
out_byte(INT_S_CTL, 0x11); // 从 8259, ICW1
out_byte(INT_M_CTLMASK, INT_VECTOR_IRQ0); //主8259,ICW2.设置'主8259'的中断入口地址为 0x20
out_byte(INT_S_CTLMASK, INT_VECTOR_IRQ8); //从8259,ICW2.设置'从8259'的中断入口地址为 0x28
out_byte(INT_M_CTLMASK, 0x4); // 主 8259, ICW3. IR2 对应 '从8259'
out_byte(INT_S_CTLMASK, 0x2); // 从 8259, ICW3. 对应 '主8259' 的 IR2
out_byte(INT_M_CTLMASK, 0x1); // 主 8259, ICW4
out_byte(INT_S_CTLMASK, 0x1); // 从 8259, ICW4
//默认一开始屏蔽掉所有外部中断
out_byte(INT_M_CTLMASK, 0xFF); // 主 8259, OCW1
out_byte(INT_S_CTLMASK, 0xFF); // 从 8259, OCW1
int i;
for(i=0;i<NR_IRQ;i++)
irq_table[i] = spurious_irq; //为16个硬件中断处理函数指针表初始化一个默认的调用函数
}
//初始化386中断门
void init_idt_desc(unsigned char vector, t_8 desc_type, t_pf_int_handler handler, unsigned char privilege)
{
GATE *p_gate = &idt[vector];
t_32 base = (t_32)handler;
p_gate->offset_low = base & 0xFFFF;
p_gate->selector = SelectorCode32;
p_gate->dcount = 0;
p_gate->attr = desc_type | (privilege << 5);
p_gate->offset_high = (base >> 16) & 0xFFFF;
}
//异常处理函数,显示错误信息
void exception_handler(int vec_no, int err_code, int eip, int cs, int eflags)
{
int i;
int text_color = 0xA0;
disp_pos = 0; //从顶格开始显示错误信息
disp_color_str("Exception! --> ", text_color);
disp_color_str(err_description[vec_no], text_color);
disp_color_str("\nEFLAGS:", text_color);
disp_int(eflags);
disp_color_str(" CS:", text_color);
disp_int(cs);
disp_color_str(" EIP:", text_color);
disp_int(eip);
if(err_code != 0xFFFFFFFF)
{
disp_color_str("Error code:", text_color);
disp_int(err_code);
}
}
asm void exception()
{
call exception_handler //显示错误信息
add esp, 4*2 //让栈顶指向 EIP,堆栈中从顶向下依次是:EIP、CS、EFLAGS
hlt
}
//中断和异常 -- 异常,设置错误代码和中断号
asm void divide_error()
{
push 0xFFFFFFFF //没有错误代码
push 0 //vector_no = 0
jmp exception
}
asm void single_step_exception()
{
push 0xFFFFFFFF //没有错误代码
push 1 //vector_no = 1
jmp exception
}
asm void nmi()
{
push 0xFFFFFFFF //没有错误代码
push 2 //vector_no = 2
jmp exception
}
asm void breakpoint_exception()
{
push 0xFFFFFFFF //没有错误代码
push 3 //vector_no = 3
jmp exception
}
asm void overflow()
{
push 0xFFFFFFFF //没有错误代码
push 4 //vector_no = 4
jmp exception
}
asm void bounds_check()
{
push 0xFFFFFFFF //没有错误代码
push 5 //vector_no = 5
jmp exception
}
asm void inval_opcode()
{
push 0xFFFFFFFF //没有错误代码
push 6 //vector_no = 6
jmp exception
}
asm void copr_not_available()
{
push 0xFFFFFFFF //没有错误代码
push 7 //vector_no = 7
jmp exception
}
asm void double_fault()
{
push 8 //vector_no = 8
jmp exception
}
asm void copr_seg_overrun()
{
push 0xFFFFFFFF //没有错误代码
push 9 //vector_no = 9
jmp exception
}
asm void inval_tss()
{
push 10 //vector_no = A
jmp exception
}
asm void segment_not_present()
{
push 11 //vector_no = B
jmp exception
}
asm void stack_exception()
{
push 12 //vector_no = C
jmp exception
}
asm void general_protection()
{
push 13 //vector_no = D
jmp exception
}
asm void page_fault()
{
push 14 //vector_no = E
jmp exception
}
asm void copr_error()
{
push 0xFFFFFFFF //没有错误代码
push 16 //vector_no = 10h
jmp exception
}
#define EOI 0x20
//中断和异常 -- 硬件中断
#define hwint_master(irq_No) \
in al, INT_M_CTLMASK /* ┓ */ \
or al, (1 << irq_No) /* ┣ 屏蔽当前中断 */ \
out INT_M_CTLMASK, al /* ┛ */ \
mov al, EOI /* ┓置EOI位 */ \
out INT_M_CTL, al /* ┛ */ \
sti /* CPU在响应中断的过程中会自动关中断,这句之后就允许响应新的中断*/ \
push irq_No /* ┓ */ \
call dword [&irq_table + 4 * irq_No] /* ┣ 中断处理程序 */ \
pop ecx /* ┛ */ \
cli \
in al, INT_M_CTLMASK /* ┓ */ \
and al, ~(1 << irq_No) /* ┣ 恢复接受当前中断 */ \
out INT_M_CTLMASK, al /* ┛ */ \
iretd \
ret \
#pragma align(16)
asm void hwint00() //Interrupt routine for irq 0 (the clock).
{
hwint_master(0)
}
#pragma align(16)
asm void hwint01() //Interrupt routine for irq 1 (keyboard)
{
hwint_master(1)
}
#pragma align(16)
asm void hwint02() //Interrupt routine for irq 2 (cascade!)
{
hwint_master(2)
}
#pragma align(16)
asm void hwint03() //Interrupt routine for irq 3 (second serial)
{
hwint_master(3)
}
#pragma align(16)
asm void hwint04() //Interrupt routine for irq 4 (first serial)
{
hwint_master(4)
}
#pragma align(16)
asm void hwint05() //Interrupt routine for irq 5 (XT winchester)
{
hwint_master(5)
}
#pragma align(16)
asm void hwint06() //Interrupt routine for irq 6 (floppy)
{
hwint_master(6)
}
#pragma align(16)
asm void hwint07() //Interrupt routine for irq 7 (printer)
{
hwint_master(7)
}
#define hwint_slave(irq_No) \
push irq_No \
call spurious_irq \
add esp, 4 \
hlt \
#pragma align(16)
asm void hwint08() //Interrupt routine for irq 8 (realtime clock).
{
hwint_slave(8)
}
#pragma align(16)
asm void hwint09() //Interrupt routine for irq 9 (irq 2 redirected)
{
hwint_slave(9)
}
#pragma align(16)
asm void hwint10() //Interrupt routine for irq 10
{
hwint_slave(10)
}
#pragma align(16)
asm void hwint11() //Interrupt routine for irq 11
{
hwint_slave(11)
}
#pragma align(16)
asm void hwint12() //Interrupt routine for irq 12
{
hwint_slave(12)
}
#pragma align(16)
asm void hwint13() //Interrupt routine for irq 13 (FPU exception)
{
hwint_slave(13)
}
#pragma align(16)
asm void hwint14() //Interrupt routine for irq 14 (AT winchester)
{
hwint_slave(14)
}
#pragma align(16)
asm void hwint15() //Interrupt routine for irq 15
{
hwint_slave(15)
}
//初始化IDT
void init_prot()
{
init_8259A();
// 全部初始化成中断门(没有陷阱门)
// 中断向量 中断门类型值 处理函数 权限
//异常
init_idt_desc(INT_VECTOR_DIVIDE, DA_386IGate, divide_error, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_DEBUG, DA_386IGate, single_step_exception,PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_NMI, DA_386IGate, nmi, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_BREAKPOINT, DA_386IGate, breakpoint_exception, PRIVILEGE_USER);
init_idt_desc(INT_VECTOR_OVERFLOW, DA_386IGate, overflow, PRIVILEGE_USER);
init_idt_desc(INT_VECTOR_BOUNDS, DA_386IGate, bounds_check, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_INVAL_OP, DA_386IGate, inval_opcode, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_COPROC_NOT, DA_386IGate, copr_not_available, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_DOUBLE_FAULT,DA_386IGate, double_fault, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_COPROC_SEG, DA_386IGate, copr_seg_overrun, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_INVAL_TSS, DA_386IGate, inval_tss, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_SEG_NOT, DA_386IGate, segment_not_present, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_STACK_FAULT, DA_386IGate, stack_exception, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_PROTECTION, DA_386IGate, general_protection, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_PAGE_FAULT, DA_386IGate, page_fault, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_COPROC_ERR, DA_386IGate, copr_error, PRIVILEGE_KRNL);
//外部中断
init_idt_desc(INT_VECTOR_IRQ0 + 0, DA_386IGate, hwint00, PRIVILEGE_KRNL);
init_idt_desc(INT_VECTOR_IRQ0 + 1, DA_386IGate, hwint01, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ0 + 2, DA_386IGate, hwint02, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ0 + 3, DA_386IGate, hwint03, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ0 + 4, DA_386IGate, hwint04, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ0 + 5, DA_386IGate, hwint05, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ0 + 6, DA_386IGate, hwint06, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ0 + 7, DA_386IGate, hwint07, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ8 + 0, DA_386IGate, hwint08, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ8 + 1, DA_386IGate, hwint09, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ8 + 2, DA_386IGate, hwint10, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ8 + 3, DA_386IGate, hwint11, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ8 + 4, DA_386IGate, hwint12, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ8 + 5, DA_386IGate, hwint13, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ8 + 6, DA_386IGate, hwint14, PRIVILEGE_KRNL);
//init_idt_desc(INT_VECTOR_IRQ8 + 7, DA_386IGate, hwint15, PRIVILEGE_KRNL);
//自定义中断
//init_idt_desc(INT_VECTOR_SYS_CALL, DA_386IGate, sys_call, PRIVILEGE_USER);
*(t_16*)(&idt_ptr[0]) = IDT_SIZE * sizeof(GATE);
*(t_32*)(&idt_ptr[2]) = (t_32)&idt + ProtecAddr;
asm{lidt idt_ptr} //加载idt
}
//关闭特定的中断
asm void disable_irq(int irq)
{
mov ecx, [esp + 4] //irq
pushf
cli
mov ah, 1
rol ah, cl //ah = (1 << (irq % 8))
cmp cl, 8
jae disable_8 //disable irq >= 8 at the slave 8259
disable_0:
in al, INT_M_CTLMASK
test al, ah
jnz dis_already //already disabled?
or al, ah
out INT_M_CTLMASK, al //set bit at master 8259
popf
mov eax, 1 //disabled by this function
ret
disable_8:
in al, INT_S_CTLMASK
test al, ah
jnz dis_already //already disabled?
or al, ah
out INT_S_CTLMASK, al //set bit at slave 8259
popf
mov eax, 1 //disabled by this function
ret
dis_already:
popf
xor eax, eax //already disabled
ret
}
//打开特定的中断
asm void enable_irq(int irq)
{
mov ecx, [esp + 4] ; irq
pushf
cli
mov ah, ~1
rol ah, cl //ah = ~(1 << (irq % 8))
cmp cl, 8
jae enable_8 //enable irq >= 8 at the slave 8259
enable_0:
in al, INT_M_CTLMASK
and al, ah
out INT_M_CTLMASK, al //clear bit at master 8259
popf
ret
enable_8:
in al, INT_S_CTLMASK
and al, ah
out INT_S_CTLMASK, al //clear bit at slave 8259
popf
ret
}
//向特定的中断注册处理函数
void put_irq_handler(int irq, t_pf_irq_handler handler)
{
disable_irq(irq);
irq_table[irq] = handler;
}
[ 本帖最后由 miaowangjian 于 2010-5-31 16:16 编辑 ]