linux内核对于指令异常的处理
2017-01-11 17:21
1236 查看
1.处理流程
以arm64来介绍一下流程,如果在用户层发生指令异常时,首先进入入口el0_undef( arch/arm64/kernel/entry.s )
el0_undef: /* * Undefined instruction */ // enable interrupts before calling the main handler enable_dbg_and_irq ct_user_exit mov x0, sp bl do_undefinstr-----------------------------------调用此函数如下 b ret_to_user
( arch/arm64/kernel/traps.c )
asmlinkage void __exception do_undefinstr(struct pt_regs *regs) { siginfo_t info; void __user *pc = (void __user *)instruction_pointer(regs); /* check for AArch32 breakpoint instructions */ if (!aarch32_break_handler(regs)) return; if (call_undef_hook(regs) == 0)----------------------进入此函数执行真正的处理过程,正确处理完后,直接返回不进入Oops,相反会出错 return; if (unhandled_signal(current, SIGILL) && show_unhandled_signals_ratelimited()) { pr_info("%s[%d]: undefined instruction: pc=%p\n", current->comm, task_pid_nr(current), pc); dump_instr(KERN_INFO, regs); } info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_ILLOPC; info.si_addr = pc; arm64_notify_die("Oops - undefined instruction", regs, &info, 0); }
( arch/arm64/kernel/traps.c )
static int call_undef_hook(struct pt_regs *regs) { struct undef_hook *hook; unsigned long flags; u32 instr; int (*fn)(struct pt_regs *regs, u32 instr) = NULL; void __user *pc = (void __user *)instruction_pointer(regs); if (!user_mode(regs)) return 1; if (compat_thumb_mode(regs)) { /* 16-bit Thumb instruction */ if (get_user(instr, (u16 __user *)pc)) goto exit; instr = le16_to_cpu(instr); if (aarch32_insn_is_wide(instr)) { u32 instr2; if (get_user(instr2, (u16 __user *)(pc + 2))) goto exit; instr2 = le16_to_cpu(instr2); instr = (instr << 16) | instr2; } } else { /* 32-bit ARM instruction */ if (get_user(instr, (u32 __user *)pc)) goto exit; instr = le32_to_cpu(instr); } raw_spin_lock_irqsave(&undef_lock, flags); list_for_each_entry(hook, &undef_hook, node)--------------遍历链表undef_hook中的每一个hook if ((instr & hook->instr_mask) == hook->instr_val && (regs->pstate & hook->pstate_mask) == hook->pstate_val) fn = hook->fn;----------------------------匹配成功后把hook->fn赋给fn raw_spin_unlock_irqrestore(&undef_lock, flags); exit: return fn ? fn(regs, instr) : 1;--------------------------执行fn,正确执行返回0 }
2.未定义指令的注册
结构体struct undef_hook用来封装一个未定义指令struct undef_hook { struct list_head node; u32 instr_mask;---------------instruction mask匹配用的掩码 u32 instr_val;----------------instruction val匹配的关键值 u64 pstate_mask; u64 pstate_val; int (*fn)(struct pt_regs *regs, u32 instr);--相关的处理函数 };
如果想要把一个指令加入到内核的未定义指令处理框架中,要先实现一个结构体insn_emulation_ops
struct insn_emulation_ops { const char *name; enum legacy_insn_status status;--有两种:INSN_DEPRECATED和INSN_OBSOLETE struct undef_hook *hooks;-- int (*set_hw_mode)(bool enable); };
在这里对于未定义指令可以有两种方式:
(1)INSN_DEPRECATED : 表示指令虽然未定义,但是可以进行处理来使这条指令得以正确执行
(2)INSN_OBSOLETE : 表示指令没有定义,不注册入异常指令处理框架中
2.1 异常指令注册函数
( arch/arm64/kernel/armv8_deprecated.c )static void register_insn_emulation(struct insn_emulation_ops *ops) { unsigned long flags; struct insn_emulation *insn; insn = kzalloc(sizeof(*insn), GFP_KERNEL); insn->ops = ops; insn->min = INSN_UNDEF; switch (ops->status) { case INSN_DEPRECATED: insn->current_mode = INSN_EMULATE; /* Disable the HW mode if it was turned on at early boot time */ run_all_cpu_set_hw_mode(insn, false); insn->max = INSN_HW; break; case INSN_OBSOLETE: insn->current_mode = INSN_UNDEF; insn->max = INSN_EMULATE; break; } raw_spin_lock_irqsave(&insn_emulation_lock, flags); list_add(&insn->node, &insn_emulation);----------把定义的异常指令加入到链表insn_emulation中 nr_insn_emulated++; raw_spin_unlock_irqrestore(&insn_emulation_lock, flags); /* Register any handlers if required */ update_insn_emulation_mode(insn, INSN_UNDEF);----把待处理的异常指令注册到框架中 }
( arch/arm64/kernel/armv8_deprecated.c )
static int update_insn_emulation_mode(struct insn_emulation *insn, enum insn_emulation_mode prev) { int ret = 0; switch (prev) { case INSN_UNDEF: /* Nothing to be done */ break; case INSN_EMULATE: remove_emulation_hooks(insn->ops); break; case INSN_HW: if (!run_all_cpu_set_hw_mode(insn, false)) pr_notice("Disabled %s support\n", insn->ops->name); break; } switch (insn->current_mode) { case INSN_UNDEF: break; case INSN_EMULATE: register_emulation_hooks(insn->ops);----如果指令是可以仿真(也就是可以正常执行的),就调用此函数进行注册 break; case INSN_HW: ret = run_all_cpu_set_hw_mode(insn, true); if (!ret) pr_notice("Enabled %s support\n", insn->ops->name); break; } return ret; }
static void register_emulation_hooks(struct insn_emulation_ops *ops) { struct undef_hook *hook; BUG_ON(!ops->hooks); for (hook = ops->hooks; hook->instr_mask; hook++) register_undef_hook(hook); pr_notice("Registered %s emulation handler\n", ops->name); }
整个注册流程最终就是要调用register_undef_hook来进行注册
( arch/arm64/kernel/traps.c )
void register_undef_hook(struct undef_hook *hook) { unsigned long flags; raw_spin_lock_irqsave(&undef_lock, flags); list_add(&hook->node, &undef_hook);---------加入到链表undef_hook raw_spin_unlock_irqrestore(&undef_lock, flags); }
2.2 内核初始化注册入口
late_initcall(armv8_deprecated_init); static int __init armv8_deprecated_init(void) { if (IS_ENABLED(CONFIG_SWP_EMULATION)) register_insn_emulation(&swp_ops); if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION)) register_insn_emulation(&cp15_barrier_ops); if (IS_ENABLED(CONFIG_SETEND_EMULATION)) { if(system_supports_mixed_endian_el0()) register_insn_emulation(&setend_ops); else pr_info("setend instruction emulation is not supported on the system"); } register_cpu_notifier(&insn_cpu_hotplug_notifier); register_insn_emulation_sysctl(ctl_abi); return 0; }
change log
date | content | linux |
---|---|---|
2017.1.11 | linux 4.4 |
相关文章推荐
- ASP.NET 中对于异常的处理
- 事务对于自定义异常的处理
- 对于普通异常的处理
- 字符设备驱动-Linux内核异常处理体系结构
- 对于异常处理的初步总结
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】深入剖析Linux中断机制之三--Linux对异常和中断的处理
- 对于Python异常处理慎用“except:pass”建议
- ECOS对于ARM平台异常的处理分析
- 如何解决“不允许有匹配 "[xX][mM][lL]" 的处理指令目标。”的异常信息。同时提供几个spring xml配置文件标头!(干货)
- Silverlight 3 中改进的对于获取WCF服务的异常信息处理
- ARMv7用户层发生指令异常的处理流程?是否每个进程都有一个APSR的副本?
- SQLite数据库指令参数出现中文引起执行异常问题处理
- spring中@Transactional对于事务异常的处理
- Linux内核对于信号的实现机制和应用层的相关处理
- 利用Windows异常处理和RDTSC指令反调试学习
- spring中@Transactional对于事务异常的处理
- ARMv7用户层发生指令异常的处理流程?是否每个进程都有一个APSR的副本?
- java中对于异常的处理,代码简单描述
- (二十五)异常处理指令和同步指令
- 对于异常出现,而导致android崩溃的处理