Matjaz Zibert
Created May 7, 2025 © GPL3+

Project-4: Turn Ubuntu Rootfs into a Bootable Image for Kria

Build a custom Ubuntu root filesystem and boot it on Kria over NFS or SD card — ideal for extending or replacing PetaLinux userspace.

ExpertProtip24 hours73
Project-4: Turn Ubuntu Rootfs into a Bootable Image for Kria

Things used in this project

Hardware components

AMD Kria™ KR260 Robotics Starter Kit
AMD Kria™ KR260 Robotics Starter Kit
×1

Software apps and online services

Ubuntu 22.04 base for ARM64

Story

Read more

Code

Dockerfile.arm64

Dockerfile
ARG PLATFORM=linux/arm64

# Use official Ubuntu ARM64 base image
FROM --platform=$PLATFORM ubuntu:22.04

# Set non-interactive frontend
ENV DEBIAN_FRONTEND=noninteractive

# Arguments for user setup
ARG USERNAME=kria
ARG USER_UID=1000
ARG USER_GID=1000

# Install basic packages
RUN apt-get update && apt-get install -y --no-install-recommends \
    sudo \
    locales \
    vim \
    bash-completion \
    net-tools \
    iproute2 \
    iputils-ping \
    less \
    tzdata \
    systemd \
    ca-certificates \
    && rm -rf /var/lib/apt/lists/*

# Set locale
RUN locale-gen en_US.UTF-8
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8

# Create user and set up permissions
RUN groupadd --gid $USER_GID $USERNAME && \
    useradd --uid $USER_UID --gid $USER_GID -m $USERNAME && \
    echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

# Set working directory
WORKDIR /home/$USERNAME/workspace

# Switch to user
USER root

# Default command
CMD ["/bin/bash"]

make_wic_image.sh

SH
#!/bin/bash
set -e

# Configuration
BOOT_DIR=boot
ROOTFS_DIR=rootfs
IMAGE_NAME=custom-linux-image.wic
WORK_DIR=wic-tmp
BOOT_SIZE_MB=128
ROOTFS_SIZE_MB=4096

# Clean previous build
rm -rf "$WORK_DIR" "$IMAGE_NAME"
mkdir -p "$WORK_DIR"

echo "[1/6] Creating empty image file..."
IMAGE_SIZE_MB=$((BOOT_SIZE_MB + ROOTFS_SIZE_MB + 64))  # Extra padding
dd if=/dev/zero of=$IMAGE_NAME bs=1M count=$IMAGE_SIZE_MB

echo "[2/6] Partitioning image..."
parted --script $IMAGE_NAME \
    mklabel msdos \
    mkpart primary fat32 1MiB ${BOOT_SIZE_MB}MiB \
    mkpart primary ext4 ${BOOT_SIZE_MB}MiB 100% \
    set 1 boot on

LOOPDEV=$(losetup --show -f -P "$IMAGE_NAME")
echo "Using loop device: $LOOPDEV"

echo "[3/6] Creating filesystems..."
mkfs.vfat "${LOOPDEV}p1"
mkfs.ext4 "${LOOPDEV}p2"

echo "[4/6] Copying files to image..."

mkdir -p "$WORK_DIR/boot" "$WORK_DIR/rootfs"
mount "${LOOPDEV}p1" "$WORK_DIR/boot"
mount "${LOOPDEV}p2" "$WORK_DIR/rootfs"

cp -rv ${BOOT_DIR}/* "$WORK_DIR/boot/"
cp -a ${ROOTFS_DIR}/* "$WORK_DIR/rootfs/"

sync
umount "$WORK_DIR/boot"
umount "$WORK_DIR/rootfs"
losetup -d "$LOOPDEV"

# Clean build dir
rm -rf "$WORK_DIR"

echo "[5/6] Compressing the image..."

zip ${IMAGE_NAME}.zip $IMAGE_NAME
rm $IMAGE_NAME

echo "[6/6] Image creation complete: ${IMAGE_NAME}.zip"

build.sh

SH
docker buildx build --platform linux/arm64 -f Dockerfile.arm64 -t ubuntu-arm64:kria --load .

run.sh

SH
docker run --rm -it --platform linux/arm64 \
  --privileged \
  -v $(pwd)/workspace:/home/kria/workspace \
  -v $(pwd)/ubuntu-rootfs-arm64:/mnt/rootfs \
  ubuntu-arm64:kria

mount-chroot-ro.sh

SH
#!/bin/bash
set -e

ROOTFS="/mnt/rootfs"
echo "[INFO] Mounting pseudo filesystems (read-write) into $ROOTFS"

sudo mount --rbind /proc "$ROOTFS/proc"
sudo mount --make-rslave "$ROOTFS/proc"

sudo mount --rbind /sys "$ROOTFS/sys"
sudo mount --make-rslave "$ROOTFS/sys"

sudo mount --rbind /dev "$ROOTFS/dev"
sudo mount --make-rslave "$ROOTFS/dev"

sudo mount --rbind /dev "$ROOTFS/run"
sudo mount --make-rslave "$ROOTFS/run"

# Handle resolv.conf (replace symlink or file with custom nameserver)
if [ -L "$ROOTFS/etc/resolv.conf" ] || [ -f "$ROOTFS/etc/resolv.conf" ]; then
    sudo rm -f "$ROOTFS/etc/resolv.conf"
fi
echo "nameserver 8.8.8.8" | sudo tee "$ROOTFS/etc/resolv.conf" > /dev/null

echo "[INFO] All mounts completed in read-write mode."

umount-chroot-ro.sh

SH
#!/bin/bash
#set -e

ROOTFS=/mnt/rootfs

echo "[INFO] Unmounting pseudo filesystems from $ROOTFS"

umount -lf "$ROOTFS/proc" || true
umount -lf "$ROOTFS/sys" || true
umount -lf "$ROOTFS/dev/pts" || true
umount -lf "$ROOTFS/dev" || true
umount -lf "$ROOTFS/run" || true

# Restore resolv.conf to systemd-resolved symlink for Kria runtime
if [ ! -L "$ROOTFS/etc/resolv.conf" ]; then
    sudo rm -f "$ROOTFS/etc/resolv.conf"
    sudo ln -sf /run/systemd/resolve/resolv.conf "$ROOTFS/etc/resolv.conf"
    echo "[INFO] Restored /etc/resolv.conf symlink for systemd-resolved"
fi

echo "[INFO] All mounts safely unmounted."

boot-sd.cmd

Plain text
setenv kernel_addr 0x2000000
setenv fdt_addr 0x1000000 

echo "Loading device tree..."
fatload usb 0:1 ${fdt_addr} system.dtb

echo "Loading kernel Image..."
fatload usb 0:1 ${kernel_addr} Image

echo "Setting bootargs..."
setenv bootargs 'console=ttyPS1,115200 root=/dev/sda2 rw rootwait earlycon ip=dhcp'

echo "Booting..."
booti $kernel_addr - $fdt_addr

Credits

Matjaz Zibert
14 projects • 31 followers
Hardware Engineer with Software Development Skills, Extensive background in telecommunications, FPGA integration, Callsign S59MZ (Ham-Radio)

Comments