ARM Linux Kernel Makefile의 이해와 실행 순서 정리
|
ARM Linux Kernel Makefile의 이해와 실행 순서 정리
v2.4.0-text? 커널에 있는 Makefile을 기초로 zImage가 어떻게 만들어지는지 정리했습니다. 그리고 실행되는 순서를 정리했습니다.
$(TOPDIR)은 linux kernel source code가 위치한 root directory를 말한다. 보통 /usr/src/linux일 것이다.
Makefile에서 사용되는 Flag 들은 $(TOPDIR)/arch/arm/Makefile을 참조한다.
make mrproper
make xconfig
make dep
make modules
make modules_install
make zImage
2. Make 되는 순서
$(TOPDIR)/vmlinux
$(TOPDIR)/arch/arm/boot/compressed/piggy.o
$(TOPDIR)/arch/arm/boot/compressed/head.o
$(TOPDIR)/arch/arm/boot/compressed/misc.o
$(TOPDIR)/arch/arm/boot/compressed/vmlinux
$(TOPDIR)/arch/arm/boot/zImage
3. $(TOPDIR)/vmlinux
vmlinux는 압축되지 않는 Kernel core를 말한다. 이 file은 elf32 format executable 이다. 시작 점은 $(TOPDIR)/arch/arm/kernel/head-armv.S의 stext 또는 _stext가 된다.
4. $(TOPDIR)/arch/arm/boot/compressed/piggy.o
$(TOPDIR)/vmlinux를 objcopy를 사용해 binary로 만들고 gzip으로 압축한 후 다시 elf32 relocatable file(executable이 아니다)로 만들어 놓은 것이다.
5. $(TOPDIR)/arch/arm/boot/compressed/vmlinux
gzip을 풀기위한 함수들과 32bit startup code를 piggy.o와 묶어 준다. 이 놈들이 위치할 .text의 offset도 함께 준다.
text offset은 0x00008000이고 부팅 시에 vmlinux는 반드시 해당 위치에 올려져야 한다.
만들어진 vmlinux는 elf32 executable이다.
6. $(TOPDIR)/arch/arm/boot/zImage
$(TOPDIR)/arch/arm/boot/compressed/vmlinux를 objcopy를 사용해 binary로 만든다. 이 것이 최종의 커널 이미지가 된다.
7. SA-110 Footbridge System의 Memory Map
Function Start Address End Address Size
SDRAM 0000 0000h 0FFF FFFFh 256MB
Reserved 1000 0000h 3FFF FFFFh -
SDRAM array 0 mode register 4000 0000h 4000 3FFFh 16KB
SDRAM array 1 mode register 4000 4000h 4000 7FFFh 16KB
SDRAM array 2 mode register 4000 8000h 4000 BFFFh 16KB
SDRAM array 3 mode register 4000 C000h 4000 FFFFh 16KB
X-Bus XCS0 4001 0000h 4001 0FFFh 4KB
X-Bus XCS1 4001 1000h 4001 1FFFh 4KB
X-Bus XCS2 4001 2000h 4001 2FFFh 4KB
X-Bus no CS 4001 3000h 4001 3FFFh 4KB
Reserved 4001 4000h 40FF FFFFh -
ROM 4100 0000h 41FF FFFFh 16MB
CSR space 4200 0000h 420F FFFFh 1MB
Reserved 4210 0000h 4FFF FFFFh -
SA-110 cache flush 5000 0000h 50FF FFFFh 16MB
Reserved 5100 0000h 77FF FFFFh -
Outbound write flush 7800 0000h 78FF FFFFh 16MB
PCI IACK/special space 7900 0000h 79FF FFFFh 16MB
PCI type 1 configuration 7A00 0000h 7AFF FFFFh 16MB
PCI type 0 configuration 7B00 0000h 7BFF FFFFh 16MB
PCI I/O space 7C00 0000h 7C00 FFFFh 64KB
Reserved 7C01 0000h 7FFF FFFFh -
PCI memory space 8000 0000h FFFF FFFFh 2GB
8. Footbridge System의 부팅 순서
$(TOPDIR)/arch/arm/boot/compressed/head.S에 보면 kernel start address, decompress kernel start의 두 address가 사용된다. 이 두 값이 실제로 커널이 실행될 위치와 압축이 풀릴 위치에 해당하는 address를 나타낸다.
kernel start address는 처음엔 head.S가 실행될 위치로 사용되고 이어 decompress kernel start에 커널이 압축 풀리고, 압축이 풀린 커널은 다시 kernel start address로 옮겨진 후 마지막으로 kernel start address에서 커널이 실행된다.
이렇게 해야 메모리의 낭비를 막을 수 있기 때문에 그렇다. 실제로 head.S의 코드 중 커널 압축을 푸는 과정 까지의 코드는 압축이 풀린 후 다시 사용될 일이 전혀 없기 때문에 버려도 된다. 그리고 압축이 풀린 위치와 head.S의 시작 위치 사이는 적어도 1MB정도 떨어져 있으므로 압축 풀린 커널을 kernel start address로 옮기지 않고 그냥 실행하면 head.S에서 부터의 약 1MB를 사용하지 않는 꼴이 된다.
Footbridge System의 경우 kernel start address는 0x8000, decompress kernel start는 대충 (kernel start address) + sizeof(zImage) + 64KB 정도가 된다.
Assabet은 kernel start address가 0xc0008000이다.
만들어진 zImage는 아래와 같이 구성되어있다.
head.S
misc.c
piggy.o
$(TOPDIR)/arch/arm/boot/compress/vmlinux가 만들어질 때 사용되는 LD scrip file의 내용을 살펴 보면 load_addr과 .text의 시작이 0x8000으로 명시되어있다. 즉 zImage는 0x8000에서 부터 시작되도록 만들어져 있으므로 부팅시에 반드시 이 위치에 올려져야 한다(이 값이 바로 kernel start address다).
그리고 ROM에 올라갈 start-up code와 zImage를 합친 것은 다음과 같이 만들었다. 중간에 dummy를 넣은 것은 zImage의 시작 위치를 항상 같은 곳으로 고정하기 위한 것이다. dummy에는 그냥 0을 채워 넣었다.
start-up code 시작=0, 크기=약 110000Bytes
dummy
zImage 시작=120000, 크기=약 800KB
일반 적인 Footbridge System에는 ROM이 있고 여기에 start-up code와 zImage가 들어가게 될 것이다. 이 ROM에 있는 start-up code는 시스템 초기화(SDRAM 초기화가 주된 목적일 것이다)를 하고 ROM의 어딘가에 있을 zImage를 SDRAM으 0x8000으로 복사해 놓고 커널 부팅에 필요한 parameter를 0x100에 설정해 놓은 다음 0x8000으로 jump하면 리눅스 부팅이 시작되게 된다.
그러나 zImage가 어디에 얼마 만한 크기로 있을지 알기 힘들기 때문에 위와 같이 절대 위치에 zImage를 무조건 올려놓고 zImage를 복사할 땐 120000에서 부터 약 1MB를 복사하도록 했다. 이렇게 하면 zImage의 시작 부터 끝까지 충분히 커버 되므로 이상 없이 동작할 수 있을 것이다(물론 linking할 때 제대로 만들어 줄 수도 있지만 start-up code 자체가 elf executable을 추출해 만든 것이기 때문에 linking을 할 수 없었다).
절차를 나타내면 아래와 같은 식이 된다.
a. CPU Reset
ROM의 시작 번지인 0x41000000에서 부터 실행된다(Footbridge인 21285가 알아서 0x00000000을 0x41000000으로 인식하게 해준다).
Assabet이라면 angel을 이용해 zImage가 그대로 0xc0008000에 올려 지므로 e단계로 바로 가면 될 것이다.
b. System Initialization
start-up code는 SDRAM을 초기화해 SDRAM을 사용할 수 있는 상태로 만들어 놓는다.
c. zImage Copying
ROM의 시작인 0x41000000에서부터 120000에 위치한(0x4101D4C0가 된다) zImage를 0x8000에서 부터 복사해 놓는다. 복사할 땐 임의로 1MB를 복사한다. zImage의 크기가 얼마인지 모르기 때문이고 1MB면 충분하기 때문에 그렇다.
d. Kernel Parameter
0x100에 커널에 넘겨질 parameter를 담은 structure를 만들어 놓는다. parameter는 $(TOPDIR)/include/asm/setup.h에 있는 struct param_struct의 내용을 따른다.
e. Run head.S
kernel start address로 jump한다.
f. gunzip
head.S가 실행되고 piggy.o의 뒤쪽 어딘가 RAM에 압축을 풀어 커널을 올려 놓는다.
g. Relocating Kernel
압축이 풀린 커널의 뒤에 압축 풀린 커널을 head.S의 시작위치인 kenrel start address로 옮길 코드를 복사해 준다(이 코드는 head.S가 포함하고 있고 나중에 커널 뒤에 복사되고 실행된다). 복사후 압축 풀린 커널의 끝에 있는 relocating을 위한 코드를 실행한다. 이 코드는 압축 풀린 커널을 kernel start address에서 시작하도록 복사한다.
h. Run Kernel
압축 풀린 커널 이미지는 kernel start address로 옮겨 졌고 이 위치로 jump해 리눅스 커널을 실행한다.
h. 리눅스 부팅 시작
흔히들 모듈을 만들기 위해서는 obj-m를 사용하고 빌트인으로 사용하기 위해서는 obj-y로 사용한다.
조금 더 자세히 알아보도록 해볼까?
obj-m := hello.o
을 Makefile 에다가 넣어 놓는다면 hello.ko 라는 모듈이 만들어 진다.
그러면 insmod 혹은 modprobe를 사용해 모듈을 로드 시키면 사용할 수 있다.
obj-y := hello.o
이 것은 built-in 으로 사용하게 하는 것이다.
그러면.. built-in 이라는게 어떻게 사용된다는 것일까?? 한번 따라가 보도록 해보자.
android/kernel/scripts/Makfile.build
modorder-target := $(obj)/modules.order
# We keep a list of all modules in $(MODVERDIR)
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
$(subdir-ym) $(always)
@:
obj-m 이면 modules.order가 생성됨
|
'개발관련' 카테고리의 다른 글
커널 spin lock의 차이점 (0) | 2015.03.17 |
---|---|
C 언어 자료형과 Print format (0) | 2015.02.11 |
Linux Error 종류 및 코드값 (0) | 2014.11.23 |
블루투스 Service Discovery Protocol(SDP) UUID (0) | 2014.11.23 |
SIGNAL ERROR 정의 및 설명 (0) | 2014.09.03 |