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

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

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/kvm/arm64/hypercalls.c
Extension
.c
Size
9258 bytes
Lines
335
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

struct kvm_fw_reg_info {
	u64 reg;		/* Register definition */
	u64 max_feat_bit;	/* Bit that represents the upper limit of the feature-map */
	u64 reset_val;	/* Reset value for the register */
};

#define FW_REG_INFO(r)			\
	{					\
		.reg = r,			\
		.max_feat_bit = r##_BIT_MAX,	\
		.reset_val = r##_RESET_VAL	\
	}

static const struct kvm_fw_reg_info fw_reg_info[] = {
	FW_REG_INFO(KVM_REG_ARM_STD_BMAP),
	FW_REG_INFO(KVM_REG_ARM_STD_HYP_BMAP),
	FW_REG_INFO(KVM_REG_ARM_VENDOR_HYP_BMAP),
	FW_REG_INFO(KVM_REG_ARM_VENDOR_HYP_BMAP_2),
};

enum test_stage {
	TEST_STAGE_REG_IFACE,
	TEST_STAGE_HVC_IFACE_FEAT_DISABLED,
	TEST_STAGE_HVC_IFACE_FEAT_ENABLED,
	TEST_STAGE_HVC_IFACE_FALSE_INFO,
	TEST_STAGE_END,
};

static int stage = TEST_STAGE_REG_IFACE;

struct test_hvc_info {
	u32 func_id;
	u64 arg1;
};

#define TEST_HVC_INFO(f, a1)	\
	{			\
		.func_id = f,	\
		.arg1 = a1,	\
	}

static const struct test_hvc_info hvc_info[] = {
	/* KVM_REG_ARM_STD_BMAP */
	TEST_HVC_INFO(ARM_SMCCC_TRNG_VERSION, 0),
	TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_TRNG_RND64),
	TEST_HVC_INFO(ARM_SMCCC_TRNG_GET_UUID, 0),
	TEST_HVC_INFO(ARM_SMCCC_TRNG_RND32, 0),
	TEST_HVC_INFO(ARM_SMCCC_TRNG_RND64, 0),

	/* KVM_REG_ARM_STD_HYP_BMAP */
	TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_HV_PV_TIME_FEATURES),
	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_HV_PV_TIME_ST),
	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_ST, 0),

	/* KVM_REG_ARM_VENDOR_HYP_BMAP */
	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID,
			ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0),
	TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, KVM_PTP_VIRT_COUNTER),
};

/* Feed false hypercall info to test the KVM behavior */
static const struct test_hvc_info false_hvc_info[] = {
	/* Feature support check against a different family of hypercalls */
	TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID),
	TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_TRNG_RND64),
	TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_TRNG_RND64),
};

static void guest_test_hvc(const struct test_hvc_info *hc_info)
{
	unsigned int i;
	struct arm_smccc_res res;
	unsigned int hvc_info_arr_sz;

	hvc_info_arr_sz =
	hc_info == hvc_info ? ARRAY_SIZE(hvc_info) : ARRAY_SIZE(false_hvc_info);

	for (i = 0; i < hvc_info_arr_sz; i++, hc_info++) {
		memset(&res, 0, sizeof(res));
		do_smccc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res);

		switch (stage) {
		case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:
		case TEST_STAGE_HVC_IFACE_FALSE_INFO:
			__GUEST_ASSERT(res.a0 == SMCCC_RET_NOT_SUPPORTED,
				       "a0 = 0x%lx, func_id = 0x%x, arg1 = 0x%lx, stage = %u",
					res.a0, hc_info->func_id, hc_info->arg1, stage);
			break;
		case TEST_STAGE_HVC_IFACE_FEAT_ENABLED:

Annotation

Implementation Notes