DSB, ISB, DMB Barrier 명령어들

Core Architecture Barrier

우리가 직관적으로 생각하기에는 ARM Core에서 메모리 시스템이 메모리 트랜잭션을 생성한 인스트럭션의 순서와 같은 순서로 트랜잭션이 실행될 것이라고 생각하기 쉬우나 이는 틀린 생각입니다.

 

메모리 트랜잭션의 순서는 하드웨어의 특성에 적응하기 위해 변경될 수 있습니다. 예를 들어, 기저 물리 메모리에 접근하기 위해 필요한 대기 상태나 마이크로코드 수준에서 구현된 추측 분기 예측 메커니즘 같은 것을 말합니다.

 

Cortex-M 마이크로컨트롤러가 주변장치 및 시스템 구역에 걸쳐 엄격한 트랜잭션 순서를 보장하기는 하지만, 경우에 따라서는 실행 순서를 고려해 코드를 구현해야 합니다.

 

다음 인스트럭션을 실행하기 전에, 이전 메모리 트랜잭션이 수행됐음을 확인하기 위해 적절한 메모리 배리어(barrier)를 집어 넣음으로써 말입니다. 이 경우 인스트럭션 순서 또는 메모리 접근 동작들 사이에 순서를 바꾸지 못하게 강제됩니다.

 

Cortex-M 인스트럭션 세트는 다음과 같은 세종류의 배리어를 포함합니다.

 

  • 데이터 메모리 배리어(DMB, data memory barrier) : 모든 지연된 load/store가 모두 완료(Flush)될 때까지 대기.
    • 예)R,W,R,W,R,W → 효율을 위해 R,R,R,W,W,W 순으로 바꿀 수 있는데 이를 방지하기 위함.
/**
  \brief   Data Memory Barrier
  \details Ensures the apparent order of the explicit memory operations before
           and after the instruction, without ensuring their completion.
 */
__STATIC_FORCEINLINE void __DMB(void)
{
  __ASM volatile ("dmb 0xF":::"memory");
}
 
  • 데이터 동기화 배리어(DSB, data synchronization barrier) : 아래 명령이 실행되는 것을 기다리며 DMB보다 느림.
    • Instruction 캐시 및 Data 캐시 조작
    • Branch predictor 캐시 flush
    • 지연된 load/store 명령의 처리 <- DMB 명령이 하는 일
    • TLB 캐시 조작 완료
/**
  \brief   Data Synchronization Barrier
  \details Acts as a special kind of Data Memory Barrier.
           It completes when all explicit memory accesses before this instruction complete.
 */
__STATIC_FORCEINLINE void __DSB(void)
{
  __ASM volatile ("dsb 0xF":::"memory");
}
 
  • 인스트럭션 동기화 배리어(ISB, instruction synchronization barrier)
    • ISB 명령이 동작하는 순간 파이프라인으로 인해 다음 명령이 뒤 따라 들어오게 되는데 이를 모두 버리게 합니다.(Flush) Out of order execution 기능으로 인해 뒤 따라 Fetch된 명령이 먼저 동작이 될 가능성이 있는데 이럴 경우 문제가 벌어질 가능성이 있습니다. 특별히 두 명령의 우선 순위를 확실히 구분해야 하는 루틴에서는 두 명령 사이에 ISB를 실행시켜 두 명령어의 실행 순서를 명확히 보장해야 합니다.
    • ARMv7에서는 ISB를 지원하지만 다른 아키텍처에서 ISB를 지원하지 않는 경우가 있습니다. 이럴때 파이프 라인을 비우는 것과 비슷한 효과를 내려면 nop 또는 mov a0, a0등의 명령 사용을 사용하여 명령어 수행이 바뀌는 순간에도 문제가 없도록 할 수 있습니다. 또한 메모리 참조의 순서를 dependency하게 유도하여 일정 루틴을 in-order로 수행될 수 밖에 없도록 만들기도 합니다.
    • Use Case
      • 실시간 코드 변경
        • 만일 코드부분이 바뀐 후 캐시된 명령이 재실행되면 문제가 발생되므로 이 때에도 ISB를 사용하여야 합니다. (JIT가 명령을 바꾸면서 동작)
      • MMU on/off
        • MMU 전환 시점에도 ISB 명령을 사용합니다.
        • Out of Order Execution: CPU가 Out of Order Execution(ARMv6 아키텍처 부터 지원하지만 대부분 ARMv7부터 제품이 있음)을 지원하는 병렬 파이프라인을 사용하는 경우 캐시 사용이 바뀌는 시점에 이전 명령이 다음 이어지는 명령과 연관성이 없는 경우 다음 명령이 먼저 실행되면서 MMU 상태가 바뀌기 전후로 주소 참조에 문제가 될 수 있음을 막기 위함이입니다.
/**
  \brief   Instruction Synchronization Barrier
  \details Instruction Synchronization Barrier flushes the pipeline in the processor,
           so that all instructions following the ISB are fetched from cache or memory,
           after the instruction has been completed.
 */
__STATIC_FORCEINLINE void __ISB(void)
{
  __ASM volatile ("isb 0xF":::"memory");
}
 

크게 배리어의 사용이 필요한 경우는 다음과 같습니다.

 

  • Interrupt vector의 주소를 변경하기 위해 VTOR을 갱신한 후
  • 메모리 매핑을 갱신한 후
  • 스스로 수정하는 코드 실행 중

 

 

Complier Barrier

컴파일러 최적화 장벽으로 최적화 시 실행 코드가 생략, 축약 또는 실행 순서가 변경되지 못하도록 막아야하는 경우에 사용됩니다.

 

C 함수

  • barrier()
    • barrier() 이전 메모리 액세스와 이후 메모리 액세스가 컴파일러의 최적화에 의해 순서가 바뀌는 일이 없도록 제한한다.
  • 컴파일러 지시어
    • __volatile__
      • 컴파일러의 optimization을 제한하기 위해 __volatile__을 사용
      • 변수 앞에 사용될 때
        • 변수 사용에 대한 optimization을 제한한다.
          • 컴파일러가 속도 향상을 위해 변수를 레지스터에 배치하는 것을 막는다.
      • 함수 앞에 사용될 때
        • 함수안의 모든 optiomization을 제한한다.

 

 

 

 

참조 : 임베디드 시스템 아키텍쳐(다니엘 라카메라)

참조 : http://jake.dothome.co.kr/barriers/