Unverified Commit a64ebe8e authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!5264 [OLK-6.6]HYGON: Support CSV Reuse ASID feature on Hygon CPUs

Merge Pull Request from: @hanliyang 
 
Support CSV Reuse ASID feature on Hygon CPUs

issue:
https://gitee.com/open_euler/dashboard?issue_id=I98WUF

There are only 15 ASIDs can be used for CSV/CSV2 guest in maximum on Hygon CPU before C86-4G, that is, only 15 CSV virtual machines encrypted with different keys are supported. However, some deployment scenarios need to run more than 15 encrypted virtual machines, which makes the CPU before C86-4G difficult to meet the requirements. Through reuse ASID feature, users can deploy a group of CSV virtual machines or CSV kata containers to share the same asid. This patch provides reuse asid support for the KVM module part, which requires user to add application code to userspace VMM, such as Qemu. 
 
Link:https://gitee.com/openeuler/kernel/pulls/5264

 

Reviewed-by: default avatarKevin Zhu <zhukeqian1@huawei.com>
Signed-off-by: default avatarZhang Peng <zhangpeng362@huawei.com>
parents 3dce4f55 1e361b51
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -163,4 +163,14 @@ config ARCH_VCPU_STAT

	  If unsure, say N.

config KVM_SUPPORTS_CSV_REUSE_ASID
	def_bool y
	bool "Reuse the same ASID for different HYGON CSV guests"
	depends on KVM_AMD_SEV && CPU_SUP_HYGON && HYGON_CSV
	depends on !CGROUP_MISC
	help
	  Provide support for reuse the same ASID for difference HYGON
	  CSV guests, this allow the user to create more CSV guests on
	  HYGON CPUs with limited ASIDs.

endif # VIRTUALIZATION
+27 −0
Original line number Diff line number Diff line
@@ -1058,6 +1058,33 @@ static int csv_control_post_system_reset(struct kvm *kvm)
	return 0;
}

#ifdef CONFIG_KVM_SUPPORTS_CSV_REUSE_ASID

struct csv_asid_userid *csv_asid_userid_array;

int csv_alloc_asid_userid_array(unsigned int nr_asids)
{
	int ret = 0;

	csv_asid_userid_array = kcalloc(nr_asids, sizeof(struct csv_asid_userid),
					GFP_KERNEL_ACCOUNT);
	if (!csv_asid_userid_array)
		ret = -ENOMEM;

	if (ret)
		pr_warn("Fail to allocate array, reuse ASID is unavailable\n");

	return ret;
}

void csv_free_asid_userid_array(void)
{
	kfree(csv_asid_userid_array);
	csv_asid_userid_array = NULL;
}

#endif	/* CONFIG_KVM_SUPPORTS_CSV_REUSE_ASID */

void csv_exit(void)
{
}
+22 −0
Original line number Diff line number Diff line
@@ -32,6 +32,28 @@ struct csv_ringbuf_infos {
	int num;
};

#ifdef CONFIG_KVM_SUPPORTS_CSV_REUSE_ASID

#define ASID_USERID_LENGTH 20

struct csv_asid_userid {
	int refcnt; // reference count of the ASID
	u32 userid_len;
	char userid[ASID_USERID_LENGTH];
};

extern struct csv_asid_userid *csv_asid_userid_array;

int csv_alloc_asid_userid_array(unsigned int nr_asids);
void csv_free_asid_userid_array(void);

#else

static inline int csv_alloc_asid_userid_array(unsigned int nr_asids) { return -ENOMEM; }
static inline void csv_free_asid_userid_array(void) { }

#endif	/* CONFIG_KVM_SUPPORTS_CSV_REUSE_ASID */

#ifdef CONFIG_HYGON_CSV

/*
+122 −8
Original line number Diff line number Diff line
@@ -145,7 +145,11 @@ static void sev_misc_cg_uncharge(struct kvm_sev_info *sev)
	misc_cg_uncharge(type, sev->misc_cg, 1);
}

#ifdef CONFIG_KVM_SUPPORTS_CSV_REUSE_ASID
static int sev_asid_new(struct kvm_sev_info *sev, const char *userid, u32 userid_len)
#else
static int sev_asid_new(struct kvm_sev_info *sev)
#endif
{
	/*
	 * SEV-enabled guests must use asid from min_sev_asid to max_sev_asid.
@@ -180,6 +184,34 @@ static int sev_asid_new(struct kvm_sev_info *sev)

	mutex_lock(&sev_bitmap_lock);

#ifdef CONFIG_KVM_SUPPORTS_CSV_REUSE_ASID
	/* For Hygon CPU, check whether the userid exists */
	if (is_x86_vendor_hygon() && userid && userid_len &&
	    !WARN_ON_ONCE(!csv_asid_userid_array)) {
		int i = !min_sev_asid ? 1 : min_sev_asid;

		for (; i <= max_sev_asid; i++) {
			/* skip ASIDs without correspond userid */
			if (!csv_asid_userid_array[i].userid_len)
				continue;

			/* skip if length of userid is different */
			if (csv_asid_userid_array[i].userid_len != userid_len)
				continue;

			if (!memcmp(csv_asid_userid_array[i].userid,
				    userid, userid_len)) {
				pr_debug("Found reusable asid %d\n", i);
				/* Increase reference count if userid exists */
				csv_asid_userid_array[i].refcnt++;

				mutex_unlock(&sev_bitmap_lock);
				return i;
			}
		}
	}
#endif

again:
	asid = find_next_zero_bit(sev_asid_bitmap, max_asid + 1, min_asid);
	if (asid > max_asid) {
@@ -194,6 +226,16 @@ static int sev_asid_new(struct kvm_sev_info *sev)

	__set_bit(asid, sev_asid_bitmap);

#ifdef CONFIG_KVM_SUPPORTS_CSV_REUSE_ASID
	/* For Hygon CPU, initialize the new userid */
	if (is_x86_vendor_hygon() && userid && userid_len &&
	    !WARN_ON_ONCE(!csv_asid_userid_array)) {
		memcpy(csv_asid_userid_array[asid].userid, userid, userid_len);
		csv_asid_userid_array[asid].userid_len = userid_len;
		csv_asid_userid_array[asid].refcnt = 1;
	}
#endif

	mutex_unlock(&sev_bitmap_lock);

	return asid;
@@ -218,8 +260,26 @@ static void sev_asid_free(struct kvm_sev_info *sev)

	mutex_lock(&sev_bitmap_lock);

#ifdef CONFIG_KVM_SUPPORTS_CSV_REUSE_ASID
	/* For Hygon CPU, decrease the reference count if userid exist */
	if (!is_x86_vendor_hygon() || !csv_asid_userid_array ||
	    !csv_asid_userid_array[sev->asid].userid_len) {
		__set_bit(sev->asid, sev_reclaim_asid_bitmap);
	} else {
		/* If reach here, reference count should large than 0. */
		WARN_ON(csv_asid_userid_array[sev->asid].refcnt <= 0);

		if (--csv_asid_userid_array[sev->asid].refcnt == 0) {
			__set_bit(sev->asid, sev_reclaim_asid_bitmap);

			memset(&csv_asid_userid_array[sev->asid], 0,
			       sizeof(struct csv_asid_userid));
		}
	}
#else
	__set_bit(sev->asid, sev_reclaim_asid_bitmap);
#endif

	for_each_possible_cpu(cpu) {
		sd = per_cpu_ptr(&svm_data, cpu);
		sd->sev_vmcbs[sev->asid] = NULL;
@@ -274,7 +334,46 @@ static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)

	sev->active = true;
	sev->es_active = argp->id == KVM_SEV_ES_INIT;

#ifdef CONFIG_KVM_SUPPORTS_CSV_REUSE_ASID
	/* Try reuse ASID iff userid array is available for HYGON CSV guests */
	if (is_x86_vendor_hygon() && csv_asid_userid_array) {
		struct kvm_csv_init params;
		void *csv_blob = NULL;

		memset(&params, 0, sizeof(params));

		if (argp->data &&
		    copy_from_user(&params,
				(void __user *)(uintptr_t)argp->data, sizeof(params)))
			return -EFAULT;

		if (params.userid_addr) {
			if (params.len >= ASID_USERID_LENGTH) {
				pr_err("Invalid length of userid %d > %d\n",
				       params.len, ASID_USERID_LENGTH);
				return -EINVAL;
			}

			csv_blob = psp_copy_user_blob(params.userid_addr, params.len);
			if (IS_ERR(csv_blob)) {
				pr_err("Copy userid failed, %llx (%u)\n",
				       params.userid_addr, params.len);
				return PTR_ERR(csv_blob);
			}
		}

		asid = sev_asid_new(sev, (const char *)csv_blob, params.len);

		/* The buffer @csv_blob is no longer used, free it. */
		kfree(csv_blob);
	} else {
		asid = sev_asid_new(sev, NULL, 0);
	}
#else
	asid = sev_asid_new(sev);
#endif

	if (asid < 0)
		goto e_no_asid;
	sev->asid = asid;
@@ -2348,13 +2447,19 @@ void __init sev_hardware_setup(void)
		 */
		sev_install_hooks();

		if (sev_enabled) {
			/*
			 * Allocate a memory pool to speed up live migration of
			 * the CSV/CSV2 guests. If the allocation fails, no
			 * acceleration is performed at live migration.
			 */
		if (sev_enabled)
			csv_alloc_trans_mempool();
			/*
			 * Allocate a buffer to support reuse ASID, reuse ASID
			 * will not work if the allocation fails.
			 */
			csv_alloc_asid_userid_array(nr_asids);
		}
	}
#endif

@@ -2366,9 +2471,11 @@ void sev_hardware_unsetup(void)
	if (!sev_enabled)
		return;

	/* Free the memory pool that allocated in sev_hardware_setup(). */
	if (is_x86_vendor_hygon())
	/* Free the memory that allocated in sev_hardware_setup(). */
	if (is_x86_vendor_hygon()) {
		csv_free_trans_mempool();
		csv_free_asid_userid_array();
	}

	/* No need to take sev_bitmap_lock, all VMs have been destroyed. */
	sev_flush_asids(1, max_sev_asid);
@@ -2727,6 +2834,13 @@ void pre_sev_run(struct vcpu_svm *svm, int cpu)
	/* Assign the asid allocated with this SEV guest */
	svm->asid = asid;

#ifdef CONFIG_KVM_SUPPORTS_CSV_REUSE_ASID
	/* If ASID is shared with other guests, then flush TLB before VMRUN */
	if (is_x86_vendor_hygon() && csv_asid_userid_array &&
	    csv_asid_userid_array[asid].userid_len)
		svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ASID;
#endif

	/*
	 * Flush guest TLB:
	 *
+5 −0
Original line number Diff line number Diff line
@@ -2334,6 +2334,11 @@ struct kvm_csv_receive_update_vmsa {
	__u32 trans_len;
};

struct kvm_csv_init {
	__u64 userid_addr;
	__u32 len;
};

/* ioctls for control vm during system reset, currently only for CSV */
#define KVM_CONTROL_PRE_SYSTEM_RESET	 _IO(KVMIO, 0xe8)
#define KVM_CONTROL_POST_SYSTEM_RESET	 _IO(KVMIO, 0xe9)