Arm 동작 모드를 이해하려면 Privilege level(PL)의 개념을 먼저 알면 좋습니다. Arm 동작 모드는 PL의 기반 위에서 정의했기 때문입니다. 
 
PL과 Arm 동작 모드에 대한 Arm 스팩 문서 분석
 
먼저 Arm 스팩 문서에서 PL0를 어떻게 정의했는지 알아봅시다.
 
(출처: DEN0013D_cortex_a_series_PG.pdf)
PL0 
The privilege level of application software, that executes in User mode. Software executed in User mode is described as unprivileged software. This software cannot access some features of the architecture. In particular, it cannot change many of the configuration settings. Software executing at PL0 can make only unprivileged memory accesses.
 
스팩 문서의 내용은 다음과 같이 요약할 수 있습니다.
 
   ❑ User 모드에서 실행되는 애플리케이션 소프트웨어가 실행되는 PL이다.
   ❑ User 모드에서 실행되는 소프트웨어는 unprivileged 소프트웨어라고 명시한다.
   ❑ PL0에서는 몇 가지 아키텍처 기능을 설정할 수 없다.
   ❑ PL0에서는 메모리 접근 권한에 제약이 있다. 
 
PL0에서 설정할 수 없는 몇 가지 아키텍처 기능이 있습니다. 그 중 하나는 MMU 설정이나 인터럽트 설정입니다. Arm 아키텍처에서는 메모리에 접근할 때 권한을 체크하는데, PL0에서는 접근할 수 있는 메모리 공간에 제약이 있습니다.  
이번에는 PL1에 대해 설명한 Arm 스팩 문서를 보면서 PL1에 대해 알아봅시다.
 
(출처: DEN0013D_cortex_a_series_PG.pdf)
PL1 
Software execution in all modes other than User mode and Hyp mode is at PL1.
Normally, operating system software executes at PL1. The PL1 modes refers to all the modes other than User mode and Hyp mode.
 
스팩 문서의 내용은 다음과 같이 요약할 수 있습니다.
 
   ❑ User 모드와 Hyp 모드를 제외한 모든 모드가 PL1에서 실행된다. 
   ❑ 보통 운영체제의 시스템(커널)이 PL1에서 실행된다.
 
User와 Hyp를 모드를 빼고는 PL1에서 실행되는데요. 더 구체적으로 PL1에서 실행되는 동작 모드는, Supervisor (SVC), IRQ, FIQ, Abort (ABT), Undef (UND), System (SYS) 모드입니다.
 
PL1에서는 메모리에 아무런 제약 없이 접근할 수 있으며, CoProcessor와 같은 Configuration 레지스터를 엑세스할 수 있습니다. 
 
이어서 아래 표를 보면서 PL와 해당 Arm 동작 모드에 대해 알아봅시다.
 
 
표 3.1 Armv7 아키텍처의 동작 모드와 PL
 
표 3.1에서 명시된 Arm 동작 모드에 대해 더 자세히 알아봅시다.
 
먼저 User 모드는 유저 애플리케이션이 실행되는 모드로 PL0입니다. 여러분이 자주 사용하는 카카오톡, 유튜브나 브라우저와 같은 애플이케이션은 User 모드에서 실행됩니다. 그런데 PL0에서는 시스템 설정에 제약이 있습니다. MMU나 인터럽트 혹은 CoProcessor 레지스터에 접근할 수 없습니다. 또한 User 모드에서는 접근할 수 있는 메모리 공간에 제약이 있습니다.
 
슈퍼바이저(Supervisor) 모드는 주로 운영체제의 커널이 구동되며, PL1으로 실행됩니다. 슈퍼바이저 모드에 진입하려면 svc 명령어를 실행해야 하는데, 주로 User 모드에서 svc 명령어를 실행해 진입합니다. 
 
User 모드에서 구동되는 유저 애플리케이션에서 svc 명령어를 실행하는 동작을 보통 시스템 콜 이라고 하는데, 이를 통해 운영체제 커널이 구동되는 슈퍼바이저 모드에 진입합니다.
 
이어서 IRQ 모드와 FIQ모드는 'IRQ 인터럽트'나 'FIQ 인터럽트'와 같은 익셉션이 발생하면 진입하는 모드입니다. 대부분 운영체제에서는 IRQ 인터럽트가 발생하면 인터럽트를 직접 처리하며, 'FIQ 인터럽트'는 트러스트존의 Secure OS에서 처리하도록 설정합니다.
 
Abort(ABT) 모드는 '프리페치 어보트(Prefetch Abort)나 데이터 어보트(Data Abort)를 유발하는 명령어를 실행하면 진입하는 모드입니다. 이어서 Undef(UND) 모드는 Arm 아키텍처에서 정의되지 않은 명령어가 실행되면 진입하는 모드입니다. 
 
Arm 아키텍처에서는 익셉션의 유형을 크게 메모리 어보트로 유발되는 익셉션과 인터럽트로 유발되는 익셉션으로 분류하는데, Abort(ABT)와 Undef(UND) 모드는 메모리 어보트를 유발하는 어셈블리 명령어가 실행되면 진입하는 모드입니다.
 
각각 Arm 동작 모드를 소개했으니 PL 관점으로 Arm 동작 모드를 분류해봅시다. PL0의 권한이 부여된 Arm 동작 모드는 User 모드이며, 이를 제외한 나머지 모드들은 PL1에서 실행됩니다. 
 
이번에는 다음 그림을 보면서 PL별로 정의된 Arm 동작 모드를 정리합시다.
 

 
 
그림 3.1 PL별로 정의된 Arm 동작 모드 
 
그림의 가장 윗 부분은 PL0을 나타내며 User 모드는 PL0 권한이 있습니다. 이어서 그림의 아랫 부분은 PL1인데, User 모드를 제외만 모든 Arm 동작 모드가 PL1 권한으로 실행됩니다.
 
어떤 Arm 동작 모드를 선택해야 할까
 
이어서 Arm 아키텍처에서 정의된 동작 모드가 운영체제나 RTOS에서는 어떻게 활용되는지 알아봅시다.
 
User 모드는 유저 애플리케이션이 실행되고, Supervisor 모드는 운영제체의 커널이나 커널 드라이버가 실행되는 모드입니다. Supervisor 모드는 svc 명령어가 실행되면 진입하는 모드이기도 합니다. 
 
그런데 Arm 동작 모드에 대한 내용을 처음 접하면 낯선데, 다양한 의문이 생깁니다. 특히 이 기능들이 실전 프로젝트에서 어떻게 활용되는지 궁금해합니다.
 
그래서 세미나에서 다음과 같은 질문을 자주 듣습니다.  
 
   "Arm 모드는 왜 존재하며, 각각 어떻게 활용될까?"
 
   "개발하려는 프로젝트에서 혹시 운영체제를 사용하지 않는 경우엔 User 모드만 
    사용하면 될까?"
 
이 질문에 대해 "시스템을 디자인하는 개발자가 자신이 개발하는 시스템에 맞게 Arm 동작 모드를 선택하면 된다"라고 말씀드리고 싶습니다.
 
어떤 시스템이 부팅을 한 다음에 디스플레이 디바이스에 'Hello, world'만을 출력하는 동작만을 실행하는 제품을 예로 듭시다. 다른 디바이스에서 인터럽트가 트리거되지도 않고 메모리를 설정할 필요가 없습니다. 이런 기능은 슈퍼바이저 모드에서 모두 프로그래밍해도 됩니다. 혹은 User 모드에서 코드가 실행되도 상관없습니다. 
 
이번에는 음악만 재생하는 소형 MP3 플레이어를 예로 들겠습니다. 그런데 이 장비에서 애플리케이션을 유저가 설치할 수 없습니다. 해당 시스템에 매우 심플한 RTOS가 구동이 되는 상황이면, 이번에도 모든 프로그램을 슈퍼바이저 모드에서 실행되도록 시스템을 디자인할 수 있을까요? 그런데 한 가지 중요한 스팩이 떠올랐습니다. '소형 MP3 플레이어에 블루투스 기능이 있어야 하는데, 블루투스를 연결할 때 인터럽트가 발생한다'고 합니다. 이럴 때는 IRQ 모드에서도 프로그램이 동작하도록 시스템을 구성해야 합니다. 
 
마지막으로 유저 애플리케이션을 설치할 수 있는 범용 운영체제를 예로 들겠습니다. 이 시스템에서는 어떤 모드에서 코드가 실행돼야 할까요?
 
User 모드에서는 유저 애플리케이션이 구동되고, 슈퍼바이저 모드에서는 리눅스 커널와 같은 운영체제의 커널이 실행되도록 시스템을 구성하면 좋을 것입니다. 물론 인터럽트가 발생하면 IRQ 모드로 진입하니 IRQ 모드에서 인터럽트를 처리하게 시스템을 설계할 수 있습니다.
 
그런데 실전 프로젝트에서 개발자가 실수로 NULL 포인터 익셉션을 유발하는 코드를 작성할 수 있습니다. 이런 코드(명령어)가 실행되면 Arm 프로세서는 '데이터 어보트'나 '프리페치 어보트' 익셉션을 유발하면서 Abort 모드에 진입합니다. 이런 조건에서는 무엇인가 시스템의 오류 정보를 출력하고 시스템을 리셋시키거나 프로세스를 종료시키는 코드가 구현되면 좋을 것입니다.
 
이처럼 Arm 동작 모드의 특징을 잘 살려서 시스템을 디자인을 하는 개발자는 적절한 모드를 선택할 수 있습니다. 
 
[중요]
시스템을 디자인할 때 Arm의 동작 모드의 특성을 잘 파악하는게 중요한데, 각 Arm 모드가 어떤 PL에서 실행되는지 염두에 둬야 합니다. User 모드는 PL0이고 나머지 모드는 PL1으로 실행됩니다.
 
Arm 동작 모드를 선택할 때 기본 원칙 
 
이어서 Arm 동작 모드를 선택할 때 고려해야 할 2가지 기본 원칙을 설명하겠습니다. 
 
첫 번째, PL0에서 PL1으로 자유스럽게 진입할 수 없습니다. PL1으로 정의된 Arm 동작 모드에서는 spsr 레지스터의 모드 필드를 이동하고 싶은 모드로 설정한 후, 'subs pc lr' 혹은 'movs pc lr'과 같은 명령어를 실행하면 PL1로 정의된 Arm 동작 모드로 바로 진입할 수 있습니다.
 
하지만 PL0으로 정의된 User 모드에서는 svc 명령어를 실행해 익셉션이 유발돼야 PL1으로 진입할 수 있습니다.
 
두 번째, PL0에서는 MMU나 IRQ나 FIQ 인터럽트를 직접 설정할 수 없습니다. 이렇게 하드웨어적으로 시스템을 설정하는 동작은 PL1에서 수행되야 합니다. 
 
Arm 동작 모드에 대해 소개했으니 이어서 Arm 동작 모드는 어떻게 진입하는지 알아봅시다.
 
< '시스템 소프트웨어 개발을 위한 Arm 아키텍처의 구조와 원리' 저자>

 

 

 

 

+ Recent posts