tools/testing/selftests/kvm/arm64/smccc_filter.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/kvm/arm64/smccc_filter.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/kvm/arm64/smccc_filter.c
Extension
.c
Size
7091 bytes
Lines
282
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0-only
/*
 * smccc_filter - Tests for the SMCCC filter UAPI.
 *
 * Copyright (c) 2023 Google LLC
 *
 * This test includes:
 *  - Tests that the UAPI constraints are upheld by KVM. For example, userspace
 *    is prevented from filtering the architecture range of SMCCC calls.
 *  - Test that the filter actions (DENIED, FWD_TO_USER) work as intended.
 */

#include <linux/arm-smccc.h>
#include <linux/psci.h>
#include <stdint.h>

#include "processor.h"
#include "test_util.h"

enum smccc_conduit {
	HVC_INSN,
	SMC_INSN,
};

static bool test_runs_at_el2(void)
{
	struct kvm_vm *vm = vm_create(1);
	struct kvm_vcpu_init init;

	kvm_get_default_vcpu_target(vm, &init);
	kvm_vm_free(vm);

	return init.features[0] & BIT(KVM_ARM_VCPU_HAS_EL2);
}

#define for_each_conduit(conduit)					\
	for (conduit = test_runs_at_el2() ? SMC_INSN : HVC_INSN;	\
	     conduit <= SMC_INSN; conduit++)

static void guest_main(u32 func_id, enum smccc_conduit conduit)
{
	struct arm_smccc_res res;

	if (conduit == SMC_INSN)
		smccc_smc(func_id, 0, 0, 0, 0, 0, 0, 0, &res);
	else
		smccc_hvc(func_id, 0, 0, 0, 0, 0, 0, 0, &res);

	GUEST_SYNC(res.a0);
}

static int __set_smccc_filter(struct kvm_vm *vm, u32 start, u32 nr_functions,
			      enum kvm_smccc_filter_action action)
{
	struct kvm_smccc_filter filter = {
		.base		= start,
		.nr_functions	= nr_functions,
		.action		= action,
	};

	return __kvm_device_attr_set(vm->fd, KVM_ARM_VM_SMCCC_CTRL,
				     KVM_ARM_VM_SMCCC_FILTER, &filter);
}

static void set_smccc_filter(struct kvm_vm *vm, u32 start, u32 nr_functions,
			     enum kvm_smccc_filter_action action)
{
	int ret = __set_smccc_filter(vm, start, nr_functions, action);

	TEST_ASSERT(!ret, "failed to configure SMCCC filter: %d", ret);
}

static struct kvm_vm *setup_vm(struct kvm_vcpu **vcpu)
{
	struct kvm_vcpu_init init;
	struct kvm_vm *vm;

	vm = vm_create(1);
	kvm_get_default_vcpu_target(vm, &init);

	/*
	 * Enable in-kernel emulation of PSCI to ensure that calls are denied
	 * due to the SMCCC filter, not because of KVM.
	 */
	init.features[0] |= (1 << KVM_ARM_VCPU_PSCI_0_2);

	*vcpu = aarch64_vcpu_add(vm, 0, &init, guest_main);
	kvm_arch_vm_finalize_vcpus(vm);
	return vm;
}

Annotation

Implementation Notes