Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ARM assembly inline C mutex impelmentation

I am working on an embedded systems project using the Xilinx Zedboard. The board has the ability to asymmetrically split it's dual core ARM A9 processor to run two separate programs simultaneously. I've configured the board to run Linux on one core and a bare metal application on the other acting as a hardware controller. For inter processor communication I am utilizing on chip memory that is shared between the two processors. I'm struggling with my lock implementation and I'm curious if anyone experience with such things or may be able to point me in the right direction.

I found a mutex implementation on the ARM reference website http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s03s02.html and I have adapted it to C inline assembly. After testing the lock function seems to hang and I have no idea why. My experience with assembly is somewhat limited, I've seen it in school and understand the high level concepts but I'm completely lost in the low level implementation.

Does this look right or is this even the right approach? All I need is a simple mechanism that will allow me to perform atomic operations on my inter process communication structures (several message queues).

mutex.h

#ifndef __OCM_MUTEX_H__
#define __OCM_MUTEX_H__

#include <stdint.h>

#define LOCKED      1
#define UNLOCKED    0

typedef uint32_t mutex_t;

extern void ocm_lock_mutex(volatile mutex_t* mutex);
extern void ocm_unlock_mutex(volatile mutex_t* mutex);

#endif

mutex.c

#include "mutex.h"

void ocm_lock_mutex(volatile mutex_t* mutex) {
    int result;
    const uint32_t locked = LOCKED;

    __asm__ __volatile__("@ocm_lock_mutex\n"
"1: LDREX   %[r2], [%[r0]]\n"
"   CMP     %[r2], %[locked]\n"
"   BEQ     2f\n"
"   STREXNE %[r2], %[locked], [%[r0]]\n"
"   CMP     %[r2], #1\n"
"   BEQ     1b\n"
"   DMB\n"
"   B       3f\n"
"2: WFE\n"
"   B       1b\n"
"3: NOP\n"
    : [r2] "=r" (result), [r0] "=r" (mutex)
    : [locked] "r" (locked));
}

void ocm_unlock_mutex(volatile mutex_t* mutex) {
    const uint32_t unlocked = UNLOCKED;

    __asm__ __volatile__("@ocm_unlock_mutex\n"
"   DMB\n"
"   STR %[unlocked], [%[r0]]\n"
"   DSB\n"
"   SEV\n"
    : [r0] "=r" (mutex)
    : [unlocked] "r" (unlocked));
}
like image 866
Wade Avatar asked May 11 '26 15:05

Wade


1 Answers

Why don't you use GNU assembly? It should look something like this

.equ locked,1
.equ unlocked,0

@ lock_mutex
@ Declare for use from C as extern void lock_mutex(void * mutex);
    .global lock_mutex
lock_mutex:
    LDR     r1, =locked
1:  LDREX   r2, [r0]
    CMP     r2, r1        @ Test if mutex is locked or unlocked
    BEQ     2f            @ If locked - wait for it to be released, from 2
    STREXNE r2, r1, [r0]  @ Not locked, attempt to lock it
    CMPNE   r2, #1        @ Check if Store-Exclusive failed
    BEQ     1b            @ Failed - retry from 1
    # Lock acquired
    DMB                   @ Required before accessing protected resource
    BX      lr

2:  @ Take appropriate action while waiting for mutex to become unlocked
    @ WAIT_FOR_UPDATE
    B       1b            @ Retry from 1


@ unlock_mutex
@ Declare for use from C as extern void unlock_mutex(void * mutex);
    .global unlock_mutex
unlock_mutex:
    LDR     r1, =unlocked
    DMB                   @ Required before releasing protected resource
    STR     r1, [r0]      @ Unlock mutex
    @ SIGNAL_UPDATE   
    BX      lr

Then its dump looks like this

$ arm-linux-gnueabihf-objdump -d mutex.o

mutex.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <lock_mutex>:
   0:   e3a01001    mov r1, #1
   4:   e1902f9f    ldrex   r2, [r0]
   8:   e1520001    cmp r2, r1
   c:   0a000004    beq 24 <lock_mutex+0x24>
  10:   11802f91    strexne r2, r1, [r0]
  14:   13520001    cmpne   r2, #1
  18:   0afffff9    beq 4 <lock_mutex+0x4>
  1c:   f57ff05f    dmb sy
  20:   e12fff1e    bx  lr
  24:   eafffff6    b   4 <lock_mutex+0x4>

00000028 <unlock_mutex>:
  28:   e3a01000    mov r1, #0
  2c:   f57ff05f    dmb sy
  30:   e5801000    str r1, [r0]
  34:   e12fff1e    bx  lr

However what I'm wondering if you did managed to configure both cores to be included in core coherency. To my knowledge you can specify which cores participate in ldrex/strex operations.

like image 109
auselen Avatar answered May 14 '26 13:05

auselen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!