zoukankan      html  css  js  c++  java
  • Linux异常现场--pt_regs浅析

    Linux-5.4


    结构struct pt_regs用以在堆栈中保存异常发生时的现场寄存器信息,其具体定义与cpu架构相关;内核发生异常时输出的debug信息就是通过show_regs(regs)来打印的(实际上并步严谨,有些上下文中可能无法获取到pt_regs时使用dump_stack())。
    下面以arm64为背景进行介绍。

    系统发生异常时会根据异常类型核异常级别进入到对应的异常向量入口,然后开始进行异常现场的保存:

    1 kernel_ventry

    sub     sp, sp, #S_FRAME_SIZE

    在堆栈中预留出S_FRAME_SIZE大小的空间,S_FRAME_SIZE定义在arch/arm64/kernel/asm-offsets.c文件中,大小为sizeof(struct pt_regs);这里就是在堆栈中预留出sizeof(struct pt_regs)大小空间,预留后堆栈指针sp指向这个pt_reg的起始地址。

    2 kernel_entry

    stp     x0, x1, [sp, #16 * 0]
    .......
    stp     x28, x29, [sp, #16 * 14]
    ...
    /* 如果异常发生在用户态(EL0)则pt_regs将保存用户态堆栈指针sp_el0 */
    .if     el == 0
    mrs     x21, sp_el0
    .else
    /* 否则,异常发生在>EL0的异常级别,则pt_regs将保存上一次堆栈指针的起始位置 */
    add     x21, sp, #S_FRAME_SIZE
    .endif 
    
    mrs     x22, elr_el1
    mrs     x23, spsr_el1
    stp     lr, x21, [sp, #S_LR]        //将异常发生前的链接指针lr和堆栈指针sp存放到堆栈中
    
    .if el == 0
    stp     xzr, xzr, [sp, #S_STACKFRAME]
    .else
    stp     x29, x22, [sp, #S_STACKFRAME]        //对于EL != 0时,pt_regs.stackframe[]存放FP和异常LR
    .endif
    add     x29, sp, #S_STACKFRAME
    stp     x22, x23, [sp, #S_PC]    //将异常链接地址(即异常处理完毕后的返回地址)elr_el1和异常发生前PE状态存保存在堆栈中

    在kernel_entry这个宏中会将该次异常发生前的x0~x29寄存器、sp、lr、elr_el1、spsr_el1等等寄存器存放到堆栈的struct pt_regs内存中。

    3 异常处理具体流程(以中断处理为例,el0_irq 或者el1_irq)

    //irq_handler宏
    ldr_l   x1, handle_arch_irq        //irq处理函数钩子,对于gic-v3而言是gic_handle_irq(struct pt_regs *regs)
    mov     x0, sp            //用sp作为irq处理函数handle_arch_irq()的第一个参数
    blr     x1

    下面是更进一步调用关系:

    gic_handle_irq(struct pt_regs *regs)
    handle_domain_irq(gic_data.domain, irqnr, regs);
        set_irq_regs(regs)
            __this_cpu_write(__irq_regs, new_regs);

    其中__irq_regs是percpu变量,专门用于存放中断发生时的现场堆栈指针

    /*
     * Per-cpu current frame pointer - the location of the last exception frame on
     * the stack
     */
    DECLARE_PER_CPU(struct pt_regs *, __irq_regs);

     最终, 各个cpu上的中断异常发生时的现场就存放在percpu __irq_regs中,通过get_irq_regs()函数可获取到。

  • 相关阅读:
    Sublime Text 3——插件配置篇
    Sublime Text 3——基本介绍篇
    线性同余方程
    费马小定理
    一点心事
    寒诗
    e网通学习笔记
    std::cout<<"Goodbye 2019"<<" "<<"Hello 2020"<<' ';
    新砍
    NOIP2019游记
  • 原文地址:https://www.cnblogs.com/liuhailong0112/p/14916456.html
Copyright © 2011-2022 走看看