RISC-V의 핵심은 opensbi이다. 어느 RISC-V 문서를 봐도 opensbi를 확인할 수 있다.
부트로더에서 opensbi가 실행되고, 리눅스 커널이 실행될 때도 opensbi에 접근한다.
이번 포스트에서는 opensbi를 빌드하는 방법에 대해 기술한다.
opensbi는 오픈 소스로 관리되며 위치는 아래와 같다.
https://github.com/riscv-software-src/opensbi
아래 명령어로 소스를 내려 받자.
$ git clone https://github.com/riscv-software-src/opensbi
빌드하기 전에 미리 아래와 같은 유틸리티를 설치할 필요가 있다.
$ sudo apt install gcc-riscv64-linux-gnu binutils-riscv64-linux-gnu
opensbi 빌드 방법
opensbi를 빌드하는 핵심 명령어는 아래와 같다.
make O=$OUTPUT CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic
계속 CROSS_COMPILE을 명령어로 하기 귀찮으니, 빌드 셸 스크립트(./build_opensbi.sh)를 생성해서 실행하자.
아래는 ./build_opensbi.sh의 구현부이다.
#!/bin/bash
echo "build opensbi"
TOP_PATH=$( cd "$(dirname "$0")" ; pwd )
OUTPUT="$TOP_PATH/out-riscv64"
BUILD_LOG="$TOP_PATH/riscv-build_log.txt"
build_start_time=`date +%s`
#echo "RPi build start" > $BUILD_LOG
#echo "Build start : $build_start_time" >> $BUILD_LOG
echo "open Build start : $build_start_time"
OUTPUT_PATH=$( cd "$(dirname "$0")" ; pwd )
OUTPUT="$OUTPUT_PATH/out-opensbi"
pushd opensbi > /dev/null
make O=$OUTPUT CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic -j16 2>&1
popd > /dev/null
아래는 build_opensbi.sh 셸 스크립트를 실행할 때의 아웃풋이다.
$ ./build_opensbi.sh
build opensbi
open Build start : 1768870118
Loaded configuration '/home/austin/riscv_src/package_opensbi/deepack_open_sbi/opensbi/platform/generic/configs/defconfig'
Configuration saved to '/home/austin/riscv_src/package_opensbi/deepack_open_sbi/out-opensbi/platform/generic/kconfig/.config'
CPP-DEP platform/generic/firmware/fw_payload.elf.dep
CPP-DEP platform/generic/firmware/fw_jump.elf.dep
CPP-DEP platform/generic/firmware/fw_dynamic.elf.dep
[...]
AR lib/libsbi.a
ELF platform/generic/firmware/payloads/test.elf
ELF platform/generic/firmware/fw_dynamic.elf
ELF platform/generic/firmware/fw_jump.elf
OBJCOPY platform/generic/firmware/payloads/test.bin
AS platform/generic/firmware/fw_payload.o
OBJCOPY platform/generic/firmware/fw_dynamic.bin
ELF platform/generic/firmware/fw_payload.elf
OBJCOPY platform/generic/firmware/fw_jump.bin
OBJCOPY platform/generic/firmware/fw_payload.bin
빌드가 되면 다양한 오브젝트 파일이 생성되는데 핵심 파일은 fw_dynamic.bin이다.
fw_dynamic.bin 파일은 디버깅 정보가 없으니, fw_dynamic.elf 파일을 찾아서 어셈블리 명령어를 추출하자.
$ riscv64-linux-gnu-objdump -d fw_dynamic.elf > assembly_opensbi.c
이제부터 어셈블리 명령어를 분석할 수 있다.
0000000000000000 <_fw_start>:
0: 00050433 add s0,a0,zero
4: 000584b3 add s1,a1,zero
8: 00060933 add s2,a2,zero
c: 66c000ef jal ra,678 <fw_boot_hart>
[...]
00000000000003c8 <_trap_handler>:
3c8: 34021273 csrrw tp,mscratch,tp
3cc: 06523023 sd t0,96(tp) # 60 <_try_lottery+0x36>
3d0: 300022f3 csrr t0,mstatus
[...]
46c: 00010533 add a0,sp,zero
470: 16e0c0ef jal ra,c5de <sbi_trap_handler>
이제부터 전처리 파일을 추출해보자.
전처리 파일(preprocessed file)은 매크로를 전부 파싱해서 보여주므로,
처음 코드를 분석할 때 유용하다.
opensbi에서 전처리 파일을 추출하려면 아래와 같은 패치를 생성하자.
diff --git a/Makefile b/Makefile
index 46541063..85e0f685 100644
--- a/Makefile
+++ b/Makefile
@@ -381,6 +381,7 @@ CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-stack-protector -fno-st
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
CFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables
CFLAGS += -std=gnu11
+CFLAGS += -save-temps=obj
CFLAGS += $(REPRODUCIBLE_FLAGS)
# Optionally supported flags
ifeq ($(CC_SUPPORT_VECTOR),y)
CFLAGS에 -save-temps=obj 옵션을 추가하는 코드이다.
전처리 파일과 C 코드에서 확인한 루틴을 비교하자.
sbi_list_del() 함수 in C 소스 파일:
include/sbi/sbi_list.h
static inline void sbi_list_del(struct sbi_dlist *entry)
{
__sbi_list_del(entry->prev, entry->next);
entry->next = (void *)SBI_LIST_POISON_NEXT;
entry->prev = (void *)SBI_LIST_POISON_PREV;
}
sbi_list_del() 함수 in 전처리 소스 파일: SBI_LIST_POISON_NEXT 매크로가
0xFADEBABE으로 파싱되어서 출력된다.
static inline void sbi_list_del(struct sbi_dlist *entry)
{
__sbi_list_del(entry->prev, entry->next);
entry->next = (void *)0xFADEBABE;
entry->prev = (void *)0xDEADBEEF;
}
RISC-V에서 QEMU를 설정하고 빌드하는 방법은 아래 링크를 참고하자.
https://lore.kernel.org/all/20251112-v5_user_cfi_series-v23-0-b55691eacf4f@rivosinc.com/
How to test this series
=======================
Toolchain
---------
$ git clone git@github.com:sifive/riscv-gnu-toolchain.git -b cfi-dev
$ riscv-gnu-toolchain/configure --prefix=<path-to-where-to-build> --with-arch=rv64gc_zicfilp_zicfiss --enable-linux --disable-gdb --with-extra-multilib-test="rv64gc_zicfilp_zicfiss-lp64d:-static"
$ make -j$(nproc)
Qemu
----
Get the lastest qemu
$ cd qemu
$ mkdir build
$ cd build
$ ../configure --target-list=riscv64-softmmu
$ make -j$(nproc)
Opensbi
-------
$ git clone git@github.com:deepak0414/opensbi.git -b v6_cfi_spec_split_opensbi
$ make CROSS_COMPILE=<your riscv toolchain> -j$(nproc) PLATFORM=generic
Linux
-----
Running defconfig is fine. CFI is enabled by default if the toolchain
supports it.
$ make ARCH=riscv CROSS_COMPILE=<path-to-cfi-riscv-gnu-toolchain>/build/bin/riscv64-unknown-linux-gnu- -j$(nproc) defconfig
$ make ARCH=riscv CROSS_COMPILE=<path-to-cfi-riscv-gnu-toolchain>/build/bin/riscv64-unknown-linux-gnu- -j$(nproc)
Running
-------
Modify your qemu command to have:
-bios <path-to-cfi-opensbi>/build/platform/generic/firmware/fw_dynamic.bin
-cpu rv64,zicfilp=true,zicfiss=true,zimop=true,zcmop=true
References
==========
[1] - https://github.com/riscv/riscv-cfi
[2] - https://lore.kernel.org/all/20240814081126.956287-1-samuel.holland@sifive.com/
[3] - https://lwn.net/Articles/889475/
[4] - https://developer.arm.com/documentation/109576/0100/Branch-Target-Identification
[5] - https://www.intel.com/content/dam/develop/external/us/en/documents/catc17-introduction-intel-cet-844137.pdf
[6] - https://lwn.net/Articles/940403/
'RISC-V > RISC-V 빌드 및 환경' 카테고리의 다른 글
| [펌] RISC-V 시스템에서 QEMU를 설정하고 빌드하는 방법 (feat. riscv) (0) | 2026.01.20 |
|---|---|
| RISC-V는 차세대 CPU 아키텍처로 Arm을 대체할까? (0) | 2025.08.22 |
| [RISC-V] u-boot 크로스 컴파일 (0) | 2024.10.19 |
| [RISC-V] How to run QEMU (Window) (0) | 2024.05.22 |
| RISC-V ISA-interpreter (0) | 2024.04.03 |
