OpenAMP / libmetal

An abstraction layer across RTOS, baremetal, and user-space Linux environments
https://www.openampproject.org/
Other
259 stars 172 forks source link

Acquiring spinlock in ZYNQ 7000 loops forever #309

Open f-zl opened 2 weeks ago

f-zl commented 2 weeks ago

I'm using ZYNQ 7000 and want to use spinlock to synchronize the two cores (baremetal). The problem is metal_spinlock_acquire loops forever.

The code of core0's main.c:

// some includes

#define SHARED_MEM_BASE_ADDR // an address of DDR or OCM unused by both cores' linkers, like 0x30000000 or 0xffff0000
typedef struct {
  struct some_struct variable;
  struct metal_spinlock lock;
} SharedMem;
#define SHARED_MEM ((volatile SharedMem *)SHARED_MEM_BASE_ADDR)

void protected_read(struct some_struct *s) {
  metal_spinlock_acquire(&SHARED_MEM->lock);
  *s = SHARED_MEM->variable;
  metal_spinlock_release(&SHARED_MEM->lock);
}
int main() {
  init_system(); 
  metal_spinlock_init(&SHARED_MEM->lock);
  wake_up_core1();
  struct some_struct s;
  for(;;) {
    protected_read(&s);
    // process data
    // core1 is supposed to read and write to variable with lock too
  }
}

metal_spinlock_acquire compiles to this:

 0:   e3a02001        mov     r2, #1 ; r2 = 1
 4:   f57ff05b        dmb     ish ; data memory barrier
 8:   e1d03f9f        ldrexb  r3, [r0] ; r3 = *r0, r0's type is struct metal_spinlock *, aka atomic_flag *
 c:   e1c01f92        strexb  r1, r2, [r0] ; *r0 = r2 = 1, save status in r1
10:   e3510000        cmp     r1, #0 ; exclusive store succeed?
14:   1afffffb        bne     8 <metal_spinlock_acquire+0x8> ; if not succeed, try again
18:   e31300ff        tst     r3, #255 ; any bit set in r3? was the lock held by others?
1c:   f57ff05b        dmb     ish
20:   1afffff7        bne     4 <metal_spinlock_acquire+0x4> ; if lock was held by others, try again
24:   e12fff1e        bx      lr

In metal_spinlock_acquire, strexb always fails, so it loops forever, even when core1 is halted by a debugger and never accesses the lock.

I find this link that says ZYNQ 7000 doesn't support exclusive access of OCM. But the behavior is still the same if SHARED_MEM_BASE_ADDR is a DDR address. How to make spinlock work on ZYNQ 7000?

P.S.:

  1. Xil_SetTlbAttributes(SHARED_MEM_BASE_ADDR, 0x14de2) is called in both cores' init function as in xapp1079, to mark the address as sharable
  2. -DUSE_AMP=1 is added in core1's bsp
arnopo commented 1 week ago

@tnmysh : Do you have any idea what the issue might be?

tnmysh commented 1 week ago

@arnopo zynq7000 use and development is not active for long time. So, I am not sure. I think libmetla support will be deprecated on zynq7000 platform, so I am not sure if I will get chance to debug this.