mips linux trap_init函数分析(转)

转自: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.Sgenex.S内。
except_vec3_generic
内有exception_handlers,它是用来储存每一个硬件中断的lower- ISRtrap_init负责将所有的lower-ISR填入exception_handlers中。所有的lower-ISR都是存在于 entry-armv.Sgenex.S内。硬件的lower-ISR称作handle_int,说来奇怪,所有硬件都使用这唯一的lower- ISR,这是因为CPU分配给硬件的中断源只有一个,不管是MIPSARMPPC都是这样的。一有硬件异常或中断发生时,程序计数器(porgam counterPC)会跳到异常来源区,执行except_vec3_generic,再跳到handle_int,最后跳到 plat_irq_dispatch-这就是high-ISR

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值