예전에 연구실에서 라즈베리파이 캐시에 관해서 진행했던 프로젝트가 있었다. 연구실 후배가 진행했던 것이었는데, 당시에 나는 졸업 준비를 하고 있어서 제대로 도와주지 못했다. 이제 졸업 준비도 모두 마무리 했고, 시도하고 싶은 내용이 있어서 남은 시간에 확인해보려고 한다. 이를 위해서 라즈베리파이를 로우 레벨(low level)에서 다뤄봐야 하는데, 이를 위해서 u-boot를 사용하여 라즈베리파이3 B 모델에 raspbian을 부팅해보려고 한다.
U-Boot
U-Boot는 임베디드 보드를 위한 부트로더 중 하나이다. 아키텍처는 ARM, MIPS, PowerPC 등을 지원한다. 이를 사용해서 하드웨어를 테스팅하거나 어플리케이션 코드를 수행할 수 있도록 할 수 있다. U-Boot는 리눅스와 밀접한 관계로 개발되고 있으며, 리눅스 소스 트리의 한 부분으로 존재하고 있다. 이 때문에 U-Boot를 사용하여 리눅스를 부팅할 수 있도록 할 수 있다.
U-Boot는 기본적으로 Command Line Interface를 지원하고 있다. CLI를 통해서 네트워크 연결하여 PXE 부팅을 할 수도 있다. 뿐만 아니라, SD Card에 있는 이미지 파일을 로드하여 부팅할 수 있는 강력한 부트로더이다. 추후에 U-Boot 명령어를 정리하는 글을 작성할 예정이다.
Raspbian
Rapbian은 라즈베리파이 재단에서 공식적으로 지원하고 있는 운영체제이며 데비안 리눅스를 기반하고 있다. 특징은 라즈베리 파이 특성상 낮은 성능의 ARM CPU를 사용하고 있는데, 자원을 효율적으로 사용하기 위하여 최적화가 잘 되어 있다. 기본적으로 PIXEL(Pi Improved X-Window Environment, Lightweight) 기반의 데스크탑 환경을 지원하고 있으며, LXDE 데스크탑 환경과 Openbox 윈도우 매니저를 수정해서 제공한다. 재미있게도 Mathmatica를 제공하고 Minecraft의 Pi 버전이 기본적으로 설치되어 있다(Recommend Software 버전).
U-Boot를 이용하여 Raspbian 부팅 과정
지금부터 U-Boot를 사용하요 Raspbian을 부팅하는 과정을 간단하게 메모하려고 한다.
본 글은 Fedora 29 환경에서 시도하였다.
먼저 리눅스 환경에서 u-boot 소스코드를 github에서 clone 한다. 본 글에서는 ~/u-boot 로 clone 하였다.
$ git clone https://github.com/u-boot/u-boot
그리고, 다음과 같이 ARCH 환경변수와 CROSS_COMPILE 환경변수를 설정한다. ARCH 환경변수는 컴파일 할 대상에 대한 아키텍처를 의미하고, CROSS_COMPILE은 컴파일 할 대상을 위한 Cross Compiler를 설정하는 것이다.
~/u-boot$ export ARCH=arm
~/u-boot$ export CROSS_COMPILE=arm-linux-gnu-
주의할 점은 CROSS_COMPILE에 입력해야 할 Cross Compiler Toolchain은 리눅스 배포판마다 다르다. 이를 주의하여 입력한다. 우분투 같은 경우에는 arm-linux-gnueabihf- 툴을 설치하는 것으로 알고 있다. arm-linux-gnu는 Fedora 배포판에서 제공하고 있다.
ARCH 환경변수와 CROSS_COMPILE 환경변수를 입력하였으면, 다음과 같이 컴파일을 진행한다.
~/u-boot$ make rpi_3_32b_defconfig
~/u-boot$ make all
rpi_3_32b_defconfig에는 Raspberry Pi 3 32bit에 대한 컴파일 옵션을 포함하고 있다. 자세한 옵션은 여기에서 확인할 수 있다.
컴파일이 완료 되었으면, raspbian을 설치한 microSD 카드를 리눅스 머신에 연결하여 boot 파티션을 마운트 한다. 본 글에서는 /media/pi 에 마운트하였다. boot 파티션을 마운트 완료했으면, config.txt 파일 마지막에 다음 한 줄을 추가한다.
kernel=u-boot.bin
그리고, 위에서 컴파일된 u-boot.bin 파일을 마운트한 boot 파티션에 복사한다.
/media/pi$ sudo cp ~/u-boot/u-boot.bin .
이제 마운트된 볼륨을 언마운트하고 microSD 카드를 라즈베리파이에 삽입하고 USB 키보드를 연결한다. HDMI로 모니터 연결 후 전원을 인가하면 U-Boot로 부팅이 되는 것을 확인 할 수 있다. 바로 네트워크 부팅에 대한 프로세스로 진행하게 되는데, 이때 3초 이내 아무 키를 입력하게 되면 U-Boot CLI가 뜨는 것을 확인 할 수 있다. 이제 다음과 같이 명령어를 입력한다.
fatload mmc 0:1 ${kernel_addr_r} kernel7.img
fatload mmc 0:1 ${fdt_addr_r} bcm2710-rpi-3-b.dtb
bootz ${kernel_addr_r} - ${fdt_addr_r}
fatload 명령어는 FAT 파일 시스템으로부터 존재하는 파일을 파일을 메모리 상으로 로드하는 명령어이다. mmc는 SD Card 같은 물리적 메모리를 디바이스로 매핑해서 접근할 수 있도록 하는 컨트롤러이다. 0:1 은 FAT 파일 시스템의 Device와 Part를 가르키고 있다. boot 파티션이라고 보면 된다. ${kernel_addr_r}과 ${fdt_add_r}은 이미 라즈베리파이 3에 대해서 적절한 메모리 주소를 환경변수로 가지고 있다. 모든 시스템이 해당하는 환경 변수를 포함하고 있지 않는다(U-Boot 컴파일이 선택한 target 덕분에 존재). 각각 주소에 커널 이미지와 Device Tree Blob 파일을 로드한다.
bootz 명령어를 통해서 메모리에 있는 zImage를 가지고 부팅한다. 부팅하는 메모리 주소는 ${kernel_addr_r} - ${fdt_addr_r} 를 통해서 메모리 상에서 커널 이미지의 시작 주소르 가르키도록 한다.
이와 같이 입력하면 정상적으로 Raspbian으로 부팅하는 것을 확인할 수 있다.
Troubleshootings
Kernel panic-not syncing: VFS: unable to mount root fs on unknown-block(0,0)
이와 같은 에러 메세지가 발생하면서 커널 패닉(Kernel Panic)이 발생한다면, 제대로 된 디스크를 찾지 못한다는 의미이다. 다음과 같이 부팅 시 명시적으로 root에 대한 디스크를 명시하면 된다.
fatload mmc 0:1 ${kernel_addr_r} kernel7.img
fatload mmc 0:1 ${fdt_addr_r} bcm2710-rpi-3-b.dtb
setenv bootargs console=tty0 console=ttyAMA0 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait
bootz ${kernel_addr_r} - ${fdt_addr_r}
Comments