Commit 1fa7a0d5 authored by hanliyang's avatar hanliyang
Browse files

KVM: SVM: CSV: Provide KVM_CAP_HYGON_COCO_EXT interface

hygon inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IBGDLQ


CVE: NA

---------------------------

The CSV1/2/3 firmware will provide more confidential features, it's
recommended that the user space VMM (e.g. Qemu) inquiry about which
features are supported by the system and decide to utilise some of these
supported features. Provide KVM_CAP_HYGON_COCO_EXT ioctl interface so
that the user space VMM, KVM, and firmware can negotiate how to
interoperate with each other.

The KVM_CAP_HYGON_COCO_EXT interface will address many compatibility
issues when any one of the user space VMM, KVM, or firmware is not
up-to-date.

Signed-off-by: default avatarhanliyang <hanliyang@hygon.cn>
parent ef788e7b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -139,6 +139,8 @@ KVM_X86_OP_OPTIONAL(get_untagged_addr)
KVM_X86_OP_OPTIONAL(vm_attestation)
KVM_X86_OP_OPTIONAL(control_pre_system_reset)
KVM_X86_OP_OPTIONAL(control_post_system_reset)
KVM_X86_OP_OPTIONAL(get_hygon_coco_extension)
KVM_X86_OP_OPTIONAL(enable_hygon_coco_extension)

#undef KVM_X86_OP
#undef KVM_X86_OP_OPTIONAL
+2 −0
Original line number Diff line number Diff line
@@ -1778,6 +1778,8 @@ struct kvm_x86_ops {
	int (*vm_attestation)(struct kvm *kvm, unsigned long gpa, unsigned long len);
	int (*control_pre_system_reset)(struct kvm *kvm);
	int (*control_post_system_reset)(struct kvm *kvm);
	int (*get_hygon_coco_extension)(struct kvm *kvm);
	int (*enable_hygon_coco_extension)(struct kvm *kvm, u32 arg);
};

struct kvm_x86_nested_ops {
+83 −0
Original line number Diff line number Diff line
@@ -869,6 +869,13 @@ struct kvm_csv_info {

	struct list_head smr_list; /* List of guest secure memory regions */
	unsigned long nodemask; /* Nodemask where CSV3 guest's memory resides */

	/* The following 5 fields record the extension status for current VM */
	bool fw_ext_valid;	/* if @fw_ext field is valid */
	u32 fw_ext;		/* extensions supported by current platform */
	bool kvm_ext_valid;	/* if @kvm_ext field is valid */
	u32 kvm_ext;		/* extensions supported by KVM */
	u32 inuse_ext;		/* extensions inused by current VM */
};

struct kvm_svm_csv {
@@ -2690,6 +2697,80 @@ static void csv_free_asid_userid_array(void)

#endif	/* CONFIG_KVM_SUPPORTS_CSV_REUSE_ASID */

/**
 * When userspace recognizes these extensions, it is suggested that the userspace
 * enables these extensions through KVM_ENABLE_CAP, so that both the userspace
 * and KVM can utilize these extensions.
 */
static int csv_get_hygon_coco_extension(struct kvm *kvm)
{
	struct kvm_csv_info *csv;
	size_t len = sizeof(uint32_t);
	int ret = 0;

	if (!kvm)
		return 0;

	csv = &to_kvm_svm_csv(kvm)->csv_info;

	if (csv->fw_ext_valid == false) {
		ret = csv_get_extension_info(&csv->fw_ext, &len);

		if (ret == -ENODEV) {
			pr_err("Unable to interact with CSV firmware!\n");
			return 0;
		} else if (ret == -EINVAL) {
			pr_err("Need %ld bytes to record fw extension!\n", len);
			return 0;
		}

		csv->fw_ext_valid = true;
	}

	/* The kvm_ext field of kvm_csv_info is filled in only if the fw_ext
	 * field of kvm_csv_info is valid.
	 */
	if (csv->kvm_ext_valid == false) {
		/* Currently, KVM doesn't support any extensions, we don't need
		 * to fill in kvm_ext field of kvm_csv_info here.
		 */
		csv->kvm_ext_valid = true;
	}

	/* Return extension info only if both fw_ext and kvm_ext fields of
	 * kvm_csv_info are valid.
	 */
	pr_debug("%s: fw_ext=%#x kvm_ext=%#x\n",
		 __func__, csv->fw_ext, csv->kvm_ext);
	return (int)csv->kvm_ext;
}

/**
 * Return 0 means KVM accept the negotiation from userspace. Both the
 * userspace and KVM should not utilise extensions if failed to negotiate.
 */
static int csv_enable_hygon_coco_extension(struct kvm *kvm, u32 arg)
{
	struct kvm_csv_info *csv;

	if (!kvm)
		return -EINVAL;

	csv = &to_kvm_svm_csv(kvm)->csv_info;

	/* Negotiation is accepted only if both the fw_ext and kvm_ext fields
	 * of kvm_csv_info are valid and the virtual machine is a CSV3 guest.
	 */
	if (csv->fw_ext_valid && csv->kvm_ext_valid && csv3_guest(kvm)) {
		csv->inuse_ext = csv->kvm_ext & arg;
		pr_debug("%s: inuse_ext=%#x\n", __func__, csv->inuse_ext);
		return csv->inuse_ext;
	}

	/* Userspace should not utilise the extensions */
	return -EINVAL;
}

void __init csv_hardware_setup(unsigned int max_csv_asid)
{
	unsigned int nr_asids = max_csv_asid + 1;
@@ -2743,6 +2824,8 @@ void __init csv_init(struct kvm_x86_ops *ops)
	ops->vm_attestation = csv_vm_attestation;
	ops->control_pre_system_reset = csv_control_pre_system_reset;
	ops->control_post_system_reset = csv_control_post_system_reset;
	ops->get_hygon_coco_extension = csv_get_hygon_coco_extension;
	ops->enable_hygon_coco_extension = csv_enable_hygon_coco_extension;

	if (boot_cpu_has(X86_FEATURE_SEV_ES) && boot_cpu_has(X86_FEATURE_CSV3)) {
		ops->vm_destroy = csv_vm_destroy;
+23 −0
Original line number Diff line number Diff line
@@ -4722,6 +4722,18 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
			r = static_call(kvm_x86_has_emulated_msr)(kvm,
							MSR_AMD64_SEV_ES_GHCB);
		break;
	case KVM_CAP_HYGON_COCO_EXT:
		r = 0;

		/*
		 * Before running a Hygon confidential guest, the userspace
		 * should find the advanced extensions of the Hygon CSV
		 * technology. If the userspace recognize the extensions, it's
		 * suggested that the userspace to utilise extensions.
		 */
		if (is_x86_vendor_hygon() && kvm_x86_ops.get_hygon_coco_extension)
			r = static_call(kvm_x86_get_hygon_coco_extension)(kvm);
		break;
	default:
		break;
	}
@@ -6599,6 +6611,17 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
		}
		mutex_unlock(&kvm->lock);
		break;
	case KVM_CAP_HYGON_COCO_EXT:
		r = -EINVAL;

		/*
		 * The userspace negotiate with KVM to utilise extensions of
		 * Hygon CSV technology.
		 */
		if (is_x86_vendor_hygon() && kvm_x86_ops.enable_hygon_coco_extension)
			r = static_call(kvm_x86_enable_hygon_coco_extension)(kvm,
								(u32)cap->args[0]);
		break;
	default:
		r = -EINVAL;
		break;
+7 −0
Original line number Diff line number Diff line
@@ -1202,6 +1202,13 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES 229

#define KVM_CAP_SEV_ES_GHCB 500
#define KVM_CAP_HYGON_COCO_EXT 501
/* support userspace to request firmware to build CSV3 guest's memory space */
#define KVM_CAP_HYGON_COCO_EXT_CSV3_SET_PRIV_MEM  (1 << 0)
/* support request to update CSV3 guest's memory region multiple times */
#define KVM_CAP_HYGON_COCO_EXT_CSV3_MULT_LUP_DATA (1 << 1)
/* support request to inject secret to CSV3 guest */
#define KVM_CAP_HYGON_COCO_EXT_CSV3_INJ_SECRET    (1 << 2)

#define KVM_CAP_ARM_VIRT_MSI_BYPASS 799