이번 시간에는 ARM 프로세서를 리눅스 시스템 개발자가 배워야 하는 지 설명합니다.
 
브링업을 제대로 하기 위해서
 
임베디드 개발자들이 진행하는 프로젝트의 단계는 '보드 브링업 - 기능 안정화 - 유지 보수'로 분류할 수 있습니다.
3단계에서 보드 브링업은 어떤 단계를 거쳐 진행될까요? 과제에 따라 다르지만 개발 업무의 내용을 소개하면 다음과 같습니다.
 
   * 부트로더에서 스타트업 코드를 작성
   * 메모리와 같은 하드웨어를 초기화
  
먼저 스타트업 코드를 작성하는 업무에 대해서 조금 더 설명을 드려볼까요?
전원이 시스템에 들어오면 가장 먼저 실행되는 코드가 reset 익셉션 벡터 코드입니다. 
 
이 코드에서 기본적인 메모리를 설정을 초기화하고 ARM 모드 별로 스택 사이즈를 지정해야 합니다.
이 모든 코드를 제대로 작성하려면 ARM 어셈블리 명령어를 알아야 됩니다.
 
또한 DDR 와 같은 메모리를 초기화하기 위해서는 관련 ARM 어셈블리 명령어는 기본으로 알아야 겠죠.
 
와 같은 업무를 수행하려면 ARM 명령어는 기본으로 알아야 하고 ARM 아키텍처를 제대로 이해하고 있어야 합니다.
 
디바이스 드라이버 개발을 잘 하기 위해서
 
리눅스 디바이스 드라이버 개발자들은 ARM 프로세서를 잘 알면 더 안정적인 코드를 작성할 수 있습니다.
특히 많은 하드웨어 디바이스가 인터럽트를 통해 드라이버와 커뮤니케이션을 합니다. 그런데 ARM 프로세서가 인터럽트를 어떤 방식으로 처리하는지 미리 파악한 
개발자는 조금 더 안정적인 드라이버 코드를 작성할 수 있습니다.
 
무엇보다 멀티미디어 드라이버를 작성할 때는 CPU 코어의 성능을 최대한 올려는 코드를 작성할 필요가 있습니다.
ARM 프로세서가 어떻게 동작하는지 머리 속으로 그리면서 코드를 작성하면 더 성능을 올리는 코드를 작성할 수 있습니다.
 
RTOS나 리눅스 커널에 대한 깊이있는 이해를 위해서
 
리눅스 커널이나 RTOS를 깊이 있게 배우려면 ARM 프로세서의 동작 원리를 제대로 알아야 합니다.
그 이유는 커널을 구성하는 세부 시스템의 핵심 루틴은 ARM 어셈블리 명령어로 구현되어 있기 때문입니다.
 
구체적으로 리눅스 커널의 다음 서브 시스템은 어셈블리 명령어로 구현돼 있습니다.
 
   * 인터럽트 벡터
   * 컨텍스트 스위칭 루틴
   * Preemption 처리 루틴
   * 시그널을 받아 처리하는 루틴
   * 시스템 콜 핸들러를 처리하는 루틴
 
많은 분들이 리눅스 커널의 고수들은 리눅스 커널만 잘 알고 있다고 생각할 수 있는데요.
실제 제가 만나 본 많은 리눅스 커널의 고수들은 ARM 아키텍처에 대해서 정말 깊이 있게 알고 있습니다. 
 
디버깅을 잘 해 문제를 잘 해결하기 위해서
 
난이도나 복잡도가 높은 드라이버를 맡으면 커널 패닉이나 심하면 와치독 리셋과 같은 문제를 만날 가능성이 높습니다.
이런 크래시 문제를 디버깅하기 위해서는 ARM 프로세서를 제대로 알고 있어야 합니다.
 
커널 패닉이 발생하면 커널 로그는 커널 패닉이 발생한 코드의 위치를 ARM 레지스터 세트와 함꼐 출력합니다.
다음은 커널 패닉이 발생할 때의 커널 로그입니다.
 
[  262.401303] Unable to handle kernel NULL pointer dereference at virtual address 00000000
[  262.401365] pgd = dbdc4000
[  262.401389] [00000000] *pgd=00000000
[  262.401433] Internal error: Oops: 80000005 [#1] PREEMPT SMP ARM
[  262.401459] Modules linked in:
[  262.401495] CPU: 0 PID: 7107 Comm: Framework Tainted: G        W    3.10.49-g356bd9f-00007-gadca646 #1
[  262.401522] task: da6b0540 ti: d9412000 task.ti: d9412000
[  262.401549] PC is at 0x0
[  262.401590] LR is at xfrm_local_error+0x4c/0x58
[  262.401619] pc : [<00000000>]    lr : [<c0adc274>]    psr: a00f0013
[  262.401619] sp : d9413c68  ip : c0ac6c20  fp : 0000dd86
[  262.401654] r10: 0000010e  r9 : 0000010a  r8 : de0ddc20
[  262.401678] r7 : c13ddf00  r6 : 00000500  r5 : d9094540  r4 : c13e3780
[  262.401703] r3 : 00000000  r2 : 00000001  r1 : 00000500  r0 : d9094540
 
보시다시피 ARM 코어의 레지스터 세트가 출력되는데 각 레지스터의 역할과 동작 원리를 파악하고 있어야,
디버깅을 시작할 수 있습니다.
 
또한 스택이 오염되거나 메모리 비트 플립이 발생하는 하드웨어 버그도 만날 수 있습니다.
 
  
crash> bt e5752c00
PID: 1787   TASK: e5752c00  CPU: 4   COMMAND: "net_socket"
bt: WARNING:  stack address:0xe853fa38, program counter:0xc0ee5b60
 #0 [<c0ed8b64>] (panic) from [<c0125038>]
 #1 [<c0125038>] (__stack_chk_fail) from [<c032b6cc>]
 #2 [<c032b6cc>] (sock_has_perm) from [<c0327d00>]
 #3 [<c0327d00>] (security_socket_recvmsg) from [<c0ceb1c8>]
 #4 [<c0ceb1c8>] (sock_recvmsg) from [<c0cec474>]
 #5 [<c0cec474>] (___sys_recvmsg) from [<c0ced5b4>]
 #6 [<c0ced5b4>] (__sys_recvmsg) from [<c0106820>]
 
이런 현상을 제대로 분석해서 해결책을 찾으려면 먼저 ARM 프로세서에 대해서 제대로 알고 있어야 합니다.
 
많은 고수 프로그래머들은 컴퓨터의 동작 원리가 중요하다고 강조합니다.
 
분야를 막론하고 많은 개발자들이 각 분야의 고수 프로그래머들에게 '어떻게 하면 고수가 될 수 있는지' 질문을 합니다.
이해를 돕기 위해 '코딩의 신 아샬'님이 올린 아래 동영상을 소개합니다.
 
 
54 초 정도에 이 분은 컴퓨터를 올바르게 이해하는게 중요하다고 강조합니다.
 
아, 임베디드 개발자 입장에서 여기서 말하는 컴퓨터는 무엇을 의미할까요?
전 ARM 프로세서일 수 밖에 없다고 생각합니다.
 
정리
 
가끔 '주위 선배들이나 친구들이 임베디드를 개발하는데 ARM 프로세서를 뭐 그리 잘 배울 필요가 없다'라고 하시나요?
모두 거짓말입니다. +11여간의 제 개발 경험과 외부 커뮤니티 활동을 비추어 봤을 때, 고수 임베디드 BSP 개발자 중에 ARM 프로세서를 잘 모르는 분은 한 번도 만나 본 적이 없습니다.
 

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

 
 
 

+ Recent posts