NOTE:为了方便大家阅读,制作了PDF版文档。下载请猛戳这里

老样子,为了赚点积分下载其它人的文件,下载以上资料须要资源分2分。 假设没有积分请留言全部文档,留下邮箱就可以。

看了Linaro提供的开源ARMv8 Linux内核源代码,发现ARMv8异常处理与ARMv7及之前的架构有所不同,简单分析。

LinaroARMv8工程:http://www.linaro.org/engineering/engineering-projects/armv8

1.1 Linux内核异常处理相关文件

Linux内核中,异常处理主要由两个文件完毕,entry.S和traps.c。当然另一些其他异常处理函数分布于fault.c, memory.c等等。entry.S包括异常的入口、进入异常处理C函数前的压栈、退出C函数前的出栈、一些fork函数相关的处理代码(暂不分析)、任务切换汇编处理过程(cpu_switch_to函数,暂不分析)。

traps.c主要包括异常处理C函数。

本文主要分析entry.S,对于traps.c作简要介绍。

1.2 运行kernel_entry之前的栈


1.3 运行kernel_entry时的栈


1.4 运行kernel_exit 时的栈


1.5 entry.s代码分析

/*

* Low-level exception handling code

*

* Copyright (C) 2012 ARM Ltd.

* Authors: CatalinMarinas <catalin.marinas@arm.com>

*         WillDeacon <will.deacon@arm.com>

*

* This program is free software; you canredistribute it and/or modify

* it under the terms of the GNU General PublicLicense version 2 as

* published by the Free Software Foundation.

*

* This program is distributed in the hope thatit will be useful,

* but WITHOUT ANY WARRANTY; without even theimplied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULARPURPOSE.  See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNUGeneral Public License

* along with this program.  If not, see<http://www.gnu.org/licenses/>.

*/

#include<linux/init.h>

#include<linux/linkage.h>

#include<asm/assembler.h>

#include<asm/asm-offsets.h>

#include<asm/errno.h>

#include<asm/thread_info.h>

#include<asm/unistd.h>

#include<asm/unistd32.h>

/*

* Bad Abort numbers

*-----------------

*/

#defineBAD_SYNC       0

#defineBAD_IRQ           1

#defineBAD_FIQ           2

#defineBAD_ERROR     3

//依据该结构体内容

/*

structpt_regs {

union {

struct user_pt_regs user_regs;//结构体user_pt_regs和结构体pt_regs内容一样

struct {                              //共用体存储31个通用寄存器,外加sp,pc,pstate三个特殊寄存器

//该结构体用于异常处理的压栈弹栈操作

u64 regs[31];

u64 sp;

u64 pc;

u64 pstate;

};

};

u64 orig_x0;

u64 syscallno;

};

*/

//S_FRAME_SIZE定义在asm-offsets.c中,DEFINE(S_FRAME_SIZE,sizeof(structpt_regs));

//即结构体pt_regs的大小。结构体pt_regs的定义见上面

//S_LR定义:DEFINE(S_LR,offsetof(structpt_regs, regs[30]));

//即31号寄存器在结构体pt_regs中的偏移量

//阅读下面内容请參考图1 和图2

.macro   kernel_entry,el, regsize = 64

sub sp,sp, #S_FRAME_SIZE - S_LR  // room for LR,SP, SPSR, ELR,见图2中sp'指向的位置

.if   \regsize== 32

mov       w0,w0                       // zero upper 32bits of x0

.endif

/*

*.macro      push,xreg1, xreg2     //压栈两个寄存器

*stp     \xreg1,\xreg2, [sp, #-16]! //注意!。。push指令也改变sp的值!

*.endm

*/

push      x28,x29              //进行压栈操作,push也是一个宏定义,由于ARMv8没有push指令,用stp取代

push      x26,x27

push      x24,x25

push      x22,x23

push      x20,x21

push      x18,x19

push      x16,x17

push      x14,x15

push      x12,x13

push      x10,x11

push      x8,x9

push      x6,x7

push      x4,x5

push      x2,x3

push      x0,x1           //此时sp指向位置见图2中sp''

.if   \el== 0         //假设异常级是el0,把el0的sp栈指针给x21寄存器

mrs x21,sp_el0

.else

add x21,sp, #S_FRAME_SIZE     //假设异常级不是el0,把sp指针指向的地方加上pt_regs大小后的地址放入x21,

//即指向没进入kernel_entry函数钱的sp指向的位置,见图2中x21指向的地址

.endif

mrs x22,elr_el1                //把el1的lr寄存器给x22

mrs x23,spsr_el1                    //把spsr给x23

stp  lr,x21, [sp, #S_LR]   //把lr。x21寄存器存入sp+S_LR指向的地方

stp  x22,x23, [sp, #S_PC]       //把lr,存入sp+s_PC指向的位置。用于异常返回

/*

*Set syscallno to -1 by default (overridden later if real syscall).

*/

.if   \el== 0

mvn       x21,xzr

str   x21,[sp, #S_SYSCALLNO]

.endif

/*

*Registers that may be useful after this macro is invoked:

*

*x21 - aborted SP

*x22 - aborted PC

*x23 - aborted PSTATE

*/

.endm

.macro   kernel_exit,el, ret = 0

//把此时sp(即图2中sp'')+S_PC位置处開始的16字节内容分别给x21,x22

//即把栈中存的x21和x22内容取出来

ldp  x21,x22, [sp, #S_PC]              // load ELR,SPSR

.if   \el== 0

ldr  x23,[sp, #S_SP]        // load return stackpointer,取出

.endif

.if   \ret

ldr  x1,[sp, #S_X1]                 // preserve x0(syscall return)。假设ret=1,则保存x0,用于系统调用,暂不分析

add sp,sp, S_X2

.else

pop x0,x1                         //假设ret=0,弹出x0,x1

.endif

pop x2,x3                         // load therest of the registers

pop x4,x5

pop x6,x7

pop x8,x9

msr elr_el1,x21                // set up the returndata。把前面弹出的x21,x22分别赋值给elr_el1,spsr_el1

msr spsr_el1,x22

.if   \el== 0

msr sp_el0,x23

.endif

pop x10,x11

pop x12,x13

pop x14,x15

pop x16,x17

pop x18,x19

pop x20,x21

pop x22,x23

pop x24,x25

pop x26,x27

pop x28,x29

ldr  lr,[sp], #S_FRAME_SIZE - S_LR // load LR andrestore SP。把lr弹出

eret                             //return to kernel,异常返回,该指令会把lr给pc,完毕跳转

.endm

.macro   get_thread_info,rd

mov       \rd,sp

and \rd,\rd, #~((1 << 13) - 1)  // top of 8Kstack

.endm

/*

* These are the registers used in the syscallhandler, and allow us to

* have in theory up to 7 arguments to afunction - x0 to x6.

*

* x7 is reserved for the system call number in32-bit mode.

*/

sc_nr    .req x25        // number of system calls

scno      .req x26        // syscall number

stbl       .req x27        // syscall table pointer

tsk .req x28        // current thread_info

/*

* Interrupt handling.

*/

.macro   irq_handler

ldr  x1,handle_arch_irq

mov       x0,sp

blr  x1

.endm

.text

/*

* Exception vectors.

*/

.macro   ventry    label      //这里是2^7对齐。即对齐到内存地址的0x80

.align     7

b     \label

.endm

.align     11

/*ENTRY也是一个宏,定义在include/linkage.h中

*#ifndef ENTRY

*#define ENTRY(name) \

*.globl name; \

*ALIGN; \

*name:

*#endif

*/

ENTRY(vectors)

ventry    el1_sync_invalid       // Synchronous EL1t,ventry 是一个宏,见上面定义

ventry    el1_irq_invalid                 // IRQ EL1t,这个版本号的内核,对于XXX_invalid类异常都是不真正处理的。

这里以el1_irq_invalid进行分析

ventry    el1_fiq_invalid                 // FIQ EL1t

ventry    el1_error_invalid              // Error EL1t

ventry    el1_sync                     // Synchronous EL1h。以el1级发生同步异常为例,具体分析内核异常处理过程

ventry    el1_irq                       // IRQ EL1h

ventry    el1_fiq_invalid                 // FIQ EL1h

ventry    el1_error_invalid              // Error EL1h

ventry    el0_sync                     // Synchronous 64-bit EL0

ventry    el0_irq                       // IRQ 64-bit EL0

ventry    el0_fiq_invalid                 // FIQ 64-bit EL0

ventry    el0_error_invalid              // Error 64-bit EL0

#ifdefCONFIG_COMPAT

ventry    el0_sync_compat                     // Synchronous 32-bit EL0

ventry    el0_irq_compat                // IRQ 32-bit EL0

ventry    el0_fiq_invalid_compat          // FIQ 32-bit EL0

ventry    el0_error_invalid_compat       // Error 32-bit EL0

#else

ventry    el0_sync_invalid       // Synchronous 32-bit EL0

ventry    el0_irq_invalid                 // IRQ 32-bit EL0

ventry    el0_fiq_invalid                 // FIQ 32-bit EL0

ventry    el0_error_invalid              // Error 32-bit EL0

#endif

END(vectors)

/*

* Invalid mode handlers

*/

.macro   inv_entry,el, reason, regsize = 64

kernel_entry el, \regsize        //kernel_entry是宏,主要完毕寄存器压栈操作。

mov       x0,sp                                       //x0,x1,x2是传给函数bad_mode函数的參数。

sp是当前栈指针。

mov       x1,#\reason                      //x1是发生异常的原因,用于读取一个结构体。在函数bad_mode中会介绍

mrs x2,esr_el1                               //通过分析bad_mode及其它函数。确定esr_el1是el1级异常分类寄存器,

//用于在一个大类异常(比如syc异常)中细分异常类型

b     bad_mode

.endm

el0_sync_invalid:

inv_entry 0, BAD_SYNC

ENDPROC(el0_sync_invalid)

el0_irq_invalid:

inv_entry 0, BAD_IRQ

ENDPROC(el0_irq_invalid)

el0_fiq_invalid:

inv_entry 0, BAD_FIQ

ENDPROC(el0_fiq_invalid)

el0_error_invalid:

inv_entry 0, BAD_ERROR

ENDPROC(el0_error_invalid)

#ifdefCONFIG_COMPAT

el0_fiq_invalid_compat:

inv_entry 0, BAD_FIQ, 32

ENDPROC(el0_fiq_invalid_compat)

el0_error_invalid_compat:

inv_entry 0, BAD_ERROR, 32

ENDPROC(el0_error_invalid_compat)

#endif

el1_sync_invalid:

inv_entry 1, BAD_SYNC

ENDPROC(el1_sync_invalid)

el1_irq_invalid:

inv_entry 1, BAD_IRQ     //inv_entry是一个宏定义,主要工作就是将寄存器压栈后跳到bad_mode函数执行。

//后面紧跟的1代表异常级是el1。即内核态。

//BAD_IRQ定义在前面。值为1,代表发生异常的原因

ENDPROC(el1_irq_invalid)

el1_fiq_invalid:

inv_entry 1, BAD_FIQ

ENDPROC(el1_fiq_invalid)

el1_error_invalid:

inv_entry 1, BAD_ERROR

ENDPROC(el1_error_invalid)

/*

* EL1 mode handlers.

*/

.align     6

el1_sync:

kernel_entry 1                  //把寄存器信息压栈

//读异常类型寄存器

mrs x1,esr_el1                 // read thesyndrome register

//逻辑右移26位。取31-27位

lsr   x24,x1, #26               // exception class

//推断异常类型

cmp       x24,#0x25                 // data abort in EL1

//假设是el1的数据中止(data_abort)异常。跳转到el1_da标号处

b.eq el1_da

cmp       x24,#0x18                 // configurable trap

b.eq el1_undef

cmp       x24,#0x26                 // stack alignmentexception

b.eq el1_sp_pc

cmp       x24,#0x22                 // pc alignmentexception

b.eq el1_sp_pc

cmp       x24,#0x00                 // unknown exceptionin EL1

b.eq el1_undef

cmp       x24,#0x30                 // debug exceptionin EL1

b.ge el1_dbg

b     el1_inv

el1_da:

/*

*Data abort handling,数据中止异常处理函数

*/

mrs x0,far_el1          //看过函数do_mem_abort内容后确定,far_el1寄存器是异常地址寄存器

/* 该宏定义在arm64/include/asm/assembler.h中:

*.macro     enable_dbg_if_not_stepping, tmp

*mrs   \tmp, mdscr_el1  //通过该宏名称确定,mdscr_el1寄存器是关于硬件debug的。不影响异常处理不分析

*tbnz  \tmp, #1, 9990f

*enable_dbg

*9990:

*.endm

*/

//通过以上内容及该宏名称能够推測,其作用仅仅是依据条件决定是否开启dbg模式,不影响异常运行,不做分析

enable_dbg_if_not_stepping x2

// re-enable interrupts if they wereenabled in the aborted context

//依据x23(在kernel_entry中定义,存储spsr的值)推断是否开启中断

tbnz       x23,#7, 1f                  // PSR_I_BIT

enable_irq

1:

mov       x2,sp                         // structpt_regs。sp中存储的是运行完kernel_entry后的值,其指向压栈后的栈顶。作为參数传给函数do_mem_abort

//do_mem_abort函数在arm64/mm/fault.c中。分析见代码最后面

bl    do_mem_abort          //传给该函数的x0发生异常的地址信息,x1是异常类型。x2就是压入栈中的寄存器堆首地址。

// disable interrupts before pulling preserveddata off the stack

disable_irq

kernel_exit 1              //异常返回,把全部压入栈中的寄存器弹出。

相应于kernel_entry。

el1_sp_pc:

/*

*Stack or PC alignment exception handling

*/

mrs x0,far_el1

mov       x1,x25

mov       x2,sp

b     do_sp_pc_abort

el1_undef:

/*

*Undefined instruction

*/

mov       x0,sp

b     do_undefinstr

el1_dbg:

/*

*Debug exception handling

*/

tbz  x24,#0, el1_inv         // EL1 only

mrs x0,far_el1

mov       x2,sp                         // structpt_regs

bl    do_debug_exception

kernel_exit 1

el1_inv:

// TODO: add support for undefined instructionsin kernel mode

mov       x0,sp

mov       x1,#BAD_SYNC

mrs x2,esr_el1

b     bad_mode

ENDPROC(el1_sync)

.align     6

el1_irq:

kernel_entry 1

enable_dbg_if_not_stepping x0

#ifdefCONFIG_TRACE_IRQFLAGS

bl    trace_hardirqs_off

#endif

#ifdefCONFIG_PREEMPT

get_thread_info tsk

ldr  x24,[tsk, #TI_PREEMPT]             // getpreempt count

add x0,x24, #1                 // increment it

str   x0,[tsk, #TI_PREEMPT]

#endif

irq_handler

#ifdefCONFIG_PREEMPT

str   x24,[tsk, #TI_PREEMPT]             // restorepreempt count

cbnz      x24,1f                        // preempt count!= 0

ldr  x0,[tsk, #TI_FLAGS]             // get flags

tbz  x0,#TIF_NEED_RESCHED, 1f     // needsrescheduling?

bl    el1_preempt

1:

#endif

#ifdefCONFIG_TRACE_IRQFLAGS

bl    trace_hardirqs_on

#endif

kernel_exit 1

ENDPROC(el1_irq)

#ifdefCONFIG_PREEMPT

el1_preempt:

mov       x24,lr

1:   enable_dbg

bl    preempt_schedule_irq             // irq en/disable is done inside

ldr  x0,[tsk, #TI_FLAGS]             // get newtasks TI_FLAGS

tbnz       x0,#TIF_NEED_RESCHED, 1b    // needsrescheduling?

ret   x24

#endif

/*

* EL0 mode handlers.

*/

.align     6

el0_sync:

kernel_entry 0

mrs x25,esr_el1               // read the syndromeregister

lsr   x24,x25, #26                    // exceptionclass

cmp       x24,#0x15                 // SVC in 64-bitstate

b.eq el0_svc

adr  lr,ret_from_exception

cmp       x24,#0x24                 // data abort in EL0

b.eq el0_da

cmp       x24,#0x20                 // instruction abortin EL0

b.eq el0_ia

cmp       x24,#0x07                 // FP/ASIMD access

b.eq el0_fpsimd_acc

cmp       x24,#0x2c                 // FP/ASIMDexception

b.eq el0_fpsimd_exc

cmp       x24,#0x18                 // configurable trap

b.eq el0_undef

cmp       x24,#0x26                 // stack alignmentexception

b.eq el0_sp_pc

cmp       x24,#0x22                 // pc alignmentexception

b.eq el0_sp_pc

cmp       x24,#0x00                 // unknown exceptionin EL0

b.eq el0_undef

cmp       x24,#0x30                 // debug exceptionin EL0

b.ge el0_dbg

b     el0_inv

#ifdefCONFIG_COMPAT

.align     6

el0_sync_compat:

kernel_entry 0, 32

mrs x25,esr_el1               // read the syndromeregister

lsr   x24,x25, #26                    // exceptionclass

cmp       x24,#0x11                 // SVC in 32-bitstate

b.eq el0_svc_compat

adr  lr,ret_from_exception

cmp       x24,#0x24                 // data abort in EL0

b.eq el0_da

cmp       x24,#0x20                 // instruction abortin EL0

b.eq el0_ia

cmp       x24,#0x07                 // FP/ASIMD access

b.eq el0_fpsimd_acc

cmp       x24,#0x28                 // FP/ASIMDexception

b.eq el0_fpsimd_exc

cmp       x24,#0x00                 // unknown exceptionin EL0

b.eq el0_undef

cmp       x24,#0x30                 // debug exceptionin EL0

b.ge el0_dbg

b     el0_inv

el0_svc_compat:

/*

*AArch32 syscall handling

*/

adr  stbl,compat_sys_call_table    // load compatsyscall table pointer

uxtw      scno,w7                     // syscall numberin w7 (r7)

mov    sc_nr, #__NR_compat_syscalls

b     el0_svc_naked

.align     6

el0_irq_compat:

kernel_entry 0, 32

b     el0_irq_naked

#endif

el0_da:

/*

*Data abort handling

*/

mrs x0,far_el1

disable_step x1

isb

enable_dbg

// enable interrupts before calling themain handler

enable_irq

mov       x1,x25

mov       x2,sp

b     do_mem_abort

el0_ia:

/*

*Instruction abort handling

*/

mrs x0,far_el1

disable_step x1

isb

enable_dbg

// enable interrupts before calling themain handler

enable_irq

orr  x1,x25, #1 << 24              // usereserved ISS bit for instruction aborts

mov       x2,sp

b     do_mem_abort

el0_fpsimd_acc:

/*

*Floating Point or Advanced SIMD access

*/

mov       x0,x25

mov       x1,sp

b     do_fpsimd_acc

el0_fpsimd_exc:

/*

*Floating Point or Advanced SIMD exception

*/

mov       x0,x25

mov       x1,sp

b     do_fpsimd_exc

el0_sp_pc:

/*

*Stack or PC alignment exception handling

*/

mrs x0,far_el1

disable_step x1

isb

enable_dbg

// enable interrupts before calling themain handler

enable_irq

mov       x1,x25

mov       x2,sp

b     do_sp_pc_abort

el0_undef:

/*

*Undefined instruction

*/

mov       x0,sp

b     do_undefinstr

el0_dbg:

/*

*Debug exception handling

*/

tbnz       x24,#0, el0_inv         // EL0 only

mrs x0,far_el1

disable_step x1

mov       x1,x25

mov       x2,sp

b     do_debug_exception

el0_inv:

mov       x0,sp

mov       x1,#BAD_SYNC

mrs x2,esr_el1

b     bad_mode

ENDPROC(el0_sync)

.align     6

el0_irq:

kernel_entry 0

el0_irq_naked:

disable_step x1

isb

enable_dbg

#ifdefCONFIG_TRACE_IRQFLAGS

bl    trace_hardirqs_off

#endif

get_thread_info tsk

#ifdefCONFIG_PREEMPT

ldr  x24,[tsk, #TI_PREEMPT]             // getpreempt count

add x23,x24, #1               // increment it

str   x23,[tsk, #TI_PREEMPT]

#endif

irq_handler

#ifdefCONFIG_PREEMPT

ldr  x0,[tsk, #TI_PREEMPT]

str   x24,[tsk, #TI_PREEMPT]

cmp       x0,x23

b.eq 1f

mov       x1,#0

str   x1,[x1]               // BUG

1:

#endif

#ifdefCONFIG_TRACE_IRQFLAGS

bl    trace_hardirqs_on

#endif

b     ret_to_user

ENDPROC(el0_irq)

/*

* This is the return code to user mode forabort handlers

*/

ret_from_exception:

get_thread_info tsk

b     ret_to_user

ENDPROC(ret_from_exception)

/*

* Register switch for AArch64. Thecallee-saved registers need to be saved

* and restored. On entry:

*   x0 =previous task_struct (must be preserved across the switch)

*   x1 =next task_struct

* Previous and next are guaranteed not to bethe same.

*

*/

ENTRY(cpu_switch_to)

add x8,x0, #THREAD_CPU_CONTEXT

mov       x9,sp

stp  x19,x20, [x8], #16           // storecallee-saved registers

stp  x21,x22, [x8], #16

stp  x23,x24, [x8], #16

stp  x25,x26, [x8], #16

stp  x27,x28, [x8], #16

stp  x29,x9, [x8], #16

str   lr,[x8]

add x8,x1, #THREAD_CPU_CONTEXT

ldp  x19,x20, [x8], #16           // restorecallee-saved registers

ldp  x21,x22, [x8], #16

ldp  x23,x24, [x8], #16

ldp  x25,x26, [x8], #16

ldp  x27,x28, [x8], #16

ldp  x29,x9, [x8], #16

ldr  lr,[x8]

mov       sp,x9

ret

ENDPROC(cpu_switch_to)

/*

* This is the fast syscall return path.  We do as little as possible here,

* and this includes saving x0 back into thekernel stack.

*/

ret_fast_syscall:

disable_irq                        // disable interrupts

ldr  x1,[tsk, #TI_FLAGS]

and x2,x1, #_TIF_WORK_MASK

cbnz      x2,fast_work_pending

tbz  x1,#TIF_SINGLESTEP, fast_exit

disable_dbg

enable_step x2

fast_exit:

kernel_exit 0, ret = 1

/*

* Ok, we need to do extra processing, enterthe slow path.

*/

fast_work_pending:

str   x0,[sp, #S_X0]                 // returned x0

work_pending:

tbnz       x1,#TIF_NEED_RESCHED, work_resched

/* TIF_SIGPENDING or TIF_NOTIFY_RESUMEcase */

ldr  x2,[sp, #S_PSTATE]

mov       x0,sp                         // 'regs'

tst   x2,#PSR_MODE_MASK              // user moderegs?

b.ne no_work_pending                    // returning to kernel

enable_irq                         //enable interrupts for do_notify_resume()

bl    do_notify_resume

b     ret_to_user

work_resched:

enable_dbg

bl    schedule

/*

* "slow" syscall return path.

*/

ENTRY(ret_to_user)

disable_irq                        // disable interrupts

ldr  x1,[tsk, #TI_FLAGS]

and x2,x1, #_TIF_WORK_MASK

cbnz      x2,work_pending

tbz  x1,#TIF_SINGLESTEP, no_work_pending

disable_dbg

enable_step x2

no_work_pending:

kernel_exit 0, ret = 0

ENDPROC(ret_to_user)

/*

* This is how we return from a fork.

*/

ENTRY(ret_from_fork)

bl    schedule_tail

get_thread_info tsk

b     ret_to_user

ENDPROC(ret_from_fork)

/*

* SVC handler.

*/

.align     6

el0_svc:

adrp       stbl,sys_call_table           // load syscalltable pointer

uxtw      scno,w8                     //syscall number in w8

mov       sc_nr,#__NR_syscalls

el0_svc_naked:                              // compat entrypoint

stp  x0,scno, [sp, #S_ORIG_X0]   // save theoriginal x0 and syscall number

disable_step x16

isb

enable_dbg

enable_irq

get_thread_info tsk

ldr  x16,[tsk, #TI_FLAGS]           // check forsyscall tracing

tbnz       x16,#TIF_SYSCALL_TRACE, __sys_trace // are we tracing syscalls?

adr  lr,ret_fast_syscall            // returnaddress

cmp    scno, sc_nr                     //check upper syscall limit

b.hs ni_sys

ldr  x16,[stbl, scno, lsl #3]     // address in thesyscall table

br    x16                      // call sys_* routine

ni_sys:

mov       x0,sp

b     do_ni_syscall

ENDPROC(el0_svc)

/*

*This is the really slow path.  We'regoing to be doing context

*switches, and waiting for our parent to respond.

*/

__sys_trace:

mov       x1,sp

mov       w0,#0                        // trace entry

bl    syscall_trace

adr  lr,__sys_trace_return              // returnaddress

uxtw      scno,w0                     // syscall number(possibly new)

mov       x1,sp                         // pointer toregs

cmp       scno,sc_nr                 // check uppersyscall limit

b.hs ni_sys

ldp  x0,x1, [sp]                 // restore thesyscall args

ldp  x2,x3, [sp, #S_X2]

ldp  x4,x5, [sp, #S_X4]

ldp  x6,x7, [sp, #S_X6]

ldr  x16,[stbl, scno, lsl #3]     // address in thesyscall table

br    x16                      // call sys_* routine

__sys_trace_return:

str   x0,[sp]                // save returned x0

mov       x1,sp

mov       w0,#1                        // trace exit

bl    syscall_trace

b     ret_to_user

/*

* Special system call wrappers.

*/

ENTRY(sys_execve_wrapper)

mov       x3,sp

b     sys_execve

ENDPROC(sys_execve_wrapper)

ENTRY(sys_clone_wrapper)

mov       x5,sp

b     sys_clone

ENDPROC(sys_clone_wrapper)

ENTRY(sys_rt_sigreturn_wrapper)

mov       x0,sp

b     sys_rt_sigreturn

ENDPROC(sys_rt_sigreturn_wrapper)

ENTRY(sys_sigaltstack_wrapper)

ldr  x2,[sp, #S_SP]

b     sys_sigaltstack

ENDPROC(sys_sigaltstack_wrapper)

ENTRY(handle_arch_irq)

.quad     0

/*

* Dispatch a data abort to the relevanthandler.

*/

/*

asmlinkagevoid __exception do_mem_abort(unsigned long addr, unsigned int esr,

struct pt_regs *regs)

{

const struct fault_info *inf = fault_info+ (esr & 63);//取esr全部有效位。用于选择fault_info数组中的对应处理函数,该数组定义在后面

struct siginfo info;

if (!inf->fn(addr, esr, regs))           //假设处理成功(返回0),则直接返回,否则继续运行。

return;

//异常处理不成功。打印出错信息,进一步处理,不做分析。这里如果异常处理正常返回。

pr_alert("Unhandled fault: %s(0x%08x) at 0x%016lx\n",

inf->name, esr, addr);

info.si_signo = inf->sig;

info.si_errno = 0;

info.si_code  = inf->code;

info.si_addr  = (void __user *)addr;

arm64_notify_die("", regs,&info, esr);

}

*/

/*

staticstruct fault_info {

int   (*fn)(unsignedlong addr, unsigned int esr, struct pt_regs *regs);//对应的异常处理函数

int   sig;

int   code;

const char *name;

}fault_info[] = {

{ do_bad,            SIGBUS,  0,             "ttbraddress size fault"    },

{ do_bad,            SIGBUS,  0,             "level1 address size fault"      },

{ do_bad,            SIGBUS,  0,             "level2 address size fault"      },

{ do_bad,            SIGBUS,  0,             "level3 address size fault"      },

{ do_translation_fault,     SIGSEGV, SEGV_MAPERR,  "input address range fault"     },

{ do_translation_fault,     SIGSEGV, SEGV_MAPERR,  "level 1 translation fault"     },

{ do_translation_fault,     SIGSEGV, SEGV_MAPERR,  "level 2 translation fault"     },

{ do_page_fault, SIGSEGV, SEGV_MAPERR,  "level3 translation fault" },

{ do_bad,            SIGBUS,  0,             "reservedaccess flag fault"     },

{ do_bad,            SIGSEGV,SEGV_ACCERR,  "level 1 access flagfault" },

{ do_bad,            SIGSEGV,SEGV_ACCERR,  "level 2 access flagfault" },

{ do_page_fault, SIGSEGV, SEGV_ACCERR,  "level3 access flag fault" },

{ do_bad,            SIGBUS,  0,             "reservedpermission fault"    },

{ do_bad,            SIGSEGV,SEGV_ACCERR,  "level 1 permissionfault" },

{ do_sect_fault,  SIGSEGV, SEGV_ACCERR,  "level2 permission fault" },

{ do_page_fault, SIGSEGV, SEGV_ACCERR,  "level3 permission fault" },

{ do_bad,            SIGBUS,  0,             "synchronousexternal abort"  },

{ do_bad,            SIGBUS,  0,             "asynchronousexternal abort"       },

{ do_bad,            SIGBUS,  0,             "unknown18"                   },

{ do_bad,            SIGBUS,  0,             "unknown19"                   },

{ do_bad,            SIGBUS,  0,             "synchronousabort (translation table walk)" },

{ do_bad,            SIGBUS,  0,             "synchronousabort (translation table walk)" },

{ do_bad,            SIGBUS,  0,             "synchronousabort (translation table walk)" },

{ do_bad,            SIGBUS,  0,             "synchronousabort (translation table walk)" },

{ do_bad,            SIGBUS,  0,             "synchronousparity error"      },

{ do_bad,            SIGBUS,  0,             "asynchronousparity error"    },

{ do_bad,            SIGBUS,  0,             "unknown26"                   },

{ do_bad,            SIGBUS,  0,             "unknown27"                   },

{ do_bad,            SIGBUS,  0,             "synchronousparity error (translation table walk" },

{ do_bad,            SIGBUS,  0,             "synchronousparity error (translation table walk" },

{ do_bad,            SIGBUS,  0,             "synchronousparity error (translation table walk" },

{ do_bad,            SIGBUS,  0,             "synchronousparity error (translation table walk" },

{ do_bad,            SIGBUS,  0,             "unknown32"                   },

{ do_bad,            SIGBUS,  BUS_ADRALN,   "alignmentfault"              },

{ do_bad,            SIGBUS,  0,             "debugevent"                   },

{ do_bad,            SIGBUS,  0,             "unknown35"                   },

{ do_bad,            SIGBUS,  0,             "unknown36"                   },

{ do_bad,            SIGBUS,  0,             "unknown37"                   },

{ do_bad,            SIGBUS,  0,             "unknown38"                   },

{ do_bad,            SIGBUS,  0,             "unknown39"                   },

{ do_bad,            SIGBUS,  0,             "unknown40"                   },

{ do_bad,            SIGBUS,  0,             "unknown41"                   },

{ do_bad,            SIGBUS,  0,             "unknown42"                   },

{ do_bad,            SIGBUS,  0,             "unknown43"                   },

{ do_bad,            SIGBUS,  0,             "unknown44"                   },

{ do_bad,            SIGBUS,  0,             "unknown45"                   },

{ do_bad,            SIGBUS,  0,             "unknown46"                   },

{ do_bad,            SIGBUS,  0,             "unknown47"                   },

{ do_bad,            SIGBUS,  0,             "unknown48"                   },

{ do_bad,            SIGBUS,  0,             "unknown49"                   },

{ do_bad,            SIGBUS,  0,             "unknown50"                   },

{ do_bad,            SIGBUS,  0,             "unknown51"                   },

{ do_bad,            SIGBUS,  0,             "implementationfault (lockdown abort)" },

{ do_bad,            SIGBUS,  0,             "unknown53"                   },

{ do_bad,            SIGBUS,  0,             "unknown54"                   },

{ do_bad,            SIGBUS,  0,             "unknown55"                   },

{ do_bad,            SIGBUS,  0,             "unknown56"                   },

{ do_bad,            SIGBUS,  0,             "unknown57"                   },

{ do_bad,            SIGBUS,  0,             "implementationfault (coprocessor abort)" },

{ do_bad,            SIGBUS,  0,             "unknown59"                   },

{ do_bad,            SIGBUS,  0,             "unknown60"                   },

{ do_bad,            SIGBUS,  0,             "unknown61"                   },

{ do_bad,            SIGBUS,  0,             "unknown62"                   },

{ do_bad,            SIGBUS,  0,             "unknown63"                   },

};

*/

1.6 traps.c代码分析

//该文件里代码原理非常easy,眼下暂不分析。若须要。兴许再添上。

/*

* bad_mode handles the impossible case in theexception vector.

*/

//三个參数从左到右分别相应x0~x3,该函数的作用就是打印出错原因,跳转到panic()函数

asmlinkagevoid bad_mode(struct pt_regs *regs, int reason, unsigned int esr)

{

console_verbose();

pr_crit("Bad mode in %s handlerdetected, code 0x%08x\n",

handler[reason], esr);

die("Oops - bad mode", regs, 0);

local_irq_disable();

panic("bad mode");

}

ARMv8 Linux内核异常处理过程分析的更多相关文章

  1. Linux内核异常处理体系结构详解(一)【转】

    转自:http://www.techbulo.com/1841.html 2015年11月30日 ⁄ 基础知识 ⁄ 共 6653字 ⁄ 字号 小 中 大 ⁄ Linux内核异常处理体系结构详解(一)已 ...

  2. Linux内核编译过程分析

    http://pan.baidu.com/s/1mgtACVu 其中是我总结生成的一些文档,以便于理解当我们输入make uImage后,系统是怎么一步一步生成uImage的,我采用的是逆向分析的方法 ...

  3. ARMv8 Linux内核head.S源码分析

    ARMv8Linux内核head.S主要工作内容: 1. 从el2特权级退回到el1 2. 确认处理器类型 3. 计算内核镜像的起始物理地址及物理地址与虚拟地址之间的偏移 4. 验证设备树的地址是否有 ...

  4. ARMv8 Linux内核源代码分析:__flush_dcache_all()

    1.1 /* *  __flush_dcache_all() *  Flush the wholeD-cache. * Corrupted registers: x0-x7, x9-x11 */ EN ...

  5. 2018-2019-1 20189206 《Linux内核原理与分析》第四周作业

    linux内核分析学习笔记 --第三章 MenuOS的构造 计算机的"三大法宝"和操作系统的"两把宝剑" 三大法宝 程序存储计算机 即冯诺依曼体系结构,基本上是 ...

  6. linux 内核学习之五 system_call过程分析

    一   使用gdb工具跟踪分析一个自添加的系统调用 应用程序的进程通常在用户空间下运行,当它调用一个系统调用时,进程进入内核空间,执行的是kernel内部的代码,从而具有执行特权指令的权限,完成特定的 ...

  7. 【转载】linux内核启动android文件系统过程分析

    主要介绍linux 内核启动过程以及挂载android 根文件系统的过程,以及介绍android 源代码中文件系统部分的浅析. 主要源代码目录介绍Makefile (全局的Makefile)bioni ...

  8. Linux内核的启动过程分析

    秦鼎涛 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.实验目的及要求: 使用gdb跟踪调试内核从s ...

  9. Linux内核分析(三)内核启动过程分析——构造一个简单的Linux系统

    一.系统的启动(各历史节点) 在最开始的时候,计算机的启动实际上依靠一段二进制码,可以这么理解,他并不是一个真正的计算机启动一道程序.计算机在开始加电的时候几乎是没有任何用处的,因为RAM芯片中包括的 ...

随机推荐

  1. python - Django: Converting an entire set of a Model's objects into a single dictionary - Stack Overflow

    python - Django: Converting an entire set of a Model's objects into a single dictionary - Stack Over ...

  2. 你以为在用SharePoint但事实上不是

    博客地址 http://blog.csdn.net/foxdave 原文链接:http://www.techrepublic.com/blog/tech-decision-maker/you-thin ...

  3. zabbix 监控jmx 需要--enable-java

    安装Javagateway如果原来已经安装zabbix,只需要再添加以下zabbix-java # tar zxvf zabbix-2.2.0.tar.gz # cd zabbix-2.2.0 # . ...

  4. uva 1343 非原创

    uva1343 原作者 题目题意是:给你的棋盘,在A-H方向上可以拨动,问你最少拨动几次可以是中心图案的数字一致 解题思路:回溯法,剪枝 其中要把每次拨动的字母所代表的位置提前用数组表示: 然后在如果 ...

  5. TCP/IP笔记 二.网络层(1)

    1. IP 1.1 配套协议 IP 是 TCP/IP 体系中两个最主要的协议之一 . 与 IP 协议配套使用的还有四个协议:   (1)ARP (Address Resolution Protocol ...

  6. UVA 10795 - A Different Task(递归)

     A Different Task  The (Three peg) Tower of Hanoi problem is a popular one in computer science. Brie ...

  7. 14.6.2 Moving or Copying InnoDB Tables to Another Machine 移动或者copy InnoDB 表到另外的机器

    14.6.2 Moving or Copying InnoDB Tables to Another Machine 移动或者copy InnoDB 表到另外的机器 这个章节描述技术关于移动或者copy ...

  8. tomcat path设置

    zjtest7-app:/usr/local/apache-tomcat-7.0.55_8082/logs# netstat -nap | grep 8082 tcp 0 0 :::8082 :::* ...

  9. java面向对象下:Java数据库编程

    19.Java数据库编程: JDBC概述:        JDBC(Java Database Connection)是java中提供的一套数据库编程API,它定义了一套用来访问数据库的标准Java类 ...

  10. C语言数据结构----递归的应用(斐波拉契数列、汉诺塔、strlen的递归算法)

    本节主要说了递归的设计和算法实现,以及递归的基本例程斐波拉契数列.strlen的递归解法.汉诺塔和全排列递归算法. 一.递归的设计和实现 1.递归从实质上是一种数学的解决问题的思维,是一种分而治之的思 ...