
부트로더란, 컴퓨터가 켜졌을 때, 커널을 찾아 메모리에 올려주는 일을 합니다. 이러한 부트로더를 만들 때에는 사용할 rootfile 등을 잡아주어야 합니다. 또한, 하드웨어나 소프트웨어를 초기화해주기도 합니다.
만약 커널이 적재되면, 부트로더는 메모리에서 내려갑니다.
이 부트로더는 직접 만들어줄 수도 있습니다. 보통 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 컨버터를 사용한다면, 직렬 통신을 할 수 있습니다.

핀은 다음과 같이 연결해주면 됩니다. 다만, 라즈베리파이는 전송을 받는 입장이기 때문에, RX선을 TX에, TX선을 RX에 연결해주면 됩니다.
이후, 라즈베리파이로 u-boot.bin을 넘겨준 뒤, /boot/firmware/에 해당 파일을 이동시키고, /boot/firmware/config.txt 의 맨 밑에 kernel=u-boot.bin을 추가해주면 됩니다. 이를 추가해주면 라즈베리파이의 기본 부트로더가 커널을 올리지 못하고 u-boot 부트로더를 올리게 됩니다.
부트로더의 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는 초대형 프로젝트로, 공식 문서 상 약 140기가 이상의 디스크 공간, 32기가 이상의 램이 필요하다고 합니다.
현재 가상머신 스펙은 다음과 같습니다.
$ 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는 레퍼런스 배포판이라고 합니다.
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의 값을 변경해주면 됩니다.
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 직무설명 등을 진해하였다고 전해들었습니다. 다음 면접과는(있을지 모르겠지만) 겹치지 않으면 좋겠네요ㅜ
| [한화비전 VEDA 4기] 15주차 리뷰 (0) | 2026.07.05 |
|---|---|
| [한화비전 VEDA 4기] 14주차 리뷰 (0) | 2026.06.28 |
| [한화비전 VEDA 4기] 12주차 리뷰 (0) | 2026.06.14 |
| [한화비전 VEDA 4기] 11주차 리뷰 (0) | 2026.06.07 |
| [한화비전 VEDA] 10주차 리뷰 (0) | 2026.05.31 |
댓글 영역