当前位置: 首页 > news >正文

Linux-arm64中断现场保护详解

零、源码及详细注释

.macro kernel_ventry, el, label, regsize = 64sub sp, sp, #S_FRAME_SIZE     //在堆栈中预留出S_FRAME_SIZE大小的空间.macro  kernel_entry, el, regsize = 64.if \regsize == 32mov w0, w0              // zero upper 32 bits of x0.endifstp x0, x1, [sp, #16 * 0]   //入栈stp x2, x3, [sp, #16 * 1]stp x4, x5, [sp, #16 * 2]stp x6, x7, [sp, #16 * 3]stp x8, x9, [sp, #16 * 4]stp x10, x11, [sp, #16 * 5]stp x12, x13, [sp, #16 * 6]stp x14, x15, [sp, #16 * 7]stp x16, x17, [sp, #16 * 8]stp x18, x19, [sp, #16 * 9]stp x20, x21, [sp, #16 * 10]stp x22, x23, [sp, #16 * 11]stp x24, x25, [sp, #16 * 12]stp x26, x27, [sp, #16 * 13]stp x28, x29, [sp, #16 * 14].if \el == 0                            // 异常等级0 clear_gp_regs                           // 清空寄存器mrs x21, sp_el0                         // x21 = sp_el0  如果异常发生在用户态(EL0)则pt_regs将保存用户态堆栈指针sp_el0 */ldr_this_cpu    tsk, __entry_task, x20  // 设置tsk为当前进程的task_struct, x20 = tpidr_el1/tpidr_el2ldr x19, [tsk, #TSK_TI_FLAGS]           // x19 = tsk->thread_info.flagsdisable_step_tsk x19, x20               // 关闭mdscr_el1寄存器的SS位apply_ssbd 1, x22, x23          .else                                   //异常等级不为0add x21, sp, #S_FRAME_SIZE              //X21保存压入pt_regs数据之前的栈地址(栈框的位置) S_FRAME_SIZE:栈帧的大小get_thread_info tsk                     //tsk = sp_el0/* Save the task's original addr_limit and set USER_DS */ldr x20, [tsk, #TSK_TI_ADDR_LIMIT]      //x20 = tsk->thread_info.addr_limitstr x20, [sp, #S_ORIG_ADDR_LIMIT]       //pt_regs->orig_addr_limit = x20mov x20, #USER_DS                       //X2O = USER_DS = 1<<48str x20, [tsk, #TSK_TI_ADDR_LIMIT]      //tsk->thread_info.addr_limit = 1<<48/* No need to reset PSTATE.UAO, hardware's already set it to 0 for us */.endif /* \el == 0 */mrs x22, elr_el1                       //x22 = elr_el1mrs x23, spsr_el1                      //x23 = spsr_el1stp lr, x21, [sp, #S_LR]               //pt_regs.lr = lr,pt_regs.fp = x21   保存lr和fp到栈帧中/** In order to be able to dump the contents of struct pt_regs at the* time the exception was taken (in case we attempt to walk the call* stack later), chain it together with the stack frames.*/.if \el == 0                        //异常等级0stp xzr, xzr, [sp, #S_STACKFRAME]   //清0 pt_regs.stackframe[0]与[1](详见十一).else                               //异常等级不为0stp x29, x22, [sp, #S_STACKFRAME]   //pt_regs.stackframe[0] = x29 , pt_regs.stackframe[1] = x22 = elr_el1.endifadd x29, sp, #S_STACKFRAME          //x29 = pt_regs.stackframe#ifdef CONFIG_ARM64_SW_TTBR0_PANalternative_if ARM64_HAS_PANb   1f              // skip TTBR0 PANalternative_else_nop_endif.if \el != 0                        //异常等级不为0mrs x21, ttbr0_el1                  //x21 = ttbr0_el1tst x21, #TTBR_ASID_MASK            //检测ttbr0_el1的48-63位的ASIDorr x23, x23, #PSR_PAN_BIT          //设置spsr_el1的PAN位b.eq    1f              // TTBR0 access already disabledand x23, x23, #~PSR_PAN_BIT     // Clear the emulated PAN in the saved SPSR.endif__uaccess_ttbr0_disable x211:#endifstp x22, x23, [sp, #S_PC]                    //pt_regs.pc = x22 = elr_el1  pt_regs.pstate = x23 = spsr_el1/* Not in a syscall by default (el0_svc overwrites for real syscall) */.if \el == 0                                //异常等级为0mov w21, #NO_SYSCALL                        //w21 = NO_SYSCALLstr w21, [sp, #S_SYSCALLNO]                 //pt_regs.syscallno = w21 = NO_SYSCALL.endif/** Set sp_el0 to current thread_info.*/.if \el == 0                              //异常等级为0msr sp_el0, tsk                           //sp_el0 = tsk.endif/** Registers that may be useful after this macro is invoked:** x21 - aborted SP* x22 - aborted PC* x23 - aborted PSTATE*/.endm

注解:

一、ldr_this_cpu

ldr_this_cpu    tsk, __entry_task, x20</arch/arm64/include/asm/assembler.h>macro ldr_this_cpu dst, sym, tmpadr_l   \dst, \sym                                      //tsk = __entry_taskalternative_if_not ARM64_HAS_VIRT_HOST_EXTNmrs \tmp, tpidr_el1                                     //x20 = tpidr_el1  读取per_cpu变量时,计算偏移alternative_elsemrs \tmp, tpidr_el2                                    //x20 = tpidr_el2 TPIDR_EL1, EL1 Software Thread ID Registeralternative_endifldr \dst, [\dst, \tmp]                                //ldr tsk, [tsk,x20]  task += TID 获取__entry_task变量.endm

二、__entry_task

__entry_task为内核静态定义的percpu变量,在进程切换时,会将next进程的进程描述符保存到该变量中

/** We store our current task in sp_el0, which is clobbered by userspace. Keep a* shadow copy so that we can restore this upon entry from userspace.** This is *only* for exception entry from EL0, and is not valid until we* __switch_to() a user task.*/DEFINE_PER_CPU(struct task_struct *, __entry_task);static void entry_task_switch(struct task_struct *next){__this_cpu_write(__entry_task, next);}

三、per_cpu变量获取offset

static inline unsigned long __my_cpu_offset(void){unsigned long off;/** We want to allow caching the value, so avoid using volatile and* instead use a fake stack read to hazard against barrier().*/asm(ALTERNATIVE("mrs %0, tpidr_el1","mrs %0, tpidr_el2",ARM64_HAS_VIRT_HOST_EXTN): "=r" (off) :"Q" (*(const unsigned long *)current_stack_pointer));return off;}

四、偏移

</arch/arm64/kernel/asm-offsets.c>DEFINE(TSK_TI_FLAGS,        offsetof(struct task_struct, thread_info.flags));DEFINE(TSK_TI_ADDR_LIMIT,   offsetof(struct task_struct, thread_info.addr_limit));DEFINE(S_ORIG_ADDR_LIMIT,   offsetof(struct pt_regs, orig_addr_limit));

五、disable_step_tsk

  disable_step_tsk x19, x20.macro  disable_step_tsk, flgs, tmptbz \flgs, #TIF_SINGLESTEP, 9990f      //判断x19的#TIF_SINGLESTEP位是否为0,若为0,跳转到9990fmrs \tmp, mdscr_el1                    //x20 = mdscr_el1bic \tmp, \tmp, #1                     //清除x20的第0位,SS:Software step disabledmsr mdscr_el1, \tmp                    //mdscr_el1 = x20isb // Synchronise with enable_dbg9990:.endm

六、get_thread_info

   

 .macro  get_thread_info, rdmrs \rd, sp_el0      // \rd = sp_el0.endm

七、S_FRAME_SIZE

 DEFINE(S_FRAME_SIZE,       sizeof(struct pt_regs));

八、struct pt_regs

/** This struct defines the way the registers are stored on the stack during an* exception. Note that sizeof(struct pt_regs) has to be a multiple of 16 (for* stack alignment). struct user_pt_regs must form a prefix of struct pt_regs.*/struct pt_regs {union {struct user_pt_regs user_regs;struct {u64 regs[31];u64 sp;u64 pc;u64 pstate;};};u64 orig_x0;#ifdef __AARCH64EB__u32 unused2;s32 syscallno;#elses32 syscallno;u32 unused2;#endifu64 orig_addr_limit;u64 unused; // maintain 16 byte alignmentu64 stackframe[2];};

九、thread_info

struct thread_info {unsigned long       flags;      /* low level flags */mm_segment_t        addr_limit; /* address limit */#ifdef CONFIG_ARM64_SW_TTBR0_PANu64         ttbr0;      /* saved TTBR0_EL1 */#endifunion {u64     preempt_count;  /* 0 => preemptible, <0 => bug */struct {#ifdef CONFIG_CPU_BIG_ENDIANu32 need_resched;u32 count;#elseu32 count;u32 need_resched;#endif} preempt;};};

十、USER_DS

#define USER_DS     TASK_SIZE_64#define TASK_SIZE_64        (UL(1) << VA_BITS)

十一、S_LR与S_STACKFRAME与S_STACKFRAME

DEFINE(S_STACKFRAME,        offsetof(struct pt_regs, stackframe));DEFINE(S_LR,            offsetof(struct pt_regs, regs[30]));DEFINE(S_STACKFRAME,        offsetof(struct pt_regs, stackframe));#define S_PC 256 /* offsetof(struct pt_regs, pc) */


http://www.mrgr.cn/news/11486.html

相关文章:

  • 【Java设计模式】防腐层模式:确保在遗留系统中保持系统完整性
  • Nginx的核心!!! 负载均衡、反向代理
  • http方法调用接口
  • PostgreSQL自定义类型转换
  • 前端宝典十四:Node缓存、安全与鉴权
  • vue之函数式组件
  • 溺水检测数据集 代码在博客
  • 在野漏洞的应急响应流程
  • 国产数据库对比与分析
  • tornado一个请求对应一个实例
  • 基于图神经网络的EEG分类
  • 实用攻略:亲身试用,高效数据恢复软件推荐!
  • qt在ui上面给QWidget设置布局
  • 1. Java集合框架的主要接口有哪些?它们之间的关系是什么?
  • 数据结构-KMP算法
  • 团队管理之敏捷开发
  • 新零售社交电商系统案例分析
  • 数学建模学习(126):基于Python的最优最劣法(BWM)在多标准决策中的应用
  • RIP路由信息协议
  • Linux磁盘管理