历史上的今天
今天是:2024年09月07日(星期六)
2021年09月07日 | ARM64异常
2021-09-07 来源:eefocus
1. ARM64异常介绍,SError介绍




![]()

下面引用自 蜗窝科技
中断主要有两种,physical interrupt和virtual interrupt(不在本文中描述)。physical interrupt是来自cpu core(或者叫做PE)外部一种信号,它包括下面三种类型:
(1)IRQ
(2)FIQ
(3)System error,简称SError
IRQ和FIQ是广大ARM嵌入式工程师的老朋友了,大家常说的中断实际上特指IRQ和FIQ,当然,实际上SError也是一种中断类型。IRQ和FIQ分别和cpu core的nIRQ和nFIQ这两根实际的信号线相关,interrupt controller收集各种来自外设的(或者来自其他CPU core的)中断请求,通过nIRQ和nFIQ的电平信号(active low)来通知cpu core某些外设的异步事件(或者来自其他CPU core的异步事件)。其中IRQ是普通中断,而FIQ是快速中断。由于中断来自cpu core的外部,可以在任何的时间点插入,和cpu core上执行的指令没有任何的关系,因此中断这种exception被归入asynchronous exception类别。
要想理解SError interrupt这个概念,我们需要先看看external abort这个术语。external abort来自memory system,当然不是所有的来自memory system的abort都是external abort,例如来自MMU的abort就不是external abort(这里的external是针对processor(而非cpu core)而言,因此MMU实际上是internal的)。external abort发生在processor通过bus访问memory的时候(可能是直接对某个地址的读或者写,也可能是取指令导致的memory access),processor在bus上发起一次transaction,在这个过程中发生了abort,abort来自processor之外的memory block、device block或者interconnection block,用来告知processor,搞不定了,你自己看着办吧。external abort可以被实现成synchronous exception(precise exception),也可以实现成asynchronous exception(imprecise exception)。如果external abort是asynchronous的,那么它可以通过SError interrupt来通知cpu core。
我的习惯是搞清楚一个术语的定义之后,下一个问题就是why,不过大部分的资料都不会讲why,因此在回答why的时候,往往没有那么权威,多半是自己的思考,不保证是正确的。为何要定义SError interrupt?当一个abort发生的时候,如果HW如果能够通过寄存器提供一些信息的话,那么事情还没有那么糟糕,例如return address给出了发生exception的具体的位置。从这个角度看,软件工程师更喜欢precise exception,毕竟知道导致异常的指令的位置,从而找到一些蛛丝马迹,让系统恢复。从这个角度看,根本就不应该存在SError interrupt这样的imprecise exception的鬼东西,HW没有提供有意义的信息,就只是两手一摊,反正在memory access的时候发生了system error,而且我也不知道是哪一条指令干的,这让软件工程师情何以堪呐。氮素,这只是事情的一个方面,从设计CPU的IC工程师角度看,他们更喜欢设计最快的处理器来完成自己的价值。SError interrupt是imprecise exception,允许更大的指令并发,因此性能更好
2 .实例
引用下面链接
https://blog.csdn.net/shenhuxi_yu/article/details/81212008
最近在linux4.9 arm64遇到了bad mode的kernel oops
oops的内容大概如下,而且oops过后看起来系统并没有异常,oops出现的概率比较小,而且每次oops打印的信息中task 都是不同的,oops之后,看起来大部分时候系统还是可以正常运行的
[ 1259.654597] Bad mode in Error handler detected, code 0xbf000002 -- SError
[ 1259.661357] CPU: 12 PID: 2293 Comm: mate-settings-d Not tainted
4.1.15-1.el7.aarch64 #2
[ 1259.669320] Hardware name: xxxx
[ 1259.675209] task: ffffffc8c9bd1700 ti: ffffffc8c9e4c000
task.ti: ffffffc8c9e4c000
[ 1259.682665] PC is at 0x7f9c51abd8
[ 1259.685961] LR is at 0x7f942f9828
[ 1259.689259] pc : [<0000007f9c51abd8>]
lr : [<0000007f942f9828>] pstate: 80000000
[ 1259.696616] sp : ffffffc8c9e4fff0
首先先定位出现这段LOG的代码位置在traps.c,arm64的异常向量表中才有对这个函数的调用,如下图
bad_mode 的打印信息SError 和 code 都是从register esr_el1中获取的,能得到SError的只有el1 和el0的invalid_error打印的
/arch/arm64/kernel/traps.c
/*
* bad_mode handles the impossible case in the exception vector. This is always
* fatal.
*/
asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
{
console_verbose();
pr_crit("Bad mode in %s handler detected on CPU%d, code 0x%08x -- %sn",
handler[reason], smp_processor_id(), esr,
esr_get_class_string(esr));
die("Oops - bad mode", regs, 0);
local_irq_disable();
panic("bad mode");
}
/arch/arm64/kernel/entry.s
/*
* Bad Abort numbers
*-----------------
*/
#define BAD_SYNC 0
#define BAD_IRQ 1
#define BAD_FIQ 2
#define BAD_ERROR 3
//el1_sync 函数
el1_sync:
el1_inv:
// TODO: add support for undefined instructions in kernel mode
enable_dbg
mov x0, sp
mov x2, x1
mov x1, #BAD_SYNC
b bad_mode
ENDPROC(el1_sync)
//inv_entry 函数
/*
* Invalid mode handlers
*/
.macro inv_entry, el, reason, regsize = 64
kernel_entry el, regsize
mov x0, sp
mov x1, #reason
mrs x2, esr_el1//bad_mode 函数的参数传递
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)
#ifdef CONFIG_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
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)
到底SError是ARM的一种什么异常,AArch64(ARM64)架构中,主要包括如下4中类型的异常:
Synchronous exception(同步异常),“同步”可以理解为:发生异常的指令为导致异常的指令,即当导致异常发生的指令执行时能立即触发异常。 包括ARM架构中定义的所有Aborts异常,如:指令异常、数据异常、对齐异常等。
SError,System Error,是一种异步异常,后面再仔细说明。
IRQ,普通的中断,是异步异常。
FIQ,高优先级的中断,是异步异常。
SError本质上是一种异步外部abort(asynchronous external abort)。所谓异步,就说是发生异常时硬件(相关的寄存器)不能提供有效信息用于分析定位,异常发生时的指令,并不是导致异常的指令。外部意味着异常来自于外部存储系统(相较于CPU来说,MMU是内部的)。通常是硬件触发的问题,比如硬件的clock出问题或者硬件本身的问题导致的bus访问硬件时出现问题。
Linux内核中,对SError进行了捕获,设置了相应的中断向量,当并未做实际的处理,只是上报异常,并终止进程会内核,因为对于内核来说,SError是致命的,内核自身无法做相应的修复操作,内核不知道具体原因,也不知道如何修复。
分析错误打印: Bad mode in Error handler detected, code 0xbf000002 – SError
可以知道,发生了SError(也就是System Error异常),错误码(ESR寄存器内容)为:0xbf000002
从ARM developer上查到的ESR寄存器的描述
The ESR_EL1 holds syndrome information for an exception taken to EL1.
ESR_EL1 is a 32-bit register, and is part of the Exception and fault handling registers functional group.
Figure B2-34 ESR_EL1 bit assignments
EC, [31:26]
Exception Class. Indicates the reason for the exception that this register holds information about.
IL, [25]
Instruction Length for synchronous exceptions. The possible values are:
| 0 | 16-bit. |
| 1 | 32-bit. |
This field is 1 for the SError interrupt, instruction aborts, misaligned PC, Stack pointer misalignment, data aborts for which the ISV bit is 0, exceptions caused by an illegal instruction set state, and exceptions using the 0x00 Exception Class.
ISS, [24:0]
Syndrome information.
由以上信息得出前六位bit[31:26]为101111,对应具体的异常类型,查看ArmV8手册:
101111 SError interrupt即系统异常中断。
ISV, bit [24] Instruction syndrome valid. Indicates whether the rest of the syndrome information in this register is valid. 0 No valid instruction syndrome. ISS[23:0] are RES0. 1 ISS[23:0] hold a valid instruction syndrome.
本code中,该位为1,说明bit[23:0]中存放了instruction syndrome(出错指令的具体信息)
IS, bits [23:0] IMPLEMENTATION DEFINED syndrome information that can be used to provide additional information about the SError interrupt. Only valid if bit[24] of this register is 1. If bit[24] is 0, this field is RES0.
ELR_ELn n代表不同的运行优先级,这个寄存器存储着触发异常时候的指令
如何dump 该register尝试改了下entry.s,只有inv_entry 这里会有BAD_ERROR的异常会走到,所以做了如下修改,发现show_regs打印的异常发生的时候的PC就是从elr_el1的copy。
所以bad_mode dump的信息就是all kernel have了,没有想到有效的方法,只能压测看下error附近的LOG试着夹下code
/*
* Invalid mode handlers
*/
.macro inv_entry, el, reason, regsize = 64
kernel_entry el, regsize
mov x0, sp
mov x1, #reason
mrs x2, esr_el1
mrs x3, elr_el1
//add this line to pass para to bad_mode function
//SError always call this function
b bad_mode
.endm
asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr, u64 elr_regs)
//add a para
{
siginfo_t info;
void __user *pc = (void __user *)instruction_pointer(regs);
console_verbose();
pr_crit("Bad mode in %s handler detected on CPU%d, code 0x%08x -- %sn",
handler[reason], smp_processor_id(), esr,
esr_get_class_string(esr));
pr_cirt("dump elr %llxn",elr_regs);
//add printk to dump this register
__show_regs(regs);
3. 自己真实实例:
[ 138.654822] c3 sc2703-bllcd 7-004b: wled_mode(4), brightness(0)
[ 138.655402] c3 Bad mode in Error handler detected, code 0xbe000011 -- SError
[ 138.655424] c3 Internal error: Oops - bad mode: 0 [#1] PREEMPT SMP
[ 138.662026] c0 Modules linked in: sprd_fm(O) sprdbt_tty(O) pvrsrvkm(O)
[ 138.662061] c3 CPU: 3 PID: 351 Comm: light@2.0-servi Tainted: G O 4.4.83+ #1
[ 138.662071] c3 Hardware name: Spreadtrum SC9863A3H10 Board (DT)
[ 138.662082] c3 task: ffffffc072d40080 task.stack: ffffffc072d3c000
[ 138.662095] c3 PC is at 0x7b3e11085c
[ 138.662104] c3 LR is at 0x7b3d879740
[ 138.662115] c3 pc : [<0000007b3e11085c>] lr : [<0000007b3d879740>] pstate: 80000000
[ 138.662124] c3 sp : 0000007ff7df5ec0
[ 138.662134] c0 x29: 0000007ff7df5f10 x28: 0000000000000000
//从下面这个逻辑看出来,当
32static int sprd_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
33 int duty_ns, int period_ns)
34{
35 struct sprd_pwm_chip *pc = to_sprd_pwm_chip(chip);
36 static int config_state;
37 static int pwm_scale;
38 int led_level;
39 u64 clk_rate, div, val;
40
41 led_level = duty_ns * PWM_MOD_MAX / period_ns;
42 pr_debug("duty_ns = %d,period_ns = %d,led_level = %dn",
43 duty_ns, period_ns, led_level);
44
45 if (led_level > 0)
46 sprd_core_ops->pwm_early_config(chip, pwm, true); //开启pwm global寄存器
47
......
66
67 sprd_core_ops->pwm_config(chip, pwm, led_level, pwm_scale); //没有判断当前global是否关闭
68
69 if (led_level == 0)
70 sprd_core_ops->pwm_early_config(chip, pwm, false); //关闭pwm global寄存器
71
72 return 0;
73}
14static void sprd_pwm_early_config(struct pwm_chip *chip,
15 struct pwm_device *pwm, bool enable)
16{
17 struct sprd_pwm_chip *pc = container_of(chip,
18 struct sprd_pwm_chip, chip);
19 int mask, val;
20
21 mask = 0xf0;
22 if (enable) {
23 val = mask;
24 regmap_update_bits(pc->syscon, REG_AON_APB_APB_EB0, mask, val);
25 sprd_pwm_writel(pc, pwm->hwpwm, PWM_R3P0_ENABLE, 0);
26 } else {
pr_debug(“power off”);
27 val = ~mask;
28 sprd_pwm_writel(pc, pwm->hwpwm, PWM_R3P0_ENABLE, 0);
29 regmap_update_bits(pc->syscon, REG_AON_APB_APB_EB0, mask, val);
30 }
31}
上一篇:ARM架构之异常与中断
史海拾趣
|
我想把 CTreeCtrl 滚动条重绘,我找到了一份win32 的代码,第一个要处理的消息就是WM_NCPAINT,可是wince 里并不支持这个消息. CE 下是不是有别的消息,重绘CTreeCtrl 的滚动条啊.. 大家帮忙,谢谢....… 查看全部问答> |
|
我下载一个2.73G的[WINDOWS.CE..NET.WITH.PLATFORM.BUILDER].Windows.CE.NET.4.2.Platform.Builder.iso 这个是不是PB4.2? 我安装的时候 它提示安装的是wince.net4.2 而没有任何PB的相关提示 而且还要注册码 我没有 有没有PB4.2的下载 ...… 查看全部问答> |
|
硬件条件:s3c2410 CPU,nand flash k9f1208 出现的问题:通过jtag下载vivi-bootloader能下载程序,在这个下载之前也能检测到cpu,nand flash 但是在,下载完成后,调试串口没有任何信息输出. 我已经排除的可 ...… 查看全部问答> |




