Cross Compiling Kernel, Kernel Module, and User Program for PYNQ

Check PYNQ Version

First, we need to check the PYNQ version, architecture, and kernel version on the target board.

On the target board, check the PYNQ version:

xilinx@pynq:~/workspace$ pynq --version
PYNQ version: 3.0.1
Path: /usr/local/share/pynq-venv/lib/python3.10/site-packages/pynq
Git Id: 16022d5f2c61c7e5e1d4aabcfc9b3e4c91b491b6

Then, check the kernel version and CPU architecture:

xilinx@pynq:~/workspace$ uname -r -m
5.15.19-xilinx-v2022.1 armv7l

If it says armv7l, then it is 32-bit, but if it is aarch64, then it is 64-bit.

Setup Build Machine

On the build machine, we need to install a cross-compilation toolchain and several tools. I am using Ubuntu 18.04.4 running on a virtual machine.

First, update the system and install the required tools.

sudo apt-get update
sudo apt-get install make build-essential libncurses-dev bison flex libssl-dev libelf-dev

Then, install the cross-compiler depending on your target board architecture.

Install this for 32-bit:

Install this for 64-bit:

Download the Kernel Source

For my PYNQ version, this kernel version is used: https://github.com/Xilinx/linux-xlnx/tree/xlnx_rebase_v5.15_LTS_2022.1_update

So, download that via GitHub or git clone on the build machine.

Get the Kernel Configuration

Now we compile the kernel with a configuration that is close to what was used on our target board. To do that, we need to extract configuration from the target board by reading the config.gz.

On the target board, do the following command:

We will use the .config file to configure and compile the kernel source that we have downloaded before.

Go to the following folder and get the Module.symvers file for later use when compiling the kernel.

So, we have two files .config and Module.symvres that are required when we compile the kernel.

Compile the Kernel

On your build machine, extract the kernel source file that we have downloaded, linux-xlnx-xlnx_rebase_v5.15_LTS_2022.1_update.zip.

Copy the following files to the main location of extracted folder:

  • .config

  • Module.symvers

We first need to set the ARCH and CROSS_COMPILE variables.

For 32-bit system:

For 64-bit system:

Run this command to read the existing .config file that was used for an old kernel. Then, it sets every option (that are not found in the file) to their default value without asking interactively.

Run this command to build the kernel for 32-bit system:

Or for 64-bit system:

You will find the kernel image file in this location for 32-bit system:

Or for 64-bit system:

Use zImage for 32-bit and Image for 64-bit.

Convert Image File

PYNQ uses an image.ub file, so we need to convert the image file and devicetree to image.ub.

Install the required tools:

Dump Image

Copy the original image.ub file from the target board to build the machine.

Use this command to list the content of image.ub:

The contents are the kernel (parition 0) and devicetree (parition 1).

To dump the kernel we can use the following command:

To dump the devicetree we can use the following command:

Modify Devicetree

To convert the devicetree from .dtb to .dts, we can use the following command:

Open the devicetree source (.dts) using a text editor, modify the setting that you need, and compile it back to binary (.dtb).

To convert the devicetree from .dts back to .dtb, we can use the following command:

Make Image

Download the .its from https://github.com/Xilinx/PYNQ/blob/master/sdbuild/boot/image_arm.its for 32-bit or https://github.com/Xilinx/PYNQ/blob/master/sdbuild/boot/image_aarch64.its for 64-bit.

Put the required files in one folder: zImage, system.dtb, image.its. Then, run the following command to build new image.ub.

Compile the Kernel Module

On the build machine, create an example C kernel module file named hello.c:

Create a Makefile (must be named as this with capital M) for compiling the hello.c. Put this file on the same folder with hello.c.

This Makefile is for 32-bit system. Change the KERNELDIR to your respective location.

This Makefile is for 64-bit system. Change the KERNELDIR to your respective location.

Run the make command, and the result should be similar to this:

You can find the hello.ko. Copy this file to your target board.

Run using insmod and check the result on the target board:

If you find an error like this, then your compiled kernel version or configuration is different from the one that is running on your board.

Compile the User Program

Create the C user space program named hello.c.

Compile the code in 32-bit system.

Compile the code in 64-bit system.

On the target board, change the permission to hello, and rund the progam as root:

References

Last updated