/*
define SAVE_ALL
"cld;
"
"pushq %rax;
"
"pushq %rax;
"
"pushq %es, %rax;
"
"pushq %rax;
"
"pushq"
...
上面的这段汇编代码的宏定义就是在执行中断程序的时候调用的现场保留的操作, 和异常的现场保留是类似的
不同的是, 在异常中是处理器产生的任务暂停, 而在中断中是外部设备产生的任务暂停
也和异常一样, 在执行中断处理函数之前就需要执行现场保留的代码
*/
/*
- 执行的流程, 通过处理函数的入口函数, 先执行现场保留的代码,接着下来就和异常处理程序有一点不一样了, 在中断处理中, 调用一个do_IRQ函数, do_IRQ函数寄存器中的参数调用
- 对应的处理函数, 在异常中, 我们通过处理函数的入口函数执行了现场保留的代码之后, 在调用明确的异常处理函数, 当然程序的返回地址都是要记录的, 这样才能返回我们原来的程序
*/
/*
- 上面讲到的是在遇到了异常的时候CPU是怎么处理的, 前提是我们现在为中断提供了入口函数 --> 注意: 入口函数和程序处理函数不是完全一样的, 入口函数中包含有程序处理函数,
- 在入口函数中调用程序处理函数, 在异常和中断中都是这样的, 只不过正如上面提到的那样, 在中断中的程序处理函数都是交给了一个do_IRQ函数通过参数判断要调用对应的中断处理函数
- 我们现在就是要使用set_intr_gate函数将中断的入口函数们一一注册好, 注意: 这里的set_intr_gate函数虽然接受的参数是我们入口函数的地址, 但是他在中断向量表对应的index
- 写入的数据是一个门描述符, 该门描述符不仅仅是简单的是入口函数的地址在Linux中, 有一个函数指针数组, 在该数组中保存这的就是所有的中断处理函数的入口函数的地址, 也就是
- 函数指针, 需要注意的是, 我们使用for循环进行注册的时候, 起始的i是应该为32, 因为前32个中断向量号已经被异常时候, 但是有不是32个异常, 用到的是20个异常, 剩下的12个异常中断
- 向量号为Intel所保留
*/
/*
- 注册好了之后, 我们需要初始化好ICW和OCW寄存器中的数据
*/
/*
- 下面是一个do_IRQ的demo示例
- 功能: 在屏幕上打印出时钟中断的中断向量号
*/
void do_IRQ(unsigned long regs, unsigned long nr) {
color_printk(RED, BLACK, "do_IRQ:%#08x ", nr);
io_out(0x20, 0x20);
}
/*
- 通过阅读建议的键盘驱动, 发现所以的驱动编写就是在编写一个中断处理函数, 我们已经知道了, CPU根据中断向量表中的index找到键盘中断的入口函数, 在该入口函数中调用do_IRQ函数, 在
- do_IRQ函数中调用驱动程序, 就是这样而已, 所以编写驱动程序仅仅是内核中的冰山一角
*/