Try   HackMD

Build Linux Kernel with RISC-V Arch

tags: RISC-V, 64 bits, riscv64-linux-gnu-, Linux kernel, QEMU

I use Arch Linux as my working environment.

Build the Linux kernel

$ 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

$ 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.

$ 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:

    ​​​$ 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

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

Reference