GSOC 2025: How To Start With OpenRISC

2025年5月9日的清晨,阳光透过窗帘洒在书桌上,我像往常一样打开邮箱,例行公事般地扫视着堆积如山的垃圾邮件和社区订阅信件(尽管这些内容我从未真正点开过^v^)。距离我提交GSOC提案已经过去整整一个月了,最初的几天里,我几乎每隔几分钟就会刷新一次收件箱,满心期待能收到回复;而如今,这份期待早已被时间冲淡,只剩下一种机械般的习惯,让我每天早晨仍会不自觉地检查邮箱。

正当我准备关掉页面,心想今天大概又是一无所获时,屏幕突然一闪——邮箱自动刷新,一封崭新的邮件赫然出现在最上方。

GSoC 2025: Congratulations, your proposal with Free and Open Source Silicon Foundation has been accepted!》

GSoC 2025: Congratulations

我知道,我的任务开始了——这不再是一个普通的周五早晨,而是我开源生涯真正的起点。


在提案通过的那天,我正式与导师Shorne展开合作。他给我的第一个任务是搭建OpenRISC架构的编译工具链,并通过QEMU启动一个OpenRISC架构的Linux系统

起初,我花费了大量时间编写自己的构建脚本(OpenRISC-Build),但后来才发现Shorne早已维护了一个成熟的工具库(or1k-util)。由于走了弯路,两周过去,我仍未能成功启动OpenRISC Linux系统。

当Shorne询问进展时,我告诉他我的脚本卡在了启动阶段。他反问道:“为什么不直接用or1k-util?”这时我才意识到,自己又陷入了过度发散思维的陷阱,白白浪费了不少时间。

于是,我转而使用or1k-util,按照文档指引一步步配置,最终顺利运行起了OpenRISC Linux系统。

Really Docs For How To Start

本章节是正式的对如何通过or1k-util实现在本地通过QEMU运行起一个真正的OpenRISC架构的Linux内核,并且可以通过该内核进行调试的教程。

我当前使用的环境如下所示:

1
2
3
4
Ubuntu 24.10

$ uname -a
Linux nyaos 6.11.0-26-generic #26-Ubuntu SMP PREEMPT_DYNAMIC Sat Apr 12 11:25:41 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux

由于OpenRISC架构的主线版本的glibc暂时有bug,因此我们暂时使用了指定版本的编译链版本:

1
2
3
OR1K_GCC_URL="https://mirrors.aliyun.com/gnu/gcc/gcc-14.2.0/gcc-14.2.0.tar.gz"
OR1K_BINUTILS_GDB_URL="https://github.com/bminor/binutils-gdb.git"
OR1K_NEWLIB_URL="ftp://sourceware.org/pub/newlib/newlib-4.5.0.20241231.tar.gz"

在一切开始之前,我们需要确定运行并调试一个OpenRISC架构的Linux内核到底需要什么?

  • QEMU OpenRISC
  • rootfs
  • or1k-linux-gcc
  • or1k-elf-gdb
  • linux OpenRISC

虽然在前面提到,我浪费了很多时间在自己的脚本上,但是由于or1k-utils本身并不会自动下载对应的源码/软件包,只会对指定目录下是否存在对应的源码/软件包进行检测。因此我们的下载工具使用OpenRISC-Build进行自动下载,后续的编译工作则是交给or1k-utils进行。

DownLoad Source With OpenRISC-Build

首先,我们需要将脚本仓库克隆到一个任意位置:

1
git clone https://github.com/ChenMiaoi/GSO2025-OpenRISC.git OpenRISC-Build

注意:OpenRISC-Build现只有下载源码的功能,一切的编译操作由or1k-utils来进行

当仓库克隆完毕后,我们就可以进入到仓库中,然后进行源码的下载。

1
2
3
4
5
6
7
8
9
cd OpenRISC-Build
./build-or1k.sh --get-rootfs
./build-or1k.sh --get-tools

source ~/.bashrc

./build-or1k.sh --get-qemu
./build-or1k.sh --get-linux
./build-or1k.sh --get-or1k-utils

下表是关于脚本下载各种源码的命令,下载的内容以及各自源码存放的位置(根据or1k-utils所设置)

Command Work Dir
get rootfs download rootfs $HOME/work/openrisc/buildroot-rootfs
get tools download or1k-linux- $HOME/work/gnu-toolchain/local
download gcc-14.2.0 $HOME/work/gnu-toolchain/gcc
download binutils-gdb $HOME/work/gnu-toolchain/binutils-gdb
download newlib-4.5.0.20241231 $HOME/work/gnu-toolchain/newlib
get qemu download qemu $HOME/work/openrisc/qemu
get linux download linux $HOME/work/linux
get or1k-utils download or1k-utils $HOME/work/openrisc/or1k-utils

注意:一切的源码均会下载到$HOME/work/openrisc$HOME/work/linux以及$HOME/work/toolchain
注意:当使用--get-tools后,建议source ~/.bashrc一下

下面是关于各自命令下载后的目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ tree -L 1 work/
work/
├── gnu-toolchain
├── linux
└── openrisc

$ tree -L 1 work/gnu-toolchain/
work/gnu-toolchain/
├── binutils
├── gcc
├── gdb
├── local
└── newlib

$ tree -L 1 work/openrisc/
work/openrisc/
├── buildroot-rootfs
├── or1k-utils
├── qemu
└── toolchain

当一切准备就绪后,我们就可以开始进行编译了。

Build Source With Or1k-utils

虽然已经说过很多次了,但在这里还需要强调:一切的编译步骤都是通过下载的or1k-utils进行

因此,我们进入or1k-utils目录中:

1
cd or1k-utils

BUILD QEMU

首先,我们应该编译QEMUOR1K-ELF-工具链:

1
2
./qemu/config.qemu
./scripts/qemu-build

编译完成后,可以查看对应目录以及查看其对应的版本信息:

1
2
3
4
5
6
7
ls $HOME/work/openrisc/qemu/build
qemu-or1k
qemu-system-or1k

$HOME/work/openrisc/qemu/build/qemu-system-or1k --version
QEMU emulator version 10.0.50
Copyright (c) 2003-2025 Fabrice Bellard and the QEMU Project developers

注意:我们并不需要安装QEMU到一个指定路径,因为后续的使用均直接使用了编译目录的QEMU

BUILD OR1K-ELF

然后,我们开始编译OR1K-ELF-工具链:

1
NOTIFY=n ./toolchains/newlib.build

这里我们传递了一个NOTIFY参数,这时因为在newlib.build中有一个MAILTO参数,我并不需要发送邮件给自己或其他人,因此,这里使用NOTIFY=n禁止发送。

由于编译脚本会将所有的编译信息重定向到$HOME/work/gnu-toolchain/log/${CROSS}-build.log中,因此你可以使用下面的命令来实时监控:

1
tail -f $HOME/work/gnu-toolchain/log/or1k-elf-build.log

编译完成后,我们可以查看指定目录:

1
2
3
4
5
6
7
ls $HOME/work/gnu-toolchain/local/
bin include lib libexec or1k-elf share

ls $HOME/work/gnu-toolchain/local/bin/
or1k-elf-addr2line or1k-elf-c++ or1k-elf-elfedit or1k-elf-gcc-14.2.0 or1k-elf-gcc-ranlib or1k-elf-gcov-tool or1k-elf-gprof or1k-elf-ld.bfd or1k-elf-objdump or1k-elf-run or1k-elf-strip
or1k-elf-ar or1k-elf-c++filt or1k-elf-g++ or1k-elf-gcc-ar or1k-elf-gcov or1k-elf-gdb or1k-elf-gstack or1k-elf-nm or1k-elf-ranlib or1k-elf-size
or1k-elf-as or1k-elf-cpp or1k-elf-gcc or1k-elf-gcc-nm or1k-elf-gcov-dump or1k-elf-gdb-add-index or1k-elf-ld or1k-elf-objcopy or1k-elf-readelf or1k-elf-strings

我们着重需要注意的是两个东西:or1k-elf-gccor1k-elf-gdb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$HOME/work/gnu-toolchain/local/bin/or1k-elf-gcc -v
Using built-in specs.
COLLECT_GCC=/home/nya/work/gnu-toolchain/local/bin/or1k-elf-gcc
COLLECT_LTO_WRAPPER=/home/nya/work/gnu-toolchain/local/libexec/gcc/or1k-elf/14.2.0/lto-wrapper
Target: or1k-elf
Configured with: /home/nya/work/gnu-toolchain/gcc/configure --target=or1k-elf --prefix=/home/nya/work/gnu-toolchain/local --with-gnu-ld --with-gnu-as --disable-nls --disable-lto --disable-libssp --disable-shared --with-multilib-list=mcmov --enable-languages=c,c++ --with-newlib
Thread model: single
Supported LTO compression algorithms: zlib
gcc version 14.2.0 (GCC)

$HOME/work/gnu-toolchain/local/bin/or1k-elf-gdb -v
GNU gdb (GDB) 17.0.50.20250605-git
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

BUILD LINUX

当前面的所有准备就绪后,我们就可以编译OpenRISC架构的Linux内核了。

1
./scripts/make-or1k-linux virt_defconfig

Shorne曾问过我: “did you compile the kernel with debug symbols?”
当时我以为我会,事实上,我并不会。因此,Shorne手把手带我编译了一遍,感谢Shorne

接下来我们需要编译一个带调试信息的内核,因此我们使用menuconfig进行配置。

1
./scripts/make-or1k-linux menuconfig

or1k menuconfig

如上图所示,当你执行menuconfig后会进入如下的TUI界面,我们需要通过这样的路径:

1
2
3
4
5
6
7
8
Kernel hacking  --->
Kernel debugging ---> y

Kernel hacking --->
Compile-time checks and compiler options --->
Debug information (Disable debug information) --->
Rely on the toolchain's implicit default DWARF version ---> y
Provide GDB scripts for kernel debugging ---> y

menuconfig debug info

通过上面的设置,我们就将三个关键选项设置好了:

  • Kernel debugging
  • Rely on the toolchain’s implicit default DWARF version
  • Provide GDB scripts for kernel debugging

然后我们就可以开始编译内核:

1
./scripts/make-or1k-linux

如果一切没有报错,我们就可以检查内核目录下是否存在vmlinux文件:

1
2
3
4
5
ls $HOME/work/linux/
vmlinux

file $HOME/work/linux/vmlinux
/home/nya/work/linux/vmlinux: ELF 32-bit MSB executable, OpenRISC, version 1 (SYSV), statically linked, BuildID[sha1]=bab6c2d0b0a5111785bda2c9268c7a3871e3dc6e, with debug_info, not stripped

至此,所有的编译工作就完成了。

Starting And Debugging

在启动内核之前,我们需要了解启动脚本的一些参数。

Shorne又一次拷打我:”do you know what commands to run? For example, how to start qemu in debug mode?”

or1k-utils中,启动内核所使用的脚本为qemu-or1k-linux,其中有一个-S参数与QEMU的调试相关:

1
2
# Debug, add -S to stop on startup
DEBUG="-gdb tcp::10001"

我当时回答Shorne:”add the -S, using the qemu-linux -S”

显而易见的,这是截然相反的。如果我们想要调试内核,就不应该加上-S参数,这个脚本默认启动了调试端口。因此,对于调试,我们可以直接运行脚本(当然,直接启动也是可以的)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
./scripts/qemu-or1k-linux
[ 0.000000] FDT at (ptrval)
[ 0.000000] random: crng init done
[ 0.000000] Linux version 6.15.0-dirty (nya@nyaos) (or1k-linux-gcc (GCC) 14.2.0, GNU ld (GNU Binutils) 2.43.1) #2 SMP Fri Jun 13 16:02:54 UTC 2025
[ 0.000000] OF: reserved mem: Reserved memory: No reserved-memory node in the DT
[ 0.000000] CPU: OpenRISC-13 (revision 8) @20 MHz
[ 0.000000] -- dmmu: 128 entries, 1 way(s)
[ 0.000000] -- immu: 128 entries, 1 way(s)
[ 0.000000] -- additional features:
[ 0.000000] -- power management
[ 0.000000] -- PIC
[ 0.000000] -- timer
[ 0.000000] Initial ramdisk not found
......
[ 0.360000] EXT4-fs (vda2): INFO: recovery required on readonly filesystem
[ 0.360000] EXT4-fs (vda2): write access will be enabled during recovery
[ 1.590000] EXT4-fs (vda2): orphan cleanup on readonly fs
[ 1.590000] EXT4-fs (vda2): recovery complete
[ 1.600000] EXT4-fs (vda2): mounted filesystem d4e1e6f8-942f-4d45-9afe-4e73dcfff064 ro with ordered data mode. Quota mode: disabled.
[ 1.600000] VFS: Mounted root (ext4 filesystem) readonly on device 254:2.
[ 1.600000] devtmpfs: mounted
[ 1.640000] Freeing unused kernel image (initmem) memory: 264K
[ 1.640000] This architecture does not have kernel memory protection.
[ 1.640000] Run /sbin/init as init process
INIT: version 3.13 booting
INIT: No inittab.d directory found
[ 1.800000] EXT4-fs (vda2): re-mounted d4e1e6f8-942f-4d45-9afe-4e73dcfff064 r/w.
[ 1.920000] Adding 2097144k swap on /dev/vda1. Priority:-2 extents:1 across:2097144k
INIT: Entering runlevel: 3
Seeding 256 bits without crediting
Saving 256 bits of creditable seed for next boot
Starting syslogd: OK
Starting klogd: OK
Running sysctl: OK
Starting network: OK
Starting sntp: sntp 4.2.8p18@1.4062-o Wed Apr 16 22:01:36 UTC 2025 (1)
libgcc_s.so.1 must be installed for pthread_exit to work
/etc/init.d/S48sntp: line 15: 124 Aborted /usr/bin/$DAEMON $SNTP_ARGS -K $SNTP_KEY_CACHE $SNTP_SERVERS
FAIL
Starting crond: OK
Starting sshd: OK

Welcome to Linux on OpenRISC
buildroot login:

默认的用户为root,并且没有密码,因此我们键入root敲击回车后,即可直接进入系统。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Welcome to Linux on OpenRISC
buildroot login: root
_ __ __
| | /| / /__ / /______ __ _ ___
| |/ |/ / -_) / __/ _ \/ ' \/ -_)
|__/|__/\__/_/\__/\___/_/_/_/\__/
/ /____
/ __/ _ \
____ _____ \__/\___/________ ______
/ __ \___< / /_____| | / / _/ _ \/_ __/
/ /_/ / __/ / '_/___/ |/ // // , _/ / /
\____/_/ /_/_/\_\ |___/___/_/|_| /_/

32-bit OpenRISC CPUs on a QEMU Virt Platform
# uname -a
Linux buildroot 6.15.0-dirty #2 SMP Fri Jun 13 16:02:54 UTC 2025 openrisc GNU/Linux

如果我们想要调试内核,则通过编译好的or1k-elf-gdb进行调试。

注意:远程调试端口号为10001

1
2
3
or1k-elf-gdb vmlinux
(gdb) target remote :10001
Remote debugging using :10001

qemu debug