메모리 설계, 익셉션 핸들러
06 Mar 2021개발 환경
- Window 10, WSL1(Ubuntu 18.04)
- QEMU(realview-pb-a8)
- Graphic : VcXsrv Windows X Server
메모리는 크게 3가지 영역으로 나뉨.
- text 영역 : 사용자 코드
- data 영역 : 초기화된 전역, 정적 변수 저장 / 동작 모드별 스택, 태스크 스택
- bss 영역 : 초기화 되지 않은 전역, 정적 변수 저장
- stack, heap 영역 : 태스크, 동적할당
text 영역 메모리 설계
- RTOS 펌웨어를 수십 kb로 가정하고 지정
text | 1MB | 0X00000000~0X000FFFFF |
동작모드 스택을 메모리에 설계
- USR모드와 SYS모드는 메모리공간과 레지스터 공유
USR,SYS | 2MB | 0X00100000~0X002FFFFF |
SVC | 1MB | 0X00300000~0X003FFFFF |
IRQ | 1MB | 0X00400000~0X004FFFFF |
FIQ | 1MB | 0X00500000~0X005FFFFF |
ABT | 1MB | 0X00600000~0X006FFFFF |
UND | 1MB | 0X00700000~0X007FFFFF |
테스크 스택, 전역변수, 동적 할당 영역 설계
- RTOS의 동작 테스크를 1MB씩 64개 할당
테스크 스택 | 64MB | 0X00800000~0X047FFFFF |
전역 변수 | 1MB | 0X04800000~0X048FFFFF |
동적 할당 | 55MB | 0X04900000~0X07FFFFFF |
1+2+1+1+1+1+1+64+1+55=128MB
Entry.S
익셉션 벡터 테이블
#include "ARMv7AR.h" ;동작모드 전환 비트 헤더파일
#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, pfrch_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 reset_handler
svc_handler_addr: .word reset_handler
pfrch_abt_handler_addr: .word reset_handler
data_abt_handler_addr: .word reset_handler
irq_handler_addr: .word reset_handler
fiq_handler_addr: .word reset_handler
vector_end:
reset_handler:
MRS r0, cpsr
BIC r1, r0, #0X1F
ORR r1, r1, #ARM_MODE_BIT_SVC ;SVC 동작모드 비트
MSR cpsr, r1 ;cpsr에 동작모드 비트를 설정
LDR sp, =SVC_STACK_TOP ;스택포인터에 SVC스택 탑 메모리 주소 설정
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
스택은 메모리를 반대방향으로 사용하기 때문에 스택의 꼭대기 주소를 스택포인터로 지정한다.
ARMv7AR.h
동작모드 전환 비트 헤더파일
#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
MemoryMap.h
메모리맵 주소, 사이즈, 스택 탑 위치 헤더파일
#define INST_ADDR_STATRT 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_STACK_START 0X04800000
#define DALLOC_STACK_START 0X04900000
#define INST_MEM_SIZE (USRSYS_STACK_START - INST_ADDR_STATRT)
#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_STACK_START - TASK_STACK_START)
#define DALLOC_MEM_SIZE (55*1024*1024)
//스택 사이의 패딩(padding)을 위한 4바이트 비우기
#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)
Makefile
ARCH = armv7-a
MCPU = cortex-a8
CC = arm-none-eabi-gcc
AS = arm-none-eabi-as
LD = arm-none-eabi-ld
OC = arm-none-eabi-objcopy
LINKER_SCRIPT = ./milktea.ld
MAP_FILE = build/milktea.map
ASM_SRCS = $(wildcard boot/*.S)
ASM_OBJS = $(patsubst boot/%.S, build/%.os, $(ASM_SRCS))
C_SRCS = $(wildcard boot/*.c)
C_OBJS = $(patsubst boot/%.c, build/%.o, $(C_SRCS))
INC_DIRS = include
milktea = build/milktea.axf
milktea_bin = build/milktea.bin
.PHONY: all clean run debug gdb
all: $(milktea)
clean:
@rm -fr build
run: $(milktea)
qemu-system-arm -M realview-pb-a8 -kernel $(milktea) -nographic
debug: $(milktea)
qemu-system-arm -M realview-pb-a8 -kernel $(milktea) -S -gdb tcp::1234,ipv4
gdb:
arm-none-eabi-gdb
$(milktea): $(ASM_OBJS) $(C_OBJS) $(LINKER_SCRIPT)
$(LD) -n -T $(LINKER_SCRIPT) -o $(milktea) $(ASM_OBJS) $(C_OBJS) -Map=$(MAP_FILE)
$(OC) -O binary $(milktea) $(milktea_bin)
build/%.os: $(ASM_SRCS)
mkdir -p $(shell dirname $@)
$(CC) -march=$(ARCH) -mcpu=$(MCPU) -I $(INC_DIRS) -c -g -o $@ $<
build/%.o: $(C_SRCS)
mkdir -p $(shell dirname $@)
$(CC) -march=$(ARCH) -mcpu=$(MCPU) -I $(INC_DIRS) -c -g -o $@ $<