博客地址:http://home.cnblogs.com/u/zengjianrong/

内核态发生非法地址访问是否会panic

https://mp.weixin.qq.com/s?__biz=MzAwMDUwNDgxOA==&mid=2652663676&idx=1&sn=b18ab57322594ebb8e7072e635e8bd1c&chksm=810f29e1b678a0f7238e8a71fd88f14c3c71e65556d149bbe851f08f775300bc7bb6ddbb503a&mpshare=1&scene=1&srcid=07302BR8M8OSgsym8wtFHNaB&sharer_sharetime=1564482704949&sharer_shareid=6a5d5f4082de4dfaafd2e3b24b69c271&pass_ticket=%2F5q07o1VYrDuvadEaasOzg9XP3sH%2B7O3W7boz%2BUgwgRPvsLYbzZpFyYQyGgBbiiB#rd

如上链接是《宋宝华: Kernel Oops和Panic是一回事吗?》

大概介绍了在未开启panic_on_oops,内核态非中断上下文 发生 访问0地址 时,kernel只会发oops,而不会panic。

看完之后会有个疑问:缺页异常的上下文 是不是 中断上下文?

答案是否。具体解析如下:

1. 首先中断上下文是指当前HARDIRQ/NMI/softIRQ的计数不为0,code 如下:

1 #define irq_count()    (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK \
2                  | NMI_MASK))
3 #define in_interrupt()        (irq_count())

  HARDIRQ 计数 在irq_enter()/irq_exit()接口中 做增减, 题外话:在irq_exit接口中通过invoke_softirq()触发软中断,一次执行时间限制在2ms或10次以内

  NMI 计数 在nmi_enter()/nmi_exit()接口中 做增减,ARM64貌似没有找到调用的地方?????

  softIRQ 计数 在__local_bh_disable_ip/__local_bh_enable接口中 做增减

2. 对于ARM64, 异常向量表如下:

  1 // 文件:arch/arm64/kernel/entry.S
  2 
  3 // 向量表------------------------------------------------------------------------------------------------
  4     .align    11    //对齐2^7=128
  5 ENTRY(vectors)
  6     ventry    el1_sync_invalid        // Synchronous EL1t
  7     ventry    el1_irq_invalid            // IRQ EL1t
  8     ventry    el1_fiq_invalid            // FIQ EL1t
  9     ventry    el1_error_invalid        // Error EL1t
 10 
 11     ventry    el1_sync            // Synchronous EL1h 同步异常入口,缺页属于这一类
 12     ventry    el1_irq                // IRQ EL1h IRQ中断入口, HARDIRQ/SOFTIRQ 计数均在此入口增减
 13     ventry    el1_fiq_invalid            // FIQ EL1h FIQ入口,即NMI???? NMI计数应该在这个入口增减???
 14     ventry    el1_error_invalid        // Error EL1h
 15 
 16     ventry    el0_sync            // Synchronous 64-bit EL0
 17     ventry    el0_irq                // IRQ 64-bit EL0
 18     ventry    el0_fiq_invalid            // FIQ 64-bit EL0
 19     ventry    el0_error_invalid        // Error 64-bit EL0
 20 
 21 #ifdef CONFIG_COMPAT
 22     ventry    el0_sync_compat            // Synchronous 32-bit EL0
 23     ventry    el0_irq_compat            // IRQ 32-bit EL0
 24     ventry    el0_fiq_invalid_compat        // FIQ 32-bit EL0
 25     ventry    el0_error_invalid_compat    // Error 32-bit EL0
 26 #else
 27     ventry    el0_sync_invalid        // Synchronous 32-bit EL0
 28     ventry    el0_irq_invalid            // IRQ 32-bit EL0
 29     ventry    el0_fiq_invalid            // FIQ 32-bit EL0
 30     ventry    el0_error_invalid        // Error 32-bit EL0
 31 #endif
 32 END(vectors)
 33 
 34 // 同步异常:系统调用/数据abort/指令abort/未对齐/未定义/调试异常---------------------------------------------
 35     .align    6
 36 el1_sync:
 37     kernel_entry 1
 38     mrs    x1, esr_el1            // read the syndrome register
 39     lsr    x24, x1, #ESR_ELx_EC_SHIFT    // exception class
 40     cmp    x24, #ESR_ELx_EC_DABT_CUR    // data abort in EL1
 41     b.eq    el1_da
 42     cmp    x24, #ESR_ELx_EC_SYS64        // configurable trap
 43     b.eq    el1_undef
 44     cmp    x24, #ESR_ELx_EC_SP_ALIGN    // stack alignment exception
 45     b.eq    el1_sp_pc
 46     cmp    x24, #ESR_ELx_EC_PC_ALIGN    // pc alignment exception
 47     b.eq    el1_sp_pc
 48     cmp    x24, #ESR_ELx_EC_UNKNOWN    // unknown exception in EL1
 49     b.eq    el1_undef
 50     cmp    x24, #ESR_ELx_EC_BREAKPT_CUR    // debug exception in EL1
 51     b.ge    el1_dbg
 52     b    el1_inv
 53 // 数据abort
 54 el1_da:
 55     /*
 56      * Data abort handling
 57      */
 58     mrs    x0, far_el1
 59     enable_dbg
 60     // re-enable interrupts if they were enabled in the aborted context
 61     tbnz    x23, #7, 1f            // PSR_I_BIT
 62     enable_irq
 63 1:
 64     mov    x2, sp                // struct pt_regs
 65 // 跳往do_mem_abort->do_transation_fault->do_page_fault->do_kernel_fault->die->...
 66     bl    do_mem_abort
 67 
 68     // disable interrupts before pulling preserved data off the stack
 69     disable_irq
 70     kernel_exit 1
 71 el1_sp_pc:
 72     /*
 73      * Stack or PC alignment exception handling
 74      */
 75     mrs    x0, far_el1
 76     enable_dbg
 77     mov    x2, sp
 78     b    do_sp_pc_abort
 79 el1_undef:
 80     /*
 81      * Undefined instruction
 82      */
 83     enable_dbg
 84     mov    x0, sp
 85     b    do_undefinstr
 86 el1_dbg:
 87     /*
 88      * Debug exception handling
 89      */
 90     cmp    x24, #ESR_ELx_EC_BRK64        // if BRK64
 91     cinc    x24, x24, eq            // set bit '0'
 92     tbz    x24, #0, el1_inv        // EL1 only
 93     mrs    x0, far_el1
 94     mov    x2, sp                // struct pt_regs
 95     bl    do_debug_exception
 96     kernel_exit 1
 97 el1_inv:
 98     // TODO: add support for undefined instructions in kernel mode
 99     enable_dbg
100     mov    x0, sp
101     mov    x1, #BAD_SYNC
102     mrs    x2, esr_el1
103     b    bad_mode
104 ENDPROC(el1_sync)
105 
106 // IRQ-------------------------------------------------------------------------------------------------------
107     .align    6
108 el1_irq:
109     kernel_entry 1
110     enable_dbg
111 #ifdef CONFIG_TRACE_IRQFLAGS
112     bl    trace_hardirqs_off
113 #endif
114 // 中断入口调用:handle_arch_irq->handle_irq
115     irq_handler
116 
117 #ifdef CONFIG_PREEMPT
118     get_thread_info tsk
119     ldr    w24, [tsk, #TI_PREEMPT]        // get preempt count
120     cbnz    w24, 1f                // preempt count != 0
121     ldr    x0, [tsk, #TI_FLAGS]        // get flags
122     tbz    x0, #TIF_NEED_RESCHED, 1f    // needs rescheduling?
123 // 中断返回前执行抢占
124     bl    el1_preempt    
125 1:
126 #endif
127 #ifdef CONFIG_TRACE_IRQFLAGS
128     bl    trace_hardirqs_on
129 #endif
130     kernel_exit 1
131 ENDPROC(el1_irq)    

3. HARDIRQ softIRQ 计数增减 的 代码流程,即缺页异常的流程 如下图:

 

综上,在缺页的流程中:HARDIRQ/SOFTIRQ/NMI计数都没有增减,故in_interrupt()

 

posted @ 2019-08-01 02:02  black_man  阅读(907)  评论(0编辑  收藏  举报