상세 컨텐츠

본문 제목

[한화비전 VEDA 4기] 13주차 리뷰

VEDA

by 전산거북이 2026. 6. 22. 18:36

본문

부트 로더

부트로더란, 컴퓨터가 켜졌을 때, 커널을 찾아 메모리에 올려주는 일을 합니다. 이러한 부트로더를 만들 때에는 사용할 rootfile 등을 잡아주어야 합니다. 또한, 하드웨어나 소프트웨어를 초기화해주기도 합니다.
만약 커널이 적재되면, 부트로더는 메모리에서 내려갑니다.

이 부트로더는 직접 만들어줄 수도 있습니다. 보통 u-boot를 많이 이용합니다.

u-boot

설치는 다음과 같습니다.

$ git clone git://git.denx.de/u-boot.git
$ cd u-boot
$ make CROSS_COMPILE=aarch64-gcc-gnu- <board_name>_defconfig # 여기서는 rpi_4_defconfig
$ make CROSS_COMPILE=aarch64-gcc-gnu- -j 4

만약 uboot 빌드를 초기화하려면 다음 명령어를 수행하면 됩니다.

$ make CROSS_COMPILE=aarch64-gcc-gnu- distclean

빌드가 완료되면 다음 파일이 생성됩니다.

u-boot
u-boot.bin
u-boot.lds
u-boot.lds

 

여기서 u-boot.bin을 라즈베리파이로 넘기면 부트로더를 올릴 수 있는데, 그러면 커널이 올라가지 않은 상태가 되기 때문에 ssh를 사용할 수 없게 됩니다.
그럼에도 불구하고, UART 통신은 할 수 있기 때문에 이는 사용할 수 있습니다.

USB to TTL

이렇게 생긴 usb-to-ttl 컨버터를 사용한다면, 직렬 통신을 할 수 있습니다.


핀은 다음과 같이 연결해주면 됩니다. 다만, 라즈베리파이는 전송을 받는 입장이기 때문에, RX선을 TX에, TX선을 RX에 연결해주면 됩니다.
이후, 라즈베리파이로 u-boot.bin을 넘겨준 뒤, /boot/firmware/에 해당 파일을 이동시키고, /boot/firmware/config.txt 의 맨 밑에 kernel=u-boot.bin을 추가해주면 됩니다. 이를 추가해주면 라즈베리파이의 기본 부트로더가 커널을 올리지 못하고 u-boot 부트로더를 올리게 됩니다.

부트로더 cmd 만들기

부트로더의 cmd를 만들어줄 수 있습니다.

3588 U_BOOT_CMD(
3589     showled, 2, 1,  do_showled,
3590     "print local hushshell variables",
3591     "\n    - print values of all hushshell variables\n"
3592     "showvar name ...\n"
3593     "    - print value of hushshell variable 'name'"
3594 );

위와 같은 부분이 있는데, 이 형식에 맞춰 함수를 만들어주면 됩니다.
여기서는 showled 라는 명령어를 입력하면 do_showled 함수를 실행하라는 의미입니다.
물론, do_showled 함수는 직접 구현해야 합니다.

부트로더를 이용하여 커널 부팅하기

커널을 부팅하기 위해서는 커널의 위치를 알아야 합니다.
uboot/board/raspberrypi/rpi/rpi.env에서 kernel.addr을 찾을 수 있는데, 아마 0x00080000에 존재할 것입니다.

u-boot에서는 다음 명령어로 커널을 부팅할 수 있습니다.

setenv bootargs 'console=tty1 console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait rw'

setenv user_mmc_boot '
mmc dev 0;
fatload mmc 0:1 ${kernel_addr_r} kernel8.img;
fatload mmc 0:1 ${fdt_addr_r} bcm2711-rpi-4-b.dtb;
booti ${kernel_addr_r} - ${fdt_addr_r}'

setenv bootcmd 'run user_mmc_boot'

saveenv
printenv user_mmc_boot

reset

자동으로 재부팅을 하게 되며, 이 이후로는 시리얼 통신이 아닌 ssh 통신을 할 수 있을 것입니다.

디바이스트리

하드웨어를 구성하고 있는 요소를 arm에서 커널에게 알려주는 구조를 말합니다. 자료구조의 일종이라고 볼 수 있습니다.
각 보드 별로 독자적으로 코드를 구성하게 되면 같은 SoC에서 파생된 보드임에도 전혀 다른 코드가 구현될 수 있습니다. 이렇게 되면 코드의 복잡도와 코드량 자체가 늘어나는 문제가 발생할 수 있습니다.
그러나 디바이스트리를 구성하면 보드 구성이 바뀌더라도 커널 코드를 수정하지 않고도 동작할 수 있도록 만들 수 있습니다.

디바이스트리 구성

디바이스트리는 정해진 구성 방식이 있습니다.

/ {
    node@0 {
        a-string-property = "A string";
        ...

        child_node@0 {
            first-child-property;
            ...
        };
    };
};

.dts 라는 파일로 만들어집니다. 이를 빌드하여 .dtb를 만들어줍니다. 이렇게 만들어진 디바이스트리는 커널에 적재할 수 있습니다.
만약 이미 적재된 디바이스트리 대신 다른 것을 올리고 싶다면 overlay할 수 있는데, 이는 dtoverlay 라고 하며 .dtbo 확장자를 가집니다.

이렇게 만들어진 장치들은 /boot/firmware 에 등록할 수 있습니다. 여기 값을 등록한 뒤, config.txt의 맨 밑줄에 dtoverlay=gpioled,gpio=21,label=myled 라고 적는다면 dtoverlay를 사용할 수 있습니다. 물론 해당 내용은 본인의 상황에 맞게 바꾸어주어야 합니다.

만약 mydev.dts 라는 파일이 존재한다고 한 다음, 이 디바이스트리 소스를 사용하려면 다음과 같이 해주면 됩니다.
먼저, .dtbo 파일을 생성해주어야 합니다.

$ dtc -@ -I dts -O dtb -o mydev.dtbo mydev.dts

이후, 생성된 .dtbo 파일은 /boot/firmware/overlays에 위치시키고, /boot/firmware/config.txt의 맨 밑줄에 다음을 추가합니다.

dtoverlay=mydev

이제 재시작을 하면 mydev가 디바이스트리로 들어가게 됩니다.

yocto

드디어 yocto에 대해 공부하였습니다. yocto 는 툴체인, 부트로더, 커널, 루트파일시스템을 한 번에 만들어 관리할 수 있는 툴입니다.
yocto는 초대형 프로젝트로, 공식 문서 상 약 140기가 이상의 디스크 공간, 32기가 이상의 램이 필요하다고 합니다.
현재 가상머신 스펙은 다음과 같습니다.

  • 6코어 cpu
  • 30287MB 메모리
  • 250GB 디스크

설치 및 실행

ubuntu에서 dependency 다운로드

$ sudo apt-get install build-essential chrpath cpio debianutils diffstat file gawk gcc git iputils-ping libacl1 libcrypt-dev locales python3 python3-git python3-jinja2 python3-pexpect python3-pip python3-subunit socat texinfo unzip wget xz-utils zstd lz4

이렇게 먼저 필요한 패키지를 다운받아준 뒤, locale을 설정해줍니다.

$ locale --all-locales | grep en_US.utf8

만약 locale이 지원되지 않는다고 한다면, 다음을 이용해 설정해주면 됩니다.

$ sudo dpkg-reconfigure locales

poky 다운로드

이후로는 poky를 다운받습니다. poky는 레퍼런스 배포판이라고 합니다.
https://git.yoctoproject.org/poky/
위 프로젝트로 들어가면 여러 버전이 나옵니다. 저는 일단 scarthgap으로 받았습니다.

$ git clone -b scarthgap https://git.yoctoproject.org/poky

이후, 환경 설정을 위해 스크립트를 수행해주어야 합니다.

$ source oe-init-build-env

그러면 자동으로 build 폴더로 이동하게 된다. 뒤에 argument를 넣어주면 해당 폴더를 빌드 폴더로 사용하게 됩니다.
conf/local.conf 는 빌드하려는 장치의 정보가 담겨있으며, conf/bblayer.conf는 메타레이어의 경로가 들어있습니다.
만약 레이어를 추가하고 싶다면 conf/bblayer.conf의 값을 변경해주면 됩니다.

openembedded, meta-raspberrypi 다운로드

poky 폴더 안에 meta 폴더를 다운받아야 합니다.

$ git clone -b scarthgap https://git.openembedded.org/meta-openembedded
$ git clone -b scarthgap https://git.yoctoproject.org/meta-raspberrypi

이 메타 데이터들을 통해 레이어를 쌓습니다. 여기서 추가되는 것들은 새로 추가되는 거고, 바뀌는 것은 바뀌게 됩니다. 이렇게 하나하나 쌓아가기 때문에 레이어라고 부르는 듯 합니다.

$ vim conf/local.conf
# 이후, MACHINE ??= "raspberripi4" 로 수정

$ vim core/bblayers.conf
# 이후 다음을 추가해야 합니다.

/home/vboxuser/poky/meta-raspberrypi

여기까지 설정을 마친 뒤, bitbake를 이용하여 빌드를 해주면 됩니다.

 $ bitbake core-image-full-cmdline

참고로 yocto는 빌드 자체도 매우 오래걸리기 때문에 시간을 매우 많이(몇 시간 정도) 두고 빌드하면 됩니다.

레시피

만들어진 yocto에 대해서는(빌드 하기 전, 빌드파일이 생성되었을 때) $ bitbake -c listtasks core-image-minimal 과 같은 방식으로 태스크 리스트를 확인할 수 있습니다.
만약, bitbake 도중 실패하게 된다면, 어떤 작업에서 오류가 발생했는지 확인한 뒤, 해당 태스크만 clean한 뒤, 다시 빌드하는 것도 가능합니다.

$ bitbake -c clean 타깃명
$ bitbake -c fetch 타깃명
$ bitbake core-image-minimal | --runall=fetch

레시피는 다음과 같은 방식으로 만들어집니다.

  1 DESCRIPTION = "A friendly program that prints Hello World!"
  2 PROPERTY = "optional"
  3 SECTION = "hello"
  4
  5 LICENSE = "GPLv2"
  6 LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL2.0;md5=801f80980d171dd6425    610833a22dbe6"
  7
  8 SRC_URI = "file://helloworld.c"
  9
 10 S = "${WORKDIR}/sources"
 11 UNPACKDIR = "${S}"
 12
 13 do_compile() {
 14     ${CC} ${CFLAGS} ${LDFLAGS} ${S}/helloworld.c -o ${B}/helloworld
 15 }
 16
 17 do_install() {
 18     install -d ${D}${bindir}
 19     install -m 0755 ${B}/helloworld ${D}${bindir}
 20 }

md5 값은 md4sum을 통해 알아낼 수 있으며, src 파일을 넣어준다면 자동으로 빌드할 때 추가해줍니다.
이렇게 추가된 함수는 해당 yocto를 통해 빌드한 이미지 파일 위에서 특별한 작업 없이도 사용할 수 있는 기본 명령어가 됩니다.

그 외...

이번주에는 기업 면접을 가느라 아쉽게도 목요일에 참여하지 못하였습니다.
목요일은 한화비전 본사에서 취업특강과 BSP 직무설명 등을 진해하였다고 전해들었습니다. 다음 면접과는(있을지 모르겠지만) 겹치지 않으면 좋겠네요ㅜ

관련글 더보기

댓글 영역