꾸준히
Startup.s 본문
Startup.s 파일이란
arm 코어에 전원이 들어가면 arm 코어는 가장 먼저 리셋 벡터에 있는 명령을 실행한다
리셋벡터란 메모리 주소 0x00000000를 의미하며 startup.s 파일은 리셋 벡터에서 실행하는 명령어들을 담고있는 파일이다
보통 startup.s 파일은 시스템 클럭 설정, 익셉션 벡터 지정, 익셉션 핸들러 정의, 메모리 컨트롤러 설정, 스택영역 할당을 해준 뒤, main 함수를 call 한다
Startup.s 작성
Step 1. 메모리 설계
메모리 영역 | 메모리 사이즈 |
동적 할당 영역 | 0x4900000 ~ 0x7FFFFFF (55MB) |
전역 변수 영역 | 0x4800000 ~ 0x48FFFFF (1MB) |
태스크 스택 영역 | 0x800000 ~ 0x47FFFFF |
UND 모드 스택 | 0x100000 ~ 0x7FFFFF (7MB) (exception mode stack) |
ABT 모드 스택 | |
FIQ 모드 스택 | |
IRQ 모드 스택 | |
SVC 모드 스택 | |
USR, SYS 모드 스택 | |
Text 영역 | 0x0 ~ 0xFFFFF (1MB) |
* USR 모드와 SYS 모드는 메모리 공간과 레지스터를 모두 공유
Step 2. 익셉션 벡터 테이블 작성
vector_start:
LDR PC, reset_handler_addr
LDR PC, undef_handler_addr
LDR PC, svc_handler_addr
LDR PC, pftch_abt_handler_addr
LDR PC, data_abt_handler_addr
B .
LDR PC, irq_handler_addr
LDR PC, fiq_handler_addr
reset_handler_addr: .word reset_handler
undef_handler_addr: .word dummy_handler
svc_handler_addr: .word dummy_handler
pftch_abt_handler_addr: .word dummy_handler
data_abt_handler_addr: .word dummy_handler
irq_handler_addr: .word Irq_Handler
fiq_handler_addr: .word Fiq_Handler
vector_end:
Startup.s
Step 3. 익셉션 모드별 스택 설정
#define INST_ADDR_START 0
#define USRSYS_STACK_START 0x00100000
#define SVC_STACK_START 0x00300000
#define IRQ_STACK_START 0x00400000
#define FIQ_STACK_START 0x00500000
#define ABT_STACK_START 0x00600000
#define UND_STACK_START 0x00700000
#define TASK_STACK_START 0x00800000
#define GLOBAL_ADDR_START 0x04800000
#define DALLOC_ADDR_START 0x04900000
#define INST_MEM_SIZE (USRSYS_STACK_START - INST_ADDR_START)
#define USRSYS_STACK_SIZE (SVC_STACK_START - USRSYS_STACK_START)
#define SVC_STACK_SIZE (IRQ_STACK_START - SVC_STACK_START)
#define IRQ_STACK_SIZE (FIQ_STACK_START - IRQ_STACK_START)
#define FIQ_STACK_SIZE (ABT_STACK_START - FIQ_STACK_START)
#define ABT_STACK_SIZE (UND_STACK_START - ABT_STACK_START)
#define UND_STACK_SIZE (TASK_STACK_START - UND_STACK_START)
#define TASK_STACK_SIZE (GLOBAL_ADDR_START - TASK_STACK_START)
#define DALLOC_MEM_SIZE (55 * 1024 * 1024)
#define USRSYS_STACK_TOP (USRSYS_STACK_START + USRSYS_STACK_SIZE - 4)
#define SVC_STACK_TOP (SVC_STACK_START + SVC_STACK_SIZE - 4)
#define IRQ_STACK_TOP (IRQ_STACK_START + IRQ_STACK_SIZE - 4)
#define FIQ_STACK_TOP (FIQ_STACK_START + FIQ_STACK_SIZE - 4)
#define ABT_STACK_TOP (ABT_STACK_START + ABT_STACK_SIZE - 4)
#define UND_STACK_TOP (UND_STACK_START + UND_STACK_SIZE - 4)
MemoryMap.h
(c언어의 h파일 이지만 gcc로 컴파일하면 Startup.s 어셈블리어 파일에서도 사용할 수 있다)
STACK_TOP에서 -4를 안해도 되지만 Padding으로 남겨 둠
Step 4. 동작 모드 전환 값 정의
* PSR Mode Bit Values */
#define ARM_MODE_BIT_USR 0x10
#define ARM_MODE_BIT_FIQ 0x11
#define ARM_MODE_BIT_IRQ 0x12
#define ARM_MODE_BIT_SVC 0x13
#define ARM_MODE_BIT_ABT 0x17
#define ARM_MODE_BIT_UND 0x1B
#define ARM_MODE_BIT_SYS 0x1F
#define ARM_MODE_BIT_MON 0x16
ARMv7AR.h
(ARM의 cpsr에 값을 설정하여 동작 모드를 바꿀 수 있는 값을 정의)
Step 5. 익셉션 핸들러 작성
reset_handler:
MRS r0, cpsr
BIC r1, r0, #0x1F
ORR r1, r1, #ARM_MODE_BIT_SVC
MSR cpsr, r1
LDR sp, =SVC_STACK_TOP
MRS r0, cpsr
BIC r1, r0, #0x1F
ORR r1, r1, #ARM_MODE_BIT_IRQ
MSR cpsr, r1
LDR sp, =IRQ_STACK_TOP
MRS r0, cpsr
BIC r1, r0, #0x1F
ORR r1, r1, #ARM_MODE_BIT_FIQ
MSR cpsr, r1
LDR sp, =FIQ_STACK_TOP
MRS r0, cpsr
BIC r1, r0, #0x1F
ORR r1, r1, #ARM_MODE_BIT_ABT
MSR cpsr, r1
LDR sp, =ABT_STACK_TOP
MRS r0, cpsr
BIC r1, r0, #0x1F
ORR r1, r1, #ARM_MODE_BIT_UND
MSR cpsr, r1
LDR sp, =UND_STACK_TOP
MRS r0, cpsr
BIC r1, r0, #0x1F
ORR r1, r1, #ARM_MODE_BIT_SYS
MSR cpsr, r1
LDR sp, =USRSYS_STACK_TOP
BL main
dummy_handler:
B .
리셋 익셉션 핸들러에서 모든 동작 모드를 한 번씩 순회하면서 스택 꼭대기 메모리 주소를 SP에 설정하도록 작성함
(스택이 높은 주소에서 낮은 주소로 자라기 때문)
최종 Startup.s 파일
#include "MemoryMap.h"
.text
.code 32
.global vector_start
.global vector_end
vector_start:
LDR PC, reset_handler_addr
LDR PC, undef_handler_addr
LDR PC, svc_handler_addr
LDR PC, pftch_abt_handler_addr
LDR PC, data_abt_handler_addr
B .
LDR PC, irq_handler_addr
LDR PC, fiq_handler_addr
reset_handler_addr: .word reset_handler
undef_handler_addr: .word dummy_handler
svc_handler_addr: .word dummy_handler
pftch_abt_handler_addr: .word dummy_handler
data_abt_handler_addr: .word dummy_handler
irq_handler_addr: .word Irq_Handler
fiq_handler_addr: .word Fiq_Handler
vector_end:
reset_handler:
MRS r0, cpsr
BIC r1, r0, #0x1F
ORR r1, r1, #ARM_MODE_BIT_SVC
MSR cpsr, r1
LDR sp, =SVC_STACK_TOP
MRS r0, cpsr
BIC r1, r0, #0x1F
ORR r1, r1, #ARM_MODE_BIT_IRQ
MSR cpsr, r1
LDR sp, =IRQ_STACK_TOP
MRS r0, cpsr
BIC r1, r0, #0x1F
ORR r1, r1, #ARM_MODE_BIT_FIQ
MSR cpsr, r1
LDR sp, =FIQ_STACK_TOP
MRS r0, cpsr
BIC r1, r0, #0x1F
ORR r1, r1, #ARM_MODE_BIT_ABT
MSR cpsr, r1
LDR sp, =ABT_STACK_TOP
MRS r0, cpsr
BIC r1, r0, #0x1F
ORR r1, r1, #ARM_MODE_BIT_UND
MSR cpsr, r1
LDR sp, =UND_STACK_TOP
MRS r0, cpsr
BIC r1, r0, #0x1F
ORR r1, r1, #ARM_MODE_BIT_SYS
MSR cpsr, r1
LDR sp, =USRSYS_STACK_TOP
BL main
dummy_handler:
B .
.end
동작 확인
각 모드 별로 설정을 완료 했을 때 (코드에서 LDR sp, =STACK_TOP 실행 이후) 레지스터 값을 확인
위처럼 작성했을 시에 SVC 모드일 경우 sp값은 0x3ffffc값을 출력해야하고, cpsr의 마지막 바이트 값의 하위 5비트는 0x12가 저장되어 있어야 한다