考虑以下功能:
_atomic_raw_lock:
.global _atomic_raw_lock
.type _atomic_raw_lock, %function
1: ldxr x9, [x0] //atomic load from memory pointed to by x0
cbz x9, 2f //branch if zero (unlocked)
wfe //sleep if locked
b 1b
2: mov x9, #0x01 //set x9 to be LOCKED (1).
stxr w10, x9, [x0]
dsb sy
cbz w10, 3f // atomic store success?
b 1b
3: ret
该函数从c代码中调用,并将地址存储到x0中的64位整数作为第一个参数。该程序在qemu中按预期运行。我通过在调用此函数的这一行之前和之后设置硬件引脚来确定这是问题区域。该函数永不返回。 x9和w10被保存为调用者(我假设c调用代码将自动保存它们)。
详细信息: 在pi 3 b +上运行 通过toolchains.bootlin.com使用aarch64-buildroot-linux-gnu(glibc静态链接)交叉链进行编译。在调用此函数之前,一切在真实硬件上都可以正常运行。 构建命令:
aarch64-linux-g++ -g -std=gnu++17 -O0 -Wall -fno-exceptions -Wextra -Wno-attributes -fno-asynchronous-unwind-tables -Wno-sign-compare -c start.S -o
aarch64-linux-ld start.o main.o -T link.ld -o kernel8.elf -l:libc.a -l:libstdc++.a -l:libc.so -l:libgcc_s.so
ld文件:
OUTPUT_ARCH(aarch64)
ENTRY(_start)
MEMORY
{
RAM (xrw) : ORIGIN = 0x80000, LENGTH = 0x40000000
}
SECTIONS
{
PROVIDE(__start_prog_mem = .); /*I may want to use this in c somehow*/
.text : /*The place where code goes*/
{
KEEP(*(.text.boot)) /*Keep this even if it is not used*/
*(.text .text.* .gnu.linkonce.t*) /*all variations of text and
the gnu generated (for the c ability) text sections*/
} > RAM /*These sections now belong in .text*/
.bss : /*Uninitialized data goes here, will not load at runtime.*/
{
. = ALIGN(4); /*align the current location to 4 bytes*/
__bss_start = .; /*define __bss_start to be at the current location.*/
*(.bss .bss.* .gnu.linkonce.b.*)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4); /*align the current location to 4 bytes*/
__bss_end = .; /*Define __bss_end to be at the current location.*/
} > RAM
.data : /*Initialized global and static data*/
{
. = ALIGN(4); /*align the current location to 4 bytes*/
__data_begin = .;
*(.data .data.* .gnu.linkonce.d*) /*Put all data sections here.*/
*(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
. = ALIGN(4);
__data_end = .;
} > RAM
.rodata : /*const data*/
{
. = ALIGN(4); /*align the current location to 4 bytes*/
__rodata_begin = .;
*(.rodata .rodata.* .gnu.linkonce.r*) /*All const data sections,
including the gnu leftovers*/
*(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
. = ALIGN(4);
__rodata_end = .;
} > RAM
.stack_core0 :
{
. = ALIGN(16); /*stack must be 16 byte aligned*/
__stack_start_core0 = .;
. = . + 1024; /*el0 size*/
__el0_stack_core0 = .; /*el0 stack*/
. = . + 1048576; /*el1 size*/
__el1_stack_core0 = .; /*el1 stack*/
PROVIDE(__el1_stack_core0 = .);
. = . + 16384; /*el2 stack size*/
__el2_stack_core0 = .;
. = ALIGN(16);
__stack_end_core0 = .;
} > RAM
.stack_core1 :
{
. = ALIGN(16); /*stack must be 16 byte aligned*/
__stack_start_core1 = .;
. = . + 1024; /*el0 size*/
__el0_stack_core1 = .; /*el0 stack*/
. = . + 1048576; /*el1 size*/
__el1_stack_core1 = .; /*el1 stack*/
PROVIDE(__el1_stack_core1 = .);
. = . + 16384; /*el2 stack size*/
__el2_stack_core1 = .;
. = ALIGN(16);
__stack_end_core1 = .;
} > RAM
.stack_core2 :
{
. = ALIGN(16); /*stack must be 16 byte aligned*/
__stack_start_core2 = .;
. = . + 1024; /*el0 size*/
__el0_stack_core2 = .; /*el0 stack*/
. = . + 1048576; /*el1 size*/
__el1_stack_core2 = .; /*el1 stack*/
PROVIDE(__el1_stack_core2 = .);
. = . + 16384; /*el2 stack size*/
__el2_stack_core2 = .;
. = ALIGN(16);
__stack_end_core2 = .;
} > RAM
.stack_core3 :
{
. = ALIGN(16); /*stack must be 16 byte aligned*/
__stack_start_core3 = .;
. = . + 1024; /*el0 size*/
__el0_stack_core3 = .; /*el0 stack*/
. = . + 1048576; /*el1 size*/
__el1_stack_core3 = .; /*el1 stack*/
PROVIDE(__el1_stack_core3 = .);
. = . + 16384; /*el2 stack size*/
__el2_stack_core3 = .;
. = ALIGN(16);
__stack_end_core3 = .;
} > RAM
_end = .; /*Define _end to be at the current location*/
PROVIDE(__end_prog_mem = .); /*I may want to use this in c somehow*/
.heap :
{
. = ALIGN(4);
__heap_start = .;
} > RAM
/DISCARD/ : /*Any sections listed here will not be included*/
{
/* *(.comment*) /*Exclude any comments made by the compiler*/
/* *(.gnu*) /*Exclude any version numbers included by the compiler*/
/* *(.note*) /*Exclude any notes made by the compiler.*/
/* *(.eh_frame*) /*This sections is ecluded because it contains asyncronous
unwind tbles we dont need.*/
}
}
__bss_size = (__bss_end - __bss_start) >> 3; /*Define the symbol to hold the
size of the .bss sections. This size will be in single units of 8 bytes
(due to shift >> 3)*/
__prog_mem_size = (__end_prog_mem - __start_prog_mem);
删除了原子锁定机制(最顶层的代码列表),该程序可以运行,但由于非线程安全代码,输出混乱。由于普通的read-modify-write也不是多核安全的,因此即使是简单的bool标志也无法使用。
问题已重述:为什么这要在仿真器(qemu)上而不是实际的硬件上运行。上面的_atomic_raw_lock函数列表在实际硬件上而非qemu上被调用时已被确认为挂起。
编辑:该代码在QEMU中运行良好,这使我认为它不是死锁。我已通过运行测试来确认了这一点,其中所有程序所做的操作仅锁定一次并永久旋转。在这种情况下问题仍然存在。
答案 0 :(得分:1)
如果提供的内存不是 NORMAL ,则可能会(失败)失败。
Qemu不太可能为内存属性建模并模仿此类故障。
(对stxr感到抱歉,我的想法是在cswap中)。
您可能会考虑将迭代计数放入循环中,以便在调试器/崩溃转储挂在其中时,可以对其进行纾困。