2013-11-21 6 views
2

자일링스 Zedboard를 사용하는 임베디드 시스템 프로젝트에서 작업하고 있습니다. 이 보드는 두 개의 별도 프로그램을 동시에 실행하기 위해 듀얼 코어 ARM A9 프로세서를 비대칭 적으로 분리 할 수 ​​있습니다. 필자는 하나의 코어에서 Linux를 실행하고 다른 노드에서 베어 메탈 응용 프로그램을 하드웨어 컨트롤러로 작동하도록 보드를 구성했습니다. 프로세서 간 통신의 경우 두 프로세서간에 공유되는 칩 메모리를 활용합니다. 나는 자물쇠 구현에 어려움을 겪고 있으며, 누군가가 그러한 일을 경험하거나 올바른 방향으로 나를 가리킬 수 있는지 궁금합니다.ARM 어셈블리 인라인 C 뮤텍스 임펠 멘션

ARM 참조 웹 사이트 http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s03s02.html에서 뮤텍스 구현을 발견했으며이를 C 인라인 어셈블리에 적용했습니다. 테스트 후 잠금 기능이 멈춘 것처럼 보이고 이유가 없습니다. 어셈블리에 대한 나의 경험은 다소 제한적이며, 학교에서 보았으며 상위 개념을 이해했지만 저수준 구현에서는 완전히 잃어 버렸습니다.

이 모양이 맞습니까? 아니면 이것이 올바른 접근 방법입니까? 필요한 것은 인터 프로세스 통신 구조 (여러 메시지 대기열)에서 원자 연산을 수행 할 수있는 간단한 메커니즘입니다.

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)); 
} 

답변

2

왜 GNU 어셈블리를 사용하지 않는? 그것은이

.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 

처럼 보일 것이다는 다음의 덤프는 핵심 일관성에 포함 할 두 개의 코어를 구성하는 관리 않은 경우 내가 궁금하네요 그러나 어떤이

$ 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 

것 같습니다. 필자가 알고있는 한 ldrex/strex 작업에 참여하는 코어를 지정할 수 있습니다.

+0

Linux에서 잠금 및 잠금 해제를 호출 할 때 세그먼테이션 오류가 발생하는 이유는 무엇입니까? – Wade

+0

@Wade 나는 r1에 잘못된 것을 넣었다고 생각합니다. 나는 상수가 아닌 주소를로드해야한다. 나는 그것을 즉시 수정하려고 고칠 것이다. – auselen

+0

@Wade는 내 이전 의견을 무시하고, 나는 그 의미에서 결함이 있다고 생각하지 않으며, 현재로서는 내 제안을 잘못했을 수 있다는 것을 알 수 없습니다. 단어의 유효한 주소 인 단일 매개 변수로 lock_mutex/unlock_mutex를 호출하고 있습니까? 'unsigned int와 비슷하다. output_mutex = unlocked; lock_mutex (& output_mutex);'제공 한 링크의 예와 같이? – auselen

0

코드가 정지되는 이유는 WFE 명령 때문일 수 있습니다. 이벤트가 발생하지 않으면 아무 작업도 수행하지 않습니다. 영원히. 이벤트가 활성화되어 생성되었는지 먼저 확인하십시오.

는 스핀 락을 구현하는 방법에 대한 예제가있다 (또한, ARM 아키텍처 참조 문서에서 STREX 및 LDREX에 useage 제한을 확인, 그 부분 A2.9.4 "사용 제한"에 있어야합니다) 에 : https://www.doulos.com/knowhow/arm/Hints_and_Tips/Implementing_Semaphores/

이 같은 이어질 것 코드에 자신의 예를 적용 :

__asm__ __volatile__("@ocm_lock_mutex\n" 
" LDREX %[r2], [%[r0]]\n" 
" CMP  %[r2], %[locked]\n" 
" STREXNE %[r2], %[locked], [%[r0]]\n" 
" CMPNE %[r2], #1\n" 
" BEQ  ocm_lock_mutex\n" 
    : [r2] "=r" (result), [r0] "=r" (mutex) 
    : [locked] "r" (locked)); 

이 바쁜 대기와 뮤텍스를 구현합니다.

당신은 뮤텍스가 바쁜 대기하지 않고 인수 한 경우 코드는 단지 마지막 수정을 알려하려면 :

__asm__ __volatile__("@ocm_lock_mutex\n" 
[...] 
" CMPNE %[r2], #1\n" 
" BEQ  ocm_lock_mutex_end\n" 
" MOV %[r2], #2\n" 
"@ocm_lock_mutex_end\n" 
" NOP\n" 
    : [r2] "=r" (result), [r0] "=r" (mutex) 
    : [locked] "r" (locked)); 

를 그냥 C에서 확인하십시오

if (result==0) {/*You didn't get the mutex, it was locked*/} 
else if (result==1) {/*You didn't get the mutex, access not exclusive*/} 
else if (result==2) {/*You got the mutex!*/} 

(바와 같이 ARM 아키텍처 참조 문서, 버전 2005, A2.9.4 "로드 및 저장 작업")

C에서 바쁜 대기 중 루프를 구성하는 것이 합리적입니다. 또는 인터럽트 기반 체계를 사용하려면 거기에서 작업을 일시 중단하십시오. 엄지 손가락의

규칙 (들) :

  • 이 가능하고 루프가없는만큼 작은 인라인 어셈블리 코드를 유지합니다.

  • 인라인 조립품을 한 번에 하나만 만드십시오.