본문 바로가기

Hacked Brain/embeddedland.net

임베디드 프로그래머와 부트로더-3

저 자 : 유영창
출판일 : 2003년 10월호

== 리눅스 커널의 구동 환경
앞서 잠깐 언급했지만 임베디드 시스템에서 리눅스 커널이 원활하게 동작하기 위한 최소 조건이 있다고 했다. 물론 절대적인 것은 아니지만 필자의 현장 경험상 다음과 같은 조건은 충족돼야 한다.

◆ 32비트 프로세서
◆ 8MB 램(일반적으로 SDRAM을 사용한다)
◆ 8MB 롬(일반적으로 플래시를 사용한다)
◆ 시리얼 포트 1개

이 정도 사양만 있어도 리눅스 커널이 동작한다. 더 이하 사양의 시스템에 리눅스 커널을 올려 동작시킬 수도 있지만 응용 프로그램이 조금만 커져도 문제가 발생하고 프로그램 작성시 상당한 주의를 요한다.
여기에 한 가지 더 조건을 붙인다면 MMU(Memory Management Unit) 즉 메모리 관리 장치의 지원이다. 필자 개인적인 입장으로 본다면 개발의 편리성이나 기존 리눅스 커널의 응용 프로그램을 원활하게 동작시키려 한다면 거의 필수 개념이 아닐가 싶다. 이 MMU 없이 리눅스 커널이 동작하는 프로젝트로 uCLinux가 있는데 실제로 이것을 사용해 본 경험에 의하면 다시는 사용하고 싶지 않았다. 그만큼 제약 사항이 많아서 개발시에 무척 고생하게 된다. 제품의 단가 측면이 절대적이지 않다면 몇 푼 더 들어가더라도 개발하기 편한 것이 결국은 이익으로 연결될 수 있다. 주위에서 몇 푼 아끼려다 개발 진행이 늦어져서 개발에 실패한 경우도 종종 보았다.
앞서 열거한 리눅스 커널이 동작하기 위한 하드웨어적인 조건 외에 소프트웨어적인 조건도 있다. 부트로더라는 프로그램의 존재가 바로 그것이다.

== 리눅스와 부트로더
대부분의 임베디드 시스템의 프로그램들은 롬에서 동작한다. 이 롬은 보통 펌웨어 전용 프로그램들이 탑재되는데 대부분 한번 넣으면 거의 고정이다. 즉, 펌웨어 프로그램이 바뀌지 않는 이상 동작되는 프로그램이 롬의 내용을 변경하지 않는다. 롬(ROM)이라는 말 자체가 Read Only Memory라는 것도 바로 이 때문이다. 하지만 최근에 사용되는 롬들은 플래시 타입이 주종을 이룬다. 플래시의 가장 큰 특징은 읽고 쓰기가 가능하다는 것이다. 플래시가 읽고 쓰는 기능과 롬처럼 동작하는 기능을 지원하는 플래시를 플래시 롬(NOR FLASH)이라고 한다. 이와 반대로 우리가 알고 있는 USB 보조 기억 장치나 디지털 카메라에 사용되는 플래시들은 읽기 쓰기는 되지만 롬으로 사용할 수 없는 NAND 플래시들이다.
롬에 프로그램을 집어 넣어서 처리하는 것이 이전 임베디드 시스템에서는 문제가 되지 않았다. 하지만 32비트 고속 프로세서에 사용되면서 이 롬의 처리 속도가 너무 느린 것이 문제가 되었다. 때문에 요즈음의 고속 프로세서들은 프로그램이 롬에서 수행되지 않는다. 대부분 롬에 있는 프로그램의 내용을 램에 복사해 넣은 후 실제 프로그램들은 램에서 수행된다. SDRAM 같은 메모리 소자들은 그 동작 주파수가 100MHz로 매우 빠르기 때문에 접근 속도 역시 매우 빠르다. 이 때문에 롬에 있는 내용을 램에 써 넣은 후 램에서 프로그램을 동작시킨다. 리눅스 커널 역시 매우 빠르게 동작해야 하기 때문에 대부분 램에서 수행한다. 때문에 커널을 램으로 이동시켜 주는 프로그램이 필요하다.
또 한 가지 기존 리눅스 커널이 동작하는 방식을 살펴봐야 리눅스 커널이 동작하는 소프트웨어 조건에 대해 이해할 수 있다. 커널은 원칙적으로 PC 기반에서 만들어진 것이다. 이 PC 기반의 리눅스가 동작하는 과정을 살펴보면 다음과 같다.

[1] PC 부팅 시작
[2] 바이오스 루틴 수행
[3] 하드디스크 부팅
[4] 압축된 리눅스 커널 이미지를 하드디스크에서 램으로 복사
[5] 압축된 리눅스 커널 이미지 풀기
[6] 리눅스 커널 동작
[7] 하드디스크 루트 디렉토리에 마운트
[8] 실제 운영체제를 위한 응용 프로그램 수행

수행되는 과정을 살펴보면 처음부터 리눅스 커널이 수행되는 것이 아니다. 즉 다른 소프트웨어가 수행된 이후에 최종적으로 리눅스 커널이 수행되는 것이다. 임베디드 시스템에서 리눅스 커널이 동작하는 것도 유사하다.

[1] 보드 부팅 시작
[2] 부트로더 수행
[3] 압축된 리눅스 커널 이미지를 롬에서 램으로 복사
[4] 압축된 램 디스크 이미지 를 롬에서 램으로 복사
[5] 압축된 리눅스 커널 이미지 풀기
[6] 리눅스 커널 동작
[7] 압축된 램 디스크 이미지 를 풀고 루트 디렉토리에 마운트
[8] 실제 운영체제를 위한 응용 프로그램 수행

이 과정에서 [3], [4], [5] 과정을 수행하는 것이 부트로더가 수행해야 할 핵심 요소이다.

== 부트로더의 실체
부트로더(BOOTLOADER)는 BOOT+LOADER라는 단어의 합성어이다. 각 단어를 원래대로 해석한다면 조금 이상한 뜻이다. ‘장화+짐을 싣는 사람’이란 뜻이 되어 버린다. 영 말이 안 된다. 당연히 두 단어는 프로그래머들에게 통하는 속어(?)다. 부트는 시스템 프로그램의 초기 동작을 의미하고 로더는 실제 운영체제를 시스템에 올린다는 뜻이다. 즉 시스템의 초기 동작을 수행한 후에 실제 운영체제를 동작시켜 주는 프로그램을 부트로더라고 한다. 간단한 임베디드 시스템에서는 굳이 올려야 할 운영체제가 필요 없기 때문에 부트로더니 커널이니 응용 프로그램이니 하는 구별이 없다. 하지만 리눅스 커널을 사용한다면 다음과 같은 구성을 갖는다.

[1] 부트로더 프로그램
[2] 리눅스 커널 프로그램
[3] 루트 디바이스
[4] 응용 프로그램
[5] 셀 및 기타 유틸리티 프로그램

이 각각의 구성을 맞추어 주어야 동작한다. 우리가 이번 호부터 관심을 갖고 만들려고 하는 프로그램이 바로 부트로더이다. 왜 부트로더라는 프로그램을 제작해야 할까? 이제 앞서 말했던 내용과 그 외의 이유에 대해 차근차근 정리해 보면서 살펴보자. 다음은 부트로더가 가져야 할 기능들이다.

== 하드웨어 디버깅과 시스템 초기화 기능
필자가 느끼기에 소프트웨어 팀이 프로그램의 문제점을 찾는 것보다 하드웨어 팀에서 보드의 문제점을 찾아내는 것이 더 어려운 것 같다. 그 이유로는 상대적으로 열악한 디버깅 툴과 논리상으로는 예상할 수 없는 물리적인 문제점이 발생하기 때문인 것 같다. 소프트웨어보다는 하드웨어가 좀더 경험에 의한 검증에 의존하는 수밖에 없는 이유가 이 때문이다. 물론 하드웨어는 한번 동작하면 특별한 경우가 아니면 동일한 동작을 수행하기 때문에 장기적으로 보면 하드웨어 팀이 더 편하기는 하다. 소프트웨어는 납품하거나 시장에 판매되는 시점부터 문제점이 보고되는 경우가 비일비재하기 때문이다.
그런데 필자가 보기에 한 가지 특이한 것은 하드웨어 설계자 중에는 의외로 프로그램을 작성하는 능력이 없는 사람이 많다는 것이다. 회로 설계는 기막히게 잘하고 하드웨어적인 문제도 이상할 만큼 잘 잡아내지만 보드 테스트용 프로그램 하나를 제대로 작성하지 못해 고민하는 하드웨어 개발자를 종종 본다. 이렇게 하드웨어 팀과 소프트웨어 팀이 나눠지면 같은 프로젝트를 진행하는 데 거의 앙숙 관계가 되어 버린다. 서로를 이해하지 못하기 때문에 생기는 문제다. 그래서 하드웨어와 소프트웨어를 모두 잘 다루는 개발자는 현장에서 환영받는다. 문제점이 생길 때마다 대처가 빠르기 때문이다.
하드웨어 제작 과정에서 설계가 끝나고 가장 처음 시작하는 것이 프로세서를 동작시키는 것이다. 프로세서를 동작시키면서 그 나머지 회로의 이상 유무도 검증해야 하고 아트워크에 문제점이 있는지, 전기적인 특성은 제대로 나오는지를 검사해야 한다. 설계대로 착착 동작하면 별 문제가 없는데 실제 현장에서 한방에 모든 것이 끝나는 것을 필자는 본 적이 없다. 이때 프로세서를 정상적으로 동작시키려면 테스트용 프로그램을 만들어야 한다. 이 테스트용 프로그램에는 기본적인 프로세서의 환경 설정 루틴이 들어간다. 프로세서 자체의 클럭 속도를 설정하고, 주변 메모리 소자를 위한 디바이스 설정을 하며, 주변에 연결된 디바이스 역시 초기화해야 한다.
초기화 과정에서 정상적으로 동작하지 않을 때 개발비가 부족한 대부분의 개발자들은 장비보다는(실제 검증 장비들이 그리 큰 도움이 되지도 않는다) 프로그램을 이용해 시스템 동작의 이상에 따른 하드웨어 검증 루틴을 만들어야 한다. 이상하게 동작하는 디바이스에 반복적으로 접근해 일정한 검증 패턴을 만들거나 디바이스의 제어 레지스터에 대한 테스트 데이터를 넣게 하는 기능들이다. 이런 과정에서 부트로더는 자연스럽게 다음과 같은 기능을 갖는다.

◆ 프로세서 초기화 루틴
◆ 프로세서 동작 환경 설정 루틴
◆ 프로세서 동작 환경 검사 루틴
◆ 주변 디바이스 초기화 루틴
◆ 주변 디바이스 이상 유무 검사 루틴