chammoru.egloos.com

personal

포토로그



zImage, uImage 그리고 linux booting과정 IT

+ zImage
압축된 Kernel의 image이다.
1M가 넘어가면 Big zImage라는 뜻으로 bzImage 라는 파일이름으로 명명한다고 커널 교육때 배웠다.
그런데 내가 만든 zImage는 대부분의 device driver를 포함시켜서 그런지 1.6M정도였다. 별로 이름이랑 상관없는 듯하다.

zImage 앞부분에는 zImage의 압축을 푸는 코드들이 들어있다.
이 코드들의 커널 소스내 위치는
arch/arm/boot/compressed/
이고 이 디렉토리 안에서 주로
head.S, head-xscale.S
파일을 보면 된다.

+ uImage
uImage이란 u-boot에서 사용하는 압축된 커널 이미지이다.
단순히 u-boot 의 tools/mkimage(u-boot source를 컴파일을 해야 생성된다.)라는 툴을 이용해 zImage에 64byte 헤더를 추가시킨 이미지이다.
이 64byte 헤더에는 target architecture, operating system, image type, compression method, entry points, time stamp, CRC32 checksums 등과 같은 정보들이 들어간다.

- uImage 만드는 방법
./mkimage -A arm(우리가 쓰는 임베디드 종류) -O linux -T kernel -C gzip -a(sdram address 올릴 주소) 0x30008000 -e(entry point) 0x30008000 -n(name) "Linux Kernel Image" -d linux.bin .gz uImage
혹은
make uImage
명령을 통해서 한번에 uImage를 만들 수 있다.
위에서 명령행 인자들이 그대로 uImage의 header가 된다.

- 예제
mkimage -A arm -O linux -T kernel -C none -a 0xa0008000 -e 0xa0008000 -n 'Linux-2.6.21.1' -d arch/arm/boot/zImage arch/arm/boot/uImage

+ linux booting 과정 (uImage에서 부터 start kernel까지, pxa310 processor에 porting된 kernel을 예제로...)
- 선행지식 : kernel이 install되는 위치 (즉, kernel code가 처음 RAM 메모리에 위치하는 주소)
// arch/arm/kernel/head.s
#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)
#define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET)
이고 실제로 상수 값을 보려면
mach-pxa/Makefile.boot: zreladdr-y := 0xa0008000
을 확인하라.
자세한 내용은 Understanding the Linux Kernel 3rd Ed (1장, 2장) 을 확인하라.

- 상세한 설명 시작!
make uImage라는 명령으로 kernel compile이 끝났으면 uImage라는 파일이 arch/arm/boot/에 생성된다.
자~ 이제 uImage를 RAM에 올리자.
uImage는 RAM의 어느 위치에 kernel을 올려도 상관없다.
왜냐하면, bootm에 명령으로 uImage가 올라간 ram의 주소(0xa0000000)만 지정해 주면,
uImage에서 zImage를 추출해서 자동으로 0xa0008000으로 이동시킬테니 말이다.
하지만 zImage를 사용한다면 꼭 0xa0008000으로 zImage를 올려줘야 한다.

uImage를 RAM올리는 방법은 T32, USB, Ethernet cable(TFTP)을 이용한 방법 등이 있다.

이제 RAM의 일정한 주소에 uImage가 올라왔다. 0xa0000000에 올렸다고 가정하고 u-boot의
bootm a0000000
명령을 사용한다면 방금 얘기한 것 처럼 uImage에서 header정보를 이용하여 zImage를 0xa0008000으로 옮길 것이다.
그리고 bootm명령은 register r1에 machine type을 setting하고 pc의 값을 0xa0008000으로 바꾼다.

참고로, machine type은
arch/arm/toos/mach-type
디렉토리에서 확인할 수 있다.

0xa0008000에는 이제 실행할 수 있는 arm 명령어들의 sequence(즉 프로그램)이 존재하게 되었고 pc는 여기를 가르키므로,
이제 새로운 생명이 탄생하는 것처럼 kernel이 살아 움직이기 시작하는 것이다.

그런데, zImage를 사용한다면 어떻게 될까? 그럴 경우에는
go a0008000
명령어를 사용한다. go 명령은 단순히 pc값만 변경하므로 machine type을 설정은 직접 0xa0008000에 T32로 break point를 걸어놓고 r1값을 변경하도록 한다.
Register.Set R1 1362. ; 머신 타입 설정 (Magna는 Decimal로 1361)

그런데 잠깐! zImage의 제일 처음은 압축을 푸는 코드라고 했다.
그럼 압축이 풀린 커널은 어디에 위치할까?
바로 다시 0xa0008000에 위치하게 된다.

그럼 0xa0008000에 위치하는 코드는 도대체 어떤 코드일까? start kernel함수 일까? 아니다.
가장 처음에 위치하는 커널 코드는 arch/arm/kernel/head.S 파일로서 제일 처음에는 __init_begin 함수(?) 가 위치하고 (arch/arm/kernel/vmlinux.lds, arch/arm/mm/init.c 파일 참조)
우리에게 익숙한 start_kernel은 0xa00088c0 정도에 위치함을 확인하였다.