【MIPS CPU 体系结构概述2】连载4:

4.mips的异常处理

1.硬件
mips CPU的异常处理中,硬件做的事情很少,这也是RISC的特点. 和x86系统相比, 有两点大不一样:
* 硬件不负责具体鉴别异常,CPU响应异常之后需要根据状态寄存器等来确定 究竟发生哪个异常.有时候硬件会做一点简单分类,CPU能直接到某一类异常 的处理入口.
* 硬件通常不负责保存上下文.例如系统调用,所有的寄存器内容都要由软件 进行必要的保存.

各种主板的中断控制种类很多,需要根据中断控制器和连线情况来编程.

2.kernel实现

* 处理程序什么时候安装?
traps_init(arch/mips/kernel/traps.c,setup_arch之后start_kernel调用)

/* Copy the generic exception handler code to it's final destination. */
memcpy((void *)(KSEG0 + 0x80), &except_vec1_generic, 0x80);
memcpy((void *)(KSEG0 + 0x100), &except_vec2_generic, 0x80);

memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic, 0x80);
flush_icache_range(KSEG0 + 0x80, KSEG0 + 0x200);
/*
* Setup default vectors
*/
for (i = 0; i <= 31; i++)
set_except_vector(i, handle_reserved);

* 装的什么?
except_vec3_generic(head.S) (除了TLB refill例外都用这个入口): /* General exception vector R4000 version. */
NESTED(except_vec3_r4000, 0, sp)
.set noat
mfc0 k1, CP_CAUSE
andi k1, k1, 0x7c /* 从cause寄存器取出异常号 */
li k0, 31<<2 beq k1, k0, handle_vced /* 如果是vced,处理之*/
li k0, 14><<2 beq k1, k0, handle_vcei /* 如果是vcei,处理之*/
/* 这两个异常是和cache相关的,cache出了问题,不能再在这个cached的位置处理啦 */
la k0, exception_handlers /* 取出异常处理程序表 */
addu k0, k0, k1 lw k0, (k0) /*处理函数*/
nop jr k0 /*运行异常处理函数*/
nop

那个异常处理程序表是如何初始化的呢?

在traps_init中,大家会看到set_exception_vector(i,handler)这样的代码, 填的就是这张表啦.可是,如果你用souce insigh之类的东西去找那个handler,往往就落空了,??怎么没有handle_ri,handle_tlbl..._?不着急,只不过是一个小trick, 还记得x86中断处理的handler代码吗? 它们是用宏生成的:

entry.S
#define BUILD_HANDLER(exception,handler,clear,verbose)
.align 5;
NESTED(handle_##exception, PT_SIZE, sp);
.set noat;
SAVE_ALL; /* 保存现场,切换栈(如必要)*/
__BUILD_clear_##clear(exception); /*关中断?*/
.set at;
__BUILD_##verbose(exception);
jal do_##handler; /*干活*/
move a0, sp;
ret_from_exception; /*回去*/
nop;
END(handle_##exception) /*生成处理函数*/
BUILD_HANDLER(adel,ade,ade,silent) /* #4 */
BUILD_HANDLER(ades,ade,ade,silent) /* #5 */
BUILD_HANDLER(ibe,ibe,cli,verbose) /* #6 */
BUILD_HANDLER(dbe,dbe,cli,silent) /* #7 */
BUILD_HANDLER(bp,bp,sti,silent) /* #9 */

认真追究下去,这里的一些宏是很重要的,象SAVE_ALL(include/asm/stackframe.h), 异常处理要高效,正确,这里要非常小心.这是因为硬件做的事情实在太少了.
别的暂时先不说了,下面我们来看外设中断(它是一种特殊的异常).

entry.S并没有用BUILD_HANDLER生成中断处理函数,因为它是平台相关的 就以笔者的板子为例,在arch/mips/algor/p6032/kernel/中(标准内核没有)增加了p6032IRQ.S这个汇编文件,里面定义了一个p6032IRQ的函数,它负责鉴别中断源,调用相应的中断控制器处理代码,而在同目录的irq.c->init_IRQ中调用set_except_vector(0,p6032IRQ)填表(所有的中断都引发异常0,并在cause寄存器中设置具体中断原因).

--电子创新网--
粤ICP备12070055号