diff --git a/meson.build b/meson.build index 2cadd4987..63372c2ba 100644 --- a/meson.build +++ b/meson.build @@ -57,6 +57,7 @@ sysprof_req = '>= 3.37.2' gnome = import('gnome') pkg = import('pkgconfig') i18n = import('i18n') +fs = import('fs') cc = meson.get_compiler('c') prefix = get_option('prefix') @@ -269,6 +270,7 @@ have_core_tests = false have_cogl_tests = false have_clutter_tests = false have_native_tests = false +have_kvm_tests = false have_installed_tests = false if have_tests @@ -287,6 +289,15 @@ if have_tests error('Native tests require remote desktop') endif endif + have_kvm_tests = get_option('kvm_tests') + if have_kvm_tests + if not have_native_backend + error('KVM tests need the native backend tests') + endif + if host_machine.cpu_family() != 'x86_64' + error('KVM tests are only supported on x86_64') + endif + endif have_cogl_tests = get_option('cogl_tests') have_clutter_tests = get_option('clutter_tests') diff --git a/meson_options.txt b/meson_options.txt index 6609e4332..12457d261 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -141,6 +141,18 @@ option('tests', description: 'Enable tests globally. Specific test suites can be controlled with core_tests, clutter_tests, and cogl_tests' ) +option('kvm_tests', + type: 'boolean', + value: false, + description: 'Enable running certain tests in a virtual machine with a custom built kernel' +) + +option('kvm_kernel_image', + type: 'string', + value: '', + description: 'Path to a Linux kernel image to be used for KVM testing' +) + option('profiler', type: 'boolean', value: true, diff --git a/src/tests/kvm/README.md b/src/tests/kvm/README.md new file mode 100644 index 000000000..336b3df5e --- /dev/null +++ b/src/tests/kvm/README.md @@ -0,0 +1,29 @@ +## High level description of the files in this directory. + +### build-linux.sh + +Builds a Linux kernel image meant to be launched using qemu. Doesn't make any +assumptions about configuration other than that. It uses the drm kernel tree. +It's used from meson.build. + +### kernel-version.txt + +Describes the version of the Linux kernel to use; usually a tag. It's a +separate file so that changing the version will make meson build a new kernel +image. + +### virtme-run.sh + +A helper script that uses 'virtme' to launch a qemu virtual machine with the +host filesystem exposed inside the virtual machine. + +### run-kvm-test.sh + +Runs the passed test executable in a mocked environment using +'meta-dbus-runner.py' (which uses python-dbusmock to create a mocked system +environment. + +### meson.build + +Contains one rule for building the Linux kernel image, and meson test cases +that launches tests inside virtual machines. diff --git a/src/tests/kvm/build-linux.sh b/src/tests/kvm/build-linux.sh new file mode 100755 index 000000000..49f622a56 --- /dev/null +++ b/src/tests/kvm/build-linux.sh @@ -0,0 +1,74 @@ +#!/bin/bash +# +# Script for building the Linux kernel from git. It aims to build a kernel image +# that is suitable for running in a virtual machine and is aimed to used for +# testing. +# +# Usage: build-linux.sh [REPO-URL] [BRANCH|TAG] [OUTPUT-FILE] [...CONFIGS] +# +# Where [..CONFIGS] can be any number of configuration options, e.g. +# --enable CONFIG_DRM_VKMS + +set -e + +# From scripts/subarch.include in linux +function get-subarch() +{ + uname -m | sed -e s/i.86/x86/ \ + -e s/x86_64/x86/ \ + -e s/sun4u/sparc64/ \ + -e s/arm.*/arm/ -e s/sa110/arm/ \ + -e s/s390x/s390/ -e s/parisc64/parisc/ \ + -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ + -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ + -e s/riscv.*/riscv/ +} + +REPO="$1" +BRANCH_OR_TAG="$(cat $2)" +IMAGE="$3" + +ARCH=$(uname -m) +SUBARCH=$(get-subarch) + +shift +shift +shift + +# ./scripts/config --enable CONFIG_DRM_VKMS +CONFIGS=() +while [[ "x$1" != "x" ]]; do + CONFIGS+=( "$1" ) + shift +done + +echo Building Linux for $ARCH \($SUBARCH\)... + +set -x + +if [ -d linux ]; then + pushd linux + git fetch $REPO $BRANCH_OR_TAG + git checkout FETCH_HEAD +else + git clone --depth=1 --branch=$BRANCH_OR_TAG $REPO linux + pushd linux +fi + +make defconfig +sync +make kvm_guest.config + +echo Enabling ${CONFIGS[@]}... +./scripts/config ${CONFIGS[@]/#/--enable } + +make oldconfig +make -j8 + +popd + +TARGET_DIR="$(dirname "$IMAGE")" +mkdir -p "$TARGET_DIR" +mv linux/arch/$SUBARCH/boot/bzImage "$IMAGE" +mv linux/.config $TARGET_DIR/.config +#rm -rf linux diff --git a/src/tests/kvm/kernel-version.txt b/src/tests/kvm/kernel-version.txt new file mode 100644 index 000000000..5aeaf910f --- /dev/null +++ b/src/tests/kvm/kernel-version.txt @@ -0,0 +1 @@ +drm-next-2021-11-12 diff --git a/src/tests/kvm/meson.build b/src/tests/kvm/meson.build new file mode 100644 index 000000000..cd8725912 --- /dev/null +++ b/src/tests/kvm/meson.build @@ -0,0 +1,48 @@ +build_linux = find_program('build-linux.sh') + +kernel_image_path = get_option('kvm_kernel_image') +if kernel_image_path != '' + if not fs.is_absolute(kernel_image_path) + error('Kernel image path @0@ must be absolute'.format(kernel_image_path)) + endif + if not fs.is_file(kernel_image_path) + error('Kernel image @0@ does not exist'.format(kernel_image_path)) + endif + kernel_image_target = [] +else + kernel_image_target = custom_target('linux-kernel', + output: 'bzImage', + input: 'kernel-version.txt', + console: true, + command: [ + build_linux, + 'https://anongit.freedesktop.org/git/drm/drm.git', + '@INPUT@', + '@OUTPUT@', + '--enable', 'CONFIG_DRM_VKMS', + ] + ) + kernel_image_path = kernel_image_target.full_path() +endif + +virtme_run = find_program('virtme-run.sh') + +foreach test: privileged_tests + test_name = test[0] + test_executable = test[1] + + test('kvm-' + test_name, virtme_run, + suite: ['core', 'mutter/native/kvm'], + depends: [ + kernel_image_target, + ], + workdir: mutter_srcdir, + args: [ + kernel_image_path, + meta_dbus_runner.full_path(), + '--kvm', + test_executable.full_path(), + meson.current_build_dir(), + ] + ) +endforeach diff --git a/src/tests/kvm/run-kvm-test.sh b/src/tests/kvm/run-kvm-test.sh new file mode 100755 index 000000000..a6fa901ec --- /dev/null +++ b/src/tests/kvm/run-kvm-test.sh @@ -0,0 +1,23 @@ +#!/usr/bin/bash + +set -e + +WRAPPER="$1" +WRAPPER_ARGS="$2" +TEST_EXECUTABLE="$3" +TEST_RESULT="$4" + +export XDG_RUNTIME_DIR="/tmp/sub-runtime-dir-$UID" +export GSETTINGS_SCHEMA_DIR="$PWD/build/data" +export G_SLICE="always-malloc" +export MALLOC_CHECK_="3" +export NO_AT_BRIDGE="1" +export MALLOC_PERTURB_="123" + +mkdir -p -m 700 $XDG_RUNTIME_DIR + +glib-compile-schemas $GSETTINGS_SCHEMA_DIR + +"$WRAPPER" $WRAPPER_ARGS "$TEST_EXECUTABLE" + +echo $? > $TEST_RESULT diff --git a/src/tests/kvm/virtme-run.sh b/src/tests/kvm/virtme-run.sh new file mode 100755 index 000000000..6b877f1d6 --- /dev/null +++ b/src/tests/kvm/virtme-run.sh @@ -0,0 +1,25 @@ +#!/usr/bin/bash + +set -e + +DIRNAME="$(dirname "$0")" +IMAGE="$1" +WRAPPER="$2" +WRAPPER_ARGS="$3" +TEST_EXECUTABLE="$4" +TEST_BUILD_DIR="$5" + +TEST_RESULT_FILE=$(mktemp -p "$TEST_BUILD_DIR" -t test-result-XXXXXX) +echo 1 > "$TEST_RESULT_FILE" + +virtme-run \ + --memory=256M \ + --rw \ + --pwd \ + --kimg "$IMAGE" \ + --script-sh "sh -c \"env HOME=$HOME $DIRNAME/run-kvm-test.sh \\\"$WRAPPER\\\" \\\"$WRAPPER_ARGS\\\" \\\"$TEST_EXECUTABLE\\\" \\\"$TEST_RESULT_FILE\\\"\"" + +TEST_RESULT="$(cat "$TEST_RESULT_FILE")" +rm "$TEST_RESULT_FILE" + +exit "$TEST_RESULT" diff --git a/src/tests/meson.build b/src/tests/meson.build index 02460b5f3..0a0fa7a80 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -117,6 +117,8 @@ test_runner = executable('mutter-test-runner', install_dir: mutter_installed_tests_libexecdir, ) +meta_dbus_runner = find_program('meta-dbus-runner.py') + if have_installed_tests install_data('meta-dbus-runner.py', install_dir: mutter_installed_tests_libexecdir, @@ -391,11 +393,14 @@ if have_native_tests is_parallel: false, timeout: 60, ) - - test('native-kms-render', native_kms_render_tests, - suite: ['core', 'mutter/native/kms/render'], - env: test_env, - is_parallel: false, - timeout: 60, - ) +endif + +if have_kvm_tests + privileged_tests = [ + [ 'kms-render', native_kms_render_tests ], + ] + + if have_kvm_tests + subdir('kvm') + endif endif