Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 19 additions & 12 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,20 @@ jobs:
subject-digest: ${{ steps.build-and-push.outputs.digest }}
push-to-registry: true

build-riscv:

build-alt-arch:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- arch: riscv
dockerfile: Dockerfile.riscv64
tag_suffix: riscv
push_attestation: true
- arch: s390x
dockerfile: Dockerfile.s390x
tag_suffix: s390x
push_attestation: false

permissions:
packages: write
contents: read
Expand All @@ -112,29 +123,25 @@ jobs:
run: |
REGISTRY=$(./docker.sh print-registry)
echo "REGISTRY=${REGISTRY}" >> $GITHUB_ENV
echo "Registry to be published is: ${REGISTRY}"

IMAGE_NAME=$(./docker.sh print-image-name)
echo "IMAGE_NAME=${IMAGE_NAME}" >> $GITHUB_ENV
echo "Image name to be published is: ${IMAGE_NAME}"

NEXT_VERSION=$(./docker.sh print-next-version)
echo "VERSION=${NEXT_VERSION}" >> $GITHUB_ENV
echo "Next version to be published is: ${NEXT_VERSION}"

RUST_TOOLCHAIN=$(./docker.sh print-rust-toolchain)
echo "RUST_TOOLCHAIN=${RUST_TOOLCHAIN}" >> $GITHUB_ENV
echo "Rust toolchain used is: ${RUST_TOOLCHAIN}"

- name: Build and push Docker image for RISC-V
id: build-and-push-riscv
- name: Build and push Docker image for ${{ matrix.arch }}
id: build-and-push
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile.riscv64
file: ${{ matrix.dockerfile }}
push: ${{ github.event_name != 'pull_request' }}
platforms: linux/amd64
tags: ${{ env.VERSION }}-riscv,${{ env.IMAGE_NAME }}:latest-riscv
tags: ${{ env.VERSION }}-${{ matrix.tag_suffix }},${{ env.IMAGE_NAME }}:latest-${{ matrix.tag_suffix }}
build-args: RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }}
cache-from: type=gha
cache-to: type=gha,mode=max
Expand All @@ -144,5 +151,5 @@ jobs:
uses: actions/attest-build-provenance@v1
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
subject-digest: ${{ steps.build-and-push-riscv.outputs.digest }}
push-to-registry: true
subject-digest: ${{ steps.build-and-push.outputs.digest }}
push-to-registry: ${{ matrix.push_attestation }}
26 changes: 26 additions & 0 deletions Dockerfile.s390x
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Build rootfs with sshd and Rust related packages ready
# ---------------------------------------------------------
FROM --platform=linux/s390x s390x/ubuntu:24.04 AS rootfs_builder

ARG RUST_TOOLCHAIN
ENV RUST_TOOLCHAIN=${RUST_TOOLCHAIN}
ENV PATH="$PATH:/root/.cargo/bin"
COPY build_container.sh /opt/src/scripts/build.sh
RUN /opt/src/scripts/build.sh

# Finalize
# ---------------------------------------------------------
FROM ubuntu:24.04 AS final

ARG ROOTFS_DIR=/opt/rootfs

COPY --from=rootfs_builder / $ROOTFS_DIR

COPY s390x/build_finalize.sh /opt/src/scripts/finalize.sh
RUN /opt/src/scripts/finalize.sh

ENV ROOTFS_DIR=$ROOTFS_DIR WORKDIR=/workdir

# Start qemu-system-s390x as a background process
COPY s390x/start_in_qemu.sh /opt/src/scripts/start.sh
ENTRYPOINT ["/opt/src/scripts/start.sh"]
42 changes: 25 additions & 17 deletions build_container.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,22 @@ DEBIAN_FRONTEND="noninteractive" apt-get install --no-install-recommends -y \
podman libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
gstreamer1.0-plugins-base gstreamer1.0-plugins-good

# `riscv64` specific dependencies
if [ "$ARCH" == "riscv64" ]; then
# `riscv64` and `s390x` specific dependencies
if [ "$ARCH" == "riscv64" ] || [ "$ARCH" == "s390x" ]; then
DEBIAN_FRONTEND="noninteractive" apt-get install --no-install-recommends -y \
openssh-server systemd init ifupdown busybox udev isc-dhcp-client
fi

# apt dependencies not available on `riscv64`
if [ "$ARCH" != "riscv64" ]; then
# `s390x` specific dependencies
if [ "$ARCH" == "s390x" ]; then
DEBIAN_FRONTEND="noninteractive" apt-get install --no-install-recommends -y \
linux-image-generic initramfs-tools
echo -e '9p\n9pnet\n9pnet_virtio' >> /etc/initramfs-tools/modules
update-initramfs -c -k all
fi

# apt dependencies not available on `riscv64` and `s390x`
if [ "$ARCH" != "riscv64" ] && [ "$ARCH" != "s390x" ]; then
DEBIAN_FRONTEND="noninteractive" apt-get install --no-install-recommends -y \
binutils-aarch64-linux-gnu
fi
Expand All @@ -41,8 +49,8 @@ fi
apt-get clean && rm -rf /var/lib/apt/lists/*

# help musl-gcc find linux headers
# Skip on `riscv64` for now
if [ "$ARCH" != "riscv64" ]; then
# Skip on `riscv64` and `s390x` for now
if [ "$ARCH" != "riscv64" ] && [ "$ARCH" != "s390x" ]; then
pushd /usr/include/$ARCH-linux-musl
ln -s ../$ARCH-linux-gnu/asm asm
ln -s ../linux linux
Expand Down Expand Up @@ -76,7 +84,7 @@ rustup component add llvm-tools-preview # needed for coverage

# Install other rust targets.
# Skip on `riscv64` for now
if [ "$ARCH" != "riscv64" ]; then
if [ "$ARCH" != "riscv64" ] && [ "$ARCH" != "s390x" ]; then
rustup target add $ARCH-unknown-linux-musl $ARCH-unknown-none
fi

Expand All @@ -88,8 +96,8 @@ fi

cargo install cargo-llvm-cov

# Install the codecov.io uploader. Not available on riscv64, so skip there
if [ "$ARCH" != "riscv64" ]; then
# Install the codecov.io uploader. Not available on riscv64 and s390x, so skip there
if [ "$ARCH" != "riscv64" ] && [ "$ARCH" != "s390x" ]; then
pushd /usr/local/bin
if [ "$ARCH" = "x86_64" ]; then
curl -O https://uploader.codecov.io/latest/linux/codecov
Expand All @@ -104,9 +112,9 @@ cargo install cargo-all-features

# Install some dependencies required by vhost-device crates but not available
# in Ubuntu repos.
# Some of these do not support riscv64, since vhost-device crates do not
# Some of these do not support riscv64 or s390x, since vhost-device crates do not
# support riscv64 too, let's skip them for now.
if [ "$ARCH" != "riscv64" ]; then
if [ "$ARCH" != "riscv64" ] && [ "$ARCH" != "s390x" ]; then
pushd /opt

# required by vhost-device-gpu
Expand Down Expand Up @@ -158,9 +166,9 @@ fi
# dbus-daemon expects this folder
mkdir -p /run/dbus

# `riscv64` specific, which setup the rootfs for `riscv64` VM to execute actual
# RISC-V tests through prepared ssh server.
if [ "$ARCH" == "riscv64" ]; then
# QEMU specific, which setup the rootfs for `riscv64` and `s390x` VM to execute actual
# target ARCH tests through prepared ssh server.
if [ "$ARCH" == "riscv64" ] || [ "$ARCH" == "s390x" ] ; then
# Set passwd for debugging
echo 'root:rustvmm' | chpasswd
# Allow root login
Expand All @@ -170,11 +178,11 @@ if [ "$ARCH" == "riscv64" ]; then
systemctl enable ssh
mkdir -p /root/.ssh
# Setup network
echo $'auto lo\niface lo inet loopback\n\nauto eth0\niface eth0 inet dhcp\n' > /etc/network/interfaces
echo $'auto lo\niface lo inet loopback\n\nauto eth0\niface eth0 inet dhcp\n\nauto enc1\niface enc1 inet dhcp\n' > /etc/network/interfaces
fi

# Install kani in x86 and arm. Not available on riscv64, so skip there
if [ "$ARCH" != "riscv64" ]; then
# Install kani in x86 and arm. Not available on riscv64 and s390x, so skip there
if [ "$ARCH" != "riscv64" ] && [ "$ARCH" != "s390x" ] ; then
cargo install --locked kani-verifier
cargo kani setup
fi
27 changes: 27 additions & 0 deletions s390x/build_finalize.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -ex

apt-get update

DEBIAN_FRONTEND="noninteractive" apt-get install --no-install-recommends -y \
openssh-client libslirp-dev libfdt-dev libglib2.0-dev libssl-dev \
libpixman-1-dev qemu-system-s390x

# Modify fstab to mount `tmpfs` during boot
# See: https://wiki.qemu.org/Documentation/9p_root_fs#Let's_start_the_Installation
echo 'tmpfs /tmp tmpfs rw,nosuid,nodev,size=524288k,nr_inodes=204800 0 0' >> $ROOTFS_DIR/etc/fstab

# Setup container ssh config
yes "" | ssh-keygen -P ""
cat /root/.ssh/*.pub > $ROOTFS_DIR/root/.ssh/authorized_keys
cat > /root/.ssh/config << EOF
Host s390x-qemu
HostName localhost
User root
Port 2222
StrictHostKeyChecking no
EOF

# Set `nameserver` to `10.0.2.3` as QEMU User Networking documented.
# See: https://wiki.qemu.org/Documentation/Networking
echo 'nameserver 10.0.2.3' > $ROOTFS_DIR/etc/resolv.conf
45 changes: 45 additions & 0 deletions s390x/start_in_qemu.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env bash
set -ex

# Minimum resources needed
MIN_CORES=4
MIN_MEM=6
DIVISOR=5

# Try to use 1/${DIVISOR} of resources for qemu-system
TOTAL_CORES=$(nproc)
ONE_FIFTH_CORES=$(( TOTAL_CORES / DIVISOR ))
CORES=$(( ONE_FIFTH_CORES > MIN_CORES ? ONE_FIFTH_CORES : MIN_CORES ))

TOTAL_MEM=$(( $(awk '/MemTotal/ {print $2}' /proc/meminfo) / 1024 / 1024 ))
ONE_FIFTH_MEM=$(( TOTAL_MEM / DIVISOR ))
MEM=$(( ONE_FIFTH_MEM > MIN_MEM ? ONE_FIFTH_MEM : MIN_MEM ))G

qemu-system-s390x \
-M s390-ccw-virtio \
-cpu qemu \
-nographic \
-smp $CORES -m $MEM \
-fsdev local,path=$ROOTFS_DIR,security_model=none,id=rootfs \
-device virtio-9p-ccw,fsdev=rootfs,mount_tag=rootfs \
-device virtio-net-ccw,netdev=usernet \
-netdev user,id=usernet,hostfwd=tcp::2222-:22 \
-kernel $ROOTFS_DIR/boot/vmlinuz \
-initrd $ROOTFS_DIR/boot/initrd.img \
-append "root=rootfs rw rootfstype=9p rootflags=trans=virtio,cache=mmap,msize=512000 console=ttyS0 nokaslr" 2>&1 &

# Copy WORKDIR to ROOTFS_DIR
cp -a $WORKDIR $ROOTFS_DIR/root

HOST=s390x-qemu

echo "Testing SSH connectivity to $HOST..."
while ! ssh -o ConnectTimeout=1 -q $HOST exit; do
sleep 10s
echo "$HOST is not ready..."
done

# Issue command
COMMAND=$@
echo "$HOST is ready, forwarding command: $COMMAND"
ssh $HOST "export PATH=\"\$PATH:/root/.cargo/bin\" && cd workdir && $COMMAND"