Linux内核panic到ramdump基本流程

Linux内核空指针访问异常大致流程

插一下arm系统模式切换说明
/*
arm处理有很多模式,寄存器也有各个模式下专用和通用的寄存器
当从用户态等切入异常模式的时候,cpsr会发生切换,pc指针强制指向对应异常向量地址。
汇编代码vector_\name处理时会从异常模式切到svc模式,不然一些寄存器不是通用的,回不去。
vector_\name:
    .if \correction
    sub    lr, lr, #\correction
    .endif

    @
    @ Save r0, lr_ (parent PC) and spsr_
    @ (parent CPSR)
    @
    stmia    sp, {r0, lr}        @ save r0, lr
    mrs    lr, spsr
    str    lr, [sp, #8]        @ save spsr

    @
    @ Prepare for SVC32 mode.  IRQs remain disabled.
    @
    mrs    r0, cpsr
    eor    r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
    msr    spsr_cxsf, r0

之后进入对应异常处理,同时保持异常之前模式下的寄存器,sp等信息,r0和lr在上面的代码已经保存到堆栈了。
     .macro    usr_entry
 UNWIND(.fnstart    )
 UNWIND(.cantunwind    )    @ don't unwind the user space
    sub    sp, sp, #S_FRAME_SIZE
 ARM(    stmib    sp, {r1 - r12}    )

之后处理完成时,恢复这些寄存器信息,跳转pc,回到异常之前。

*/

先看下异常向量表的定义,感觉很绕

early_trap_init

#define CONFIG_VECTORS_BASE 0xffff0000
early_trap_init((void *)CONFIG_VECTORS_BASE);
        memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
	memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
	memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);

先看一个宏定义vector_stub 参数是name mode第三个应该是为b指令手动设置返回地址的

这块的解释借用别人的用下https://www.cnblogs.com/yangjiguang/p/7629928.html

参考https://blog.csdn.net/forever_2015/article/details/53235716?locationNum=6&fps=1

	.macro	vector_stub, name, mode, correction=0
	.align	5

vector_\name:
	.if \correction
	sub	lr, lr, #\correction
	.endif

	@
	@ Save r0, lr_ (parent PC) and spsr_
	@ (parent CPSR)
	@
	stmia	sp, {r0, lr}		@ save r0, lr
	mrs	lr, spsr
	str	lr, [sp, #8]		@ save spsr

	@
	@ Prepare for SVC32 mode.  IRQs remain disabled.
	@
	mrs	r0, cpsr
	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
	msr	spsr_cxsf, r0

	@
	@ the branch table must immediately follow this code
	@
	and	lr, lr, #0x0f
 THUMB(	adr	r0, 1f			)
 THUMB(	ldr	lr, [r0, lr, lsl #2]	)
	mov	r0, sp
 ARM(	ldr	lr, [pc, lr, lsl #2]	)
	movs	pc, lr			@ branch to handler in SVC mode
ENDPROC(vector_\name)
.equ    stubs_offset, __vectors_start + 0x200 - __stubs_start
__vectors_start:
 ARM(	swi	SYS_ERROR0	)
 THUMB(	svc	#0		)
 THUMB(	nop			)
	W(b)	vector_und + stubs_offset
	W(ldr)	pc, .LCvswi + stubs_offset
	W(b)	vector_pabt + stubs_offset
	W(b)	vector_dabt + stubs_offset
	W(b)	vector_addrexcptn + stubs_offset
	W(b)	vector_irq + stubs_offset
	W(b)	vector_fiq + stubs_offset

	.globl	__vectors_end
__vectors_end:
__stubs_start:
......

/*
 * Data abort dispatcher
 * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
 */
	vector_stub	dabt, ABT_MODE, 8

	.long	__dabt_usr			@  0  (USR_26 / USR_32)
	.long	__dabt_invalid			@  1  (FIQ_26 / FIQ_32)
	.long	__dabt_invalid			@  2  (IRQ_26 / IRQ_32)
	.long	__dabt_svc			@  3  (SVC_26 / SVC_32)
	.long	__dabt_invalid			@  4
	.long	__dabt_invalid			@  5
	.long	__dabt_invalid			@  6
	.long	__dabt_invalid			@  7
	.long	__dabt_invalid			@  8
	.long	__dabt_invalid			@  9
	.long	__dabt_invalid			@  a
	.long	__dabt_invalid			@  b
	.long	__dabt_invalid			@  c
	.long	__dabt_invalid			@  d
	.long	__dabt_invalid			@  e
	.long	__dabt_invalid			@  f

......
    .globl    __stubs_end
__stubs_end: 

最后会跳转到__dabt_svc-->dabt_helper

bl    CPU_DABORT_HANDLER

ENTRY(v7_early_abort)
	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
	mrc	p15, 0, r0, c6, c0, 0		@ get FAR

	/*
	 * V6 code adjusts the returned DFSR.
	 * New designs should not need to patch up faults.
	 */

#if defined(CONFIG_VERIFY_PERMISSION_FAULT)
	/*
	 * Detect erroneous permission failures and fix
	 */
	ldr	r3, =0x40d			@ On permission fault
	and	r3, r1, r3
	cmp	r3, #0x0d
	bne	do_DataAbort

	mcr	p15, 0, r0, c7, c8, 0   	@ Retranslate FAR
	isb
	mrc	p15, 0, ip, c7, c4, 0   	@ Read the PAR
	and	r3, ip, #0x7b   		@ On translation fault
	cmp	r3, #0x0b
	bne	do_DataAbort
	bic	r1, r1, #0xf			@ Fix up FSR FS[5:0]
	and	ip, ip, #0x7e
	orr	r1, r1, ip, LSR #1
#endif

	b	do_DataAbort
ENDPROC(v7_early_abort)
do_DataAbort    
    static struct fsr_info fsr_info[] = {
    /*
     * The following are the standard ARMv3 and ARMv4 aborts.  ARMv5
     * defines these to be "precise" aborts.
     */
    { do_bad,        SIGSEGV, 0,        "vector exception"           },
    { do_bad,        SIGBUS,     BUS_ADRALN,    "alignment exception"           },
    { do_bad,        SIGKILL, 0,        "terminal exception"           },
    { do_bad,        SIGBUS,     BUS_ADRALN,    "alignment exception"           },
    { do_bad,        SIGBUS,     0,        "external abort on linefetch"       },
    { do_translation_fault,    SIGSEGV, SEGV_MAPERR,    "section translation fault"       },
    { do_bad,        SIGBUS,     0,        "external abort on linefetch"       },
    { do_page_fault,    SIGSEGV, SEGV_MAPERR,    "page translation fault"       },
    { do_bad,        SIGBUS,     0,        "external abort on non-linefetch"  },
    { do_bad,        SIGSEGV, SEGV_ACCERR,    "section domain fault"           },
    { do_bad,        SIGBUS,     0,        "external abort on non-linefetch"  },
    { do_bad,        SIGSEGV, SEGV_ACCERR,    "page domain fault"           },
    { do_bad,        SIGBUS,     0,        "external abort on translation"       },
    { do_sect_fault,    SIGSEGV, SEGV_ACCERR,    "section permission fault"       },
    { do_bad,        SIGBUS,     0,        "external abort on translation"       },
    { do_page_fault,    SIGSEGV, SEGV_ACCERR,    "page permission fault"           },
    /*
     * The following are "imprecise" aborts, which are signalled by bit
     * 10 of the FSR, and may not be recoverable.  These are only
     * supported if the CPU abort handler supports bit 10.
     */
    { do_bad,        SIGBUS,  0,        "unknown 16"               },
    { do_bad,        SIGBUS,  0,        "unknown 17"               },
    { do_bad,        SIGBUS,  0,        "unknown 18"               },
    { do_bad,        SIGBUS,  0,        "unknown 19"               },
    { do_bad,        SIGBUS,  0,        "lock abort"               }, /* xscale */
    { do_bad,        SIGBUS,  0,        "unknown 21"               },
    { do_bad,        SIGBUS,  BUS_OBJERR,    "imprecise external abort"       }, /* xscale */
    { do_bad,        SIGBUS,  0,        "unknown 23"               },
    { do_bad,        SIGBUS,  0,        "dcache parity error"           }, /* xscale */
    { do_bad,        SIGBUS,  0,        "unknown 25"               },
    { do_bad,        SIGBUS,  0,        "unknown 26"               },
    { do_bad,        SIGBUS,  0,        "unknown 27"               },
    { do_bad,        SIGBUS,  0,        "unknown 28"               },
    { do_bad,        SIGBUS,  0,        "unknown 29"               },
    { do_bad,        SIGBUS,  0,        "unknown 30"               },
    { do_bad,        SIGBUS,  0,        "unknown 31"               },
};
    //硬件断点异常捕获
    hook_fault_code(FAULT_CODE_DEBUG, hw_breakpoint_pending, SIGTRAP,TRAP_HWBKPT, "watchpoint debug exception");

if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))    这里根据异常的标志,找到对应的hook函数执行。
    do_translation_fault
    do_page_fault
    __do_page_fault
    __do_kernel_fault
    die("Oops", regs, fsr);
        if (in_interrupt())
            panic("Fatal exception in interrupt");
        if (panic_on_oops)
            panic("Fatal exception");
        if (ret != NOTIFY_STOP)
            do_exit(SIGSEGV); 

void panic(const char *fmt, ...)
__die    dump线程stack和寄存器
local_irq_disable();    锁中断
dump_stack();    打印堆栈,防止二次panic
if (panic_timeout != 0) {    选择是否重启设备
        /*
         * This will not be a clean reboot, with everything
         * shutting down.  But if there is a chance of
         * rebooting the system it will be rebooted.
         */
        emergency_restart();
    }
不重启进入ramdump流程
ramdump_entry()
    dump出ap的ddr空间,需要的设备寄存器信息,通过usb的内部dma控制器写出去

应用coredump参考https://blog.csdn.net/omnispace/article/details/77600721


处理器提供专门断点寄存器保存一个地址,处理器在执行程序过程,会不断去匹配,可以设置成不同的模式来触发程序中断,如执行到这个地址,读这个地址或写这个地址, 并且可以设置长度,按8位,16位,或32位来触发。和软件断点比,好处是可以支持读写断点,程序断点不需要改写内存,可以设在ROM中,在虚拟地址映射前也可设置等等。

软硬件断点参考https://blog.csdn.net/sxw1002/article/details/77169610

http://www.360doc.com/content/17/0823/11/17136639_681458868.shtml


你可能感兴趣的:(Linux内核panic到ramdump基本流程)