From dbdc1aab39b0aa3cac1ca746cbdcc607b2fa22b8 Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Sun, 3 May 2026 12:54:39 +0530 Subject: [PATCH 1/2] virt: add common KVM validation helpers Add Runner/utils/lib_kvm.sh with shared helpers for KVM and virtualization tests. The helper library provides KVM-specific checks for: - /dev/kvm presence and permissions - KVM ioctl API validation - KVM/EL2 dmesg scanning - dynamic EL2 DTB remoteproc/IOMMU evidence - QEMU binary discovery and KVM acceleration checks - optional tun/vhost-net infrastructure checks The library is intended to be sourced after functestlib.sh and reuses the existing common logging, dependency, kernel config, dmesg, and remoteproc helpers instead of duplicating generic testkit functionality. Signed-off-by: Srikanth Muppandam --- Runner/utils/lib_kvm.sh | 619 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 619 insertions(+) create mode 100755 Runner/utils/lib_kvm.sh diff --git a/Runner/utils/lib_kvm.sh b/Runner/utils/lib_kvm.sh new file mode 100755 index 00000000..1ca0585b --- /dev/null +++ b/Runner/utils/lib_kvm.sh @@ -0,0 +1,619 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause +# +# Common KVM/virtualization validation helpers. +# +# This library must be sourced after functestlib.sh. +# +# Reuse from functestlib.sh: +# log_info/log_pass/log_fail/log_skip/log_warn +# check_dependencies +# check_kernel_config +# scan_dmesg_errors +# get_kernel_log +# detect_platform +# get_remoteproc_by_firmware, when available +# +# Return-code convention: +# 0 = validation passed / evidence found +# 1 = validation failed +# 2 = validation not applicable or dependency missing; caller should SKIP + +# Validate /dev/kvm presence, type, and access permissions. +# +# Returns: +# 0 if /dev/kvm is present, character device, readable, and writable +# 1 if /dev/kvm exists but is not usable +# 2 if /dev/kvm is not present +kvm_check_device_node() { + if [ ! -e /dev/kvm ]; then + log_skip "/dev/kvm is not present" + return 2 + fi + + if [ ! -c /dev/kvm ]; then + log_fail "/dev/kvm exists but is not a character device" + return 1 + fi + + if [ ! -r /dev/kvm ]; then + log_fail "/dev/kvm exists but is not readable" + return 1 + fi + + if [ ! -w /dev/kvm ]; then + log_fail "/dev/kvm exists but is not writable" + return 1 + fi + + log_pass "/dev/kvm is present and accessible" + return 0 +} + +# Validate the KVM userspace API through /dev/kvm ioctl calls. +# +# Checks: +# - open("/dev/kvm") succeeds +# - KVM_GET_API_VERSION returns 12 +# - KVM_CREATE_VM succeeds +# +# Notes: +# Uses python3 to avoid requiring a compiled helper binary on target. +# +# Returns: +# 0 if KVM API validation passes +# 1 if /dev/kvm API validation fails +# 2 if python3 is unavailable +kvm_check_api_version() { + if ! command -v python3 >/dev/null 2>&1; then + log_skip "python3 is not available; cannot run /dev/kvm ioctl API check" + return 2 + fi + + python3 - <<'PY' +import fcntl +import os +import sys + +KVM_GET_API_VERSION = 0xAE00 +KVM_CREATE_VM = 0xAE01 +EXPECTED_API = 12 + +try: + fd = os.open("/dev/kvm", os.O_RDWR | getattr(os, "O_CLOEXEC", 0)) +except OSError as exc: + print("open(/dev/kvm) failed: %s" % exc) + sys.exit(1) + +try: + api = fcntl.ioctl(fd, KVM_GET_API_VERSION, 0) +except OSError as exc: + print("KVM_GET_API_VERSION failed: %s" % exc) + os.close(fd) + sys.exit(1) + +if api != EXPECTED_API: + print("Unexpected KVM API version: got=%s expected=%s" % (api, EXPECTED_API)) + os.close(fd) + sys.exit(1) + +try: + vmfd = fcntl.ioctl(fd, KVM_CREATE_VM, 0) +except OSError as exc: + print("KVM_CREATE_VM failed: %s" % exc) + os.close(fd) + sys.exit(1) + +try: + os.close(vmfd) +except OSError: + pass + +os.close(fd) +print("KVM API check passed: KVM_GET_API_VERSION=%s KVM_CREATE_VM=ok" % api) +sys.exit(0) +PY + rc=$? + + if [ "$rc" -eq 0 ]; then + log_pass "/dev/kvm ioctl API validation passed" + return 0 + fi + + log_fail "/dev/kvm ioctl API validation failed" + return 1 +} + +# Scan kernel logs for fatal KVM/EL2/HYP/GIC virtualization errors. +# +# Args: +# $1 - output directory where dmesg logs should be collected +# +# Behavior: +# Uses scan_dmesg_errors from functestlib.sh when available. +# Falls back to get_kernel_log/dmesg capture otherwise. +# +# Returns: +# 0 if no fatal error is detected +# 1 if fatal KVM/EL2-related messages are detected +kvm_check_boot_dmesg_errors() { + outdir="$1" + include_regex='kvm|KVM|hyp|HYP|el2|EL2|vgic|VGIC|gicv|GICV' + exclude_regex='not found|dummy regulator|probe deferred|using dummy regulator|EEXIST' + + mkdir -p "$outdir" 2>/dev/null || true + + if command -v scan_dmesg_errors >/dev/null 2>&1; then + scan_dmesg_errors "$outdir" "$include_regex" "$exclude_regex" || true + + if [ -s "$outdir/dmesg_errors.log" ]; then + if grep -Ei 'fail|failed|error|disabled|unavailable|not in hyp|hyp mode|EL2.*unavailable|HYP.*unavailable|KVM.*not available|kvm.*not available|panic|BUG|Oops' "$outdir/dmesg_errors.log" >/dev/null 2>&1; then + log_fail "Fatal KVM/EL2 related messages found in dmesg: $outdir/dmesg_errors.log" + return 1 + fi + + log_warn "KVM/EL2 related dmesg messages found but no fatal pattern matched: $outdir/dmesg_errors.log" + return 0 + fi + + log_info "No relevant KVM/EL2 dmesg errors found." + return 0 + fi + + if command -v get_kernel_log >/dev/null 2>&1; then + get_kernel_log >"$outdir/dmesg_snapshot.log" 2>/dev/null || true + elif command -v dmesg >/dev/null 2>&1; then + dmesg >"$outdir/dmesg_snapshot.log" 2>/dev/null || true + else + log_warn "No kernel log source available for KVM dmesg validation" + return 0 + fi + + if grep -Ei 'KVM|kvm|HYP|hyp|EL2|el2' "$outdir/dmesg_snapshot.log" >/dev/null 2>&1; then + grep -Ei 'KVM|kvm|HYP|hyp|EL2|el2' "$outdir/dmesg_snapshot.log" >"$outdir/kvm_dmesg.log" 2>/dev/null || true + log_info "KVM/EL2 dmesg lines captured: $outdir/kvm_dmesg.log" + + if grep -Ei 'fail|failed|error|disabled|unavailable|not in hyp|hyp mode|EL2.*unavailable|HYP.*unavailable|KVM.*not available|kvm.*not available|panic|BUG|Oops' "$outdir/kvm_dmesg.log" >/dev/null 2>&1; then + log_fail "Fatal KVM/EL2 related messages found in dmesg: $outdir/kvm_dmesg.log" + return 1 + fi + else + log_warn "No KVM/EL2 dmesg lines found" + fi + + return 0 +} + +# Print available live device-tree root paths. +# +# Device-tree may be exposed through either: +# /proc/device-tree +# /sys/firmware/devicetree/base +# +# Returns: +# Prints existing DT roots to stdout +kvm_dt_roots() { + for root in /proc/device-tree /sys/firmware/devicetree/base; do + if [ -d "$root" ]; then + printf '%s\n' "$root" + fi + done +} + +# Log live device-tree identity information. +# +# Logs: +# - DT root path +# - model +# - compatible +# +# This helper is logging-only. +# +# Returns: +# Always returns 0 +kvm_log_dt_identity() { + for root in $(kvm_dt_roots); do + log_info "DT root: $root" + + if [ -r "$root/model" ]; then + model="$(tr '\000' ' ' <"$root/model" 2>/dev/null)" + log_info "DT model: $model" + fi + + if [ -r "$root/compatible" ]; then + compat="$(tr '\000' ' ' <"$root/compatible" 2>/dev/null)" + log_info "DT compatible: $compat" + fi + done + + return 0 +} + +# Find likely remoteproc/rproc nodes from the live device tree. +# +# Returns: +# Prints matching DT node paths to stdout. +kvm_dt_find_remoteproc_nodes() { + for root in $(kvm_dt_roots); do + find "$root" -type d 2>/dev/null | grep -Ei '/([^/]*remoteproc[^/]*|[^/]*rproc[^/]*)$' || true + done +} + +# Check whether live DT has remoteproc IOMMU evidence. +# +# Checks: +# - remoteproc/rproc DT nodes exist +# - at least one matching node or path has an iommus property +# +# Returns: +# 0 if remoteproc DT IOMMU evidence is found +# 1 if remoteproc DT nodes exist but no IOMMU evidence is found +# 2 if no remoteproc DT nodes are found +kvm_dt_remoteproc_has_iommus() { + node_file="/tmp/kvm_remoteproc_nodes.$$" + iommu_file="/tmp/kvm_remoteproc_iommus.$$" + node_count=0 + iommu_count=0 + + rm -f "$node_file" "$iommu_file" 2>/dev/null || true + + kvm_dt_find_remoteproc_nodes >"$node_file" 2>/dev/null || true + + if [ -s "$node_file" ]; then + while IFS= read -r node; do + [ -n "$node" ] || continue + node_count=$((node_count + 1)) + log_info "[EL2-DT] remoteproc DT node: $node" + + if [ -e "$node/iommus" ]; then + iommu_count=$((iommu_count + 1)) + log_info "[EL2-DT] remoteproc DT iommus present: $node/iommus" + fi + done <"$node_file" + fi + + for root in $(kvm_dt_roots); do + find "$root" -type f -name iommus 2>/dev/null | grep -Ei 'remoteproc|rproc|adsp|cdsp|gpdsp|wpss' || true + done >"$iommu_file" 2>/dev/null || true + + if [ -s "$iommu_file" ]; then + while IFS= read -r found_file; do + [ -n "$found_file" ] || continue + iommu_count=$((iommu_count + 1)) + log_info "[EL2-DT] remoteproc/iommus evidence: $found_file" + done <"$iommu_file" + fi + + rm -f "$node_file" "$iommu_file" 2>/dev/null || true + + if [ "$node_count" -eq 0 ]; then + return 2 + fi + + if [ "$iommu_count" -gt 0 ]; then + return 0 + fi + + return 1 +} + +# Log remoteproc instances using sysfs and functestlib.sh helpers when present. +# +# This helper is logging-only. It must not stop, start, or reset remoteprocs. +# +# Returns: +# 0 if at least one remoteproc instance is logged +# 2 if no remoteproc entries are found +kvm_log_remoteproc_state_summary() { + found=0 + entries="" + fw="" + rpath="" + rstate="" + rfirm="" + rname="" + + for rproc in /sys/class/remoteproc/remoteproc*; do + [ -e "$rproc" ] || continue + found=1 + + fw="$(cat "$rproc/firmware" 2>/dev/null || echo unknown)" + rstate="$(cat "$rproc/state" 2>/dev/null || echo unknown)" + rname="$(cat "$rproc/name" 2>/dev/null || echo unknown)" + + log_info "[remoteproc] path=$rproc name=$rname firmware=$fw state=$rstate" + done + + if command -v get_remoteproc_by_firmware >/dev/null 2>&1; then + for fw in adsp cdsp cdsp0 cdsp1 gpdsp gpdsp0 gpdsp1 wpss modem; do + entries="$(get_remoteproc_by_firmware "$fw" "" all 2>/dev/null || true)" + [ -n "$entries" ] || continue + + while IFS='|' read -r rpath rstate rfirm rname; do + [ -n "$rpath" ] || continue + found=1 + log_info "[remoteproc-helper] fw=$fw path=$rpath state=$rstate firmware=$rfirm name=$rname" + done <<__KVM_RPROC_ENTRIES__ +$entries +__KVM_RPROC_ENTRIES__ + done + fi + + if [ "$found" -eq 0 ]; then + log_info "No /sys/class/remoteproc entries found" + return 2 + fi + + return 0 +} + +# Check runtime sysfs evidence that remoteproc devices are connected through +# IOMMU/devlink/platform relationships. +# +# This is used as dynamic EL2-DTB evidence and avoids hardcoding board names. +# +# Returns: +# 0 if at least one sysfs evidence path is found +# 1 if no evidence path is found +kvm_sysfs_remoteproc_iommu_evidence() { + evidence_count=0 + + for path in \ + /sys/kernel/iommu_groups/*/devices/*remoteproc* \ + /sys/kernel/iommu_groups/*/devices/*rproc* \ + /sys/kernel/iommu_groups/*/devices/*adsp* \ + /sys/kernel/iommu_groups/*/devices/*cdsp* \ + /sys/kernel/iommu_groups/*/devices/*gpdsp* \ + /sys/class/devlink/*remoteproc* \ + /sys/class/devlink/*rproc* \ + /sys/class/devlink/*adsp* \ + /sys/class/devlink/*cdsp* \ + /sys/class/devlink/*gpdsp* \ + /sys/devices/platform/*/*remoteproc* \ + /sys/devices/platform/*/*rproc* \ + /sys/bus/platform/devices/*remoteproc* \ + /sys/bus/platform/devices/*rproc* + do + [ -e "$path" ] || continue + evidence_count=$((evidence_count + 1)) + log_info "[EL2-SYSFS] remoteproc/IOMMU/devlink evidence: $path" + done + + if [ "$evidence_count" -gt 0 ]; then + return 0 + fi + + return 1 +} + +# Validate dynamic EL2-DTB runtime evidence. +# +# This helper reuses functestlib.sh remoteproc discovery when available, but it +# does not duplicate secure PIL or remoteproc lifecycle validation. +# +# Checks: +# - live DT identity +# - remoteproc state summary +# - remoteproc DT iommus evidence +# - remoteproc sysfs IOMMU/devlink/platform evidence +# +# Returns: +# 0 if EL2 remoteproc/IOMMU runtime evidence is found +# 1 if remoteproc exists but EL2-style evidence is missing +# 2 if no remoteproc DT/sysfs entries exist, so validation is not applicable +kvm_check_el2_runtime_evidence() { + dt_rc=1 + sysfs_rc=1 + rproc_rc=2 + + kvm_log_dt_identity + + kvm_log_remoteproc_state_summary + rproc_rc=$? + + kvm_dt_remoteproc_has_iommus + dt_rc=$? + + kvm_sysfs_remoteproc_iommu_evidence + sysfs_rc=$? + + if [ "$rproc_rc" -eq 2 ] && [ "$dt_rc" -eq 2 ]; then + log_info "No remoteproc DT/sysfs entries found; EL2 remoteproc validation is not applicable." + return 2 + fi + + if [ "$dt_rc" -eq 0 ] || [ "$sysfs_rc" -eq 0 ]; then + log_pass "EL2 remoteproc/IOMMU runtime evidence found." + return 0 + fi + + log_fail "Remoteproc entries exist, but no EL2 remoteproc/IOMMU runtime evidence was found." + return 1 +} + +# Locate a QEMU system emulator suitable for KVM validation. +# +# Search order: +# qemu-system-aarch64 +# qemu-system-arm +# qemu-kvm +# +# Returns: +# 0 and prints binary path if found +# 1 if no suitable QEMU binary is found +kvm_find_qemu_binary() { + for bin in qemu-system-aarch64 qemu-system-arm qemu-kvm; do + if command -v "$bin" >/dev/null 2>&1; then + command -v "$bin" + return 0 + fi + done + + return 1 +} + +# Locate qemu-img. +# +# Returns: +# 0 and prints binary path if found +# 1 if qemu-img is not found +kvm_find_qemu_img() { + if command -v qemu-img >/dev/null 2>&1; then + command -v qemu-img + return 0 + fi + + return 1 +} + +# Validate whether QEMU advertises KVM acceleration support. +# +# Args: +# $1 - QEMU system binary path +# +# Returns: +# 0 if "kvm" is listed in "-accel help" +# 1 otherwise +kvm_check_qemu_kvm_accel() { + qemu_bin="$1" + accel_log="/tmp/kvm_qemu_accel_help.$$" + + [ -n "$qemu_bin" ] || return 1 + + "$qemu_bin" -accel help >"$accel_log" 2>&1 + rc=$? + + if [ "$rc" -ne 0 ]; then + log_warn "$qemu_bin -accel help failed" + while IFS= read -r line; do + log_warn "[qemu-accel] $line" + done <"$accel_log" + rm -f "$accel_log" 2>/dev/null || true + return 1 + fi + + while IFS= read -r line; do + log_info "[qemu-accel] $line" + done <"$accel_log" + + if grep -Ei '(^|[[:space:]])kvm($|[[:space:]])' "$accel_log" >/dev/null 2>&1; then + rm -f "$accel_log" 2>/dev/null || true + log_pass "QEMU advertises KVM acceleration" + return 0 + fi + + rm -f "$accel_log" 2>/dev/null || true + log_fail "QEMU does not advertise KVM acceleration" + return 1 +} + +# Log basic QEMU version, machine, and CPU capability information. +# +# Args: +# $1 - QEMU system binary path +# +# This helper is logging-only and should not fail the test by itself. +# +# Returns: +# 0 if called with a non-empty binary path +# 1 if no binary path is provided +kvm_qemu_probe() { + qemu_bin="$1" + machine_log="/tmp/kvm_qemu_machine_help.$$" + cpu_log="/tmp/kvm_qemu_cpu_help.$$" + + [ -n "$qemu_bin" ] || return 1 + + "$qemu_bin" -version 2>&1 | while IFS= read -r line; do + log_info "[qemu-version] $line" + done + + "$qemu_bin" -machine help >"$machine_log" 2>&1 || true + head -n 20 "$machine_log" 2>/dev/null | while IFS= read -r line; do + log_info "[qemu-machine] $line" + done + rm -f "$machine_log" 2>/dev/null || true + + "$qemu_bin" -cpu help >"$cpu_log" 2>&1 || true + head -n 20 "$cpu_log" 2>/dev/null | while IFS= read -r line; do + log_info "[qemu-cpu] $line" + done + rm -f "$cpu_log" 2>/dev/null || true + + return 0 +} + +# Validate /dev/net/tun availability for VM networking. +# +# This is optional infrastructure. Missing tun should warn, not fail, +# unless the caller explicitly requires networking. +# +# Returns: +# 0 if /dev/net/tun exists +# 1 otherwise +kvm_check_tun_device() { + if [ -c /dev/net/tun ]; then + log_pass "/dev/net/tun is present" + return 0 + fi + + log_warn "/dev/net/tun is not present; VM networking may be limited" + return 1 +} + +# Validate vhost-net availability for accelerated virtio-net. +# +# This is optional infrastructure. Missing vhost-net should warn, not fail, +# unless the caller explicitly requires accelerated networking. +# +# Returns: +# 0 if /dev/vhost-net exists or vhost_net module is loaded +# 1 otherwise +kvm_check_vhost_net() { + if [ -c /dev/vhost-net ]; then + log_pass "/dev/vhost-net is present" + return 0 + fi + + if grep -qw vhost_net /proc/modules 2>/dev/null; then + log_pass "vhost_net module is loaded" + return 0 + fi + + log_warn "vhost-net is not available; virtio-net acceleration may be limited" + return 1 +} + +# Log optional KVM kernel config without emitting FAIL on missing configs. +# +# Args: +# $1 - kernel config name +# +# Returns: +# 0 if config is enabled as y/m +# 1 if config is missing or config source is unavailable +kvm_log_optional_kernel_config() { + cfg="$1" + + if [ -z "$cfg" ]; then + return 1 + fi + + if [ -r /proc/config.gz ]; then + if command -v zgrep >/dev/null 2>&1; then + if zgrep -Eq "^${cfg}=(y|m)$" /proc/config.gz 2>/dev/null; then + log_info "Optional KVM config $cfg is enabled" + return 0 + fi + elif command -v gzip >/dev/null 2>&1; then + if gzip -dc /proc/config.gz 2>/dev/null | grep -Eq "^${cfg}=(y|m)$"; then + log_info "Optional KVM config $cfg is enabled" + return 0 + fi + fi + fi + + log_warn "Optional KVM config not enabled or not visible: $cfg" + return 1 +} From d928958a92a859a81a15ea08046a11803bfe3cba Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Sun, 3 May 2026 12:54:58 +0530 Subject: [PATCH 2/2] virt: add initial KVM validation tests Add the first set of KVM validation tests under the Virtualization/KVM suite. This introduces: - KVM_Driver to validate /dev/kvm usability through KVM_GET_API_VERSION and KVM_CREATE_VM - KVM_EL2_DTB to dynamically validate EL2 DTB remoteproc/IOMMU runtime evidence without hardcoding target names - KVM_Infra to validate QEMU availability, KVM acceleration support, and optional VM host infrastructure such as tun/vhost-net The tests follow the qcom-linux-testkit conventions, reuse functestlib.sh, source the shared KVM helper library, and report SKIP for unsupported or missing optional KVM/virtualization components. Signed-off-by: Srikanth Muppandam --- .../KVM/KVM_Driver/KVM_Driver.yaml | 17 ++ .../Virtualization/KVM/KVM_Driver/README.md | 183 +++++++++++++++++ .../Virtualization/KVM/KVM_Driver/run.sh | 152 ++++++++++++++ .../KVM/KVM_EL2_DTB/KVM_EL2_DTB.yaml | 17 ++ .../Virtualization/KVM/KVM_EL2_DTB/README.md | 180 +++++++++++++++++ .../Virtualization/KVM/KVM_EL2_DTB/run.sh | 134 +++++++++++++ .../KVM/KVM_Infra/KVM_Infra.yaml | 17 ++ .../Virtualization/KVM/KVM_Infra/README.md | 187 ++++++++++++++++++ .../Virtualization/KVM/KVM_Infra/run.sh | 148 ++++++++++++++ 9 files changed, 1035 insertions(+) create mode 100755 Runner/suites/Virtualization/KVM/KVM_Driver/KVM_Driver.yaml create mode 100644 Runner/suites/Virtualization/KVM/KVM_Driver/README.md create mode 100755 Runner/suites/Virtualization/KVM/KVM_Driver/run.sh create mode 100755 Runner/suites/Virtualization/KVM/KVM_EL2_DTB/KVM_EL2_DTB.yaml create mode 100644 Runner/suites/Virtualization/KVM/KVM_EL2_DTB/README.md create mode 100755 Runner/suites/Virtualization/KVM/KVM_EL2_DTB/run.sh create mode 100755 Runner/suites/Virtualization/KVM/KVM_Infra/KVM_Infra.yaml create mode 100644 Runner/suites/Virtualization/KVM/KVM_Infra/README.md create mode 100755 Runner/suites/Virtualization/KVM/KVM_Infra/run.sh diff --git a/Runner/suites/Virtualization/KVM/KVM_Driver/KVM_Driver.yaml b/Runner/suites/Virtualization/KVM/KVM_Driver/KVM_Driver.yaml new file mode 100755 index 00000000..f68f0188 --- /dev/null +++ b/Runner/suites/Virtualization/KVM/KVM_Driver/KVM_Driver.yaml @@ -0,0 +1,17 @@ +metadata: + name: KVM_Driver + format: "Lava-Test Test Definition 1.0" + description: "Validate /dev/kvm device node and KVM ioctl API" + maintainer: + - Srikanth kumar + os: + - linux + scope: + - functional + +run: + steps: + - REPO_PATH=$PWD + - cd Runner/suites/Virtualization/KVM/KVM_Driver + - ./run.sh || true + - $REPO_PATH/Runner/utils/send-to-lava.sh KVM_Driver.res diff --git a/Runner/suites/Virtualization/KVM/KVM_Driver/README.md b/Runner/suites/Virtualization/KVM/KVM_Driver/README.md new file mode 100644 index 00000000..0fd7f320 --- /dev/null +++ b/Runner/suites/Virtualization/KVM/KVM_Driver/README.md @@ -0,0 +1,183 @@ +# KVM_Driver + +## Overview + +`KVM_Driver` validates the mandatory KVM host configuration, `/dev/kvm` +runtime device node, and KVM userspace ioctl API. + +This test now covers the baseline KVM boot/config validation that was previously +covered separately by `KVM_Boot_Up`, and then performs a stronger functional +driver check by opening `/dev/kvm`, validating the KVM API version, and +attempting a safe `KVM_CREATE_VM` ioctl through the shared `lib_kvm.sh` helper. + +This test does not launch QEMU and does not boot a guest VM. + +## Test location + +```text +Runner/suites/Virtualization/KVM/KVM_Driver/ +``` + +## Files + +```text +run.sh +KVM_Driver.yaml +README.md +``` + +## Dependencies + +The test uses common helpers from: + +```text +Runner/utils/functestlib.sh +Runner/utils/lib_kvm.sh +``` + +Required target utilities: + +```text +cat grep awk sed tr mkdir uname +``` + +Additional helper dependency: + +```text +python3 +``` + +`python3` is used by `kvm_check_api_version()` to issue the `/dev/kvm` ioctl +checks without requiring a prebuilt C helper binary. If `python3` is not +present, the test reports `SKIP`. + +## Validation coverage + +The test validates: + +1. Mandatory kernel config support: + - `CONFIG_VIRTUALIZATION` + - `CONFIG_KVM` + +2. Optional KVM-related configs are logged when visible: + - `CONFIG_HAVE_KVM` + - `CONFIG_HAVE_KVM_IRQCHIP` + - `CONFIG_HAVE_KVM_IRQFD` + - `CONFIG_KVM_ARM_PMU` + - `CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT` + +3. Runtime device node: + - `/dev/kvm` exists + - `/dev/kvm` is a character device + - `/dev/kvm` is readable and writable + +4. KVM API ioctl path: + - `open("/dev/kvm")` + - `KVM_GET_API_VERSION` + - API version must be `12` + - `KVM_CREATE_VM` + +5. Kernel log scan: + - checks for fatal KVM/EL2/HYP/GIC related runtime errors + +## Result policy + +### PASS + +The test reports `PASS` when: + +- mandatory KVM configs are enabled, +- `/dev/kvm` is present and accessible, +- KVM ioctl API validation passes, +- no fatal KVM/EL2 errors are detected in kernel logs. + +### SKIP + +The test reports `SKIP` when: + +- `python3` is not available for the ioctl helper, +- required userspace utilities are missing, +- the testcase path or setup environment cannot be resolved before test + execution starts. + +### FAIL + +The test reports `FAIL` when: + +- `CONFIG_VIRTUALIZATION` is not enabled, +- `CONFIG_KVM` is not enabled, +- `/dev/kvm` is not present, +- `/dev/kvm` exists but is not usable, +- KVM ioctl API validation fails, +- fatal KVM/EL2/HYP related errors are detected in kernel logs. + +## Manual execution + +From the repository root on target: + +```sh +cd Runner/suites/Virtualization/KVM/KVM_Driver +./run.sh +cat KVM_Driver.res +``` + +Expected result file: + +```text +KVM_Driver PASS +``` + +or: + +```text +KVM_Driver SKIP +``` + +or: + +```text +KVM_Driver FAIL +``` + +## LAVA execution + +The YAML file runs: + +```sh +cd Runner/suites/Virtualization/KVM/KVM_Driver +./run.sh || true +$REPO_PATH/Runner/utils/send-to-lava.sh KVM_Driver.res +``` + +## Logs + +The test creates logs under: + +```text +results/KVM_Driver/ +``` + +KVM/EL2 dmesg logs are captured under: + +```text +results/KVM_Driver/dmesg/ +``` + +## Notes + +`KVM_Driver` intentionally includes the baseline KVM boot/config checks so a +separate `KVM_Boot_Up` test is not required. + +This test does not launch QEMU or boot a guest VM. That coverage belongs to: + +```text +KVM_Infra +QEMU_VM_Validation +``` + +This test also does not validate EL2-DTB remoteproc/IOMMU evidence. That is +covered by: + +```text +KVM_EL2_DTB +``` diff --git a/Runner/suites/Virtualization/KVM/KVM_Driver/run.sh b/Runner/suites/Virtualization/KVM/KVM_Driver/run.sh new file mode 100755 index 00000000..74bf8260 --- /dev/null +++ b/Runner/suites/Virtualization/KVM/KVM_Driver/run.sh @@ -0,0 +1,152 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause + +TESTNAME="KVM_Driver" + +# Robustly find and source init_env +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +INIT_ENV="" +SEARCH="$SCRIPT_DIR" + +while [ "$SEARCH" != "/" ]; do + if [ -f "$SEARCH/init_env" ]; then + INIT_ENV="$SEARCH/init_env" + break + fi + SEARCH=$(dirname "$SEARCH") +done + +RES_FALLBACK="$SCRIPT_DIR/${TESTNAME}.res" + +if [ -z "$INIT_ENV" ]; then + echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2 + echo "$TESTNAME SKIP" >"$RES_FALLBACK" 2>/dev/null || true + exit 0 +fi + +# Only source if not already loaded (idempotent) +if [ -z "${__INIT_ENV_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" + __INIT_ENV_LOADED=1 +fi + +# Always source functestlib.sh, using $TOOLS exported by init_env +# shellcheck disable=SC1090,SC1091 +. "$TOOLS/functestlib.sh" + +# Source KVM helper library +# shellcheck disable=SC1090,SC1091 +. "$TOOLS/lib_kvm.sh" + +test_path=$(find_test_case_by_name "$TESTNAME") +if [ -z "$test_path" ] || [ ! -d "$test_path" ]; then + log_skip "$TESTNAME SKIP - test path not found" + echo "$TESTNAME SKIP" >"$RES_FALLBACK" 2>/dev/null || true + exit 0 +fi + +if ! cd "$test_path"; then + log_skip "$TESTNAME SKIP - cannot cd into $test_path" + echo "$TESTNAME SKIP" >"$RES_FALLBACK" 2>/dev/null || true + exit 0 +fi + +# shellcheck disable=SC2034 +res_file="./$TESTNAME.res" +RESULT_DIR="./results/$TESTNAME" +DMESG_DIR="$RESULT_DIR/dmesg" + +mkdir -p "$DMESG_DIR" 2>/dev/null || true + +log_info "-----------------------------------------------------------------------------------------" +log_info "-------------------Starting $TESTNAME Testcase----------------------------" +log_info "=== Test Initialization ===" + +deps_list="cat grep awk sed tr mkdir uname" +log_info "Checking dependencies: $deps_list" +if ! check_dependencies "$deps_list"; then + log_skip "$TESTNAME SKIP - missing one or more dependencies: $deps_list" + echo "$TESTNAME SKIP" >"$res_file" + exit 0 +fi + +if command -v detect_platform >/dev/null 2>&1; then + detect_platform >/dev/null 2>&1 || true + log_info "Platform Details: machine='${PLATFORM_MACHINE:-unknown}' target='${PLATFORM_TARGET:-unknown}' kernel='${PLATFORM_KERNEL:-}' arch='${PLATFORM_ARCH:-}'" +else + log_info "Platform Details: kernel='$(uname -r 2>/dev/null || echo unknown)' arch='$(uname -m 2>/dev/null || echo unknown)'" +fi + +log_info "=== KVM Kernel Config Validation ===" + +mandatory_cfg_missing=0 + +for cfg in CONFIG_VIRTUALIZATION CONFIG_KVM; do + if ! check_kernel_config "$cfg"; then + mandatory_cfg_missing=1 + fi +done + +if [ "$mandatory_cfg_missing" -ne 0 ]; then + log_fail "$TESTNAME FAIL - mandatory KVM kernel config is missing" + echo "$TESTNAME FAIL" >"$res_file" + exit 0 +fi + +# Optional configs: log only, do not gate test result. +for cfg in \ + CONFIG_HAVE_KVM \ + CONFIG_HAVE_KVM_IRQCHIP \ + CONFIG_HAVE_KVM_IRQFD \ + CONFIG_KVM_ARM_PMU \ + CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT +do + kvm_log_optional_kernel_config "$cfg" || true +done + +log_info "=== KVM Device Node Validation ===" +kvm_check_device_node +dev_rc=$? + +if [ "$dev_rc" -eq 2 ]; then + log_fail "$TESTNAME FAIL - /dev/kvm is not available" + echo "$TESTNAME FAIL" >"$res_file" + exit 0 +fi + +if [ "$dev_rc" -ne 0 ]; then + log_fail "$TESTNAME FAIL - /dev/kvm node validation failed" + echo "$TESTNAME FAIL" >"$res_file" + exit 0 +fi + +log_info "=== KVM ioctl API Validation ===" +kvm_check_api_version +api_rc=$? + +if [ "$api_rc" -eq 2 ]; then + log_skip "$TESTNAME SKIP - KVM API helper dependency is not available" + echo "$TESTNAME SKIP" >"$res_file" + exit 0 +fi + +if [ "$api_rc" -ne 0 ]; then + log_fail "$TESTNAME FAIL - KVM ioctl API validation failed" + echo "$TESTNAME FAIL" >"$res_file" + exit 0 +fi + +log_info "=== KVM Driver Dmesg Validation ===" +if ! kvm_check_boot_dmesg_errors "$DMESG_DIR"; then + log_fail "$TESTNAME FAIL - fatal KVM/EL2 dmesg errors detected" + echo "$TESTNAME FAIL" >"$res_file" + exit 0 +fi + +log_pass "$TESTNAME PASS - KVM kernel config, /dev/kvm, and ioctl API are valid" +echo "$TESTNAME PASS" >"$res_file" + +log_info "-------------------Completed $TESTNAME Testcase----------------------------" +exit 0 diff --git a/Runner/suites/Virtualization/KVM/KVM_EL2_DTB/KVM_EL2_DTB.yaml b/Runner/suites/Virtualization/KVM/KVM_EL2_DTB/KVM_EL2_DTB.yaml new file mode 100755 index 00000000..9e5f5da2 --- /dev/null +++ b/Runner/suites/Virtualization/KVM/KVM_EL2_DTB/KVM_EL2_DTB.yaml @@ -0,0 +1,17 @@ +metadata: + name: KVM_EL2_DTB + format: "Lava-Test Test Definition 1.0" + description: "Validate dynamic EL2-DTB remoteproc/IOMMU runtime evidence for KVM boot" + maintainer: + - Srikanth kumar + os: + - linux + scope: + - functional + +run: + steps: + - REPO_PATH=$PWD + - cd Runner/suites/Virtualization/KVM/KVM_EL2_DTB + - ./run.sh || true + - $REPO_PATH/Runner/utils/send-to-lava.sh KVM_EL2_DTB.res diff --git a/Runner/suites/Virtualization/KVM/KVM_EL2_DTB/README.md b/Runner/suites/Virtualization/KVM/KVM_EL2_DTB/README.md new file mode 100644 index 00000000..5716d3ef --- /dev/null +++ b/Runner/suites/Virtualization/KVM/KVM_EL2_DTB/README.md @@ -0,0 +1,180 @@ +# KVM_EL2_DTB + +## Overview + +`KVM_EL2_DTB` validates that the running target exposes dynamic EL2-DTB +runtime evidence required for KVM and remoteproc/IOMMU coexistence. + +This test is designed for Qualcomm ARM64 embedded targets where EL2 boot may +use an EL2-specific DTB or overlay. It intentionally avoids maintaining a +per-board allowlist and instead validates the live DT/sysfs evidence. + +The test is non-destructive. It does not stop, start, reset, or otherwise +control any remoteproc instance. + +## Test location + +```text +Runner/suites/Virtualization/KVM/KVM_EL2_DTB/ +``` + +## Files + +```text +run.sh +KVM_EL2_DTB.yaml +README.md +``` + +## Dependencies + +The test uses common helpers from: + +```text +Runner/utils/functestlib.sh +Runner/utils/lib_kvm.sh +``` + +Required target utilities: + +```text +cat grep awk sed find tr mkdir uname +``` + +## Validation coverage + +The test validates: + +1. Mandatory KVM availability gate: + - `CONFIG_KVM` + - `/dev/kvm` exists and is usable + +2. Live device-tree identity logging: + - `/proc/device-tree` + - `/sys/firmware/devicetree/base` + - `model` + - `compatible` + +3. Dynamic remoteproc inspection: + - logs `/sys/class/remoteproc/remoteproc*/name` + - logs `/sys/class/remoteproc/remoteproc*/firmware` + - logs `/sys/class/remoteproc/remoteproc*/state` + - uses existing `functestlib.sh` remoteproc helpers when available + +4. EL2-DTB evidence: + - remoteproc/rproc DT nodes + - remoteproc/rproc `iommus` properties + - runtime sysfs IOMMU/devlink/platform evidence for remoteproc devices + +5. Kernel log scan: + - checks for fatal KVM/EL2/HYP/GIC related runtime errors + +## What counts as EL2 runtime evidence + +The shared `lib_kvm.sh` helper checks for evidence such as: + +```text +/proc/device-tree/...remoteproc.../iommus +/sys/firmware/devicetree/base/...remoteproc.../iommus +/sys/kernel/iommu_groups/*/devices/*remoteproc* +/sys/kernel/iommu_groups/*/devices/*adsp* +/sys/kernel/iommu_groups/*/devices/*cdsp* +/sys/class/devlink/*remoteproc* +/sys/class/devlink/*adsp* +/sys/class/devlink/*cdsp* +/sys/bus/platform/devices/*remoteproc* +``` + +The goal is to detect whether the live boot has the EL2-style remoteproc/IOMMU +layout without hardcoding each board or DTB name. + +## Result policy + +### PASS + +The test reports `PASS` when: + +- `CONFIG_KVM` is enabled, +- `/dev/kvm` is available and usable, +- remoteproc/IOMMU EL2 runtime evidence is found, +- no fatal KVM/EL2/HYP related dmesg errors are detected. + +### SKIP + +The test reports `SKIP` when: + +- no remoteproc DT/sysfs entries exist, so EL2 remoteproc validation is not + applicable on this target, +- required userspace utilities are missing, +- the testcase path or setup environment cannot be resolved before test + execution starts. + +### FAIL + +The test reports `FAIL` when: + +- `CONFIG_KVM` is not enabled, +- `/dev/kvm` is not present, +- `/dev/kvm` exists but is not usable, +- remoteproc entries exist but no EL2-style DT/sysfs evidence is found, +- fatal KVM/EL2/HYP related errors are detected in kernel logs. + +## Manual execution + +From the repository root on target: + +```sh +cd Runner/suites/Virtualization/KVM/KVM_EL2_DTB +./run.sh +cat KVM_EL2_DTB.res +``` + +Expected result file: + +```text +KVM_EL2_DTB PASS +``` + +or: + +```text +KVM_EL2_DTB SKIP +``` + +or: + +```text +KVM_EL2_DTB FAIL +``` + +## LAVA execution + +The YAML file runs: + +```sh +cd Runner/suites/Virtualization/KVM/KVM_EL2_DTB +./run.sh || true +$REPO_PATH/Runner/utils/send-to-lava.sh KVM_EL2_DTB.res +``` + +## Logs + +The test creates logs under: + +```text +results/KVM_EL2_DTB/ +``` + +KVM/EL2 dmesg logs are captured under: + +```text +results/KVM_EL2_DTB/dmesg/ +``` + +## Notes + +This test does not duplicate secure PIL or remoteproc lifecycle validation. +Dedicated remoteproc tests should continue to cover stop/start/reset flows. + +`KVM_EL2_DTB` only validates that the live EL2-compatible DT/runtime layout is +present when KVM is available. diff --git a/Runner/suites/Virtualization/KVM/KVM_EL2_DTB/run.sh b/Runner/suites/Virtualization/KVM/KVM_EL2_DTB/run.sh new file mode 100755 index 00000000..e687b1eb --- /dev/null +++ b/Runner/suites/Virtualization/KVM/KVM_EL2_DTB/run.sh @@ -0,0 +1,134 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause + +TESTNAME="KVM_EL2_DTB" + +# Robustly find and source init_env +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +INIT_ENV="" +SEARCH="$SCRIPT_DIR" + +while [ "$SEARCH" != "/" ]; do + if [ -f "$SEARCH/init_env" ]; then + INIT_ENV="$SEARCH/init_env" + break + fi + SEARCH=$(dirname "$SEARCH") +done + +RES_FALLBACK="$SCRIPT_DIR/${TESTNAME}.res" + +if [ -z "$INIT_ENV" ]; then + echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2 + echo "$TESTNAME SKIP" >"$RES_FALLBACK" 2>/dev/null || true + exit 0 +fi + +# Only source if not already loaded (idempotent) +if [ -z "${__INIT_ENV_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" + __INIT_ENV_LOADED=1 +fi + +# Always source functestlib.sh, using $TOOLS exported by init_env +# shellcheck disable=SC1090,SC1091 +. "$TOOLS/functestlib.sh" + +# Source KVM helper library +# shellcheck disable=SC1090,SC1091 +. "$TOOLS/lib_kvm.sh" + +test_path=$(find_test_case_by_name "$TESTNAME") +if [ -z "$test_path" ] || [ ! -d "$test_path" ]; then + log_skip "$TESTNAME SKIP - test path not found" + echo "$TESTNAME SKIP" >"$RES_FALLBACK" 2>/dev/null || true + exit 0 +fi + +if ! cd "$test_path"; then + log_skip "$TESTNAME SKIP - cannot cd into $test_path" + echo "$TESTNAME SKIP" >"$RES_FALLBACK" 2>/dev/null || true + exit 0 +fi + +# shellcheck disable=SC2034 +res_file="./$TESTNAME.res" +RESULT_DIR="./results/$TESTNAME" +DMESG_DIR="$RESULT_DIR/dmesg" + +mkdir -p "$DMESG_DIR" 2>/dev/null || true + +log_info "-----------------------------------------------------------------------------------------" +log_info "-------------------Starting $TESTNAME Testcase----------------------------" +log_info "=== Test Initialization ===" + +deps_list="cat grep awk sed find tr mkdir uname" +log_info "Checking dependencies: $deps_list" +if ! check_dependencies "$deps_list"; then + log_skip "$TESTNAME SKIP - missing one or more dependencies: $deps_list" + echo "$TESTNAME SKIP" >"$res_file" + exit 0 +fi + +if command -v detect_platform >/dev/null 2>&1; then + detect_platform >/dev/null 2>&1 || true + log_info "Platform Details: machine='${PLATFORM_MACHINE:-unknown}' target='${PLATFORM_TARGET:-unknown}' kernel='${PLATFORM_KERNEL:-}' arch='${PLATFORM_ARCH:-}'" +else + log_info "Platform Details: kernel='$(uname -r 2>/dev/null || echo unknown)' arch='$(uname -m 2>/dev/null || echo unknown)'" +fi + +log_info "=== KVM Availability Gate ===" + +if ! check_kernel_config "CONFIG_KVM"; then + log_fail "$TESTNAME FAIL - mandatory KVM kernel config CONFIG_KVM is not enabled" + echo "$TESTNAME FAIL" >"$res_file" + exit 0 +fi + +kvm_check_device_node +dev_rc=$? + +if [ "$dev_rc" -eq 2 ]; then + log_fail "$TESTNAME FAIL - /dev/kvm is not available" + echo "$TESTNAME FAIL" >"$res_file" + exit 0 +fi + +if [ "$dev_rc" -ne 0 ]; then + log_fail "$TESTNAME FAIL - /dev/kvm exists but is not usable" + echo "$TESTNAME FAIL" >"$res_file" + exit 0 +fi + +log_info "=== Dynamic EL2-DTB Runtime Evidence Validation ===" +log_info "This test performs log-only remoteproc inspection and does not stop/start/reset remoteprocs." + +kvm_check_el2_runtime_evidence +el2_rc=$? + +if [ "$el2_rc" -eq 2 ]; then + log_skip "$TESTNAME SKIP - no remoteproc DT/sysfs entries found; EL2-DTB validation is not applicable" + echo "$TESTNAME SKIP" >"$res_file" + exit 0 +fi + +if [ "$el2_rc" -ne 0 ]; then + log_fail "$TESTNAME FAIL - EL2-DTB remoteproc/IOMMU runtime evidence is missing" + echo "$TESTNAME FAIL" >"$res_file" + exit 0 +fi + +log_info "=== EL2/KVM Dmesg Validation ===" +if ! kvm_check_boot_dmesg_errors "$DMESG_DIR"; then + log_fail "$TESTNAME FAIL - fatal KVM/EL2 dmesg errors detected" + echo "$TESTNAME FAIL" >"$res_file" + exit 0 +fi + +log_pass "$TESTNAME PASS - dynamic EL2-DTB evidence is valid" +echo "$TESTNAME PASS" >"$res_file" + +log_info "-------------------Completed $TESTNAME Testcase----------------------------" +exit 0 diff --git a/Runner/suites/Virtualization/KVM/KVM_Infra/KVM_Infra.yaml b/Runner/suites/Virtualization/KVM/KVM_Infra/KVM_Infra.yaml new file mode 100755 index 00000000..2492bb2c --- /dev/null +++ b/Runner/suites/Virtualization/KVM/KVM_Infra/KVM_Infra.yaml @@ -0,0 +1,17 @@ +metadata: + name: KVM_Infra + format: "Lava-Test Test Definition 1.0" + description: "Validate QEMU/KVM host infrastructure and KVM acceleration availability" + maintainer: + - Srikanth kumar + os: + - linux + scope: + - functional + +run: + steps: + - REPO_PATH=$PWD + - cd Runner/suites/Virtualization/KVM/KVM_Infra + - ./run.sh || true + - $REPO_PATH/Runner/utils/send-to-lava.sh KVM_Infra.res diff --git a/Runner/suites/Virtualization/KVM/KVM_Infra/README.md b/Runner/suites/Virtualization/KVM/KVM_Infra/README.md new file mode 100644 index 00000000..f2112a25 --- /dev/null +++ b/Runner/suites/Virtualization/KVM/KVM_Infra/README.md @@ -0,0 +1,187 @@ +# KVM_Infra + +## Overview + +`KVM_Infra` validates the host-side userspace infrastructure required to run +virtual machines with KVM acceleration. + +This test does not boot a guest VM. It verifies that KVM is available, a QEMU +system emulator exists, QEMU advertises KVM acceleration, and optional VM host +networking acceleration paths are visible when present. + +## Test location + +```text +Runner/suites/Virtualization/KVM/KVM_Infra/ +``` + +## Files + +```text +run.sh +KVM_Infra.yaml +README.md +``` + +## Dependencies + +The test uses common helpers from: + +```text +Runner/utils/functestlib.sh +Runner/utils/lib_kvm.sh +``` + +Required target utilities: + +```text +cat grep awk sed find tr head mkdir uname +``` + +Optional runtime tools: + +```text +qemu-system-aarch64 +qemu-system-arm +qemu-kvm +qemu-img +``` + +The test searches for a usable QEMU system emulator in this order: + +```text +qemu-system-aarch64 +qemu-system-arm +qemu-kvm +``` + +## Validation coverage + +The test validates: + +1. Mandatory KVM availability gate: + - `CONFIG_KVM` + - `/dev/kvm` exists and is usable + +2. QEMU binary availability: + - finds a QEMU system emulator suitable for the target + - logs QEMU version + - logs machine help output + - logs CPU help output + +3. QEMU KVM acceleration: + - runs `qemu-system-* -accel help` + - checks whether `kvm` acceleration is advertised + +4. Optional host infrastructure: + - `/dev/net/tun` + - `/dev/vhost-net` + - loaded `vhost_net` module + +5. Kernel log scan: + - checks for fatal KVM/EL2/HYP/GIC related runtime errors + +## Result policy + +### PASS + +The test reports `PASS` when: + +- `CONFIG_KVM` is enabled, +- `/dev/kvm` is available and usable, +- QEMU system binary is found, +- QEMU advertises KVM acceleration, +- no fatal KVM/EL2 errors are detected in kernel logs. + +### SKIP + +The test reports `SKIP` when: + +- no QEMU system emulator is installed, +- required userspace utilities are missing, +- the testcase path or setup environment cannot be resolved before test + execution starts. + +This keeps the test CI-safe for minimal images that intentionally do not ship +QEMU. + +### FAIL + +The test reports `FAIL` when: + +- `CONFIG_KVM` is not enabled, +- `/dev/kvm` is not present, +- `/dev/kvm` exists but is not usable, +- QEMU is installed but does not advertise KVM acceleration, +- fatal KVM/EL2/HYP related errors are detected in kernel logs. + +## Optional infrastructure behavior + +Missing `/dev/net/tun` or `vhost-net` is logged as a warning only. These are +not hard requirements for confirming QEMU/KVM host infrastructure, because a +guest may still boot with limited or alternate networking. + +## Manual execution + +From the repository root on target: + +```sh +cd Runner/suites/Virtualization/KVM/KVM_Infra +./run.sh +cat KVM_Infra.res +``` + +Expected result file: + +```text +KVM_Infra PASS +``` + +or: + +```text +KVM_Infra SKIP +``` + +or: + +```text +KVM_Infra FAIL +``` + +## LAVA execution + +The YAML file runs: + +```sh +cd Runner/suites/Virtualization/KVM/KVM_Infra +./run.sh || true +$REPO_PATH/Runner/utils/send-to-lava.sh KVM_Infra.res +``` + +## Logs + +The test creates logs under: + +```text +results/KVM_Infra/ +``` + +KVM/EL2 dmesg logs are captured under: + +```text +results/KVM_Infra/dmesg/ +``` + +## Notes + +This test only validates QEMU/KVM host infrastructure. Actual guest boot is +covered by the later `QEMU_VM_Validation` test. + +Related tests: + +```text +KVM_Driver +KVM_EL2_DTB +QEMU_VM_Validation +``` diff --git a/Runner/suites/Virtualization/KVM/KVM_Infra/run.sh b/Runner/suites/Virtualization/KVM/KVM_Infra/run.sh new file mode 100755 index 00000000..6091edb6 --- /dev/null +++ b/Runner/suites/Virtualization/KVM/KVM_Infra/run.sh @@ -0,0 +1,148 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause + +TESTNAME="KVM_Infra" + +# Robustly find and source init_env +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +INIT_ENV="" +SEARCH="$SCRIPT_DIR" + +while [ "$SEARCH" != "/" ]; do + if [ -f "$SEARCH/init_env" ]; then + INIT_ENV="$SEARCH/init_env" + break + fi + SEARCH=$(dirname "$SEARCH") +done + +RES_FALLBACK="$SCRIPT_DIR/${TESTNAME}.res" + +if [ -z "$INIT_ENV" ]; then + echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2 + echo "$TESTNAME SKIP" >"$RES_FALLBACK" 2>/dev/null || true + exit 0 +fi + +# Only source if not already loaded (idempotent) +if [ -z "${__INIT_ENV_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" + __INIT_ENV_LOADED=1 +fi + +# Always source functestlib.sh, using $TOOLS exported by init_env +# shellcheck disable=SC1090,SC1091 +. "$TOOLS/functestlib.sh" + +# Source KVM helper library +# shellcheck disable=SC1090,SC1091 +. "$TOOLS/lib_kvm.sh" + +test_path=$(find_test_case_by_name "$TESTNAME") +if [ -z "$test_path" ] || [ ! -d "$test_path" ]; then + log_skip "$TESTNAME SKIP - test path not found" + echo "$TESTNAME SKIP" >"$RES_FALLBACK" 2>/dev/null || true + exit 0 +fi + +if ! cd "$test_path"; then + log_skip "$TESTNAME SKIP - cannot cd into $test_path" + echo "$TESTNAME SKIP" >"$RES_FALLBACK" 2>/dev/null || true + exit 0 +fi + +# shellcheck disable=SC2034 +res_file="./$TESTNAME.res" +RESULT_DIR="./results/$TESTNAME" +DMESG_DIR="$RESULT_DIR/dmesg" + +mkdir -p "$DMESG_DIR" 2>/dev/null || true + +log_info "-----------------------------------------------------------------------------------------" +log_info "-------------------Starting $TESTNAME Testcase----------------------------" +log_info "=== Test Initialization ===" + +deps_list="cat grep awk sed find tr head mkdir uname" +log_info "Checking dependencies: $deps_list" +if ! check_dependencies "$deps_list"; then + log_skip "$TESTNAME SKIP - missing one or more dependencies: $deps_list" + echo "$TESTNAME SKIP" >"$res_file" + exit 0 +fi + +if command -v detect_platform >/dev/null 2>&1; then + detect_platform >/dev/null 2>&1 || true + log_info "Platform Details: machine='${PLATFORM_MACHINE:-unknown}' target='${PLATFORM_TARGET:-unknown}' kernel='${PLATFORM_KERNEL:-}' arch='${PLATFORM_ARCH:-}'" +else + log_info "Platform Details: kernel='$(uname -r 2>/dev/null || echo unknown)' arch='$(uname -m 2>/dev/null || echo unknown)'" +fi + +log_info "=== KVM Availability Gate ===" + +if ! check_kernel_config "CONFIG_KVM"; then + log_fail "$TESTNAME FAIL - mandatory KVM kernel config CONFIG_KVM is not enabled" + echo "$TESTNAME FAIL" >"$res_file" + exit 0 +fi + +kvm_check_device_node +dev_rc=$? + +if [ "$dev_rc" -eq 2 ]; then + log_fail "$TESTNAME FAIL - /dev/kvm is not available" + echo "$TESTNAME FAIL" >"$res_file" + exit 0 +fi + +if [ "$dev_rc" -ne 0 ]; then + log_fail "$TESTNAME FAIL - /dev/kvm exists but is not usable" + echo "$TESTNAME FAIL" >"$res_file" + exit 0 +fi + +log_info "=== QEMU Binary Detection ===" + +QEMU_BIN="$(kvm_find_qemu_binary 2>/dev/null || true)" +if [ -z "$QEMU_BIN" ]; then + log_skip "$TESTNAME SKIP - qemu-system binary is not installed" + echo "$TESTNAME SKIP" >"$res_file" + exit 0 +fi + +log_pass "QEMU binary found: $QEMU_BIN" + +QEMU_IMG="$(kvm_find_qemu_img 2>/dev/null || true)" +if [ -n "$QEMU_IMG" ]; then + log_pass "qemu-img found: $QEMU_IMG" +else + log_warn "qemu-img not found" +fi + +log_info "=== QEMU Capability Probe ===" +kvm_qemu_probe "$QEMU_BIN" || true + +log_info "=== QEMU KVM Acceleration Check ===" +if ! kvm_check_qemu_kvm_accel "$QEMU_BIN"; then + log_fail "$TESTNAME FAIL - QEMU does not advertise KVM acceleration" + echo "$TESTNAME FAIL" >"$res_file" + exit 0 +fi + +log_info "=== Optional VM Host Device Infrastructure ===" +kvm_check_tun_device || true +kvm_check_vhost_net || true + +log_info "=== KVM/QEMU Dmesg Validation ===" +if ! kvm_check_boot_dmesg_errors "$DMESG_DIR"; then + log_fail "$TESTNAME FAIL - fatal KVM/EL2 dmesg errors detected" + echo "$TESTNAME FAIL" >"$res_file" + exit 0 +fi + +log_pass "$TESTNAME PASS - QEMU/KVM host infrastructure is available" +echo "$TESTNAME PASS" >"$res_file" + +log_info "-------------------Completed $TESTNAME Testcase----------------------------" +exit 0