历史上的今天
返回首页

历史上的今天

今天是: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之后,看起来大部分时候系统还是可以正常运行的


  1. [ 1259.654597] Bad mode in Error handler detected, code 0xbf000002 -- SError

  2. [ 1259.661357] CPU: 12 PID: 2293 Comm: mate-settings-d Not tainted

  3. 4.1.15-1.el7.aarch64 #2

  4. [ 1259.669320] Hardware name: xxxx

  5. [ 1259.675209] task: ffffffc8c9bd1700 ti: ffffffc8c9e4c000

  6. task.ti: ffffffc8c9e4c000

  7. [ 1259.682665] PC is at 0x7f9c51abd8

  8. [ 1259.685961] LR is at 0x7f942f9828

  9. [ 1259.689259] pc : [<0000007f9c51abd8>]

  10. lr : [<0000007f942f9828>] pstate: 80000000

  11. [ 1259.696616] sp : ffffffc8c9e4fff0


首先先定位出现这段LOG的代码位置在traps.c,arm64的异常向量表中才有对这个函数的调用,如下图


bad_mode 的打印信息SError 和 code 都是从register  esr_el1中获取的,能得到SError的只有el1 和el0的invalid_error打印的


  1. /arch/arm64/kernel/traps.c

  2. /*

  3. * bad_mode handles the impossible case in the exception vector. This is always

  4. * fatal.

  5. */

  6. asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)

  7. {

  8. console_verbose();

  9.  

  10. pr_crit("Bad mode in %s handler detected on CPU%d, code 0x%08x -- %sn",

  11. handler[reason], smp_processor_id(), esr,

  12. esr_get_class_string(esr));

  13.  

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

  15. local_irq_disable();

  16. panic("bad mode");

  17. }

  18.  

  19. /arch/arm64/kernel/entry.s

  20.  

  21. /*

  22. * Bad Abort numbers

  23. *-----------------

  24. */

  25. #define BAD_SYNC 0

  26. #define BAD_IRQ 1

  27. #define BAD_FIQ 2

  28. #define BAD_ERROR 3

  29.  

  30. //el1_sync 函数

  31. el1_sync:

  32. el1_inv:

  33. // TODO: add support for undefined instructions in kernel mode

  34. enable_dbg

  35. mov x0, sp

  36. mov x2, x1

  37. mov x1, #BAD_SYNC

  38. b bad_mode

  39. ENDPROC(el1_sync)

  40. //inv_entry 函数

  41. /*

  42. * Invalid mode handlers

  43. */

  44. .macro inv_entry, el, reason, regsize = 64

  45. kernel_entry el, regsize

  46. mov x0, sp

  47. mov x1, #reason

  48. mrs x2, esr_el1//bad_mode 函数的参数传递

  49. b bad_mode

  50. .endm

  51.  

  52. el0_sync_invalid:

  53. inv_entry 0, BAD_SYNC

  54. ENDPROC(el0_sync_invalid)

  55.  

  56. el0_irq_invalid:

  57. inv_entry 0, BAD_IRQ

  58. ENDPROC(el0_irq_invalid)

  59.  

  60. el0_fiq_invalid:

  61. inv_entry 0, BAD_FIQ

  62. ENDPROC(el0_fiq_invalid)

  63.  

  64. el0_error_invalid:

  65. inv_entry 0, BAD_ERROR

  66. ENDPROC(el0_error_invalid)

  67.  

  68. #ifdef CONFIG_COMPAT

  69. el0_fiq_invalid_compat:

  70. inv_entry 0, BAD_FIQ, 32

  71. ENDPROC(el0_fiq_invalid_compat)

  72.  

  73. el0_error_invalid_compat:

  74. inv_entry 0, BAD_ERROR, 32

  75. ENDPROC(el0_error_invalid_compat)

  76. #endif

  77.  

  78. el1_sync_invalid:

  79. inv_entry 1, BAD_SYNC

  80. ENDPROC(el1_sync_invalid)

  81.  

  82. el1_irq_invalid:

  83. inv_entry 1, BAD_IRQ

  84. ENDPROC(el1_irq_invalid)

  85.  

  86. el1_fiq_invalid:

  87. inv_entry 1, BAD_FIQ

  88. ENDPROC(el1_fiq_invalid)

  89.  

  90. el1_error_invalid:

  91. inv_entry 1, BAD_ERROR

  92. ENDPROC(el1_error_invalid)

到底SError是ARM的一种什么异常,AArch64(ARM64)架构中,主要包括如下4中类型的异常:

  1. Synchronous exception(同步异常),“同步”可以理解为:发生异常的指令为导致异常的指令,即当导致异常发生的指令执行时能立即触发异常。 包括ARM架构中定义的所有Aborts异常,如:指令异常、数据异常、对齐异常等。

  2. SError,System Error,是一种异步异常,后面再仔细说明。

  3. IRQ,普通的中断,是异步异常。

  4. 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:

016-bit.
132-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


  1. /*

  2. * Invalid mode handlers

  3. */

  4. .macro inv_entry, el, reason, regsize = 64

  5. kernel_entry el, regsize

  6. mov x0, sp

  7. mov x1, #reason

  8. mrs x2, esr_el1

  9.  

  10. mrs x3, elr_el1

  11. //add this line to pass para to bad_mode function

  12. //SError always call this function

  13. b bad_mode

  14. .endm


  15. asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr, u64 elr_regs)

  16. //add a para

  17. {

  18. siginfo_t info;

  19. void __user *pc = (void __user *)instruction_pointer(regs);

  20. console_verbose();

  21.  

  22. pr_crit("Bad mode in %s handler detected on CPU%d, code 0x%08x -- %sn",

  23. handler[reason], smp_processor_id(), esr,

  24. esr_get_class_string(esr));

  25. pr_cirt("dump elr %llxn",elr_regs);

  26. //add printk to dump this register

  27. __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}

推荐阅读

史海拾趣

福斯特半导体(Foster)公司的发展小趣事

对于能判断障碍物的机器人电路,网友可能还有以下几个问题及其相应回答:

问题一:机器人通常使用哪些传感器来判断障碍物?

回答
机器人通常使用多种传感器来判断障碍物,主要包括但不限于以下几种:

  1. 超声波传感器:这是最常见的一种传感器,通过发射超声波并接收其反射回来的信号,根据信号的时间差和波速计算障碍物的距离。超声波传感器在检测大范围、非接触式的障碍物时非常有效。

  2. 红外传感器:红外传感器通过发射红外光并接收其反射光来判断障碍物的存在和距离。红外传感器在近距离和快速检测中表现优异,且成本相对较低。

  3. 激光传感器:激光传感器利用激光束进行测距,具有高精度、长距离测量的特点。但相比超声波和红外传感器,激光传感器的成本更高,适用于对精度要求极高的应用场景。

  4. 视觉传感器:一些高级的机器人还配备了视觉传感器,如摄像头,通过图像处理技术来识别并判断障碍物。这种方法可以实现更复杂的场景理解和避障策略。

问题二:如何设计能判断障碍物的机器人电路?

回答
设计能判断障碍物的机器人电路需要考虑以下几个关键步骤:

  1. 选择合适的传感器:根据机器人的应用场景、成本预算和精度要求选择合适的传感器。

  2. 设计信号处理电路:将传感器采集到的原始信号(如电压、电流等)进行放大、滤波等处理,以便于后续的数字处理或微控制器读取。

  3. 微控制器编程:根据传感器的输出信号编写微控制器的程序,实现障碍物的判断、避障策略的制定和执行。

  4. 执行机构控制:通过微控制器控制机器人的执行机构(如电机、舵机等),实现机器人的移动和避障动作。

  5. 整体调试与优化:对整个电路进行调试和优化,确保机器人能够准确、稳定地判断障碍物并执行避障动作。

问题三:如何提高机器人判断障碍物的准确性和稳定性?

回答
提高机器人判断障碍物的准确性和稳定性可以从以下几个方面入手:

  1. 选用高质量的传感器:高质量的传感器具有更高的精度和稳定性,能够减少误判和漏判的情况。

  2. 优化信号处理电路:通过合理的电路设计和元器件选择,减少信号噪声和干扰,提高信号的信噪比和可靠性。

  3. 算法优化:对微控制器的算法进行优化,采用更先进的算法或策略来提高障碍物的判断精度和避障效果。

  4. 多传感器融合:利用多种传感器进行融合处理,可以弥补单一传感器的不足,提高整个系统的鲁棒性和可靠性。

  5. 实验验证与迭代优化:通过大量的实验验证和迭代优化,不断调整和优化机器人的参数和算法,以提高其判断障碍物的准确性和稳定性。

CommScope Inc公司的发展小趣事

随着全球经济的不断发展,亚洲市场逐渐成为通信行业的重要增长点。康普公司敏锐地捕捉到了这一机遇,于1997年在苏州工业园区成立了康普通讯技术(中国)有限公司,这是康普在亚洲开设的第一家工厂。该工厂的成立不仅提高了康普在亚洲市场的生产效率,也为其进一步开拓亚洲市场提供了有力的支持。此后,康普在亚洲市场的业务逐渐扩大,为众多国内大型项目提供了网络解决方案。

胜利(VICTOR)公司的发展小趣事

进入21世纪,胜利公司加大了对技术研发的投入,不断推出具有创新性的产品。例如,公司研发的碳纤维羽毛球拍,不仅轻盈耐用,而且性能卓越,迅速成为市场上的热销产品。此外,公司还积极引入新材料、新工艺,不断提升产品的品质和性能。

科达嘉CODACA公司的发展小趣事

科达嘉电子创建于2001年,起初是一家专注于功率电感、共模电感的研发、生产与销售的初创企业。在电子行业激烈的市场竞争中,科达嘉凭借对电感技术的深入研究和不断创新,逐渐赢得了市场的认可。公司团队经过近二十年的努力,从一个小型创业公司发展成为拥有多家子公司的集团企业,员工总数超过900人,厂房总面积达到30000平方米。

FRONTIER公司的发展小趣事

背景:虽然此处的FRONTIER可能指的是边疆通信公司(Frontier Communications),但为符合电子行业背景,我们假设其在农村宽带服务方面的创新。

发展故事:在21世纪初期,FRONTIER Communications认识到农村地区对于宽带服务的迫切需求,于是开始大规模投资农村宽带基础设施建设。通过引入先进的通信技术和设备,FRONTIER Communications成功地将高速互联网带到了偏远地区,极大地改善了当地居民的生活和工作条件。这一举措不仅赢得了市场的广泛赞誉,也为公司带来了稳定的收入来源和持续增长的动力。

ALCOA公司的发展小趣事

ALCOA,全称美国铝业公司,其发展历程可追溯至19世纪末。当时,铝在地球上蕴藏丰富,但提炼单质的铝却十分困难。年轻的查尔斯·霍尔(Charles Hall)发明了用电解方式生产单质铝的方法,并于1889年获得专利。随后,他与艾尔弗雷德·亨特(Alfred E. Hunt)船长合作,投资建厂,开始批量生产铝。这一技术创新不仅推动了铝产量的快速上升,还使得铝这种曾经比金子还贵的金属逐渐走进了人们的日常生活。

问答坊 | AI 解惑

还得上传资料VHDL语言详解.pdf

啥也不说了  拿新币 传资料…

查看全部问答>

堪称一绝的键盘扫描方法.

堪称一绝的键盘扫描方法.pdf…

查看全部问答>

WINCE CTreeCtrl 滚动条自绘

我想把 CTreeCtrl 滚动条重绘,我找到了一份win32 的代码,第一个要处理的消息就是WM_NCPAINT,可是wince 里并不支持这个消息. CE 下是不是有别的消息,重绘CTreeCtrl 的滚动条啊.. 大家帮忙,谢谢....…

查看全部问答>

提醒:最近有人外包为名,骗人!小心为妙!居说北京的!

提醒:最近有人外包为名,骗人!小心为妙!居说北京的! 个人意见,仅供参考! …

查看全部问答>

蓝牙串口开发

WINCE下 开发一个蓝牙串口通讯的小软件.用在PDA手机上.软件用来主动搜索其他蓝牙设备.…

查看全部问答>

求PB4.2下载地址

我下载一个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串口调试的问题

硬件条件:s3c2410 CPU,nand flash k9f1208 出现的问题:通过jtag下载vivi-bootloader能下载程序,在这个下载之前也能检测到cpu,nand flash           但是在,下载完成后,调试串口没有任何信息输出. 我已经排除的可 ...…

查看全部问答>

帮助 for

always @ (posedge clock)    if(reset == 1) begin       for(k=1; k…

查看全部问答>

EE_FPGA_V2.0 预览

根据前面大家使用情况以及器件的采购情况,准备做点小小的调整 1. 把红外模块去掉         价格高,还不容易买 2. 去掉一个晶振            &n ...…

查看全部问答>

verilog硬件原语

verilog硬件原语课件…

查看全部问答>