diff --git a/tools/fvp/Dockerfile b/tools/fvp/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..901a0b6bd093e6eb7fe9b344aaf72c388d3cff6a --- /dev/null +++ b/tools/fvp/Dockerfile @@ -0,0 +1,31 @@ +# +# SPDX-FileCopyrightText: Copyright 2024 Arm Limited and/or its affiliates +# +# SPDX-License-Identifier: Apache-2.0 +# + +FROM ubuntu:24.04 + +RUN --mount=type=cache,target=/var/cache/apt \ + apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + build-essential \ + ca-certificates \ + clang \ + g++-aarch64-linux-gnu \ + cmake \ + git \ + ninja-build \ + python3 \ + python3-pip \ + wget \ + autoconf \ + automake \ + device-tree-compiler \ + flex \ + bison \ + bc \ + libssl-dev + +RUN --mount=type=bind,source=build.sh,target=build.sh \ + ./build.sh diff --git a/tools/fvp/README.md b/tools/fvp/README.md new file mode 100644 index 0000000000000000000000000000000000000000..77c4935271df6f668954551bf55179cadaebad08 --- /dev/null +++ b/tools/fvp/README.md @@ -0,0 +1,153 @@ + + +# Create a Linux virtual machine on Fixed Virtual Platform + +In order to develop and test KleidiAI microkernels without hardware supporting certain architectural features, we should use [Fixed Virtual Platform (FVP)](https://developer.arm.com/Tools%20and%20Software/Fixed%20Virtual%20Platforms). This guide shows how to create a minimum Linux virtual machine running on FVP with internet connection and the ability to access using SSH. + +Note: In this guide, commands that run on the host machine starts with `host>` prompt and commands that run on the FVP starts with `fvp>` prompt. + +## Prerequisites + +The following tools are needed in the host system: + +- `wget` to download the Linux image. +- `xz` to extract the Linux image. +- Container management tool such as Docker. +- Telnet client to connect to the FVP. +- SSH client to connect to the operating system running in the FVP. + +## Prepare the FVP and the operating system + +Build the Docker image: + +``` +host> docker build -t fvp . +``` + +Download a Linux image: + +``` +host> wget -O disk.img.xz "https://cdimage.ubuntu.com/releases/24.04.1/release/ubuntu-24.04.1-preinstalled-server-arm64+raspi.img.xz" +xz -d disk.img.xz +``` + +Run the FVP: + +``` +host> docker run \ + --rm -t -i \ + -p 5000:5000 \ + -p 5001:5001 \ + -p 5002:5002 \ + -p 5003:5003 \ + -p 8022:8022 \ + --mount=type=bind,source="$PWD/disk.img",target=/disk.img \ + fvp \ + /opt/devtools/fvp/models/FVP_Base_RevC-2xAEMvA \ + -C cache_state_modelled=0 \ + -C bp.refcounter.non_arch_start_at_default=1 \ + -C bp.secure_memory=0 \ + -C bp.pl011_uart0.out_file=output.txt \ + -C bp.pl011_uart0.shutdown_tag="System halted" \ + -C bp.terminal_0.mode=telnet \ + -C bp.terminal_0.start_telnet=0 \ + -C bp.terminal_1.mode=raw \ + -C bp.terminal_1.start_telnet=0 \ + -C bp.terminal_2.mode=raw \ + -C bp.terminal_2.start_telnet=0 \ + -C bp.terminal_3.mode=raw \ + -C bp.terminal_3.start_telnet=0 \ + -C bp.smsc_91c111.enabled=1 \ + -C bp.hostbridge.userNetPorts=8022=22 \ + -C bp.hostbridge.userNetworking=1 \ + -C cluster0.NUM_CORES=4 \ + -C cluster0.has_arm_v8-1=1 \ + -C cluster0.has_arm_v8-2=1 \ + -C cluster0.has_arm_v8-3=1 \ + -C cluster0.has_arm_v8-4=1 \ + -C cluster0.has_arm_v8-5=1 \ + -C cluster0.has_arm_v8-6=1 \ + -C cluster0.has_arm_v8-7=1 \ + -C cluster0.has_arm_v8-8=1 \ + -C cluster0.has_arm_v9-0=1 \ + -C cluster0.has_arm_v9-1=1 \ + -C cluster0.has_arm_v9-2=1 \ + -C cluster0.has_arm_v9-3=1 \ + -C cluster0.has_arm_v9-4=1 \ + -C cluster0.has_arm_v9-5=1 \ + -C cluster0.has_sve=1 \ + -C cluster0.sve.has_b16b16=1 \ + -C cluster0.sve.has_sve2=1 \ + -C cluster0.sve.has_sme=1 \ + -C cluster0.sve.has_sme2=1 \ + -C cluster0.sve.has_sme_f16f16=1 \ + -C cluster0.sve.has_sme_fa64=1 \ + -C cluster0.sve.has_sme_lutv2=1 \ + -C cluster0.sve.sme2_version=1 \ + -C cluster0.sve.veclen=2 \ + -C cluster0.sve.sme_veclens_implemented=4 \ + -C bp.virtio_rng.enabled=1 \ + -C bp.virtioblockdevice.image_path=/disk.img \ + -C bp.vis.disable_visualisation=1 \ + -a cluster*.cpu*=/opt/devtools/linux-system.axf +``` + +It should print out the port for each terminal. For example: + +``` +terminal_0: Listening for serial connection on port 5000 +terminal_1: Listening for serial connection on port 5001 +terminal_2: Listening for serial connection on port 5002 +terminal_3: Listening for serial connection on port 5003 +``` + +In this case, `terminal_0` is in port 500. +We need to connect to `terminal_0` using `telnet`: + +``` +host> telnet 127.0.0.1 5000 +``` + +Login with the default username `ubuntu` and password `ubuntu`. +It will prompt to change the password after the first login. + +Allow SSH login using password. + +``` +fvp> sudo rm /etc/ssh/sshd_config.d/50-cloud-init.conf +fvp> sudo systemctl restart ssh +``` + +## Setup SSH + +Copy the public key into the machine: + +``` +host> ssh-copy-id -p 8022 ubuntu@127.0.0.1 +``` + +Initiating a new SSH connection is very slow since the cryptography primitives used in the key exchange process is computationally heavy. +It's better if the long lived connection can be established and shared. + +Putting the following config into `~/.ssh/config` file: + +``` +Host fvp + User ubuntu + HostName 127.0.0.1 + Port 8022 + ControlMaster auto + ControlPath ~/.ssh/ssh_mux_%h_%p_%r +``` + +Start the first SSH connection: + +``` +host> ssh fvp +``` + +If this connection is kept alive, all subsequent SSH commands can be executed almost instantly. diff --git a/tools/fvp/build.sh b/tools/fvp/build.sh new file mode 100755 index 0000000000000000000000000000000000000000..efae923f89e64172897f310e196a16136f9baf5d --- /dev/null +++ b/tools/fvp/build.sh @@ -0,0 +1,120 @@ +#!/bin/bash + +# +# SPDX-FileCopyrightText: Copyright 2024 Arm Limited and/or its affiliates +# +# SPDX-License-Identifier: Apache-2.0 +# + +set -e + +GCC_VERSION=13.3.rel1 + +FVP_MAJOR=11 +FVP_MINOR=26 +FVP_PATCH=11 + +KERNEL_MAJOR=6 +KERNEL_MINOR=10 +KERNEL_PATCH=9 + +BOOTLOADER_VERSION=d62de19c866141cb450576040439de233438fb60 + +WORKDIR="/opt/devtools" + +ARCH=$(uname -m) + +mkdir -p "$WORKDIR" + +pushd "$WORKDIR" > /dev/null + +# ================================================================================================== +# Downloads the bare-metal toolchain. +# ================================================================================================== + +mkdir toolchain-aarch64-none-elf +wget -O- "https://developer.arm.com/-/media/Files/downloads/gnu/${GCC_VERSION}/binrel/arm-gnu-toolchain-${GCC_VERSION}-${ARCH}-aarch64-none-elf.tar.xz" | tar xJ --strip-components=1 -C toolchain-aarch64-none-elf + +export PATH="$PWD/toolchain-aarch64-none-elf/bin:$PATH" + +# ================================================================================================== +# Downloads and builds the Linux kernel. +# ================================================================================================== + +mkdir linux +wget -O- "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${KERNEL_MAJOR}.${KERNEL_MINOR}.${KERNEL_PATCH}.tar.xz" | tar xJ --strip-components=1 -C linux + +cd linux + +make ARCH=arm64 CROSS_COMPILE=aarch64-none-elf- defconfig +make ARCH=arm64 CROSS_COMPILE=aarch64-none-elf- "-j$(nproc)" Image + +cd .. + +# ================================================================================================== +# Downloads and builds the device tree. +# ================================================================================================== + +mkdir devicetree-rebasing +wget -O- "https://git.kernel.org/pub/scm/linux/kernel/git/devicetree/devicetree-rebasing.git/snapshot/devicetree-rebasing-${KERNEL_MAJOR}.${KERNEL_MINOR}-dts.tar.gz" | tar xz --strip-components=1 -C devicetree-rebasing + +cd devicetree-rebasing + +make CPP=aarch64-none-elf-cpp src/arm64/arm/fvp-base-revc.dtb + +cd .. + +# ================================================================================================== +# Downloads the builds the bootloader. +# ================================================================================================== + +mkdir boot-wrapper-aarch64 +wget -O- "https://git.kernel.org/pub/scm/linux/kernel/git/mark/boot-wrapper-aarch64.git/snapshot/boot-wrapper-aarch64-${BOOTLOADER_VERSION}.tar.gz" | tar xz --strip-components=1 -C boot-wrapper-aarch64 + +cd boot-wrapper-aarch64 + +autoreconf -i + +./configure \ + --host=aarch64-linux-gnu \ + --enable-psci \ + --enable-gicv3 \ + --with-kernel-dir=../linux \ + --with-dtb=../devicetree-rebasing/src/arm64/arm/fvp-base-revc.dtb \ + --with-cmdline="console=ttyAMA0 earlycon=pl011,0x1c090000 root=/dev/vda2 rw" + +make "-j$(nproc)" +mv linux-system.axf "$WORKDIR" + +cd .. + +# ================================================================================================== +# Downloads the lastest Fixed Virtual Platform. +# ================================================================================================== + +case "$ARCH" in + x86_64) + FVP_PLATFORM=Linux64 + ;; + + arm64|aarch64) + FVP_PLATFORM=Linux64_armv8l + ;; + + *) + echo "Unknown CPU architecture $ARCH!" + exit 1 + ;; +esac + +mkdir fvp +wget -O- "https://developer.arm.com/-/cdn-downloads/permalink/Fixed-Virtual-Platforms/FM-${FVP_MAJOR}.${FVP_MINOR}/FVP_Base_RevC-2xAEMvA_${FVP_MAJOR}.${FVP_MINOR}_${FVP_PATCH}_${FVP_PLATFORM}.tgz" | tar xz -C fvp + +ln -s /opt/devtools/fvp/Base_RevC_AEMvA_pkg/models/${FVP_PLATFORM}_GCC-9.3 /opt/devtools/fvp/models +ln -s /opt/devtools/fvp/Base_RevC_AEMvA_pkg/plugins/${FVP_PLATFORM}_GCC-9.3 /opt/devtools/fvp/plugins + +# ================================================================================================== +# Done. +# ================================================================================================== + +popd > /dev/null