이어서 Arm 아키텍처에서 정의된 동작 모드가 운영체제나 RTOS에서는 어떻게 활용되는지 알아봅시다.

유저 모드는 유저 애플리케이션이 실행되는 모드이고, 슈퍼바이저 모드는 운영제체의 커널이나 커널 드라이버가 실행되는 모드입니다. 

그런데 동작 모드에 대한 내용을 처음 접하면 다음과 같은 다양한 의문이 생깁니다.

동작 모드는 왜 존재하며, 각각 어떻게 활용될까?
진행 중인 프로젝트에서 혹시 운영체제를 사용하지 않는 경우에는 유저 모드만 사용하면 될까?

이 질문에 대해 "프로젝트의 스펙에 맞게 동작 모드를 선택하면 된다"라고 말씀드리고 싶습니다. 

동작 모드를 선택하는 예시

한 가지 예를 들까요? 디스플레이 디바이스에 'Hello, world'만을 출력하는 동작만 수행하는 제품을 만든다고 가정해 봅시다. 키보드나 마우스와 같은 외부 입출력 디바이스에서 인터럽트가 유발되지도 않고 메모리를 설정할 필요도 없습니다. 이런 기능은 슈퍼바이저 모드에서 모두 프로그래밍해도 됩니다. 혹은 유저 모드에서 코드가 실행돼도 상관없습니다.

이번에는 음악만 재생하는 소형 MP3 플레이어를 예로 듭시다. 그런데 소형 MP3 플레이어에는 애플리케이션을 설치할 수 없는 조건입니다. 이처럼 매우 심플한 RTOS가 구동되는 상황이면 이번에도 모든 프로그램을 슈퍼바이저 모드에서 실행되도록 시스템을 설계할 수 있을까요?

그런데 한 가지 중요한 스펙이 제안됐습니다. '소형 MP3 플레이어에 블루투스 기능이 있어야 하는데, 블루투스를 연결할 때 인터럽트가 발생한다'라는 요구사항입니다. 이럴 때는 IRQ 모드에서도 프로그램이 반응해 동작하도록 시스템을 구성해야 합니다.

마지막으로 다양한 유저 애플리케이션을 설치해 실행되는 범용 운영체제를 예로 듭시다. 이 시스템에서는 어떤 모드에서 어떤 소프트웨어 스택이 실행되도록 설계할까요? 

유저 모드에서는 유저 애플리케이션이 구동되고 슈퍼바이저 모드에서는 리눅스 커널과 같은 운영체제의 커널이 실행되도록 시스템을 구성하면 좋을 것입니다. 물론 인터럽트가 발생하면 IRQ 모드로 진입하니 IRQ 모드에서도 인터럽트를 처리하도록 시스템을 설계할 수 있습니다.

그런데 실전 프로젝트에서 개발자가 실수로 NULL 포인터 익셉션을 유발하는 코드를 작성할 수 있습니다. 이러한 코드(명령어)가 실행되면 Arm 코어는 'Data Abort'나 'Prefetch Abort' 익셉션을 유발하면서 Abort 모드에 진입합니다. 이런 조건에서는 시스템의 오류 정보를 출력하고 시스템을 리셋하거나 프로세스를 종료시키는 코드가 구현되면 좋을 것입니다.

이처럼 시스템을 설계하는 개발자는 동작 모드의 특징을 잘 살려서 적절한 모드에 소프트웨어를 구현하면 됩니다. 

[중요] 동작 모드와 특권 레벨과의 관계

시스템을 설계할 때 동작 모드의 특성을 잘 파악하는 것이 중요합니다. 그래서 각 동작 모드가 어떤 PL에서 실행되는지 염두에 둬야 합니다. 유저 모드는 PL0이고 나머지 모드는 PL1으로 실행됩니다.


동작 모드를 선택할 때의 기본 원칙 

이어서 동작 모드를 선택할 때 고려해야 할 세 가지 기본 원칙을 설명하겠습니다. 

첫 번째, PL0에서 PL1으로 자유롭게 진입할 수 없습니다. PL0에서 실행되는 유저 모드에서는 SVC 명령어를 실행해 익셉션(트랩)이 유발돼야 PL1으로 진입할 수 있습니다.

두 번째, PL0에서는 MMU나 IRQ나 FIQ 인터럽트를 직접 설정할 수 없습니다. 하드웨어적으로 시스템을 설정하는 동작은 PL1에서 수행돼야 합니다. 

세 번째, PL1으로 정의된 동작 모드에서는 SPSR 레지스터의 모드 필드에 변경하려는 모드 비트를 설정한 후, 'SUBS PC LR' 혹은 'MOVS PC LR'과 같은 명령어를 실행하면 PL1으로 정의된 동작 모드로 바로 스위칭됩니다. PL1에서 실행되는 동작 모드끼리는 익셉션 없이 스위칭될 수 있습니다.






















이번 절에서는 동작 모드를 소개하고 각 동작 모드에 진입하는 방법을 알아봤습니다. 이어지는 절에서 동작 모드와 관련된 레지스터에 대해 알아봅시다. 

+ Recent posts