Building an Embedded Linux Environment on RISC-V Architecture: A Complete Guide from Scratch

Building an Embedded Linux Environment on RISC-V Architecture: A Complete Guide from Scratch

As an open instruction set architecture, RISC-V is gaining increasing attention in the embedded field. This article takes the SiFive HiFive Unleashed development board as an example to detail the process of setting up an embedded Linux development environment under the RISC-V architecture.

Building an Embedded Linux Environment on RISC-V Architecture: A Complete Guide from Scratch

Hardware and Software Requirements

Hardware requirements:

  • SiFive HiFive Unleashed (FU540)
  • 16GB DDR4 RAM
  • 32GB microSD card
  • USB-JTAG debugger
  • Power adapter
  • Gigabit Ethernet cable

Software requirements:

  • Host system: Ubuntu 22.04 LTS
  • RISC-V GNU toolchain
  • OpenOCD
  • Freedom-U-SDK
  • QEMU RISC-V emulator

Overview of the Development Environment

The RISC-V development environment includes a cross-compilation toolchain, OpenSBI firmware, U-Boot, Linux kernel, and root filesystem. We will build a complete development chain that supports local development and QEMU emulation testing.

Toolchain Installation and Configuration

# Install basic development tools
sudo apt-get update && sudo apt-get install -y \
    autoconf automake autotools-dev curl python3 \
    libmpc-dev libmpfr-dev libgmp-dev gawk build-essential \
    bison flex texinfo gperf libtool patchutils bc zlib1g-dev \
    libexpat-dev pkg-config git libglib2.0-dev libpixman-1-dev

# Build RISC-V toolchain
git clone https://github.com/riscv/riscv-gnu-toolchain
cd riscv-gnu-toolchain
./configure --prefix=/opt/riscv --with-arch=rv64gc --with-abi=lp64d
make -j$(nproc)

# Set environment variables
echo 'export PATH=$PATH:/opt/riscv/bin' >> ~/.bashrc
echo 'export RISCV=/opt/riscv' >> ~/.bashrc
source ~/.bashrc

OpenSBI Compilation

# Get OpenSBI source code
git clone https://github.com/riscv/opensbi.git
cd opensbi

# Compile OpenSBI firmware
make PLATFORM=sifive/fu540 CROSS_COMPILE=riscv64-unknown-linux-gnu-

# Copy firmware file
cp build/platform/sifive/fu540/firmware/fw_payload.elf /boot/

U-Boot Build

# Get U-Boot source code
git clone https://github.com/u-boot/u-boot.git
cd u-boot

# Configure U-Boot
make sifive_unleashed_defconfig
make CROSS_COMPILE=riscv64-unknown-linux-gnu- -j$(nproc)

# Create boot script
cat > boot.cmd << "EOF"
setenv bootargs "console=ttySIF0,115200 root=/dev/mmcblk0p2 rw"
load mmc 0:1 ${kernel_addr_r} Image
load mmc 0:1 ${fdt_addr_r} sifive/hifive-unleashed-a00.dtb
booti ${kernel_addr_r} - ${fdt_addr_r}
EOF

mkimage -A riscv -O linux -T script -C none -n "Boot Script" \
    -d boot.cmd boot.scr

Kernel Configuration and Compilation

# Get Linux kernel source code
git clone https://github.com/torvalds/linux.git
cd linux
git checkout v6.1

# Configure kernel
make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- defconfig
make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- menuconfig

# Compile kernel
make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- -j$(nproc) Image
make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- -j$(nproc) dtbs

Root Filesystem Build

# Use Buildroot to build root filesystem
git clone https://github.com/buildroot/buildroot.git
cd buildroot

# Configure Buildroot
make riscv64_defconfig
make menuconfig

# Build system
make -j$(nproc)

# Create custom initialization script
cat > board/sifive/rootfs_overlay/etc/init.d/S99custom << "EOF"
#!/bin/sh
case "$1" in
  start)
    echo "Starting custom services..."
    # Add custom service start commands
    ;;
  stop)
    echo "Stopping custom services..."
    ;;
  *)
    echo "Usage: $0 {start|stop}"
    exit 1
esac
EOF
chmod +x board/sifive/rootfs_overlay/etc/init.d/S99custom

QEMU Environment Configuration

# Install QEMU
sudo apt-get install -y qemu-system-riscv64

# Create QEMU startup script
cat > run_qemu.sh << "EOF"
#!/bin/bash
qemu-system-riscv64 \
    -machine sifive_u \
    -smp 4 \
    -m 8G \
    -nographic \
    -bios fw_payload.elf \
    -kernel Image \
    -append "console=ttyS0 root=/dev/vda" \
    -drive file=rootfs.ext4,format=raw,id=hd0 \
    -device virtio-blk-device,drive=hd0 \
    -netdev user,id=net0 \
    -device virtio-net-device,netdev=net0
EOF
chmod +x run_qemu.sh

Development Tool Configuration

# VSCode configuration
cat > .vscode/c_cpp_properties.json << "EOF"
{
    "configurations": [
        {
            "name": "RISC-V",
            "includePath": [
                "${workspaceFolder}/**",
                "/opt/riscv/riscv64-unknown-linux-gnu/include"
            ],
            "defines": [],
            "compilerPath": "/opt/riscv/bin/riscv64-unknown-linux-gnu-gcc",
            "cStandard": "c11",
            "cppStandard": "c++14",
            "intelliSenseMode": "gcc-x64"
        }
    ],
    "version": 4
}
EOF

# GDB debugging configuration
cat > .gdbinit << "EOF"
set architecture riscv:rv64
set remotetimeout 250
target remote localhost:1234
EOF

Automated Build Tools

# Create Makefile
cat > Makefile << "EOF"
CROSS_COMPILE ?= riscv64-unknown-linux-gnu-
ARCH ?= riscv

all: opensbi u-boot kernel rootfs

opensbi:
 $(MAKE) -C opensbi PLATFORM=sifive/fu540 CROSS_COMPILE=$(CROSS_COMPILE)

u-boot:
 $(MAKE) -C u-boot sifive_unleashed_defconfig
 $(MAKE) -C u-boot CROSS_COMPILE=$(CROSS_COMPILE)

kernel:
 $(MAKE) -C linux ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) defconfig
 $(MAKE) -C linux ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -j$(nproc)

rootfs:
 $(MAKE) -C buildroot riscv64_defconfig
 $(MAKE) -C buildroot -j$(nproc)

clean:
 $(MAKE) -C opensbi clean
 $(MAKE) -C u-boot clean
 $(MAKE) -C linux ARCH=$(ARCH) clean
 $(MAKE) -C buildroot clean

.PHONY: all opensbi u-boot kernel rootfs clean
EOF

Debugging Tool Setup

# OpenOCD configuration
cat > sifive-unleashed.cfg << "EOF"
adapter driver ftdi
ftdi_vid_pid 0x0403 0x6010
ftdi_channel 0
ftdi_layout_init 0x0008 0x001b
transport select jtag
adapter speed 10000

set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5

set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME riscv -chain-position $_TARGETNAME
$_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1

init
halt
EOF

Troubleshooting Common Issues

  1. Handling Compilation Errors:
# Clean build cache
make clean
make distclean
rm -rf build/

# Check toolchain version
riscv64-unknown-linux-gnu-gcc --version
  1. Device Tree Issues:
# Validate device tree
dtc -I dtb -O dts -f sifive/hifive-unleashed-a00.dtb > check.dts

Through the above configuration, we have established a complete RISC-V development environment. This environment supports local development and QEMU emulation, meeting most RISC-V embedded Linux development needs. It is recommended to further study the RISC-V privileged instruction set, interrupt handling mechanisms, and development methods for SoC-specific features.

Leave a Comment