64位 RT-Thread 移植到 Cortex-A53 系统 bug 修复笔记

RT-Thread 版本:4.1.0 master 版本。
完整工程代码如下:可运行在 Cortex-A53 架构上的 RTT

1. Idle 默认栈大小为 256 字节,导致任务切换触发异常

Arch64 状态下,RT-thead 的任务切换触发未知错误。

经过测试,是因为 idle 初始化时,栈溢出,修改了就绪列表的值,导致任务切换失败.

#ifndef IDLE_THREAD_STACK_SIZE
#if defined (RT_USING_IDLE_HOOK) || defined(RT_USING_HEAP)
#define IDLE_THREAD_STACK_SIZE  256
#else
#define IDLE_THREAD_STACK_SIZE  128
#endif /* (RT_USING_IDLE_HOOK) || defined(RT_USING_HEAP) */
#endif /* IDLE_THREAD_STACK_SIZE */

可以手动设置 IDLE_THREAD_STACK_SIZE 大小更改 IDLE 任务栈大小。问题解决。

2. 栈初始化时,未对栈指针进行对齐操作,导致任务切换时触发 sp 指针对齐失败异常

串口报错如下:
[0]switch to priority#255 thread:tidle0(sp:0x41019024), from thread:tshell(sp: 0x42058f20)
[SYNC Error]: in EL1
ELR_EL1 =0x000000004100045c
ESR_EL1 =0x000000009a000000
current Exception Level exception, SPsel = 0
x0 =0x0000000000000000  x1 =0x0000000000000001
x2 =0x0000000000000000  x3 =0x0000000000000000
x29 =0x000000000000001d x30 =0x0000000041003134
[INFO]: CPU Reboot now!!!

查看手册得知,ELR_EL1 =0x000000004100045c,该异常由 sp 指针对齐失败导致的。

解决:由于当前 sp 指针为 4 字节对齐的,所以失败,在 rt_hw_stack_init() 中 将 sp 指针进行 16 字节对齐,问题解决。

    /*
     * TODO sp 指针4字节对齐不行,64位任务环境下的任务切换会失败,更改为 16 字节对齐
     */
    stack_addr = RT_ALIGN_DOWN((rt_ubase_t)stack_addr, sizeof(rt_ubase_t) * 2);

注意:栈指针16字节对齐,是编程向导手册中要求的(8.2.1章节)!!!经过测试,8字节对齐确实不行

64位 RT-Thread 移植到 Cortex-A53 系统 bug 修复笔记_第1张图片

3.每一次通过 shell 命令读取系统 tick 计数都是 0

测试发现,shell 输入回车以及任一shell命令导致系统 tick 计数清零。

经过调试分析,在rt_sem_take(&shell->rx_sem, RT_WAITING_FOREVER) 代码前后将 rt_tick 清零。

继续测试,是rt_sem_release() 中的rt_schedule()rt_tick清零。

继续测试,问题出现在rt_schedule()中的 rt_hw_context_switch_interrupt()的汇编实现中。

原因:汇编代码中变量访问越界造成该问题。

rt_hw_context_switch_interrupt()的汇编实现中,会用到三个外部定义的变量:

.globl rt_thread_switch_interrupt_flag
.globl rt_interrupt_from_thread
.globl rt_interrupt_to_thread

这三个外部变量定义在 libcpu 文件夹下对应架构的 interrupt.c 文件中。

volatile rt_ubase_t rt_interrupt_from_thread = 0;
volatile rt_ubase_t rt_interrupt_to_thread = 0;
volatile rt_uint32_t rt_thread_switch_interrupt_flag = 0;

其中,变量 rt_thread_switch_interrupt_flag 定义为无符号的32位整型,而在rt_hw_context_switch_interrupt()的汇编实现中,我们使用 Xn 寄存器来访问这个变量,而 Xn 寄存器是64位的,导致访问越界,而刚好, rt_thread_switch_interrupt_flag 变量地址为 0x41019144, 变量rt_tick 地址为 0x41019148, 所以当我们以 64 位宽度对 rt_thread_switch_interrupt_flag 置1或清0时,我们都会将 rt_tick 清0。

解决:

变量 rt_thread_switch_interrupt_flag 的初始类型为:

volatile rt_uint32_t rt_thread_switch_interrupt_flag = 0;

现在更改为:

volatile rt_ubase_t rt_thread_switch_interrupt_flag = 0;

问题解决。

你可能感兴趣的:(armv8,RT-Thread,ARM,bug)