ARM을 공부하면 가장 먼저 만나는 용어가 있습니다. 바로 ARM 동작 모드입니다. ARM 모드는 ARM의 세부 동작을 배우려면 반드시 알아야 하므로 잘 익혀 둘 필요가 있습니다. 
 
특히 64비트 기반의 ARMv8 아키텍처는 기존 ARM의 모드에 대응되는 익셉션 레벨이란 개념을 도입했습니다. 익셉션 레벨이란 개념이 기존 ARMv7 아키텍처의 ARM 모드에서 발전됐으니 먼저 ARM의 동작 모드부터 살펴봅시다.
 
ARM 모드의 종류
 
이 ARM 동작 모드를 잘 익혀야 시스템을 디자인하고 디버깅할 때 배운 내용을 유용하게 활용할 수 있습니다.  실행 모드를 잘 살펴 보면 유저(User) 모드는 표준 사용자 모드라고 부르는데 나머지 6가지 모드는 Privileged mode라고 분류됩니다. ARM User Manual을 열어 보면 각 모드에 대한 설명은 아래와 같이 되어 있습니다. 
 
#출처: DDI0406C_arm_architecture_reference_manual
 
User mode
An operating system to runs applications in User mode to restrict the use of system resources.
Application programs normally execute in User mode, and any program executed in User mode:
  • makes only unprivileged accesses to system resources, meaning it cannot access protected system resources
  • makes only unprivileged access to memory
 
System mode 
* Software executing in System mode executes at PL1. System mode has the same registers available
as User mode, and is not entered by any exception
 
Supervisor mode
* Supervisor mode is the default mode to which a Supervisor Call exception is taken.
* Executing a SVC (Supervisor Call) instruction generates an Supervisor Call exception, that is taken to Supervisor mode.
* A processor enters Supervisor mode on Reset.
 
Abort mode 
* Abort mode is the default mode to which a Data Abort exception or Prefetch Abort exception is taken.
 
Undefined mode
* Undefined mode is the default mode to which an instruction-related exception, including any
attempt to execute an UNDEFINED instruction, is taken.
 
FIQ mode 
* FIQ mode is the default mode to which an FIQ interrupt is taken.
 
IRQ mode 
* IRQ mode is the default mode to which an IRQ interrupt is taken.
 
Monitor mode
* Monitor mode is the mode to which a Secure Monitor Call exception is taken.
 
보시다시피 ARM 코어는 위에서 소개한 모드 중 하나를 사용합니다. 그런데 문제는 ARM 모드에 대한 내용으 읽어도 감이 잘 안온다는 점입니다. 
 
   * 무슨 모드가 이렇게 많아? 이걸 왜 쓰는 거지? 
   * 난 어떤 ARM 모드를 써야 할까?
 
의문은 끊이지 않습니다. 먼저 범용 리눅스를 기반으로 자주 사용하는 모드를 알아봅시다.
먼저 유저 모드(User mode) 입니다. 쉽게 설명하면 리눅스 애플리케이션은 유저 모드에서 동작합니다.
 
한 가지 예를 들겠습니다. 여러분이 라즈베리 파이나 우분투에서 다음과 같은 코드를 작성해 실행을 시켰습니다. 너무나 쉬운 예제 코드라 코드 내용과 컴파일을 하는 방법은 설명하지 않겠습니다.
 
#include <stdio.h>
int main() 
{
printf("Hello World! \n");
 
return 0;
}
 
위 코드는 라즈베리 파이나 우분투에서 어느 모드로 동작할 까요? ARM의 유저 모드입니다.
여기서 또 한 가지 의문이 생깁니다. 
 
   * 리눅스 애플리케이션이 ARM의 유저 모드에서 동작한다고 설명을 했다.
   * 당신은 이 사실을 어떻게 증명할 것인가?
 
좋은 질문입니다. 어떤 지식이든 그대로 답습을 하지 말고 배운 내용이 정말로 맞는지 증명해보는 습관을 갖는 것은 매우 중요합니다. '사실 - 증명'의 과정을 거치는 게 진정한 공부입니다.
 
현재 실행 중인 코드가 ARM의 어떤 모드에서 실행 중인지를 알려면 ARM에서 제공하는 CPSR(Current Program Status Register)를 읽어보면 됩니다. 보통 CPSR 레지스터의 [0:4] 비트가 0x10 이면 ARM의 유저 모드에서 동작한다고 볼 수 있습니다. 
 
어떤 ARM 모드를 써야 할까?
 
여기서 다음과 같은 의문이 생깁니다.
 
    * 평소에 애플리케이션을 실행할 때는 유저 모드를 사용하고 커널 레벨의 프로세스를 실행할 때는 시스템 모드를 사용하나?
    * 리눅스나 RTOS를 사용하지 않으면 유저 모드만 사용하면 되나?
 
이 질문에는 2가지 유형의 답이 가능하겠는데요. 
 
먼저 리눅스와 같은 범용 운영체제를 사용하는 시스템을 가정하겠습니다. 이 경우, 이미 라즈베리 파이나 안드로이드 그리고 우분투와 같은 리눅스 배포판 업체에서 리눅스 커널과 리눅스 애플리케이션을 구동할 수 있는 리눅스 유틸리티 프로그램을 미리 구성해 패키지로 배포합니다. 따라서, 리눅스 시스템 프로그래머 입장에서 일부러 유저 모드나 커널 모드를 어셈블리 명령어로 바꿀 필요가 없습니다. 유저 공간에서는 GNU C(glibc)과 커널이 알아서 바꿔주죠. 따라서 지금 실행하는 코드가 ARM의 어떤 모드에서 구동되는지 파악하면 됩니다. 유저 애플리케이션은 유저 모드, 커널의 프로세스는 시스템 모드(조금 더 정확히 슈퍼바이저 모드)에서 실행됩니다.
 
그런데, RTOS나 아예 RTOS로 탑재하지 않은 단순한 시스템에서는 디바이스의 스팩에 따라 시스템 모드를 구성하면 됩니다.
만약, SW 개발자 2명이서 시스템 전체를 개발한다면 모두 슈퍼바이저 모드에서 코드를 작성해도 됩니다. 혹은 시스템 모드에서 작성해도 되죠. 두 개발자가 메모리 맵을 다 알고 있고 메모리를 어떤 방식으로 처리하는지 이야기를 하면 끝나기 때문입니다.
 
만약 임베디드 개발자가 10명이고 애플리케이션을 다른 팀 개발자 5명이 개발한다면, ARM 모드를 어떻게 설정해야 할까요?
15명 전체 개발자가 모두 커뮤니케이션이 잘 된다면 모두 슈퍼바이저 모드에서 개발해도 되지만, 되도록 애플리케이션은 유저 모드 커널 프로세스는 슈퍼바이저 모드에서 실행되도록 구성하는 게 좋습니다. 
 
정리하면 사용하고 있는 디바이스의 스팩이나 시스템 구성에 따라 어떻게 모드를 설정할지 결정하면 됩니다.
 

< '시스템 소프트웨어 개발을 위한 Arm 아키텍처의 구조와 원리' 저자>

 
 

+ Recent posts