RISC-V Assembly Programming with openEuler on QEMU
Introduction to openEuler for RISC-V Development
This guide provides a comprehensive approach to setting up a RISC-V development environment using openEuler Linux distribution. After working extensively with various distributions on RISC-V architecture, I found that openEuler offers superior stability and package management compared to other alternatives like Fedora, which often suffers from dependency conflicts and instability on RISC-V platforms.
Understanding openEuler
openEuler represents a significant advancement in the Chinese open-source ecosystem. Originally derived from EulerOS developed by Huawei based on Red Hat Enterprise Linux source code, it has evolved into an independent community-driven project managed by the OpenAtom Foundation.
The evolution path of openEuler reflects the changing landscape of enterprise Linux distributions:
- Originated from the gap left by CentOS's transition away from stable long-term support
- Expanded beyond server applications to support cloud computing, edge computing, and embedded systems
- Maintains packages acros multiple architectures including ARM, SW64, RISC-V, and LoongArch
Current Version Landscape
openEuler maintains several active versions including 24.03 LTS, 22.03 LTS SP3, 20.03 LTS SP4, and 22.03 LTS SP1. For development purposes, we'll focus on the latest stable release, openEuler 24.03.
Setting Up openEuler RISC-V Environment
Acquiring System Images
Download the appropriate openEuler RISC-V image files from the official repository:
mkdir riscv_environment
cd riscv_environment
wget https://repo.tarsier-infra.isrc.ac.cn/openEuler-RISC-V/testing/20240618/v0.3/QEMU/fw_payload_oe_uboot_2304.bin
wget https://repo.tarsier-infra.isrc.ac.cn/openEuler-RISC-V/testing/20240618/v0.3/QEMU/openEuler-24.03-V1-base-qemu-testing.qcow2.zst
If download interruptions occur, use the resume option:
wget https://repo.tarsier-infra.isrc.ac.cn/openEuler-RISC-V/testing/20240618/v0.3/QEMU/openEuler-24.03-V1-base-qemu-testing.qcow2.zst -c
Decompressing the Image
Two methods are available for decompression:
Method 1 - Using zstd:
zstd -d openEuler-24.03-V1-base-qemu-testing.qcow2.zst
Install zstd if not available:
sudo dnf install zstd
Method 2 - Using qemu-img:
qemu-img convert -c -O qcow2 -o compression_type=zstd openEuler-24.03-V1-base-qemu-testing.qcow2.zst openEuler-24.03-V1-base-qemu-testing.qcow2
Creating Launch Script
Create a custom launch script named launch_riscv.sh:
#!/bin/bash
qemu-system-riscv64 \
-nographic -machine virt \
-smp 8 -m 4G \
-bios fw_payload_oe_uboot_2304.bin \
-drive file=openEuler-24.03-V1-base-qemu-testing.qcow2,format=qcow2,id=disk0 \
-object rng-random,filename=/dev/urandom,id=rng_device \
-device virtio-gpu \
-device virtio-rng-pci,rng=rng_device \
-device virtio-blk-pci,drive=disk0 \
-device virtio-net-pci,netdev=network_interface \
-netdev user,id=network_interface,hostfwd=tcp::10000-:22
The port forwarding configuration maps local port 10000 to virtual machine port 22, enabling SSH access.
System Initialization
Make the script exeecutable and launch the system:
chmod +x launch_riscv.sh
./launch_riscv.sh
Upon successful boot, you'll see OpenSBI initialization messages. OpenSBI serves as the firmware layer in RISC-V systems, providing the interface between hardware and operating system.
Default login credentials:
Username: root
Password: openEuler12#$
Environment Configuration
Security Setup
Change the default root password:
[root@openeuler-riscv64 ~]# passwd
Changing password for user root.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
SSH Access Configuration
For better terminal experience, establish SSH connection:
ssh -p 10000 root@localhost
Repository Configuration
Navigate to repository directory and create new configuration:
cd /etc/yum.repos.d
rm -rf openEuler.repo
vim openEuler.repo
Add the following repository configuration:
[OS]
name=OS
baseurl=http://repo.openeuler.org/openEuler-24.03-LTS/OS/$basearch/
enabled=1
gpgcheck=1
gpgkey=http://repo.openeuler.org/openEuler-24.03-LTS/OS/$basearch/RPM-GPG-KEY-openEuler
[everything]
name=everything
baseurl=http://repo.openeuler.org/openEuler-24.03-LTS/everything/$basearch/
enabled=1
gpgcheck=1
gpgkey=http://repo.openeuler.org/openEuler-24.03-LTS/everything/$basearch/RPM-GPG-KEY-openEuler
[EPOL]
name=EPOL
baseurl=http://repo.openeuler.org/openEuler-24.03-LTS/EPOL/main/$basearch/
enabled=0
gpgcheck=1
gpgkey=http://repo.openeuler.org/openEuler-24.03-LTS/OS/$basearch/RPM-GPG-KEY-openEuler
Package Management Optimizaton
Update package database and refresh system:
rpm --rebuilddb
dnf update
Install essential development tools:
dnf install gcc gcc-c++ rust python zsh tmux cmake neofetch git htop vim gdb
Configure DNF for faster downloads:
vim /etc/dnf/dnf.conf
Modify configuration:
[main]
arch=riscv64
max_parallel_downloads=10
gpgcheck=True
installonly_limit=3
clean_requirements_on_remove=True
best=False
skip_if_unavailable=True
fastestmirror=True
keepcache=True
assumeyes=False
Shell Enhancement
Installing Oh My Zsh
Set up enhanced shell environment:
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
Powerlevel10k Theme Installation
Enhance terminal appearance:
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k
Configure theme in .zshrc:
ZSH_THEME="powerlevel10k/powerlevel10k"
Essential Plugin Installation
Add productivity plugins:
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
Tmux Configuration
Set up terminal multiplexer:
cd
git clone https://github.com/gpakosz/.tmux.git
ln -s -f .tmux/.tmux.conf
cp .tmux/.tmux.conf.local .
Custom tmux settings:
set -g mouse on
bind -n MouseDown2Pane choose-window
bind | split-window -h
bind - split-window -v
bind Space next-layout
bind y setw synchronize-panes
RISC-V Function Calling Convention
Understanding register usage during function calls is crucial for RISC-V assembly programming. The calling convention defines which registers need preservation across function calls:
Examine compiler-generated assembly for function calls:
Example C program (example.c):
int helper_function(void) {
return 42;
}
int main_function(void) {
int result = helper_function();
return result + 1;
}
Generate assembly output:
gcc -S example.c -o example.S
The generated assembly demonstrates proper stack frame management and register preservation according to RISC-V calling conventions.