Yocto Project는 임베디드 시스템에서 커스터마이즈된 리눅스 배포판을 생성하는 강력한 도구이다. 최근 RISC-V는 오픈소스 RISC 프로세서 아키텍처로 많은 관심을 받고 있으며, Yocto를 사용해 RISC-V 플랫폼에서 실행 가능한 리눅스 이미지를 생성할 수 있다. 이 글에서는 Yocto 빌드 환경에 RISC-V 지원을 추가하고 리눅스 이미지를 생성하는 방법에 대해 알아본다.
RISC-V 지원 Yocto 환경 준비
1. Yocto 프로젝트 소스코드 다운로드
Yocto 프로젝트의 최신 릴리즈를 다운로드 한다.
git clone git://git.yoctoproject.org/poky.git
cd poky
git checkout kirkstone # 원하는 Yocto 릴리스를 선택
2. RISC-V 레이어 추가
RISC-V 지원을 추가하려면 meta-riscv
라는 레이어를 추가해야 한다. 이 레이어는 RISC-V 플랫폼에 대한 보드 지원 패키지(BSP)를 제공한다.
git clone https://github.com/riscv/meta-riscv.git
cd meta-riscv
git checkout kirkstone # 호환 브랜치 선택
빌드 환경 설정
Yocto 빌드를 설정하려면 환경을 초기화하고 RISC-V와 관련된 설정을 추가해야 줘야 한다.
1. 빌드 디렉토리 초기화
oe-init-build-env
스크립트를 실행하여 Yocto 빌드 디렉토리를 초기화한다.
source oe-init-build-env
스크립트를 실행하면 build
라는 디렉토리가 생성된다. 이 디렉토리에서 모든 빌드가 진행된다.
2. bblayers.conf
업데이트
아래와 같이 conf/bblayers.conf
파일에 meta-riscv
레이어를 추가 한다.
bitbake-layers add-layer ../meta-riscv
수정 후 bblayers.conf
에 meta-riscv
가 추가되었는지 확인한다.
BBLAYERS ?= " \
/path/to/poky/meta \
/path/to/poky/meta-poky \
/path/to/poky/meta-yocto-bsp \
/path/to/meta-riscv \
"
3. local.conf
설정
conf/local.conf
파일에서 빌드 타겟과 기타 설정을 정의한다.
- MACHINE 설정: RISC-V를 대상으로 하는 빌드 환경을 설정하려면
MACHINE
변수를 수정한다. 예를 들어, QEMU에서 실행 가능한 RISC-V 이미지를 생성하려면 아래와 같이qemuriscv64
로 설정한다.
MACHINE ?= "qemuriscv64"
- 병렬 빌드 설정: 빌드 속도를 높이기 위해 CPU 코어 수를 기반으로 병렬 빌드 설정을 최적화한다.
BB_NUMBER_THREADS = "4"
PARALLEL_MAKE = "-j 4"
- 이미지 유형 설정: 최소한의 리눅스 시스템 이미지를 생성하려면
core-image-minimal
을 선택한다.
DISTRO_FEATURES:append = " systemd"
VIRTUAL-RUNTIME_init_manager = "systemd"
Yocto 빌드 실행
이제 모든 설정이 완료되었으므로 이미지를 빌드한다.
1. 이미지 빌드
다음 명령어를 사용하여 RISC-V 기반의 최소한의 리눅스 이미지를 생성한다.
bitbake core-image-minimal
jammy@ubuntu:~/work/poky/build$ bitbake core-image-minimal
Loading cache: 100% | | ETA: --:--:--
Loaded 0 entries from dependency cache.
Parsing recipes: 100% |##########################################################################| Time: 0:00:13
Parsing of 894 .bb files complete (0 cached, 894 parsed). 1659 targets, 81 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies
Build Configuration:
BB_VERSION = "2.0.0"
BUILD_SYS = "x86_64-linux"
NATIVELSBSTRING = "ubuntu-22.04"
TARGET_SYS = "riscv64-poky-linux"
MACHINE = "qemuriscv64"
DISTRO = "poky"
DISTRO_VERSION = "4.0.23"
TUNE_FEATURES = "riscv64"
meta
meta-poky
meta-yocto-bsp = "kirkstone:c0dcc563322cbe8b4c323172d66d04d16d2067e8"
meta-riscv = "kirkstone:0bd22610f8f4f0b17efcfba08b29f58fb3e6d3f0"
NOTE: Fetching uninative binary shim http://downloads.yoctoproject.org/releases/uninative/4.6/x86_64-nativesdk-libc-4.6.tar.xz;sha256sum=6bf00154c5a7bc48adbf63fd17684bb87eb07f4814fbb482a3fbd817c1ccf4c5 (will check PREMIRRORS first)
Initialising tasks: 100% |#################################################| Time: 0:00:02
Sstate summary: Wanted 1509 Local 0 Mirrors 0 Missed 1509 Current 0 (0% match, 0% complete)
NOTE: Executing Tasks
Setscene tasks: 1509 of 1509
Currently 4 running tasks (1969 of 3920) 50% |#################### |
0: linux-yocto-5.15.166+gitAUTOINC+567f0adb9d_a78a104311-r0 do_fetch - 18m15s (pid 1225721) 84% |################################################################### |
1: coreutils-9.0-r0 do_compile - 22s (pid 1664720)
2: makedepend-native-1_1.0.6-r0 do_configure - 7s (pid 1671901)
3: chrpath-native-0.16-r0 do_configure - 7s (pid 1671916)
...
2. 빌드 결과 확인
빌드가 완료되면 생성된 이미지를 tmp/deploy/images/<MACHINE>
디렉토리에서 확인할 수 있다.
ls tmp/deploy/images/qemuriscv64/
$ ls tmp/deploy/images/qemuriscv64/core-image-minimal*
tmp/deploy/images/qemuriscv64/core-image-minimal.env tmp/deploy/images/qemuriscv64/core-image-minimal-qemuriscv64.ext4
tmp/deploy/images/qemuriscv64/core-image-minimal-qemuriscv64-20241128184902.qemuboot.conf tmp/deploy/images/qemuriscv64/core-image-minimal-qemuriscv64.manifest
tmp/deploy/images/qemuriscv64/core-image-minimal-qemuriscv64-20241128184902.rootfs.ext4 tmp/deploy/images/qemuriscv64/core-image-minimal-qemuriscv64.qemuboot.conf
tmp/deploy/images/qemuriscv64/core-image-minimal-qemuriscv64-20241128184902.rootfs.manifest tmp/deploy/images/qemuriscv64/core-image-minimal-qemuriscv64.tar.bz2
tmp/deploy/images/qemuriscv64/core-image-minimal-qemuriscv64-20241128184902.rootfs.tar.bz2 tmp/deploy/images/qemuriscv64/core-image-minimal-qemuriscv64.testdata.json
tmp/deploy/images/qemuriscv64/core-image-minimal-qemuriscv64-20241128184902.rootfs.wic.qcow2 tmp/deploy/images/qemuriscv64/core-image-minimal-qemuriscv64.wic.qcow2
tmp/deploy/images/qemuriscv64/core-image-minimal-qemuriscv64-20241128184902.testdata.json
생성된 이미지 실행
QEMU를 사용하여 빌드된 RISC-V 이미지를 실행해 본다.
1. QEMU 실행
다음 명령어로 빌드된 이미지를 실행한다.
runqemu qemuriscv64
$ runqemu qemuriscv64
runqemu - INFO - Running MACHINE=qemuriscv64 bitbake -e ...
runqemu - INFO - Continuing with the following parameters:
KERNEL: [/home/jammy/work/poky/build/tmp/deploy/images/qemuriscv64/Image]
BIOS: [/home/jammy/work/poky/build/tmp/deploy/images/qemuriscv64/fw_jump.elf]
MACHINE: [qemuriscv64]
FSTYPE: [ext4]
ROOTFS: [/home/jammy/work/poky/build/tmp/deploy/images/qemuriscv64/core-image-minimal-qemuriscv64-20241128184902.rootfs.ext4]
CONFFILE: [/home/jammy/work/poky/build/tmp/deploy/images/qemuriscv64/core-image-minimal-qemuriscv64-20241128184902.qemuboot.conf]
runqemu - INFO - Setting up tap interface under sudo
[sudo] password for jammy:
2. QEMU에서 리눅스 부팅
QEMU가 실행되면, RISC-V 기반의 리눅스 시스템이 부팅된다. 로그인 프롬프트가 표시되면, 기본 사용자 이름과 비밀번호를 사용하여 로그인할 수 있다.

아래는 nographic으로 실행하여 root로 로그인 한 결과이다.
$ runqemu nographic qemuriscv64
runqemu - INFO - Running MACHINE=qemuriscv64 bitbake -e ...
runqemu - INFO - Continuing with the following parameters:
KERNEL: [/home/jammy/work/poky/build/tmp/deploy/images/qemuriscv64/Image]
BIOS: [/home/jammy/work/poky/build/tmp/deploy/images/qemuriscv64/fw_jump.elf]
MACHINE: [qemuriscv64]
FSTYPE: [ext4]
ROOTFS: [/home/jammy/work/poky/build/tmp/deploy/images/qemuriscv64/core-image-minimal-qemuriscv64-20241128184902.rootfs.ext4]
CONFFILE: [/home/jammy/work/poky/build/tmp/deploy/images/qemuriscv64/core-image-minimal-qemuriscv64-20241128184902.qemuboot.conf]
runqemu - INFO - Using preconfigured tap device tap0
runqemu - INFO - If this is not intended, touch /tmp/qemu-tap-locks/tap0.skip to make runqemu skip tap0.
runqemu - INFO - Network configuration: ip=192.168.7.2::192.168.7.1:255.255.255.0::eth0:off:8.8.8.8
runqemu - INFO - Running /home/jammy/work/poky/build/tmp/work/x86_64-linux/qemu-helper-native/1.0-r1/recipe-sysroot-native/usr/bin/qemu-system-riscv64 -device virtio-net-device,netdev=net0,mac=52:54:00:12:34:02 -netdev tap,id=net0,ifname=tap0,script=no,downscript=no -object rng-random,filename=/dev/urandom,id=rng0 -device virtio-rng-pci,rng=rng0 -drive id=disk0,file=/home/jammy/work/poky/build/tmp/deploy/images/qemuriscv64/core-image-minimal-qemuriscv64-20241128184902.rootfs.ext4,if=none,format=raw -device virtio-blk-device,drive=disk0 -device virtio-tablet-pci -device virtio-keyboard-pci -machine virt -smp 4 -m 256 -serial mon:stdio -serial null -nographic -device bochs-display -bios /home/jammy/work/poky/build/tmp/deploy/images/qemuriscv64/fw_jump.elf -kernel /home/jammy/work/poky/build/tmp/deploy/images/qemuriscv64/Image -append 'root=/dev/vda rw mem=256M ip=192.168.7.2::192.168.7.1:255.255.255.0::eth0:off:8.8.8.8 console=ttyS0 console=hvc0 earlycon=sbi '
runqemu - INFO - Host uptime: 1183.96
OpenSBI v1.0-11-gce4c018
____ _____ ____ _____
/ __ \ / ____| _ \_ _|
| | | |_ __ ___ _ __ | (___ | |_) || |
| | | | '_ \ / _ \ '_ \ \___ \| _ < | |
| |__| | |_) | __/ | | |____) | |_) || |_
\____/| .__/ \___|_| |_|_____/|____/_____|
| |
|_|
Platform Name : riscv-virtio,qemu
Platform Features : medeleg
Platform HART Count : 4
Platform IPI Device : aclint-mswi
Platform Timer Device : aclint-mtimer @ 10000000Hz
Platform Console Device : uart8250
Platform HSM Device : ---
Platform Reboot Device : sifive_test
Platform Shutdown Device : sifive_test
Firmware Base : 0x80000000
Firmware Size : 268 KB
Runtime SBI Version : 0.3
Domain0 Name : root
Domain0 Boot HART : 1
Domain0 HARTs : 0*,1*,2*,3*
Domain0 Region00 : 0x0000000002000000-0x000000000200ffff (I)
Domain0 Region01 : 0x0000000080000000-0x000000008007ffff ()
Domain0 Region02 : 0x0000000000000000-0xffffffffffffffff (R,W,X)
Domain0 Next Address : 0x0000000080200000
Domain0 Next Arg1 : 0x0000000082200000
Domain0 Next Mode : S-mode
Domain0 SysReset : yes
Boot HART ID : 1
Boot HART Domain : root
Boot HART ISA : rv64imafdcsu
Boot HART Features : scounteren,mcounteren,time
Boot HART PMP Count : 16
Boot HART PMP Granularity : 4
Boot HART PMP Address Bits: 54
Boot HART MHPM Count : 0
Boot HART MIDELEG : 0x0000000000000222
Boot HART MEDELEG : 0x000000000000b109
[ 0.000000] Linux version 5.15.166-yocto-standard (oe-user@oe-host) (riscv64-poky-linux-gcc (GCC) 11.5.0, GNU ld (GNU Binutils) 2.38.20220708) #1 SMP PREEMPT Fri Sep 6 17:42:25 UTC 2024
[ 0.000000] OF: fdt: Ignoring memory range 0x80000000 - 0x80200000
[ 0.000000] Machine model: riscv-virtio,qemu
[ 0.000000] Memory limited to 256MB
[ 0.000000] efi: UEFI not found.
[ 0.000000] Zone ranges:
[ 0.000000] DMA32 [mem 0x0000000080200000-0x000000008fffffff]
[ 0.000000] Normal empty
[ 0.000000] Movable zone start for each node
[ 0.000000] Early memory node ranges
[ 0.000000] node 0: [mem 0x0000000080200000-0x000000008fffffff]
[ 0.000000] Initmem setup node 0 [mem 0x0000000080200000-0x000000008fffffff]
[ 0.000000] SBI specification v0.3 detected
[ 0.000000] SBI implementation ID=0x1 Version=0x10000
[ 0.000000] SBI TIME extension detected
[ 0.000000] SBI IPI extension detected
[ 0.000000] SBI RFENCE extension detected
[ 0.000000] SBI v0.2 HSM extension detected
[ 0.000000] riscv: ISA extensions acdfimsu
[ 0.000000] riscv: ELF capabilities acdfim
[ 0.000000] percpu: Embedded 26 pages/cpu s67480 r8192 d30824 u106496
[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 64008
[ 0.000000] Kernel command line: root=/dev/vda rw mem=256M ip=192.168.7.2::192.168.7.1:255.255.255.0::eth0:off:8.8.8.8 console=ttyS0 console=hvc0 earlycon=sbi
... 생략 ...
[ 3.413408] VFS: Mounted root (ext4 filesystem) on device 253:0.
[ 3.415512] devtmpfs: mounted
[ 3.438495] Freeing unused kernel image (initmem) memory: 2464K
[ 3.440599] Run /sbin/init as init process
[ 3.779625] systemd[1]: System time before build time, advancing clock.
[ 3.887171] systemd[1]: systemd 250.5+ running in system mode (-PAM -AUDIT -SELINUX -APPARMOR +IMA -SMACK +SECCOMP -GCRYPT -GNUTLS -OPENSSL +ACL +BLKID -CURL -ELFUTILS -FIDO2 -IDN2 -IDN -IPTC +KMOD -LIBCRYPTSETUP +LIBFDISK -PCRE2 -PWQUALITY -P11KIT -QRENCODE -BZIP2 -LZ4 -XZ -ZLIB +ZSTD -BPF_FRAMEWORK +XKBCOMMON +UTMP +SYSVINIT default-hierarchy=hybrid)
[ 3.891300] systemd[1]: Detected architecture riscv64.
Welcome to Poky (Yocto Project Reference Distro) 4.0.23 (kirkstone)!
[ 3.951779] systemd[1]: Hostname set to <qemuriscv64>.
[ 4.159999] systemd-sysv-generator[115]: SysV service '/etc/init.d/halt' lacks a native systemd unit file. Automatically generating a unit file for compatibility. Please update package to include a native systemd unit file, in order to make it more safe and robust.
[ 4.162096] systemd-sysv-generator[115]: SysV service '/etc/init.d/reboot' lacks a native systemd unit file. Automatically generating a unit file for compatibility. Please update package to include a native systemd unit file, in order to make it more safe and robust.
... 생략 ...
[ OK ] Started Getty on tty1.
[ OK ] Started Serial Getty on ttyS0.
[ OK ] Reached target Login Prompts.
Starting User Login Management...
[ OK ] Started D-Bus System Message Bus.
[ OK ] Started Network Name Resolution.
[ OK ] Reached target Network.
[ OK ] Reached target Host and Network Name Lookups.
[ OK ] Started User Login Management.
[ OK ] Reached target Multi-User System.
Starting Record Runlevel Change in UTMP...
[ OK ] Finished Record Runlevel Change in UTMP.
Poky (Yocto Project Reference Distro) 4.0.23 qemuriscv64 ttyS0
qemuriscv64 login: root
root@qemuriscv64:~#