인트로

with MK·2020년 10월 24일
0

펌웨어

목록 보기
1/3

크로스 컴파일러 = ARM용 GCC
ARM 개발 보드 대신 QEMU 사용 qemu-system-arm
realview-pb-a8
아키텍쳐 - armv7-a
cpu - arm cortex-a8

인트로

ARM 코어에 전원이 들어가면 ARM 코어가 가장 먼저 하는 일은 리셋 벡터에 있는 명령을 실행하는 일이다.
리셋 벡터는 그냥 메모리 주소 0x00000000를 뜻한다.
즉, 코어에 전원이 들어오면 0x00000000에서 32비트를 읽어 명령을 실행한다.

.text
~
.end

소프트웨어는 데이터와 그 데이터를 변경하는 코드로 구성되어 있는데, text 섹션은 그 중 코드 섹션을 말한다.

.global은 C언어 지시어인 extern과 같은 일을 한다. 즉, 외부 파일에서 심벌로 읽을 수 있게 설정 해 준다.

arm-none-eabi 어셈블러를 통해 Entry.s 파일을 Entry.o 파일로 컴파일을 한다.

QEMU가 펌웨어 파일을 읽어서 부팅하려면 펌웨어 바이너리 파일이 ELF 파일 형식이어야 한다. ELF 파일을 만들기 위해서는 링커가 필요한데, 링커는 여러 오브젝트 파일을 묶어 섹션을 배치한 후 하나의 실행 파일로 만드는 프로그램이다.

부팅하기

펌웨어에서 부팅은 시스템 전원이 들어가서 모든 초기화 작업을 마치고 펌웨어가 대기 상태가 될 때까지를 말하거나, ARM 코어가 리셋 익셉션 핸들러를 모두 처리한 다음 C 코드로 점프하기 직전까지를 말한다.

메모리 설계

보통 임베디드 시스템은 메모리 구조가 꽤 복잡하다. 성능과 비용 사이에서 최적의 결과를 내기 위해 다양한 메모리 종류를 섞어 쓰기도 한다.
실행 파일은 메모리를 크게 3가지로 나누어 사용한다.

  • text 영역 : 코드가 있는 공간, 코드가 있으믈 임의 변경을 하면 안된다.
  • data 영역 : 초기화한 전역 변수가 있는 공간, 전역 변수 선언 시 초기 값을 할당한 경우 이 공간에 할당된다.
    데이터의 형태 : 동작 모드별 스택, 태스크 스택, 전역 변수, 동적 메모리 할당 영역
    데이터의 속성 : 성능 중시 데이터, 큰 공간이 필요한 데이터, 공유 데이터
  • BSS 영역 : 초기화하지 않은 전역 변수가 있는 공간, 초기화하지 않은 전역 변수이므로 빌드 완료되어 생선된 바이너리 파일에는 심벌과 크기만 들어있다.

text 영역은 빠른 메모리에 배치해야 하고 data 중에서도 일부 속도에 민감한 데이터들은 링커에게 정보를 주어 빠른 메모리에 배치해야 한다. 나머지는 속도는 느려도 용량이 큰 메모리에 배치하면 된다.

전체적인 메모리 구조는 아래와 같다.
동적 할당 영역
전역 변수 영역
태스크 스택 영역
모드별 스택
Text 영역

익셉션 벡터 테이블 만들기

익셉션 벡터들의 테이블
익셉션 핸들러 동작을 코딩한다.

가장 먼저 만들어야 할 익셉션 핸들러는 당연히 리셋 익셉션 핸들러이다. 리셋 익셉션 핸들러에서 가장 먼저 해야 할 일은 무엇일까? 바로 메모리 맵을 설정해 주는 것이다. 설계한 동작 모드별 스택 주소를 각 동작 모드의 뱅크드 레지스터 SP에 설정하는 작업이다. 다른 메모리의 경우 펌웨어가 아닌 OS 영역에서 관리할 것이다.
동작 모드별 스택이 모두 설정되면 C언어 main() 함수로 진입한다.
ARM의 cpsr에 값을 설정하여 동작 모드를 바꿀 수 있다.

동작 모드의 스택을 지정하는 코드는 다음과 같은 루틴이다.

MRS r0, cpsr
BIC r1, r0, #0x1F
ORR r1, r1, #동작 모드
MSR cpsr, r1
LDR sp, =스택 꼭대기 메모리 주소

그런데 왜 시작 주소를 넣는 것이 아니라 꼭대기 주소를 계산해서(시작 주소 + size) 그 값을 넣는 것일까? 스택이 높은 주소에서 낮은 주소로 자라는 특징을 가지고 있기 때문이다.

실무에서 어셈블리어로 하드웨어 시스템 클럭 설정, 메모리 컨트롤러 초기화 같은 일들을 한다.

메인으로 진입하기

C 언어의 시작 지점(entry point)는 관습적으로 main함수이다. 이는 컴파일러가 그 기본값으로 main을 사용하기 때문이다.
메인 함수로 점프하는 코드는 다음과 같다.

BL main

어셈블리어 코드에서 브랜치 명령(BL)으로 점프를 하려면 점프 대상 레이블이 같은 파일 안에 있어야 한다. 즉 레이블을 .global로 선언해야 한다.
컴파일러는 C 언어 함수 이름을 링커가 자동으로 접근할 수 있는 전역 심벌로 만든다.

0개의 댓글