mips linux trap_init函数分析(转)
CAC_BASE 表明支持CACHE 的base 地址,由于是32 的 CPU ,所以等于0x80000000;per_cpu_trap_init()中初始化CUP 的TLB 和cache ,以及它们的异常处理程序;set_handler(0x180, &except_vec3_generic, 0x80)设置通用异常入口(ebase+0x180)的处理程序为except_vec3_generic
转自:http://qgjie456.blog.163.com/blog/static/35451367200811241594048/
void __init trap_init(void)
{
extern char except_vec3_generic, except_vec3_r4000;
extern char except_vec4;
unsigned long i;
在我们的系统中没有定义这两个变量 == 0。
if (cpu_has_veic || cpu_has_vint)
ebase = (unsigned long) alloc_bootmem_low_pages (0x200 + VECTORSPACING*64);
else
ebase = CAC_BASE;
这个 CAC_BASE 表明支持 CACHE 的 base 地址,由于是 32 的 CPU ,所以等于 0x80000000。
这个 ebase 变量表示异常入口点的基地址。
一般情况下不配置 CONFIG_CPU_MIPSR2_SRSS 这个宏,所以这个函数为空函数。
mips_srs_init();
初始化 CUP 的 TLB 和 cache ,以及它们的异常处理程序。
per_cpu_trap_init();
设置通用异常入口(ebase+0x180)的处理程序为 except_vec3_generic 。
set_handler(0x180, &except_vec3_generic, 0x80);
---------------------------------
在通用异常处理程序中,读取 CAUSE 寄存器的 ExcCode 域的值,这个预在发生异常时,
由 CPU 自动设置,使软件也可以知道异常的原因。
通用异常处理程序使用 ExcCode 域的值,来索引异常处理表 exception_handlers[]。
这个通用异常处理表其实是一个 unsigned long exception_handlers[32] 数组,表示
相应异常的处理程序地址,下面的代码进行初始化为保留的异常处理。
---------------------------------
for (i = 0; i <= 31; i++)
set_except_vector(i, handle_reserved);
---------------------------------
如果 CPU 有 EJTAG,设置 EJTAG 的异常处理程序。
这个可以在 probe_cpu() 函数中自动检测,并设置 cpu_data 的 option 成员。
也可以在 include/asm-mips/mach-XXXX/cpu-feature-overrides.h
头文件中设置 。
移植相关,移植时需要配置。
---------------------------------
if (cpu_has_ejtag && board_ejtag_handler_setup)
board_ejtag_handler_setup ();
设置 CPU 是否有 watch (内存的访问检测点)异常,如果有进行设置。
移植相关,移植时需要配置。
if (cpu_has_watch)
set_except_vector(23, handle_watch);
---------------------------------
初始化中断处理器,如果有外部中断控制器或者支持中断向量模式,
或者除法异常时 (cpu_has_divec) ,需要进行特殊的操作。
下面的我们的 CPU 不执行,不支持。
---------------------------------
if (cpu_has_veic || cpu_has_vint) {
int nvec = cpu_has_veic ? 64 : 8;
for (i = 0; i < nvec; i++)
set_vi_handler(i, NULL);
}else if (cpu_has_divec)
set_handler(0x200, &except_vec4, 0x8);
设置 CPU 的 cache 的奇偶检测位。
parity_protection_init();
由于 Data Bus Errors / Instruction Bus Errors 异常是由外部硬件通知的,
所以这两种异常需要有板级的特殊处理程序。
if (board_be_init)
board_be_init();
根据 ExcCode 域的值对通用异常处理表进行初始化,注册各个通用异常处理程序。
可以查看 CACUS 寄存器 ExcCode 域的值所对应的异常种类。
set_except_vector(0, handle_int); 中断的处理程序
set_except_vector(1, handle_tlbm);
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);
set_except_vector(7, handle_dbe);
set_except_vector(8, handle_sys);
set_except_vector(9, handle_bp);
set_except_vector(10, rdhwr_noopt ? handle_ri :
(cpu_has_vtag_icache ?
handle_ri_rdhwr_vivt : handle_ri_rdhwr));
set_except_vector(11, handle_cpu);
set_except_vector(12, handle_ov);
set_except_vector(13, handle_tr);
if (current_cpu_data.cputype == CPU_R6000 ||
current_cpu_data.cputype == CPU_R6000A) {
如果 CPU 的类型是 CPU_R6000 或者 CPU_R6000A,就
注册一些专用的通用异常处理程序。
}
如果 CPU 支持不可屏蔽中断,设置不可屏蔽中断的处理函数。
移植相关,移植时需要配置。
if (board_nmi_handler_setup)
board_nmi_handler_setup();
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)
set_except_vector(25, handle_mt);
set_except_vector(26, handle_dsp);
--------------------------------------
选择特殊的通用异常处理程序,并拷贝到通用异常入口(ebase+0x180)。
--------------------------------------
if (cpu_has_vce)
memcpy((void *)(CAC_BASE + 0x180), &except_vec3_r4000, 0x100);
else if (cpu_has_4kex)
memcpy((void *)(CAC_BASE + 0x180), &except_vec3_generic, 0x80);
else
memcpy((void *)(CAC_BASE + 0x080), &except_vec3_generic, 0x80);
设置浮点处理器的保存和加载程序指针。
signal_init();
这个 flush_icache_range()是一个函数指针,在 r4k_cache_init() 函数中赋值。
参考《linux-mips启动分析(9-1)》。
把 ebase 地址到 ebase + 0x400 地址的指令装入 指令 cache 中去。
flush_icache_range(ebase, ebase + 0x400);
把 TLB 修改、加载和读取异常的处理代码加载到指令缓存中。
flush_tlb_handlers();
}
********************************************
这个 cpu_has_vint 变量是在 include/asm-mips/cpu-features.h 文件中定义的,
这个 CONFIG_CPU_MIPSR2_IRQ_VI 宏定义,表明 CPU 是否支持 Vectored interrupt mode。
这种模式能够使中断分发反应更加快速。这种模式的代码兼容非 Vectored interrupt mode。
所以如果一个 CPU 不支持这种模式,也可以选择上这个选项。
---------------------------------
#if defined(CONFIG_CPU_MIPSR2_IRQ_VI) && !defined(cpu_has_vint)
# define cpu_has_vint (cpu_data[0].options & MIPS_CPU_VINT)
#elif !defined(cpu_has_vint)
# define cpu_has_vint 0
#endif
********************************************
这个 CONFIG_CPU_MIPSR2_SRS 宏配置的帮助信息:
Allow the kernel to use shadow register sets for fast interrupts.
Interrupt handlers must be specially written to use shadow sets.
Say N unless you know that shadow register set upport is needed.
********************************************
把 addr 起始地址的代码(异常处理程序)拷贝到 (ebase + offset) 地址(异常处理入口点)。
---------------------------------
void __init set_handler (unsigned long offset, void *addr, unsigned long size)
{
memcpy((void *)(ebase + offset), addr, size);
flush_icache_range(ebase + offset, ebase + offset + size);
}
********************************************
这个 signal_init() 函数被 trap_init() 函数所调用。
这个函数初始化 save_fp_context 和 restore_fp_context 这两个函数指针。
这两个变量 save_fp_context 和 restore_fp_context 是两个函数指针。
这个两个函数用来保存和重新加载协处理器浮点处理器的上下文。
asmlinkage int (*save_fp_context)(struct sigcontext __user *sc);
asmlinkage int (*restore_fp_context)(struct sigcontext __user *sc);
-----------------------------------------
static inline void signal_init(void)
{
if (cpu_has_fpu) {
save_fp_context = _save_fp_context;
restore_fp_context = _restore_fp_context;
} else {
save_fp_context = fpu_emulator_save_context;
restore_fp_context = fpu_emulator_restore_context;
}
}
********************************************
这个 flush_icache_range()是一个函数指针,在 r4k_cache_init() 函数中赋值。
参考《linux-mips启动分析(9-1)》。
在 r4k_cache_init()赋值 flush_icache_range = r4k_flush_icache_range 。
这个函数的主要作用是刷新 指定指令 cache 的范围。
-----------------------------------------
static void r4k_flush_icache_range(unsigned long start, unsigned long end)
{
struct flush_icache_range_args args;
args.start = start;
args.end = end;
r4k_on_each_cpu(local_r4k_flush_icache_range, &args, 1, 1);
instruction_hazard();
}
********************************************
这个 flush_tlb_handlers() 函数被 trap_init() 函数所调用。
这个函数把 TLB 修改、加载和读取异常的处理代码加载到指令缓存中。
-----------------------------------------
void __init flush_tlb_handlers(void)
{
把 TLB 读取异常的处理代码加载到指令缓存中。
flush_icache_range((unsigned long)handle_tlbl,
(unsigned long)handle_tlbl + sizeof(handle_tlbl));
把 TLB 加载异常的处理代码加载到指令缓存中。
flush_icache_range((unsigned long)handle_tlbs,
(unsigned long)handle_tlbs + sizeof(handle_tlbs));
把 TLB 修改异常的处理代码加载到指令缓存中。
flush_icache_range((unsigned long)handle_tlbm,
(unsigned long)handle_tlbm + sizeof(handle_tlbm));
}
********************************************
except_vec3_generic是硬件的异常处 理程序(exception handler),它和其它异常处理程序全部存在于entry-armv.S或genex.S内。
except_vec3_generic 内有exception_handlers,它是用来储存每一个硬件中断的lower- ISR,trap_init负责将所有的lower-ISR填入exception_handlers中。所有的lower-ISR都是存在于 entry-armv.S或genex.S内。硬件的lower-ISR称作handle_int,说来奇怪,所有硬件都使用这唯一的lower- ISR,这是因为CPU分配给硬件的中断源只有一个,不管是MIPS或ARM或PPC都是这样的。一有硬件异常或中断发生时,程序计数器(porgam counter;PC)会跳到“异常来源区”,执行except_vec3_generic,再跳到handle_int,最后跳到 plat_irq_dispatch-这就是high-ISR。
更多推荐
所有评论(0)