간만에 SBC(Single Board Computer)를 하나 입수했다. 이번 시간과 다음 시간에는 2차례에 걸쳐서 RISC-V AI CPU를 탑재한 Orange Pi RV2 보드를 사용해 보고, U-Boot 및 Linux kernel 관련 다양한 이야기를 꺼내 보고자 한다. 😎
목차
1. OrangePi RV2 보드 소개
2. BSP Code Build 하기
3. U-Boot 이야기
4. Linux Kernel 이야기
5. LLM과 AI 이야기
6. References
지금은 AI 시대~ Every Tom, Dick and Harry 모두 AI를 말한다. 그렇다면 나도 ㅋ. 근데, u-boot이나 linux kernel은 AI로도 어찌할 수 없지 않을까 ? 😋
1. OrangePi RV2 보드 소개
OrangePi RV2는 Ky X1이라는 Octa-core RISC V AI CPU(64bit)를 장착한 SBC(Single Board Computer)이다. 그동안 RISC-V CPU를 사용한 보드를 두어차례 사용해 본 적이 있긴 한데, SBC 형태로 직접 구매해 보는 것은 이번이 처음인 듯 하다. 😍
[그림 1.1] OrangePi RV2 보드 [출처 - 참고문헌 1]
📌 OrangePi는 Shenzhen Xunlong Software Co., Ltd에서 개발하였다.
Ky X1 SoC는 2TOPS(Tera of Operations Per Second - 초당 테라(1조) 연산 횟수)의 AI 프로세싱 성능을 자랑한다. 보통은 NPU에서 AI 처리를 담당하지만, Ky X1의 경우는 (별도의 NPU 없이) CPU mode에서 AI 연산 처리를 한단다(AI accelerator 개념인 듯). 그런데, 문제는 Ky X1 SoC 관련 공식 문서(datasheet)를 어디에서도 찾을 길이 없다. 이런~ 😱
인터넷 검색을 좀 해 보니, 아무래 SpacemiT 사에서 만든 Key Stone K1 processor가 동일한 SoC인 듯 보인다(아래 link를 참조).
OrangePi RV2 board 관련 자세한 H/W 스펙과 PCB Top & Bottom view는 차례로 다음과 같다.
- SoC – Ky X1
- CPU – 8-core 64-bit RISC-V processor
- GPU – Not mentioned
- VPU – Not mentioned
- AI Accelerator – 2 TOPS
- System Memory – 2GB, 4GB, or 8GB LPDDR4X
- Storage
- Optional 16GB, 32GB, 64GB, or 128GB eMMC flash module
- 128Mbit (default) or 256Mbit SPI flash
- 2x M.2 M-Key sockets (PCIe 2.0 x2) for NVMe SSD (one 2280, the other 2230)
- MicroSD card slot (SDIO 3.0)
- Video Output
- HDMI 2.0 up to 1920×1440 @ 60 Hz
- 4-lane MIPI DSI connector
- Dual independent display support
- Camera I/F – 2x 4-lane MIPI CSI camera connector
- Audio
- 3.5mm headphone jack using ES8388 audio codec
- Audio output via HDMI port
- Networking
- 2x Gigabit Ethernet RJ45 ports via YT8531C-CA controller
- WiFi 5.0 and Bluetooth 5.0 LE via Ampak AP6256 module
- USB
- 3x USB 3.0 ports
- USB2.0 host/device port
- USB 2.0 host via 4-pin header
- Expansion
- 26-pin expansion header with GPIO, UART, I2C, SPI, PWM, etc.
- 2x M.2 (PCIe Gen2 x2) sockets for SSDs or other add-on modules
- Debugging – 3-pin (3.3V) serial debug header
- Misc
- BOOT, RESET, and Power buttons
- 2-pin connector for RTC battery (1.25mm pitch)
- Power Supply
- 5V/5A via USB Type-C port
- 2-pin connector 5V/1A output; can also be used as a fan connector.
- Dimensions – 89 x 56 mm
[그림 1.3] OrangePi RV2 PCB Top View [출처 - 참고문헌 1]
📌 금전적인 이유로 RAM은 2GB짜리를 구매했다. 구매하고 보니, AI 관련 program을 돌릴 때 문제가 될 것 같아 후회 막급이다. 😓📌 RV2 보드는 eMMC를 탈부착 가능하도록 설계되어 있다. ES8388은 audio codec chip이다.
끝으로, RV2 보드에는 26개의 확장 pin이 나와 있는데, 각 pin의 용도는 다음과 같다. 이 부분은 device driver를 소개하는 장에서 다시 살펴 보기로 하자. 😊
___________________________________
백견이 불여일타 ! 보드가 도착했으니, 켜 보는게 순서다~ 😀
microSD에 OS image를 설치하는 절차는 이어지는 장에서 설명하기로 하고, OS가 탑재된 microSD를 장착한 후, 부팅을 시켜 보도록 한다.
Serial console cable을 보드 앞면의 Debug TTL UART 핀(GND, UART TX, RX)에 연결한 후, 5V/5A USB 전원을 인가해 보도록 하자.
이후, Red LED와 Green LED에 불이 켜지면서, 부팅이 시작된다.
지금까지 OrangePi RV2 board의 H/W 스펙을 대략적으로 확인해 본 후, 가벼운 마음으로 부팅을 시도해 보았다. 이어지는 장에서는 RV2 board용 BSP source code를 build해 보고, 부팅 가능한 image를 하나 만들어 돌려 보는 과정을 살펴 보기로 하자.
2. BSP Code Build 하기
이번 장에서는 RV2 board용 BSP source code를 build하여 OS image(Ubuntu Server - Orange Pi 1.0.0 Noble)를 생성한 후, 이를 target board에 올리는 방법에 관해 알아 보고자 한다. 이장에서 소개하는 내용은 모두 아래 문서를 기초로 하였다.
OrangePi_RV2_X1_User Manual_v1.0.1.pdf
먼저, OrangePi RV2 보드의 booting 방법을 정리해 보면 다음과 같다.
<OrangePi RV2 보드 부팅 방법>
1. SPI flash + microSD를 이용한 방법
2. SPI flash + eMMC를 이용한 방법
- microSD로 부팅 후, eMMC에 linux image writing 후, eMMC로 다시 부팅(microSD는 당연히 제거한 상태에서 시도해야 함)
3. SPI flash + NVMe SSD를 이용한 방법
- microSD로 부팅 후, SPI flash + NVMe SSD에 linux image writing 후, 재 부팅
- SPI flash에는 bootloader를 설치하고, NVMe SSD에는 linux kernel과 rootfs를 설치
4. SPI flash + USB를 이용한 방법
- microSD로 부팅 후, SPI flash + USB에 linux image writing 후, 재 부팅
- SPI flash에는 bootloader를 설치하고, USB에는 linux kernel과 rootfs를 설치
이중에서 이번 posting에서는 (eMMC, NVMe SSD가 별도로 준비되지 않은 관계로) 어쩔 수 없이 microSD를 이용하여 부팅하는 방법만을 소개하기로 한다. 😂
2.1 BSP source code build 하기
<How to download source code & build>
$ git clone https://github.com/orangepi-xunlong/orangepi-build.git -b next
$ cd orangepi-build
$ sudo ./build.sh
-> source code를 build하는 절차는 아래 그림과 같이 간단하게 구성되어 있다.
-> 아래 4개의 menu를 차례로 선택하기만 하면 된다.
[그림 2.1] build.sh script 실행 모습(1)
build.sh에서 제일 먼저 하는 일은 (toolchain이 존재하지 않을 경우) toolchain을 download하는 것이다.
$ cd toolchain
chyi@earth:/mnt/hdd/workspace/mini_devices/bpi/orangepi-build/toolchains$ ls -la
합계 60
drwxrwxr-x 15 root root 4096 5월 28 17:15 .
drwxrwxr-x 11 chyi chyi 4096 5월 28 17:45 ..
drwxr-xr-x 9 root root 4096 5월 28 17:15 gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu
drwxr-xr-x 9 root root 4096 5월 28 17:14 gcc-arm-11.2-2022.02-x86_64-arm-none-linux-gnueabihf
drwxr-xr-x 9 root root 4096 5월 28 17:09 gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu
drwxr-xr-x 9 root root 4096 5월 28 17:05 gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf
drwxr-xr-x 8 root root 4096 5월 28 16:57 gcc-linaro-4.9.4-2017.01-x86_64_aarch64-linux-gnu
drwxr-xr-x 8 root root 4096 5월 28 16:56 gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi
drwxr-xr-x 8 root root 4096 5월 28 17:01 gcc-linaro-5.5.0-2017.10-x86_64_arm-linux-gnueabihf
drwxr-xr-x 8 root root 4096 5월 28 17:02 gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu
drwxr-xr-x 8 root root 4096 5월 28 17:01 gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabi
drwxr-xr-x 7 root root 4096 5월 28 16:54 gcc-linaro-aarch64-none-elf-4.8-2013.11_linux
drwxr-xr-x 7 root root 4096 5월 28 16:56 gcc-linaro-arm-linux-gnueabihf-4.8-2014.04_linux
drwxr-xr-x 7 root root 4096 5월 28 16:55 gcc-linaro-arm-none-eabi-4.8-2014.04_linux
drwxr-xr-x 10 root root 4096 5월 28 16:51 ky-toolchain-linux-glibc-x86_64-v1.0.1
📌 ky x1용 riscv64 toolchain 말고도 다른 orangepi board를 위한 arm toolchain도 함께 download 받는다(시간이 오래 걸림).
chyi@earth:/mnt/hdd/workspace/mini_devices/bpi/orangepi-build/toolchains/ky-toolchain-linux-glibc-x86_64-v1.0.1/bin$ ./riscv64-unknown-linux-gnu-gcc --version
-> riscv64용 gcc 13.2.1 버젼이 설치된다.
riscv64-unknown-linux-gnu-gcc (g09b62c20e09) 13.2.1 20240423
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ cd /mnt/hdd/workspace/mini_devices/bpi/orangepi-build; $ ls -la
합계 84
drwxrwxr-x 11 chyi chyi 4096 5월 28 17:45 .
drwxrwxr-x 5 chyi chyi 4096 5월 30 16:06 ..
drwxrwxr-x 8 chyi chyi 4096 5월 28 17:53 .git
-rw-rw-r-- 1 chyi chyi 1411 5월 28 16:37 .gitignore
drwxrwxr-x 4 root root 4096 5월 28 18:02 .tmp
-rw-rw-r-- 1 chyi chyi 18026 5월 28 16:37 LICENSE
-rw-rw-r-- 1 chyi chyi 402 5월 28 16:37 README.md
-rwxrwxr-x 1 chyi chyi 9277 5월 28 16:37 build.sh
drwxrwxr-x 7 chyi chyi 4096 5월 28 16:37 external
drwxrwxr-x 3 root root 4096 5월 28 17:59 kernel
drwxrwsr-x 7 root sudo 4096 5월 28 16:47 output
drwxrwxr-x 2 chyi chyi 4096 5월 28 16:37 scripts
drwxrwxr-x 15 root root 4096 5월 28 17:15 toolchains
drwxrwxr-x 3 root root 4096 5월 28 17:15 u-boot
drwxrwsr-x 5 root sudo 4096 5월 28 17:15 userpatches
________________________________________
Build 과정에서 생성된 중간 파일(u-boot, kernel, rootfs)과 최종 결과물(img file)은 각각 아래와 같다.
<u-boot>
[ o.k. ] Building deb [ linux-u-boot-current-orangepirv2_1.0.0_riscv64.deb ]
[ o.k. ] U-boot build done [ @host ]
[ o.k. ] Target directory [ /mnt/hdd/workspace/mini_devices/bpi/orangepi-build/output/debs/u-boot ]
[ o.k. ] File name [ linux-u-boot-current-orangepirv2_1.0.0_riscv64.deb ]
[ o.k. ] Runtime [ 0 min ]
[ o.k. ] Repeat Build Options [ sudo ./build.sh BOARD=orangepirv2 BRANCH=current BUILD_OPT=u-boot ]
<linux kernel>
[ o.k. ] Using kernel config file [ /mnt/hdd/workspace/mini_devices/bpi/orangepi-build/external/config/kernel/linux-ky-current.config ]
[ o.k. ] Kernel build done [ @host ]
[ o.k. ] Target directory [ /mnt/hdd/workspace/mini_devices/bpi/orangepi-build/output/debs/ ]
[ o.k. ] File name [ linux-image-current-ky_1.0.0_riscv64.deb ]
[ o.k. ] Runtime [ 6 min ]
[ o.k. ] Repeat Build Options [ sudo ./build.sh BOARD=orangepirv2 BRANCH=current BUILD_OPT=kernel KERNEL_CONFIGURE=no ]
<rootfs and debian packages>
[ o.k. ] Building deb [ orangepi-plymouth-theme ]
[ o.k. ] Merging and packaging linux firmware [ @host ]
[ o.k. ] Checking git sources [ /mnt/hdd/workspace/mini_devices/bpi/orangepi-build/external/cache/sources/orangepi-firmware-git master ]
[ .... ] Up to date
[ o.k. ] Building firmware package [ orangepi-firmware_1.0.0_all ]
[ o.k. ] Creating board support package for CLI [ orangepi-bsp-cli-orangepirv2 ]
[ o.k. ] Starting rootfs and image building process for [ current orangepirv2 noble null null no ]
[ o.k. ] Extracting noble-cli-riscv64.0b1...822.tar.lz4 [ 3 days old ]
[ .... ] noble-cli-riscv64.0b1...822.tar.lz4: 433MiB [ 178MiB/s] [==================================>] 100%
[ o.k. ] Rootfs build done [ @host ]
[ o.k. ] Target directory [ /mnt/hdd/workspace/mini_devices/bpi/orangepi-build/external/cache/rootfs ]
[ o.k. ] File name [ noble-cli-riscv64.0b11a5db1aa31dff97ccd66f0b25c822.tar.lz4 ]
<ubuntu server image for flashing>
[ o.k. ] Free SD cache [ 6% ]
[ o.k. ] Mount point [ 86% ]
[ o.k. ] Writing U-boot bootloader [ /dev/loop24 ]
[ o.k. ] SHA256 calculating [ Orangepirv2_1.0.0_ubuntu_noble_server_linux6.6.63.img ]
[ o.k. ] Done building [ /mnt/hdd/workspace/mini_devices/bpi/orangepi-build/output/images/Orangepirv2_1.0.0_ubuntu_noble_server_linux6.6.63/Orangepirv2_1.0.0_ubuntu_noble_server_linux6.6.63.img ]
[ o.k. ] Runtime [ 5 min ]
[ o.k. ] Repeat Build Options [ sudo ./build.sh BOARD=orangepirv2 BRANCH=current BUILD_OPT=image RELEASE=noble BUILD_MINIMAL=no BUILD_DESKTOP=no KERNEL_CONFIGURE=no COMPRESS_OUTPUTIMAGE=sha,gpg,img ]
2.2 OS image 설치 및 부팅하기
부팅용 image 파일이 준비되었으니, microSD를 Linux PC에서 장착한 후, 아래와 같이 balenaEtcher program을 이용하여, img 파일을 설치하도록 하자.
Orangepirv2_1.0.0_ubuntu_noble_server_linux6.6.63.img -> microSD
$ sudo dd if=./Orangepirv2_1.0.0_ubuntu_noble_server_linux6.6.63.img of=/dev/sdb bs=1M conv=fsync
이후, microSD를 target board에 장착한 후, 전원을 켜도록 한다(LAN cable도 연결하자).
Minicom으로 확인해 보니, Ubuntu server가 정상적으로 올라오는 모습이 보인다.
📌 CPU core의 수는 8개가 확실하다.
지금까지, 조금은 뻔한 얘기였지만, BSP source code를 build해 보고, bootable image로 부팅을 시도하는 과정까지 알아 보았다.
3. U-Boot 이야기
이번 장에서는 오랫만에 u-boot code의 주요 흐름(booting flow)과 device driver model에 관하여 상세히 분석(deep dive)해 보고자 한다. (U-boot의 경우는) 코드의 량은 그리 많지 않지만 low-level의 내용을 포함하고 있는 관계로 분석이 쉽지가 않은게 사실이다. 😓 그럼에도 불구하고, u-boot의 전반적인 코드 흐름을 파악해 보고, 필요시 어느 부분을 수정해야 하는지를 숙지하는 것만으로도, (나중에) 커다란 도움이 될 것으로 믿는다. 💢
[그림 3.1] U-Boot 로고
📌 예전에는 bootloader의 종류가 참으로 많았는데, (embedded linux의 경우) 요즘은 거의 대부분 u-boot으로 통일(?)되는 느낌이다. 💪 물론, 뭐 여전히 건재한 bootloader도 많이 있긴 하지만 zzz
<이번 장에서 언급하는 주요 keyword>
- u-boot SPL, u-boot proper
- FIT image
- SBI
- Device Tree
- Driver Model
- boot sequence
U-Boot와 관련해서는 아주 오래 전에 한 차례 내용 정리를 한 바가 있다(현 시점에서 도움이 되려나 ?).
3.1 U-Boot code build 및 FIT image 생성하기
2장에서는 OrangePi 측에서 제공하는 build.sh script를 사용하여 u-boot을 build해 보았지만, 코드를 보다 자유롭게 수정 및 테스트하기 위해서는, u-boot의 original build 방법을 따를 필요가 있다.
<How to build u-boot>
$ export CCACHE_BASEDIR="/mnt/hdd/workspace/mini_devices/bpi/orangepi-build/u-boot/v2022.10-ky"
$ export PATH=/mnt/hdd/workspace/mini_devices/bpi/orangepi-build/toolchains/ky-toolchain-linux-glibc-x86_64-v1.0.1/bin:$PATH
$ CROSS_COMPILE=riscv64-unknown-linux-gnu- make -j8 x1_defconfig
$ CROSS_COMPILE=riscv64-unknown-linux-gnu- make menuconfig
$ CROSS_COMPILE=riscv64-unknown-linux-gnu- make
...
...
CROSS_COMPILE="riscv64-unknown-linux-gnu-" PLATFORM_DEFCONFIG=k1_defconfig PLATFORM=generic make -C /mnt/hdd/workspace/mini_devices/bpi/orangepi-build/u-boot/v2022.10-ky/opensbi
...
tools/mkimage -f uboot-opensbi.its -r u-boot-opensbi.itb //이 명령어로 fit image를 생성함.
...
Build를 통해 최종적으로 생성된 binary는 다음과 같다. 뭐가 뭔지 파일이 좀 많다. 😂
$ ls -l u-boot*
-rwxr-xr-x 1 root root 13061424 6월 4 11:31 u-boot
-rw-r--r-- 1 root root 1325181 6월 4 11:32 u-boot-dtb.bin
-rw-r--r-- 1 root root 1326144 6월 4 11:32 u-boot-dtb.img
-rw-r----- 1 root root 16384 6월 4 11:31 u-boot-env-default.bin
-rw-r--r-- 1 root root 10896 6월 4 11:31 u-boot-env-default.txt
-rw-r--r-- 1 root root 1385632 6월 4 11:31 u-boot-fit-dtb.bin
-rwxr-xr-x 1 root root 1265672 6월 4 11:31 u-boot-nodtb.bin
-rw-r--r-- 1 root root 1459332 6월 4 11:32 u-boot-opensbi.itb //u-boot proper를 포함한 전체 image
-rw-r--r-- 1 root root 1385632 6월 4 11:31 u-boot.bin
-rw-r--r-- 1 root root 24696 6월 4 11:31 u-boot.cfg
-rw-r--r-- 1 root root 15887 6월 4 11:31 u-boot.cfg.configs
-rw-r--r-- 1 root root 59509 6월 4 11:32 u-boot.dtb
-rw-r--r-- 1 root root 1326144 6월 4 11:32 u-boot.img
-rw-r--r-- 1 root root 1324254 6월 4 11:32 u-boot.itb //u-boot spl을 포함한 전체 image
-rw-r--r-- 1 root root 1020 6월 4 11:31 u-boot.lds
-rw-r--r-- 1 root root 1691754 6월 4 11:31 u-boot.map
-rwxr-xr-x 1 root root 3638946 6월 4 11:31 u-boot.srec
-rw-r--r-- 1 root root 476690 6월 4 11:31 u-boot.sym
이렇게 build된 파일은 최종적으로 FIT(Flat Image Tree) image 형태로 만들어 지고, 부팅시 통째로 사용된다. FIT image는 크게 2개가 만들어지는데, 먼저, u-boot spl과 device tree blob으로 묶여진 u-boot.itb 파일이 그것이다.
[그림 3.3] u-boot.itb 파일 구성(1)
📌 예전에는 다양한 image(uboot, dtb, initrd, kernel 등)를 개별적으로 일일이 RAM으로 올려 부팅하는 방식을 사용했다면, 최근의 추세는 FIT image 형태로 통합하여 부팅하는 방식을 선호하는 것 같다.
참고로, 위의 파일을 생성하기 위해서는 아래와 같은 ITS(Image Tree Source) file이 필요하다. ITS 파일 안에는 itb 파일을 구성하는 구성 요소와 RAM의 주소(번지) 등의 정보가 담겨 있다.
다음으로 생성되는 파일은 u-boot proper(일반적으로 말하는 u-boot을 의미함) image와 device tree blob 및 (앞으로 3.2절에서 설명할) opensbi image로 구성된 u-boot-opensbi.itb 파일이다.
[그림 3.5] u-boot-opensbi.itb 파일 구성(1)
[그림 3.6] u-boot-opensbi.itb 파일 구성(2) - uboot-opensbi.its
참고로, u-boot-opensbi.itb FIT image는 아래와 같은 명령을 통해 만들어지게 된다.
$ tools/mkimage -f uboot-opensbi.its -r u-boot-opensbi.itb
끝으로, minicom을 통해 2개의 FIT image가 차례로 구동되는 모습을 확인해 보면 다음과 같다.
3.2 RISC-V OpenSBI 개요
RISC-V에는 ARMv7, ARMv8의 Trusted Firmware 개념과 유사하게 SBI(Supervisor Binary Interface)라는 개념이 있다. SBI의 개념이 필요한 이유는 가령 kernel(S-Mode)에 대해서는 hardware의 critical한 부분 즉, memory protection, CPU control, I/O resources에 대한 직접적인 처리 권한을 제한하고, 이를 M-Mode(Machine Mode)에서만 처리 가능하도록 하므로써, system을 보다 안정적으로 통제할 수 있게 하기 위해서이다. Kernel에서는 이미 RAM에 상주하고 있는 SBI Run-time을 대상으로 SBI function 호출(ecall)을 하므로써 앞서 언급한 hardware critical한 제어가 가능하게 된다.
<RISC-V SBI privilege level>
- M-Mode (machine mode) : 최상위 특권 계층(Highest and most privileged)
- S-Mode (supervisor mode) : OS 동작을 처리하기 위해 Kernel이 사용하는 계층(Used by kernels for regular OS-level operations)
- U-Mode (user mode) : 사용자 영역을 위한 계층(user applications)
아래 두개의 그림은 OpenSBI가 포함된 (전체적인) 부팅 flow를 보여준다.
[그림 3.10] OpenSBI와 RISCV booting flow(1) [출처 - 참고문헌 8]
📌 여기서 말한는 LOADER는 u-boot SPL에 해당하며, BOOTLOADER는 u-boot(proper)을 말한다.
끝으로, RISC-V용 SBI source code 즉, OpenSBI는 아래 github에서 확인 가능하다.
3.3 u-boot booting flow
이 절에서는 u-boot의 initialization sequence(or booting flow)에 관하여 상세히 분석해 보고자 한다.
<U-Boot SPL이 구동되면서 하는 일>
1) board_init_f():
- driver initialization including DDR initialization (mininimal stack and heap: CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN)
- configuration of heap in DDR memory (CONFIG_SPL_SYS_MALLOC_F_LEN)
2) board_init_r():
- initialization of the other drivers activated in the SPL device tree
- loading and execution of U-Boot (or Kernel in Falcon mode).
📌 정확한 의미 전달을 위해 일부러 영문 원문을 그대로 옮겨 보았다.
위의 내용과 source code를 분석한 내용을 토대로, U-Boot의 booting flow를 하나의 그림으로 표현해 보면 다음과 같다. 아래 그림에서 (1) ~ (5)까지는 U-Boot SPL의 흐름을 나타내고, (6) ~ (10)까지는 U-Boot Proper의 흐름을 보여준다.
한편, 아래 2개의 코드는 위의 그림에 표현되어 있는 init_sequence_f[ ]와 init_sequence_r[ ]에 대한 정의부를 capture한 것으로, 각각의 array에 있는 callback function이 순차적으로 실행되면서 booting flow를 완성하는 것으로 이해하면 된다. 😀
[그림 3.14] u-boot booting sequence(3) - init_sequence_f [ ]
[그림 3.15] u-boot booting sequence(4) - init_sequence_r [ ]
따라서 이제 부터는 init_sequence_f [ ] 를 구성하는 callback function과 init_sequece_r [ ] 을 구성하는 callback function을 차례로 분석하기만 하면 된다.
3.4 Device Tree와 U-Boot Device Driver Model
마지막으로, U-Boot에서 사용하는 device tree와 이를 기반으로 동작하는 device driver에 관한 얘기를 안하고 넘어갈 수가 없다.
U-Boot에도 linux kernel의 경우와 마찬가지로 device driver 구현 model이 정의되어 있는데, 이를 하나의 그림으로 표현해 보면 대략적으로 다음과 같다(아래에 있는 Linux Driver Model 그림과 비교해 보는 것도 좋을 듯 하다).
📌 Linux의 경우는 중간에 Bus driver라는 것이 존재한다. 하지만 그럼에도 불구하고, 기본적인 concept은 서로 동일하다고 볼 수 있다.
U-Boot Driver Model 관련하여 보다 자세한 사항은 아래 site를 참고하기 바란다.
Driver Model을 완성하기 위해, 이제부터는 Device Tree를 살펴볼 차례이다.
arch/riscv/dts 디렉토리를 보면, 다양한 dts 파일이 존재함을 알 수 있는데, 이 중에서, RV2 board 관련 내용만 일부 추출해 보면 다음과 같다.
<RV2 보드 DTS 계층 구조>
x1.dtsi | x1_pinctrl.dtsi | x1_spm8821.dtsi
^
|
x1_orangepi-rv2.dts
Device Tree와 이를 사용하는 driver의 관계를 제대로 파악하기 위해서는 적당한 device를 하나 선정한 후, 그에 관한 코드를 들여다 보는 것이 답일 듯하다. 😋 예를 들어 qspi controller(adapter)와 이와 연결된 qspi flash(consumer device)를 device tree로 표현한 부분을 발췌해 보면 다음과 같다.
📌 QSPI Master(Controller or Adapter)는 SoC 내에 존재하고, Slave 장치는 QSPI를 통해 연결된다.
(이미 아는 바와 같이) Device Tree와 device driver를 연결하는 부분은 compatible property를 통해서이다. 따라서 아래 2개의 compatible property string에 해당하는 driver code를 검색해 보면, 관련 driver를 쉽게 찾아낼 수가 있다.
compatible = "ky,x1-qspi";
compatible = "jedec,spi-nor";
$ grep -rl "ky,x1-qspi" *
-> drivers/spi/x1_qspi.c
$ grep -rl "jedec,spi-nor" *
-> drivers/mtd/spi/sf_probe.c
앞서 U-Boot Driver Model 그림에서도 보았듯이, 각각의 driver는 U_BOOT_DRIVER라는 macro를 사용하여 정의된다. 또한 Driver를 시작하는 부분은 linux의 경우와 마찬가지로 probe( ) 함수를 사용하는 것을 알 수 있다.
휴~ 나머지 자세한 코드 분석은 독자 여러분의 몫으로 남긴다. 😓
_______________________
(좀 아쉬움이 남긴하지만) 이상으로 OrangePi RV2의 u-boot code를 대략적으로 분석해 보았다. 이어지는 장에서는 linux kernel의 이모 저모를 해부해 보는 시간을 갖도록 하자. 😋
4. Linux Kernel 이야기
이번 장에서는 OragePi RV2 BSP code에 포함되어 있는 linux kernel(6.6.63) code의 주요 흐름(booting flow)을 분석해 보기로 하겠다. 또한, OrangePi RV2 board의 device tree와 몇몇 device driver에 관한 내용을 이어 소개하고자 한다.
4.1 How to build linux kernel
우리는 이미 2장에서 (OrangePi에서 제공하는 방법을 이용하여) kernel code를 build해 보았다. 하지만, u-boot의 경우와 마찬가지로 자유롭게 kernel code를 수정하고, 테스트하기 위해서는 original linux kernel build 방식을 따르는 것이 좋겠다. 😁
$ cd kernel/orange-pi-6.6-ky
$ export PATH=/mnt/hdd/workspace/mini_devices/bpi/orangepi-build/toolchains/ky-toolchain-linux-glibc-x86_64-v1.0.1/bin:$PATH
-> toolchain path 지정
$ export ARCH=riscv
$ export CROSS_COMPILE=riscv64-unknown-linux-gnu-
$ cp -p "${EXTER}/config/kernel/${LINUXCONFIG}.config" .config
-> cp ../../external/config/kernel/linux-ky-current.config .config
📌 OrangePi BSP code에는 위의 위치에 kernel config 파일이 놓여 있다. 즉, arch/riscv/configs/x1_defconfig 파일 대신, 위의 linux-key-current.config 파일이 사용되고 있다.
$ make menuconfig
[그림 4.1] Kernel menuconfig
$ make -j16 Image modules dtbs
$ cd arch/riscv/boot; ls -la
합계 86612
drwxrwxr-x 3 root root 4096 6월 6 14:54 .
drwxrwxr-x 14 root root 4096 6월 6 14:50 ..
-rw-r--r-- 1 root root 155 6월 6 14:54 .Image.cmd
-rw-rw-r-- 1 root root 101 5월 28 17:20 .gitignore
-rwxr-xr-x 1 root root 34558464 6월 6 14:54 Image
-rw-rw-r-- 1 root root 13323594 6월 6 14:35 Image.gz
-rw-rw-r-- 1 root root 13325184 6월 6 14:35 Image.gz.itb
-rw-rw-r-- 1 root root 2442 6월 6 14:35 Image.gz.its
-rw-rw-r-- 1 root root 34560052 6월 6 14:35 Image.itb
-rw-rw-r-- 1 root root 2439 6월 6 14:35 Image.its
-rw-rw-r-- 1 root root 591 5월 28 17:34 Image.its.S
-rw-rw-r-- 1 root root 3547 5월 28 17:20 Makefile
drwxrwxr-x 10 root root 4096 5월 28 17:20 dts
-rwxrwxr-x 1 root root 961 5월 28 17:20 install.sh
-rw-rw-r-- 1 root root 143 5월 28 17:20 loader.S
-rw-rw-r-- 1 root root 206 5월 28 17:20 loader.lds.S
$ cd dts/ky
$ ls -l *.dtb
-rw-rw-r-- 1 root root 108030 6월 6 15:16 x1_orangepi-r2s.dtb
-rw-rw-r-- 1 root root 112811 6월 6 15:16 x1_orangepi-rv2.dtb
4.2 Kernel booting sequence
이 절에서는 아래의 내용을 중심으로 내용 전개를 하고자 한다.
- FIT image
- u-boot -> linux kernel
- linux kernel initialization sequence
4.3 Device Tree
3장(u-boot 이야기)에서도 device tree를 간략히 살펴 보긴 했으나, 여기서는 linux kernel 관점에서 device tree를 다시한번 조명해 보고자 한다.
#include "x1.dtsi"
#include "x1-efuse.dtsi"
#include "x1_pinctrl.dtsi"
#include "lcd/lcd_ili9881c_mipi.dtsi"
#include "x1-hdmi.dtsi"
#include "x1-lcd.dtsi"
#include "x1-camera-sdk.dtsi"
#include "x1_opp_table.dtsi"
#include "x1_thermal_cooling.dtsi"
^
|
x1_orangepi-rv2.dts
4.4 Device Driver example
이 절에서는 GPIO, I2C, SPI 등을 포함한 몇가지 device driver 예제를 소개하고자 한다.
To be contiuned...
5. LLM과 AI 이야기
OrangePi RV2 보드는 (NPU 형태는 아니지만) AI 프로세서를 탑재하고 있다. 따라서 이번 장에서는 제한된 조건이기는 하지만, 몇몇 AI LLM(Large Language Model)을 돌려 보는 시간을 갖도록 하자.
---> 이 내용은 다음 posting을 통해서 상세히 소개하고자 한다. 단, (당초 계획을 바꾸어) AI를 위해 보다 널리 사용되고 있는 NVIDIA의Jetson board를 이용할 생각이다. 😎
NVIDIA Jetson Orin Nano Super Developer Kit
To be contiuned...
6. References
[1] http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-RV2.html
[2] OrangePi_RV2_X1_User Manual_v1.0.1.pdf
[3] https://www.cnx-software.com/2025/03/08/orange-pi-rv2-low-cost-risc-v-sbc-ky-x1-octa-core-soc-2-tops-ai-accelerator/
[4] https://boilingsteam.com/orange-pi-rv2-new-risc-v-board-review/
-> orangepi rv2 board
[5] embedded-linux-slides.pdf, bootlin
[6] https://riscv.org/wp-content/uploads/2024/12/13.30-RISCV_OpenSBI_Deep_Dive_v5.pdf
[7] https://github.com/riscv-software-src/opensbi
[8] https://doc-en.rvspace.org/VisionFive/Software_Technical_Reference_Manual/VisionFive_SWTRM/compiling_opensbi.html
[9] https://www.scs.stanford.edu/~zyedidia/docs/riscv/riscv-sbi.pdf
[10] https://crvf2019.github.io/pdf/43.pdf
-> opensbi
[11] https://archive.fosdem.org/2019/schedule/event/hw_uboot/attachments/slides/3324/export/events/attachments/hw_uboot/slides/3324/Jagan_Teki___U_Boot_from_Scratch_v2019_01_edition_v2.pdf
[12] https://docs.u-boot.org/en/latest/
-> u-boot
[13] https://www.thegoodpenguin.co.uk/blog/u-boot-fit-image-overview/
[14] https://docs.u-boot.org/en/stable/usage/fit/index.html
[15] https://fitspec.osfw.foundation/
[16] https://www.gibbard.me/linux_fit_images/
[17] https://www.marcusfolkesson.se/blog/fit-vs-legacy-image-format/
[18] https://www.marcusfolkesson.se/blog/flattened-image-tree/
-> FIT image
[19] https://velog.io/@pikamon/STM32-10
[20] Linux Driver Development for Embedded Processors, Alberto Liberal de los Rios
[21] And, Google and Gemini ~
Slowboot
댓글 없음:
댓글 쓰기