我是一名硬件工程师,使用 Altera intel 的 Cyclone V SX SOC FPGA 开发新硬件。
我刚刚验证了我的 DDR3-800 内存时序(是的,它是一个旧芯片)。
我试图通过将数据位短路到地来证明 ECC 内存正在工作,这是验证硬件和软件对位错误的处理的常见做法。
然而,当我将 D1 短接到地时,内核惊慌失措。
这是“decode_stacktrace.sh”解码输出的顶部
(注意:第一行来自我添加到 Altera_EDAC 驱动程序的 printk)
[ 1299.870164] EDAC: [226 Correctable errors @ 0x000E33C4]
[ 1299.876892] EDAC MC0: 184 CE soc:sdramedac on mc#0csrow#0channel#0 (csrow:0 channel:0 page:0x6a3 offset:0xb9c grain:8 syndrome:0x0)
[ 1299.891822] Unable to handle kernel paging request at virtual address c06a3b9c
[ 1299.899021] pgd = b6c6b929
[ 1299.901724] [c06a3b9c] *pgd=0061940e(bad)
[ 1299.905736] Internal error: Oops: 80d [#1] SMP ARM
[ 1299.910515] Modules linked in:
[ 1299.913567] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.11.0-wtec #5
[ 1299.919903] Hardware name: Altera SOCFPGA
[ 1299.923900] PC is at edac_raw_mc_handle_error (./arch/arm/include/asm/edac.h:26 drivers/edac/edac_mc.c:816 drivers/edac/edac_mc.c:938 drivers/edac/edac_mc.c:1010)
[ 1299.929301] LR is at __kmap_local_page_prot (mm/highmem.c:542)
[ 1299.934344] pc : lr : psr: 000f0193
[ 1299.940587] sp : c0e01b70 ip : c0e01b58 fp : c0e01bd4
[ 1299.945792] r10: 00000000 r9 : c0e01c10 r8 : ef7f9000
[ 1299.950998] r7 : 00000000 r6 : 000006a3 r5 : 00000b9c r4 : 00000008
[ 1299.957500] r3 : c06a3b9c r2 : c06a3ba4 r1 : ebfb755f r0 : c06a3000
[ 1299.964003] Flags: nzcv IRQs off FIQs on Mode SVC_32 ISA ARM Segment none
[ 1299.971201] Control: 10c5387d Table: 02b0004a DAC: 00000051
[ 1299.976924] Process swapper/0 (pid: 0, stack limit = 0x10d9740f)
[ 1299.982911] Stack: (0xc0e01b70 to 0xc0e02000)
我通过查看 linux 内核源代码来跟踪这一点。这是我认为正在发生的事情:
- 我将 D1 短接到地。
- ECC 启动并修复该位,触发中断。
- 在这种情况下,我对 D1 信号的光刷会导致 226 个可纠正错误。
- Altera ECC 驱动程序处理中断,收集信息并将所述信息返回给 ECC 管理器。
- ECC 管理器尝试使用位于“edac.h”中的一些内联程序集来清理受影响的内存,如下所示:
static inline void edac_atomic_scrub(void *va, u32 size)
{
#if __LINUX_ARM_ARCH__ >= 6
unsigned int *virt_addr = va;
unsigned int temp, temp2;
unsigned int i;
for (i = 0; i < size / sizeof(*virt_addr); i++, virt_addr++) {
/* Very carefully read and write to memory atomically
* so we are interrupt, DMA and SMP safe.
*/
__asm__ __volatile__("\n"
"1: ldrex %0, [%2]\n"
" strex %1, %0, [%2]\n"
" teq %1, #0\n"
" bne 1b\n"
: "=&r"(temp), "=&r"(temp2)
: "r"(virt_addr)
: "cc");
}
#endif
}
#endif
- 此代码运行并在某些时候遇到非法虚拟地址并触发错误:“无法在虚拟地址 c06a3b9c 处理内核分页请求”
更新:我已经确定第一个地址导致了 oops,并且即使有很多错误,我捕获的示例的大小(在上面的那个之后)只有 8 个长。
这段代码太不合我意了。我希望有一些经验的人可以成为我的老师,并告诉我如何去做。
在这一点上,我唯一的选择是尝试查看来自硬件的物理地址是如何被内核重新映射到虚拟内存中的。我想这就是它出错的地方。
任何帮助将不胜感激。