# Build Linux Kernel with RISC-V Arch
###### tags: `RISC-V`, `64 bits`, `riscv64-linux-gnu-`, `Linux kernel`, `QEMU`
I use [Arch Linux](https://archlinux.org/) as my working environment.
## Build the [Linux kernel](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/)
```shell
$ sudo pacman -S riscv64-linux-gnu-gcc
$ make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- defconfig
$ make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j32
```
Tune the build config, if it is needed.
The option `CONFIG_SOC_VIRT` is for QEMU virtual machine.
## Quick test for the kernel with QEMU
```shell
$ sudo pacman -S qemu-system-riscv qemu-system-riscv-firmware
$ qemu-system-riscv64 -M virt -smp 4 -m 2G -display none -serial stdio -kernel arch/riscv/boot/Image -append "root=/dev/ram"
OpenSBI v1.2
____ _____ ____ _____
/ __ \ / ____| _ \_ _|
| | | |_ __ ___ _ __ | (___ | |_) || |
| | | | '_ \ / _ \ '_ \ \___ \| _ < | |
| |__| | |_) | __/ | | |____) | |_) || |_
\____/| .__/ \___|_| |_|_____/|____/_____|
| |
|_|
Platform Name : riscv-virtio,qemu
Platform Features : medeleg
Platform HART Count : 4
Platform IPI Device : aclint-mswi
Platform Timer Device : aclint-mtimer @ 10000000Hz
Platform Console Device : uart8250
Platform HSM Device : ---
Platform PMU Device : ---
Platform Reboot Device : sifive_test
Platform Shutdown Device : sifive_test
Firmware Base : 0x80000000
Firmware Size : 236 KB
Runtime SBI Version : 1.0
Domain0 Name : root
Domain0 Boot HART : 2
Domain0 HARTs : 0*,1*,2*,3*
Domain0 Region00 : 0x0000000002000000-0x000000000200ffff (I)
Domain0 Region01 : 0x0000000080000000-0x000000008003ffff ()
Domain0 Region02 : 0x0000000000000000-0xffffffffffffffff (R,W,X)
Domain0 Next Address : 0x0000000080200000
Domain0 Next Arg1 : 0x00000000bfe00000
Domain0 Next Mode : S-mode
Domain0 SysReset : yes
Boot HART ID : 2
Boot HART Domain : root
Boot HART Priv Version : v1.12
Boot HART Base ISA : rv64imafdch
Boot HART ISA Extensions : time,sstc
Boot HART PMP Count : 16
Boot HART PMP Granularity : 4
Boot HART PMP Address Bits: 54
Boot HART MHPM Count : 16
Boot HART MIDELEG : 0x0000000000001666
Boot HART MEDELEG : 0x0000000000f0b509
[ 0.000000] Linux version 6.3.1 (zack@starnight) (riscv64-linux-gnu-gcc (GCC) 12.2.0, GNU ld (GNU Binutils) 2.39) #16 SMP Sun May 7 18:03:42 CST 2023
[ 0.000000] random: crng init done
[ 0.000000] OF: fdt: Ignoring memory range 0x80000000 - 0x80200000
[ 0.000000] Machine model: riscv-virtio,qemu
[ 0.000000] efi: UEFI not found.
[ 0.000000] OF: reserved mem: 0x0000000080000000..0x000000008003ffff (256 KiB) map non-reusable mmode_resv0@80000000
[ 0.000000] Zone ranges:
[ 0.000000] DMA32 [mem 0x0000000080200000-0x00000000ffffffff]
[ 0.000000] Normal empty
[ 0.000000] Movable zone start for each node
[ 0.000000] Early memory node ranges
[ 0.000000] node 0: [mem 0x0000000080200000-0x00000000ffffffff]
[ 0.000000] Initmem setup node 0 [mem 0x0000000080200000-0x00000000ffffffff]
[ 0.000000] On node 0, zone DMA32: 512 pages in unavailable ranges
...
```
## Boot the kernel with Root Filesystem
The root filesystem can be downloaded from [starnight/build-image's Releases](https://github.com/starnight/build-image/releases).
```shell
$ qemu-system-riscv64 -M virt -smp 4 -m 2G -display none -serial stdio -kernel ~/linux-stable/arch/riscv/boot/Image -append "console=ttyS0 root=/dev/vda2 rw rootfstype=ext4" -drive file=/tmp/simple-alpine-qemu_riscv64.img,format=raw,id=hd0 -device virtio-blk-device,drive=hd0
```
## Boot the system for online debug
1. Config and build the kernel with:
* `CONFIG_DEBUG_INFO=y`
* `# CONFIG_DEBUG_INFO_REDUCED is not set`
* `CONFIG_GDB_SCRIPTS=y`
* `CONFIG_FRAME_POINTER=y`
2. Boot the QEMU virtual machine with debug feature
Append `-S` and `-s` to **QEMU** command:
```
$ qemu-system-riscv64 -h
...
-S freeze CPU at startup (use 'c' to start execution)
-overcommit [mem-lock=on|off][cpu-pm=on|off]
run qemu with overcommit hints
mem-lock=on|off controls memory lock support (default: off)
cpu-pm=on|off controls cpu power management (default: off)
-gdb dev accept gdb connection on 'dev'. (QEMU defaults to starting
the guest without waiting for gdb to connect; use -S too
if you want it to not start execution.)
-s shorthand for -gdb tcp::1234
```
The overall command to boot the QEMU virtual machine including a virtual network device:
```shell
$ qemu-system-riscv64 -M virt -smp 4 -m 2G -display none -serial stdio -kernel ~/linux-stable/arch/riscv/boot/Image -append "console=ttyS0 root=/dev/vda2 rw rootfstype=ext4" -drive file=/tmp/simple-alpine-qemu_riscv64.img,format=raw,id=hd0 -device virtio-blk-device,drive=hd0 -netdev user,id=usernet -device virtio-net-device,netdev=usernet -s -S
```
Note: It freezes CPU at startup
3. Start **RISC-V 64's GDB** in the linux project folder, then debug
```
$ sudo pacman -S riscv64-linux-gnu-gdb
$ cd ~/linux-stable && riscv64-linux-gnu-gdb vmlinux
GNU gdb (GDB) 13.1
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
...
Reading symbols from vmlinux...
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x0000000000001000 in ?? ()
(gdb) break virtnet_probe
Breakpoint 1 at 0xffffffff806b87dc: file drivers/net/virtio_net.c, line 3879.
(gdb) continue
Continuing.
[Switching to Thread 1.2]
Thread 2 hit Breakpoint 1, virtnet_probe (vdev=0xff60000001e6b040) at drivers/net/virtio_net.c:3879
3879 {
(gdb) list
3874 vi->big_packets_num_skbfrags = guest_gso ? MAX_SKB_FRAGS : DIV_ROUND_UP(mtu, PAGE_SIZE);
3875 }
3876 }
3877
3878 static int virtnet_probe(struct virtio_device *vdev)
3879 {
3880 int i, err = -ENOMEM;
3881 struct net_device *dev;
3882 struct virtnet_info *vi;
3883 u16 max_queue_pairs;
(gdb)
```
The QEMU virtual machine stops at the break point `virtnet_probe at drivers/net/virtio_net.c:3879`

## Reference
* QEMU: [‘virt’ Generic Virtual Platform (virt)](https://www.qemu.org/docs/master/system/riscv/virt.html)
* QEMU: [Documentation/Platforms/RISCV](https://wiki.qemu.org/Documentation/Platforms/RISCV)
* [Let's trace Linux Lernel with KGDB @ COSCUP 2021](https://www.slideshare.net/chienhungpan/lets-trace-linux-kernel-with-kgdb-coscup-2021)
* [OpenSBI](https://github.com/riscv-software-src/opensbi)
* [OpenSBI Deep Dive](https://riscv.org/wp-content/uploads/2019/06/13.30-RISCV_OpenSBI_Deep_Dive_v5.pdf)