3.1 Reset Vector
ARM 코어에 전원이 들어온 후 첫 수행되는 동작은 reset vector에 있는 명령을 실행하는 것
32bit기준으로 Reset vector의 주소는 0x00000000이다. (이것은 Core에 dependency하다.)
따라서, 부팅후 첫 동작을 위해 0x00000000에서 동작할 코드를 작성한다.
$sudo apt install gcc-arm-none-eabi //arm용 cross 컴파일러 설치
$sudo apt install qemu-system-arm //arm아키텍처를 가상화해서 사용하기 위한 qemu 설치
$mkdir os_project
$cd os_project
$mkdir boot
$cd boot
OS프로젝트 디렉토리를 하나 생성후 boot에 필요한 코드들을 포함하기 위해 boot 디렉토리를 생성한다.
boot 디렉토리 내에서 Entry.S를 생성한다.
.text //text ~ end까지는 text section을 의미함
.code 32 //명령어의 크기가 32bit임을 뜻함
//.global은 C언어에서 extern과 같은 역할
.global vector_start //vector_start의 주소와 vector_end의 주소를 외부 파일에서 심볼로 읽을수 있게 설정
.global vector_end
vector_start:
MOV R0, R1 //동작 수행
vector_end:
.space 1024,0 //해당 위치부터 104바이트를 0으로 채우기
.end //text section 끝
하나의 executable file이 완성되면 linking 등 여러가지 작업에 의해 파일이 생성된다. 이떄 .text, .data, .bss 등 다양한 section이 존재하게 되며 Entry.S의 .text ~ .end 까지를 text section이라 한다. .text 섹션에는 code들이 존재한다.
$cd ~/os_project/boot
$arm-none-eabi-as -march=armv7-a -mcpu=cortex-a9 -o Entry.o //어셈블리 컴파일
$arm-none-eabi-objcopy -O binary Entry.o Entry.bin //object파일에서 binary 추출
$hexdump Entry.bin
Entry.S 컴파일 후 바이너리 파일을 덤프한 결과를 나타낸다.
arm-none-eabi-as: arm용 어셈블리 소스 파일 에셈블러
arm-none-eabi-object: object파일에서 바이너리 파일만 추출한다. object 파일에는 심볼 정보 등이 포함되어 있다.
1) 0001 e1a0 : MOV R0, R1를 의미
2) * 계속 반속 되는 것을 의미
3) 4B align이므로 0000404가 보여짐
실행파일을 만들기 위해서는 다수의 object 파일들을 묶어야 한다. 이 역할을 링커가 하게 되며 링커가 어떤 정보를 바탕으로 해당 동작을 수행하게 되는데 이때 정보들을 모은 파일을 링커 스크립터라고 한다. 하드웨어 환경에 맞춰 section(text, data, rodata 등)을 배치해야 한다.
$ cd ~/os_project/
$ vi navilos.ld
링커 스크립터를 만들자.
ENTRY(vector_start) //시작 위치의 심벌을 저장
SECTIONS //3 ~ 19줄 까지의 블록이 섹션 배치 설정 정보를 가짐
{
. = 0x0; //첫 번째 섹션이 메모리 주소 0x00000000에 위치 한다는 것을 나타냄
.text : //text 섹션의 배치 순서를 지정
{
*(vector_start) //0x000000000에 reset_vector가 위치해야 함
*(.text .rodata)
}
.data :
{
*(.data)
}
.bss :
{
*(.bss)
}
}
이후에 컴파일을 수행하자.
$ arm-none-eabi-ld -n -T navilos.ld -nostdlib -o navilos.axf boot/Entry.o
$ arm-none-eabi-objdump -D navilos.axf
-n : 링커에 섹션의 정렬을 자동으로 맞추지 말라고 지시
-T : 링커 스크립트의 파일명을 알려 주는 옵션
-nostdlib : 링커가 자동으로 표준 라이브러리를 링킹하지 못하도록 지시
컴파일 완료 후 navilos.axf 파일이 생성됨
-D : disassemble 해서 어떻게 구성되어 있는지 보자
vector_start가 0x00000000에 배치되어 있고 명령이 MOV R0, R1인 것을 확인 가능하다. 기계어로는 0XE1A00001
실행파일을 실행 시켜 보면 "bash: ./navilos.axf: cannot execute binary file: Exec format error" 에러 발생한다.
이것은 cross compile된 것이기 떄문에 x86_64 아키텍처에서는 실행이 되지 않는다.
해당 파일을 실행 하는 방법은 크게 두 가지이다.
1. ARM 기반 보드에서 직접 실행
2. QEMU에서 ARM 에뮬레이트를 통해 실행
$ qemu-system-arm -M realview-pb-a8 -kernel navilos.axf -S -gdb tcp::1234,ipv4
해당 명령을 실행했을때 QEMU의 화면이 실행되며 멈춘 상태의 결과를 확인할 수 있다.
-M : 머신 지정
-S : QEMU가 동작하자마자 정지
-gdb tcp::1234, ipv4 : gdb와 연결하는 소켓 포트를 지정
$ arm-none-eabi-gdb
(gdb) target remote:1234
(gdb) x/4x 0
target remote:1234 : 1234 포트를 통해 qemu에 접속
x/4x 0 : 0x00000000주소에서 4바이트를 출력
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
LINK_SCRIPT = ./navilos.ld
ASM_SRCS = $(wildcard boot/*.S)
ASM_OBJS = $(patsubst boot/%.S, build/%.o, $(ASM_SRCS))
navilos = build/navilos.axf
navilos_bin = build/navilos.bin
.PHONY: all clean run debug gdb
all: $(navilos)
clean:
@rm -fr build
run: $(nvailos)
qemu-system-arm -M realview-pb-a8 -kernel $(navilos)
debug: $(nvailos)
qemu-system-arm -M realview-pb-a8 -kernel $(navilos) -S gdb tcp::1234, ipv4
gdb:
arm-none-eabi-gdb
$(navilos): $(ASM_OBJS) $(LINK_SCRIPT)
$(LD) -n -T $(LINK_SCRIPT) -o $(navilos) $(ASM_OBJS)
$(OC) -O binary $(navilos) $(navilos_bin)
build/%.o: boot/%.S
mkdir -p $(shell dirname $@)
$(AS) -march=$(ARCH) -mcpu=$(MCPU) -g -o $@ $<
빌드를 자동으로 해주기 위한 Makefile을 작성한 것이다.
11번째 줄은 boot 디렉토리에 있는 asm파일은 모두 ASM_SRCS 변수에 값으로 넣으라는 의미
12번째 줄은 boot디렉토리에 있는 asm파일 이름을 찾아서 확장자를 .o로 바꾼 다음 디렉토리로 build로 바꿔 ASM_OBJS변수에 값으로 넣으라는 의미
33~35번째 줄은 링커로 navilos.axf 파일을 생성. 추가로 navilos.bin도 생성
37~39번째 줄은 *.S -> *.o로 변환
vector_start부분을 아래 코드를 바꿔 보자
vector_start:
MOV R0, R1
//아래 코드로 변경
vector_start:
LDR R0, =0x10000000
LDR R1, [R0]
5~6 R0에 저장된 메모리 주소의 데이터 값을 R1 레지스터에 저장
재 컴파일 이후 GDB를 통해 QEMU에 접속하자.
$ make gdb
(gdb) target remote:1234
(gdb) file build/navilos.axf
list 입력시 Entry.S 파일 심볼에 대해 확인이 가능하다.
코드가 현재 실행되지 않았기 때문에 레지스터에는 아무런 정보가 존재하지 않아야 한다.
gdb) s : 1 step 실행. 즉, r0에 0x1000000주소값을 대입 하는 과정을 실행한 결과를 나타낸다.
(decimal)24642816은 0x1780500을 나타낸다.
책을 좀 더 참조 하자.
SYS_ID 레지스터 값을 분석하자.
[31:28] REV 보드버전 0x0
[27:16] HBI HBI 보드 번호 0x178
[15:12] BUILD 보드 빌드 변형 0x0
[11:08] ARCH 버스 아키텍처 0x5
[07:00] FPGA FPGA 빌드 0x0
해당 결과를 해석하면 보드 리비전은 Rev A, 버스 아키텍처는 AXI를 사용한다.
'Operating System' 카테고리의 다른 글
[파일시스템] FAT16 파일시스템 (1/3) (0) | 2020.05.26 |
---|---|
[파일시스템] 파티션 (1) | 2020.05.26 |
[파일시스템] 파일시스템의 이해 (0) | 2020.05.24 |
[임베디드OS개발프로젝트] 5장. UART (0) | 2020.01.20 |
[임베디드OS개발프로젝트] 4장. 부팅하기 (0) | 2020.01.12 |