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

Arm 아키텍처 학습방법

ukjin 2025. 9. 21. 20:25
반응형

Arm 프로세서는 왜 배워야 할까?

  • 브링업을 잘 하기 위해
  • 디바이스 드라이버 개발을 잘 하기 위해
  • RTOS나 리눅스 커널을 깊이 있게 이해하기 위해
  • 디버깅을 통한 문제 해결 능력을 키우기 위해

브링업을 잘 하기 위해

시스템 소프트웨어 개발자들은 다양한 유형의 프로젝트를 진행하기에 개발 업무를 간단히 정의하긴 어렵다. 하지만 간단하게 정리하면 '보드 블링업 - 기능 안정화 - 유지 보수' 단계로 분류할 수 있다.

이 가운데 '보드 브링업' 단계에서는 다음과 같은 작업을 한다.

  • 부트로더에서 '스타트업' 코드를 작성
  • 메모리나 캐시와 가은 시스템 자원을 초기화
  • 키보드나 USB 같은 주변 장치 초기화
스타트업 코드란?
시스템에 전원이 들어오면 가장 먼저 실행되는 주소에 있는 코드를 '스타트업 코드'라고 한다. 스타트업 코드는 시스템을 초기화 및 설정하는 다음과 같은 루틴으로 구성돼 있다.
* MMU(Memory Management Unit) 같은 하드웨어 유닛과 캐시를 설정
* 동작 모드 혹은 익셉션 레벨별로 스택 크기를 지정
* 익셉션 핸들러 구성
그리고 이러한 스타트업 코드는 어셈블리 명령어로 구성돼 있다.

 

스타트업 코드를 프로젝트에서 정한 스펙에 맞게 프로그래밍 하려면 Arm 어셈블리 명령어를 알야 한다. 동작 모드별로 스택 주소를 설정하고, Arm 프로세서를 초기화하는 코드는 C 언어가 아니라 어셈블리 명령어를 사용해야 하기 때문이다.

Arm 어셈블리 명령어를 이용해 시스템을 세세하게 설정하려면 어셈블리 명령어를 이해하는 것은 물론 동작 모드와 MMU 같은 Arm 아키텍처를 구성하는 주요 기능의 동작 원리도 잘 알아야 한다.

스타트업 코드는 왜 어셈블리 명령어로 구성되어 있을까?
대부분의 스타트업 코드를 처음 보면 분석하기 어렵다. 그래서 '스타트업 코드를 어셈블리 명령어가 아닌 C 언어로 프로그래밍 하면 좋지 않을까' 하는 생각도 든다. 스타트업 코드를 어셈블리 명령어로 프로그래밍하는 이유는 무엇일까? C 나 C++로 함수가 호출ㄹ되려면 각각 Arm 아키텍처별로 스택이 초기화돼 있어야 하기 때문이다.
* Armv7: 동작 모드별로 스택 초기화 및 설정
* Armv8: 익셉션 레벨별로 스택 초기화 및 설정
그런데 스택을 초기화하려면 어셈블리 명령어가 실행돼야 한다.

디바이스 드라이버 개발을 잘하기 위해

많은 외부 I/O 디바이스는 인터럽트를 통해 드라이버와 커뮤니케이션 한다. 그런데 GIC(Generic Interrupt Controller)처럼 Arm 프로세서가 인터럽트를 어떤 방식으로 처리하는지 알고 있으면 다음과 같은 세부 속성을 설정할 수 있다.

  • 인터럽트의 우선순위
  • 인터럽트를 RIQ 혹은 FIQ로 설정할지 여부

또한 멀티미디어와 관련된 드라이버를 작성할 때는 성능이 제대로 나와야 하므로, Arm 프로세서가 어떻게 동작하는지를 아는 것을 통해 성능을 최적화하는 코드를 작성할 수 있다.

RTOS나 리눅스 커널을 깊이 있게 이해하기 위해

리눅스 커널이나 RTOS를 구성하는 세부 서브시스템의 핵심 루틴은 Arm 어셈블리 명령어로 구현되어 있다. 예를 들어, 리눅스 커널이나 RTOS를 구성하는 다음과 같은 기능은 어셈블리 명령어로 구현돼 있다.

  • 인터럽트 핸들러
  • 컨텍스트 스위칭
  • 선점 스케줄링(Preemption Scheduling)
  • 시스템 콜 핸들럴를 호출하는 루틴

디버깅을 통한 문제 해결 능력을 키우기 위해

실전 프로젝트를 진행하다 보면 다양한 버그를 만나게 된다. 대표적으로 메모리 어보트가 유발되어 시스템이 크래시되는 버그다. 크래시나 메모리 어보트가 유발되면 Arm 아키텍처는 개발자가 참고할 수 있는 다음과 같은 다양한 정보를 알려준다.

  • 메모리 어보트가 유발되는 시점의 주소
  • 메모리 어보트의 세부 유발 인자
  • 스택 주소와 콜 스택

Arm 아키텍처 관점에서 메모리 어보트가 발생하면 익셉션이 유발되는데, 익셉션의 동작 원리와 관련 레지시터의 용법을 파악하면 문제가 발생한 원인을 효율적으로 확인할 수 있다.

난이도나 복잡도가 높은 드라이버를 맡으면 커널 패닉이나 와치독 리셋과 같은 문제를 만날 수 있다. 이러한 크래시 문제를 디버깅하려면 Arm 프로세서의 동작 원리를 잘 알고 있어야 한다.

 

Arm 아키텍처를 일반 소프트웨어 개발자도 배워야 하는 이유

모든 소프트웨어 개발자가 Arm 아키텍처를 배울 필요는 없다.

아래 그림의 안드로이드 OS 계층 구조를 보고 알아보자.

위 그림에서 네 가지 계층이 존재한다:

  • Application
  • Application Framework
  • Libraries
  • Linux Kernel

Application

Appilcation 계층의 코드는 대부분 JAVA 언어로 구현되며, 이 계층에서 실행되는 Application의 개발자는 Application의 시나리오나 안드로이드 프레임워크에서 제공하는 함수의 용법을 파악한다. JAVA를 사용하는 개발자들은 굳이 Arm Architecutre를 자세히 알 필요는 없다.

Application Framework & Libraries

C나 C++ 로 구현된 Application Framework나 Libaries를 개발하는 개발자들은 Arm Architecture를 잘 알아야 한다. 

이유는 "디바이스 드라이버 개발을 잘하기 위해" 이유와 유사하다.

 

Arm 아키텍처는 어떻게 공부해야 할까?

  1. 디버깅을 하면서 어셈블리 명령어을 익한다. 
  2. 운영체제의 기본 원리와 함께 Arm 아키텍처를 배운다.
  3. 실전 프로젝트에서 배운 내용이 어떤 방식으로 구현돼 있는지 확인한다.
    1. Linux Kenrel
    2. XEN Hypervisor

 

반응형