이제 리셋 익셉션 핸들러 구현하면

 

#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, 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 dummy_handler
		fiq_handler_addr:		.word dummy_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

	dummy_handler:
		B .
.end

 

 

어셈블리를 제대로 공부하지 않아서

여기서 사용되는 명령어들을 좀 찾아봤다.

 

 

 

 

ARM 어셈블리 일부 문법

- 상수는 #이 들어감 ( LDR에는 대신 = 사용)

니모닉 설명 예시 비고
LDR 레지스터 로드 명령 LDR sp, =USRSYS_STACK_TOP  
ORR 논리 OR ORR r1, r1, #ARM_MODE_BIT_SYS  
MSR 레지스터에서 PSR로 이동 MSR cpsr, r1  
MRS PSR에서 레지스터로 이동 MRS r0, cpsr  
BIC 해당되는 비트 클리어 BIC r1, r0, #0x1F R1 = R0 AND ~ 0x10
B 분기    

 

ref 

https://0xsaika.tistory.com/5

 

ARM assembly 문법정리

니모닉 간단한 설명 페이지 아키텍처[1] ADC , ADD carry 포함 더하기, 더하기 ADD, SUB, RSB, ADC, SBC 및 RSC 모두 ADR 프로그램 또는 레지스터 기준 주소 로드(짧은 범위) ADR 모두 ADRL  의사 명령어 프로그..

0xsaika.tistory.com

https://kyuhyuk.kr/article/raspberry-pi/2019/05/15/ARM-Assembly

 

ARM Assembly 기초

ARM CPU의 기본 구성 R0 ~ R14 총 15개의 범용 레지스터를 가지고 있습니다. 범용 레지스터 R13 는 특수 레지스터 SP 로 사용됩니다. SP 는 C언어 사용시 스택의 주소를 저장하는 레지스터입니다. 범용

kyuhyuk.kr

http://trace32.com/wiki/index.php/AND,_ORR,_EOR,_BIC_and_ORN

 

AND, ORR, EOR, BIC and ORN - TRACE32

이번에는 비트연산 명령어인 AND, ORR, EOR, BIC, ORN 명령에 대해 알아보겠습니다. AND : Logical AND 두 개의 비트가 모두 "1"이면 "1", 하나라도 "0"이면 "0"이 나오는 AND연산을 수행합니다. 아래의 "ANDS R6,R6,

trace32.com

 

 

 

 

 

동작 모드 전환하는 부분을 보면

1. MSR r0, cpsr

r0에다가 cpsr 저장

 

2. BIC r1, r0, #0x1F

r1 = r0 AND ~0x1F

 

3. ORR r1, r1 #ARM_MODE_BIT_UND

r1과 #ARM_MODE_BIT_UND 그러니까 0x1B와 or 연산

 

4. MSR cpsr, r1

r1의 값을 cpsr에 대입

 

5. LDR sp, =UND_STACK_TOP

스택 포인터 값을 UND_STACK_TOP (=UND_STACK_START + UND_STACK_SIZE - 4= 0x007F 0000)으로 변경

=> 대강 cpsr의 모드 비트를 UND 모드로 바꾸고 스택 포인터도 UND 스택 탑으로 바꾸는 내용

		MRS r0, cpsr
		BIC r1, r0, #0x1F
		ORR r1, r1, #ARM_MODE_BIT_UND
		MSR cpsr, r1
		LDR sp, =UND_STACK_TOP

 

 

정리하면 위 어셈블리 코드의 리셋 핸들러 부분은

모든 모드를 돌아가면서 스택 탑 주소를 sp에 넣어보는 동작인듯 하다.

 

 

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=./navilos.ld

ASM_SRCS=$(wildcard boot/*.S)
ASM_OBJS=$(patsubst boot/%.S, build/%.o, $(ASM_SRCS))

INC_DIRS=include

navilos=build/navilos.axf
navilos_bin=build/navilos.bin

.PHONY: all clean run debug gdb

all:$(navilos)

clean:
	@rm -fr build

run: $(navilos)
	qemu-system-arm -M realview-pb-a8 -kernel $(navilos)

debug: $(navilos)
	qemu-system-arm -M realview-pb-a8 -kernel $(navilos) -S -gdb tcp::1234,ipv4

gdb:
	gdb-multiarch

$(navilos):$(ASM_OBJS) $(LINKER_SCRIPT)
	$(LD) -n -T $(LINKER_SCRIPT) -o $(navilos) $(ASM_OBJS)
	$(OC) -O binary $(navilos) $(navilos_bin)

build/%.o: boot/%.S
	mkdir -p $(shell dirname $@)
	$(CC) -march=$(ARCH) -mcpu=$(MCPU) -I $(INC_DIRS) -c -g -o $@ $<
djc4223@ubuntu:~/github/navilos$

헤더 파일 추가하는 내용이랑

as 대신 gcc,  $(CC)

그리고 실행 파일이 아닌 오브젝트 파일이 나와야 링커에 전달할 수 있으니 -c

 

그런데 AS을 쓸때랑 달리 mcpu랑 march랑 충돌한다고 워닝이 발생해서

 

 

 

march 부분을 빼서 빌드시켰더니 이상이 없다.

 

디버그 할수 있도록 돌리고

 

 

디버거 연결하고

 

navilos.axf 심볼 로드하고

list를 치면 어셈블리 코드가 보인다.

 

 

가장 먼저 

vector_start

reset_handler_addr

통해서

MRS r0, cpsr 부터 쭉쭉 가고

36번줄 명령어 실행 후 

info register를 치면

 

지금 SVC_STACK_TOP이 sp에 들어가 있고

지금 그 sp 값이 0x3ffffc인데 이게 맞는건지 잘 모르겠다.

 

 

다시 매모리맵을 정리하면 이렇게 된다.

가장 먼저 SVC_STACK_TOP을 찾았는데

SVC 스택은 0x0030 0000 ~ 0x003F FFFF의 범위를 갖는다.

스택은 위에서부터 내려오니 스택포인터는 0x003F FFFF일것이나

다른 스택과 패딩 4바이트 정도 줘서 -4 한 위치인 0x003F FFFC가 SVC_STACK_TOP이 된다.

 

 

그다음 로드한 IRQ_STACK_TOP도

0x004f ffff에서 -4한 0x004f fffc 위 그림에다가는 잘못 적었다.

 

FIQ 모드, 마지막에 오는 USRSYS 모드도

정상적으로 잡힌다.

 

 

 

 

 

 

드디여 메인함수에 진입할 차례

boot/Main.c를 작성하는데

책에서는 stdint.h를 include 디렉토리에다가 넣어두고 ""로 가져오는걸로 적혀있긴한데

실제 코드 내용은 없어서 대신 <>를 썻더니 아무이상없이 가져와지고

 

내용은 1024 * 1024 * 100한 주소에다가 

sizeof(long)한 값을 넣는 내용이다.

 

32비트 ARM 머신이므로 int가 2바이트 long은 4바이트니 4가 들어가고,

1024 * 1024 * 100은 100mb 지만 계산결과인 104,857,600를

16진수로 바꾸면 0x640 0000이 된다.

 

0x0640 0000 번지에 4를 입력하는 코드가 되고

 

#include <stdint.h>

void main(void)
{
	uint32_t* dummyAddr = (uint32_t*)(1024 * 1024 * 100);
	*dummyAddr = sizeof(long);
}

 

boot/Entry.S는

대부분 그대로이지만 리셋 핸들러 마지막에

BL main이 추가되어 있어서

 

main 라벨로 넘어가게 된다. 아래 링크를 보니 

BL이 B 처럼 분기 하되 분기 끝나고 돌아오는 내용까지 포함된거라고 한다

그 뒤에는 dummy handler로 무한루프

https://blog.daum.net/tlos6733/132

 

[Branch] 01 - ARM Branch 명령어 분석

작성자 : 박진범 메일 : jinb.park7@gmail.com :) Goal - b, bl, blx instruction 의 opcode 를 확인한다. 바이너리 파일에서 b, bl, blx instruction 을 해석할 수 있게 한다. - bl, blx 의 차이점을 안다. - bl..

blog.daum.net

 

 

 

#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, 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 dummy_handler
		fiq_handler_addr:		.word dummy_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

 

 

Main.c의 메인 함수로 점프하게 되는데

컴파일러는 C언어 함수명을 자동으로 전역 심벌로 만들어서

Entry.S의 BL main을 통해 메인 함수로 넘어간다고 한다.

 

 

C 언어 파일도 컴파일, 링킹하는 내용도 추가하고

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=./navilos.ld
MAP_FILE=build/navilos.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

navilos=build/navilos.axf
navilos_bin=build/navilos.bin

.PHONY: all clean run debug gdb

all:$(navilos)

clean:
	@rm -fr build

run: $(navilos)
	qemu-system-arm -M realview-pb-a8 -kernel $(navilos)

debug: $(navilos)
	qemu-system-arm -M realview-pb-a8 -kernel $(navilos) -S -gdb tcp::1234,ipv4

gdb:
	gdb-multiarch

$(navilos):$(ASM_OBJS) $(C_OBJS) $(LINKER_SCRIPT)
	$(LD) -n -T $(LINKER_SCRIPT) -o $(navilos) $(ASM_OBJS) $(C_OBJS) -Map=$(MAP_FILE)
	$(OC) -O binary $(navilos) $(navilos_bin)

build/%.os: $(ASM_SRCS)
	mkdir -p $(shell dirname $@)
	$(CC) -mcpu=$(MCPU) -I $(INC_DIRS) -c -g -o $@ $<

build/%.o: $(C_SRCS)
	mkdir -p $(shell dirname $@)
	$(CC) -mcpu=$(MCPU) -I $(INC_DIRS) -c -g -o $@ $<

 

 

 

디버거로 확인해보니

메인함수에 작성한대로 0x0640 0000번지에 4라는 값이 들어가 있는걸 확인할 수 있다.

메인함수 진입 끝

 

 

 

+ Recent posts