Linux Kernel Module Initialization of FPGA Soft-Processor Instruction Memory

During the development of a hardware implementation of the Homa transport protocol I experimented with using a RISC-V soft-processor for running small user defined codelets. The Linux Kernel was responsible for initializing the PicoRV soft-processors instruction memory. This document details how to take a cross compiled RISC-V ELF file, dump it to a binary blob, convert it to an x64-64 elf, and compile it into the kernel module.

Cross-compiling for the PicoRV was accomplished with the following command, which generated a RISC-V ELF file called firmware.

riscv32-unknown-elf-gcc -ffreestanding -nostartfiles -nostdlib -Qn -static -Wl,--strip-debug,-Bstatic,-T,picorv.ld homa.c reset.s -o firmware 

The PicoRV expected a raw binary blob of instructions, not an ELF, so can we convert firmware to a blob.

riscv32-unknown-elf-objcopy -O binary firmware

The PicoRV's instruction memory space was mapped to a DMA region within the kernel module and needed to be initialized with firmware, now a blob of RISC-V instructions. The faculties for reading files from within the kernel module are limited. This made it challenging to read the contents of firmware and write it to the PicoRV's memory. Instead, I opted to copy the binary blob of RISC-V instructions into an x86 ELF file, which I would then link into the kernel module at compilation.

Copying the firmware blob to an x86 ELF can be accomplished with the following command.

objcopy -I binary -O elf64-x86-64 -B i386:x86-64 firmware firmware.o

The object file can be included in the kernel module build procedure.

obj-m := homanicmodule.o
homanicmodule-y += homanic.o firmware.o

PWD := $(CURDIR)

CFLAGS_homanic.o := -mavx2

all: 
        cp ../firmware/firmware.o .
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean: 
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
        rm -rf app

Then the raw binary blob can be accessed from within the kernel module as a char buffer.

extern char _binary_firmware_start[];
extern char _binary_firmware_end[];

RISC-V instructions can be read from this char buffer and written to the DMA buffer associated with the PicoRV's memory space.

Date: Updated 2024-5-21

Author: Colin Drewes (drewes@cs.stanford.edu)

Created: 2024-05-22 Wed 00:40

Validate