3장 일단 시작하기

이세현's avatar
Aug 21, 2024
3장 일단 시작하기
3.1 리셋 벡터
  • ARM 코어에 전원이 들어가면 → 리셋 벡터(0x00000000) 32비트를 read
  • 메모리 주소 0x00000000에 명령어 넣어주기

  • Entry.S
    • .text /*.end가 나올 때까지 모든 코드가 text 섹션 */ .code 32 /* 명령어 크기 32비트 */ .global vector_start /* .global == extern "vector_start" 레이블 선언 */ .global vector_end /* "vector_end" 레이블 선언 */ vector_start: mov r0,r1 /* R1 register copy to R0 register */ vector_end: .space 1024,0 /* 해당 위치부터 1024바이트를 0으로 채우기 */ .end /* text 섹션 끝 */
  • 어셈블러로 컴파일한 후 바이너리 덤프
    • notion image
      arm-none-eabi-as -march=armv7-a -mcpu=cortex-a8 -o Entry.o ./Entry.S // 어셈블리어 컴파일 arm-none-eabi-objcopy -O binary Entry.o Entry.bin // 바이너리 추출 hexdump Entry.bin // 바이너리 출력
0001 e1a0 → mov r0, r1 / arm은 4바이트 단위로 메모리 관리
0001 e1a0 → mov r0, r1 / arm은 4바이트 단위로 메모리 관리
3.2 실행 파일 만들기
  • QEMU가 펌웨어 파일을 읽고 부팅 하려면 입력으로 지정한 펌웨어 바이너리 파일이 ELF 파일 형식이어야 한다. (Entry.o 파일도 ELF 파일)
  • ELF 파일을 만들려면 링커(Linker)의 도움이 필요하다.
  • 링커가 동작하려면 링커에 정보를 던져주는 링커 스크립트가 필요하다.

  • 링커 스크립트 navilos.ld
ENTRY(vector_start) SECTIONS { . = 0x0; .text : { *(vector_start) *(.text .rodata) } .data : { *(.data) } .bss : { *(.bss) } }
  • 링커로 실행 파일 만들기
ubuntu@ubuntu:~/navilos$ arm-none-eabi-ld -n -T ./navilos.ld -nostdlib -o navilos.axf boot/Entry.o /* -n 링커에 섹션 자동 정렬 금지 지시 -nostdlib 링커가 자동으로 표준 라이브러리 링킹 금지 지시 링커 동작 완료하면 navilos.axf 생성 */ ubuntu@ubuntu:~/navilos$ arm-none-eabi-objdump -D navilos.axf /* 디어셈블 */
디스어셈블 결과
디스어셈블 결과
3.3 QEMU에서 실행해 보기
실행 시 에러 발생 (리눅스 커널에서 동작하지 않는 섹션 배치로 만들어져있음)
실행 시 에러 발생 (리눅스 커널에서 동작하지 않는 섹션 배치로 만들어져있음)
  • gdb와 QEMU 연결하기
sudo apt install -y gdb-multiarch qemu-system-arm -M realview-pb-a8 -kernel navilos.axf -S -gdb tcp::1234,ipv4 /* 타겟 보드에 실행파일 업로드, 포트 1234 원격 GDB 허용*/ gdb-multiarch navilos.axf // gdb와 QEMU 연결 (gdb) target remote:1234 // 1234번 포트로 원격 디버깅 연결 (gdb) x/4xb 0 . . . 0x0 <vector_start>: 0x01 0x00 0xa0 0xe1
navilos.axf 파일에 있는 코드 데이터가 QEMU의 메모리로 다운로드
navilos.axf 파일에 있는 코드 데이터가 QEMU의 메모리로 다운로드
3.4 빌드 자동화 하기
ARCH = armv7-a // RealViewPB의 아키텍쳐 MCPU = cortex-a8 // RealViewPB의 CPU /* 툴체인 */ CC = arm-none-eabi-gcc AS = arm-none-eabi-as LD = arm-none-eabi-ld OC = arm-none-eabi-objcopy LINKER_SCRIPT = ./navilos.ld /* make built-in */ ASM_SRCS = $(wildcard boot/*.S) // boot/Entry.S -> ASM_SRCS ASM_OBJS = $(patsubst boot/%.S, build/%.o, $(ASM_SRCS)) // build/Entry.o -> ASM_OBJS 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) $(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 $@) $(AS) -march=$(ARCH) -mcpu=$(MCPU) -g -o $@ $< // gdb와 QEMU 연결하기 -> 확인
3.5 하드웨어 정보 읽어오기 - 데이터시트를 읽는 방법
  • 하드웨어에서 정보를 읽어오고, 쓰는 것은 레지스터를 이용한다.
  • 레지스터는 하드웨어가 소프트웨어와 상호작용하는 인터페이스
  • 데이터 시트란 해당 하드웨어가 가지고 있는 레지스터 목록과 설명, 레지스터에 어떤 값을 썼을 때 어떻게 동작하는지 기술한 문서 (물론 다른 정보도 많음)
.text .code 32 .global vector_start .global vector_end vector_start: LDR R0, =0x10000000 // R0에 0x10000000 (ID Register) 넣기 LDR R1, [R0] // R0에 저장된 메모리 주소(0x10000000)에서 값을 읽어서 R1에 넣기 vector_end: .space 1024,0 .end

ID Register, SYS_ID

The SYS_ID register at 0x10000000 is a read-only register that identifies the board and FPGA.
The SYS_ID register at 0x10000000 is a read-only register that identifies the board and FPGA.
  • 하드웨어를 식별할 수 있는 정보를 가진 읽기 전용 레지스터
  • 주로 펌웨어가 여러 하드웨어를 대응해야 할 때 사용 (하드웨어 구분)
  • 32비트 머신의 모든 레지스터는 32비트를 목적에 맞게 나눠서 사용 (8, 4, 4, 12, 4비트씩 할당)
make make debug gdb-multiarch navilos.axf // gdb와 QEMU 연결 (gdb) target remote:1234 // 1234번 포트로 QEMU 디버깅 소켓 연결 (gdb) file navilos.axf // navilos.axf 읽기 (gdb) list // 디버깅 심벌 확인 (gdb) info register // 레지스터 정보
list 명령 → navilos.axf 내용이 그대로 출력된다.
list 명령 → navilos.axf 내용이 그대로 출력된다.
레지스터의 값이 모두 0
레지스터의 값이 모두 0
s (step) → LDR R1, =0x1000000 실행 결과
s (step) → LDR R1, =0x1000000 실행 결과
s (step) → LDR R1, R[0] 실행결과 → r1에 0x1780500
s (step) → LDR R1, R[0] 실행결과 → r1에 0x1780500
  • 0x1780500 → 00000001 01111000 00000101 00000000 (32비트)
notion image
 
Bits
Access
Name
Reset
Description
[31:28]
Read-only
REV
Board revision: 0x0 = Rev A 0x1 = Rev B 0x2 = Rev C
[27:16]
Read-only
HBI
0x178
HBI board number (0178)
[15:12]
Read-only
BUILD
Build variant of board (from BOM) 0xF: all builds
[11:8]
Read-only
ARCH
0x5
Bus architecture 0x4 = AHB 0x5 = AXI
[7:0]
Read-only
FPGA
FPGA build
  • HBI, ARCH 데이터 시트와 일치
  • 보드 리비전 Rev A, 버스 아키텍처는 AXI(Advanced eXtensible Inter-face)로 확인
 
Share article

isehyeon258