MIPS Linux异常中断处理.pdf
《MIPS Linux异常中断处理.pdf》由会员分享,可在线阅读,更多相关《MIPS Linux异常中断处理.pdf(52页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、MIPSLinux 异常中断代码分析1MIPS Linux异常中断代码分析CurrentVersion:CurrentVersion:0.16Date:Date:2007-04-12Author:Author:DajieTanAuthor:DajieTanMIPSLinux 异常中断代码分析2版本历史版本状态版本状态0.100.120.140.150.16作者作者DajieTanDajieTanDajieTanDajieTanDajieTan参与者参与者起止日期起止日期07-04-1207-04-1907-08-1707-08-1907-09-10备注备注完成草稿完善 A完善 B.1完善 B.
2、2完善 B.3Author:DajieTanMIPSLinux 异常中断代码分析3本文拟以龙芯2E (兼容MIPSIII )为例,对内核的异常、中断系统作一个框架式的描述,将结合2.6.18 的代码来说明。A A. 概述概述龙芯2E 在高优先级异常出现时,在设置了某些寄存器后,会根据异常类型跳转到相应的固定地址处(高优先级异常服务入口),操作系统会将相应的异常处理程序,置于这些地址处。龙芯2E 的高优先级异常有:冷启动、热重启、非屏蔽中断,TLB 重填(32位模式),xTLB 重填(64 位模式),cache错误,其他异常。龙芯2E 之高优先级异常入口地址有以下五个:TableA.1优先级异常
3、入口异常类型冷启动、热重启、非屏蔽中断TLB 重填xTLB 重填cache 错误其他正常运行(BEVBEV为0)0)0 xFFFFFFFFBFC000000 xFFFFFFFF800000000 xFFFFFFFF800000800 xFFFFFFFFA00001000 xFFFFFFFF80000180启动(BEVBEV 为 1)1)0 xFFFFFFFFBFC000000 xFFFFFFFFBFC002000 xFFFFFFFFBFC002800 xFFFFFFFFBFC003000 xFFFFFFFFBFC00380当龙芯正常运行时,STATUS 寄存器之 BEV 位为0 ,0 xFFF
4、FFFFF80000000 地址处不经TLB 映射、但缓存;当龙芯启动时,STATUS 寄存器之BEV位为 1,0 xFFFFFFFFBFC00200 地址处龙芯不缓存、不经 TLB映射。MIPS 下 TLB、Cache 都要OS 参与管理,在其启动时OS 尚未接管系统,这个时候不采用 TLB、Cache 机制是很重要的。注意,冷启动、热重启、非屏蔽中断的入口地址始终位于 0 xFFFFFFFFBFC00000由此可见龙芯2E启动时(冷启动异常或者热重启异常),执行的第一条指令是位于地址Author:DajieTanMIPSLinux 异常中断代码分析40 xFFFFFFFFBFC00000处
5、的,实际上龙芯电脑上所用之BOOTLOADER(PMON)的第一条指令就映射在地址空间的 0 xFFFFFFFFBFC00000处。注意到上面的五个固定的异常入口地址,有一个其他异常类入口(一般称为通用异常入口),当CPU 内部异常或者外部中断发生时,CPU 硬件设置CAUSE 寄存器的ExcCode(CAUSE6:2)位后,就跳转到该异常入口。ExcCode 位段用来描述通用异常类型,共5 位,故而可以描述25=32个异常类型。位于通用异常入口处的是操作系统设置的一个简单的异常处理程序,它会取出 CAUSE 寄存器的ExcCode 域(5 位,可以描述32个异常),用之索引一个通用异常处理表
6、(exception_handlers),并跳转到异常处理表项所指向的处理程序,通用异常处理表如下所示:-|handle_int |-中断ExcCode 值为0-|handle_tlbm|-TLB修改异常ExcCode 值为 1-|handle_tlbl|-TLB读异常ExcCode 值为2-|.|-|handle_sys|-系统调用ExcCode 值为 8-|.|该异常处理表很像 x86 的 IDT,只是他的每个表项没什么附加信息,就是一个相应异常处理程序的地址。来自硬件的中断,CPU 会自动将CAUSE 寄存器的ExcCode 域(6:2)设为0,其最终会执行总的中断处理程序 handle
7、_int。ExcCode 位为0 时,只是笼统地描述为中断,具体的是何种中断,还要借助CAUSE寄存器的IP 位(15:8,IP7-IP0) 来描述。硬件中断出现时,CPU 会根据中断信号的来源,设置Author:DajieTanMIPSLinux 异常中断代码分析5CAUSE 之 IP位。IP 位共 8位,每位对应一个中断。龙芯 2E 下,8个中断的用途分配如下:TableA.2CAUSE之 IP 位对应中断IP0IP1IP2IP3IP4IP5IP6IP7软件中断软件中断硬件中断硬件中断硬件中断硬件中断硬件中断时钟中断保留未用保留未用北桥中断控制器中断保留保留I8259A 中断Perfcou
8、nter 溢出Timer 中断IP6,IP7都是 CPU 内部产生。可以看到,一个硬件中断的流程应该是这样的(以键盘为例):1. 用户击键后,键盘控制器 8042产生中断,通过I8259A 在 CPU 的中断引脚上,引起异常2.CPU 自动设置 CAUSE的 ExcCode 位为 0,IP5 为1,并跳转到通用异常入口0 xFFFFFFFF800001803. 位于通用异常入口处的简单异常处理程序,根据 ExcCode 的值索引异常处理表(exception_handlers),获取到 0 号异常的处理程序是 handle_int,并跳转过去4.handle_int根据 CAUSE之IP 位的
9、值跳转到中断控制器8259A相关的中断处理函数do_nb2005_8259Author:DajieTanMIPSLinux 异常中断代码分析65.do_nb2005_8259读取8259A之 In-ServiceRegister(ISR,注意与x86 的差异,x86 是由 8259A 主动将中断号送上数据总线的),通过简单的计算得到中断号,进而调用do_IRQ 进入相应的中断处理程序。可以看到龙芯的整个异常处理是个树状结构,如下图所示:Author:DajieTanMIPSLinux 异常中断代码分析7B.B. 内核代码分析B.1B.1 高优先级异常入口初始化通用异常入口初始化,位于:arch
10、/mips/kernel/traps.cvoid_inittrap_init().set_handler(0 x180,&except_vec3_generic,0 x80);.set_handler 亦定义于该文件中:void_initset_handler(unsignedlongoffset,void*addr,unsignedlongsize)memcpy(void*)(ebase+offset),addr,size);flush_icache_range(ebase+offset,ebase+offset+size);很显然set_handler 完成的操作是将 addr 处,大小为
11、 size 字节的数据块复制到指定的异常入口处。其第一个参数指定入口的偏移地址,如 xTLB 重填为0 x100,通用异常为0 x180;第二个参数为异常处理程序的指针;第三个为需要复制的大小。其中 ebase是个全局变量,32 位内核下其值为 0 x80000000 。特别地,每个高优先级异常处理程序的长度不能超过 128bytes 。下面看看复制到 0 x80000180处的是什么:except_vec3_generic 是通用异常处理程序,定义于:arch/mips/kernel/genex.S/*GeneralexceptionvectorforallotherCPUs.Author:
12、DajieTanMIPSLinux 异常中断代码分析8*Becarefulwhenchangingthis,ithastobeatmost128bytes*tofitintospacereservedfortheexceptionhandler.*/NESTED(except_vec3_generic,0,sp).setpush.setnoatmfc0k1,CP0_CAUSEandik1,k1,0 x7c#ifdefCONFIG_64BITdsllk1,k1,1#endifPTR_Lk0,exception_handlers(k1)jrk0.setpopEND(except_vec3_gene
13、ric)这段程序完成的功能为:取 cause 寄存器之 ExcCode 值,然后跳转到exception_handlers+ExcCode*4 处,注意ExcCode 为 cause寄存器的位6:2,因此CAUSE&0 x7c就是 ExcCode*4。64 位下,指针长度为 8Bytes ,异常表的每项亦为8Bytes ,则索引值为 ExcCode*8,因此要在原 32 位的基础上再左移一位。cache错误入口初始化,位于:arch/mips/mm/cr4k.cvoid_initr4k_cache_init().set_uncached_handler(0 x100,&except_vec2_
14、generic,0 x80);.Author:DajieTanMIPSLinux 异常中断代码分析9因为cache 错误时可以 cache的 KSEG1 段不能用了,则 cache 错误异常处理程序位于KSEG1 之 0 xA0000000+0 x100处,长度最大为128Bytes ,异常处理程序为except_vec2_generic,定义于:arch/mips/mm/cexgen.SLEAF(except_vec2_generic).setnoreorder.setnoat.setmips0/*Thisisaverybadplacetobe.Ourcacheerror*detection
15、hastriggered.Ifwehavewritebackdata*inthecache,wemaynotbeabletorecover.Asa*firstorderdesperatemeasure,turnoffKSEG0cacheing.*/mfc0k0,CP0_CONFIGlik1,CONF_CM_CMASKandk0,k0,k1orik0,k0,CONF_CM_UNCACHEDmtc0k0,CP0_CONFIG/*Giveitafewcyclestosinkin.*/nopnopnopjcache_parity_errornopEND(except_vec2_generic)另外 s
16、et_uncached_handler 定义于:arch/mips/kernel/traps.cAuthor:DajieTanMIPSLinux 异常中断代码分析10void_initset_uncached_handler(unsignedlongoffset,void*addr,unsignedlongsize)#ifdefCONFIG_32BITunsignedlonguncached_ebase=KSEG1ADDR(ebase);#endif#ifdefCONFIG_64BITunsignedlonguncached_ebase=TO_UNCAC(ebase);#endifmemcpy
17、(void*)(uncached_ebase+offset),addr,size);其中 KSEG1ADDR 的宏用于将虚址 ebase 转化为对应的uncached 段的虚址(32bit下为 KSEG1)。32bit 下 ebase 为 0 x80000000则 KSEG1ADDR(ebase) 的值为0 xA0000000 。以上是第一层的异常处理,可以看到每个异常处理的程序所完成的功能都比较精简,且长度都限制在128Bytes ,32条指令以内。其中频繁使用的tlbrefill异常处理程序,不像上述的那样,事先编写好的,而是通过一些函数动态生成,然后复制到对应的入口处的。比如龙芯2E 的
18、 tlb_refill_handler 就是由位于 arch/mips/mm/tlbex.c 的build_r4000_tlb_refill_handler 函数则初始化阶段生成的。至于为何采取这种方式,主要是因为要根据用户的配置生成适合各种 MIPS 平台的 tlb_refill_handler ,由于要考虑的情况过多,使用通常的条件编译的方式已经不能满足需求。Author:DajieTanMIPSLinux 异常中断代码分析11B.2通用异常处理表初始化在上面的通用异常处理程序的分析中我们看到,其用 CAUSE 寄存器的 ExcCode 索引一张通用异常处理表exception_handl
19、ers,它定义于:arch/mips/kernel/traps.cunsignedlongexception_handlers32;实际上是一个数组,每个元素是相应异常的处理程序地址。初始化时则函数trap_init()中完成:arch/mips/kernel/traps.cvoid_inittrap_init(void)./*Setupdefaultvectors*/for(i=0;i=31;i+)set_except_vector(i,handle_reserved);.set_except_vector(0,handle_int);set_except_vector(1,handle_t
20、lbm);set_except_vector(2,handle_tlbl);set_except_vector(3,handle_tlbs);set_except_vector(4,handle_adel);set_except_vector(5,handle_ades);set_except_vector(6,handle_ibe);Author:DajieTanMIPSLinux 异常中断代码分析12set_except_vector(7,handle_dbe);set_except_vector(8,handle_sys);set_except_vector(9,handle_bp);s
21、et_except_vector(10,handle_ri);set_except_vector(11,handle_cpu);set_except_vector(12,handle_ov);set_except_vector(13,handle_tr);.if(cpu_has_fpu&!cpu_has_nofpuex)set_except_vector(15,handle_fpe);set_except_vector(22,handle_mdmx);if(cpu_has_mcheck)set_except_vector(24,handle_mcheck);if(cpu_has_mipsmt)
22、set_except_vector(25,handle_mt);if(cpu_has_dsp)set_except_vector(26,handle_dsp);.用于填充 exception_handlers 的 set_except_vector 定义于同一个文件中:void*set_except_vector(intn,void*addr)unsignedlonghandler=(unsignedlong)addr;Author:DajieTanMIPSLinux 异常中断代码分析13unsignedlongold_handler=exception_handlersn;exception
23、_handlersn=handler;if(n=0&cpu_has_divec)*(volatileu32*)(ebase+0 x200)=0 x08000000|(0 x03ffffff&(handler2);flush_icache_range(ebase+0 x200,ebase+0 x204);return(void*)old_handler;函数所完成的主要操作即是将传来的异常处理函数的地址 addr 赋值给exception_handlers 的元素 n。当n 为 0以及 CPU 具有除法异常时,要进行一些处理,这个与龙芯2E 无关,我们不关心,略过。在上面我们看到,内核首先用 h
24、andle_reserved 填充整个 exception_handlers,然后依次填充013 号异常的处理函数,尔后则根据各 MIPSCPU的特点填充相应的处理函数,如具有FPU 且具有FPU 异常的 MIPSCPU则填充元素15 为handle_fpe。龙芯 2E 的32个异常号(CAUSE 之 ExcCode)之含义为:Author:DajieTanMIPSLinux 异常中断代码分析14TableA.3CAUSE之 ExcCode 位ExcCodeExcCode0123456789101112131415162223243031WATCH保留保留FPEMnemonicMnemonic
25、IntIntModTLBLTLBSAdELAdELAdESAdESIBEDBESysSysBpRICpUOvTr中断TLB修改异常TLB异常(读或者取指令)TLB异常(存储)地址错误异常(读或者取指令)地址错误异常(存储)总线错误异常(取指令)总线错误异常(读或存储)系统调用异常断点异常保留指令异常协处理器不可用异常算术溢出异常陷阱异常保留浮点异常保留DescriptionDescription特别地,注意 handle_int 往往与具体的硬件平台相关,有的可能在具体平台的初始化代码里重新填充 exception_handlers0。比如龙芯 2E 的福珑miniPC上就在arch/mips
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- MIPS Linux异常中断处理 Linux 异常 中断 处理
限制150内