!156 [next-6.6]Hygon: Support reuse ASID feature for Hygon CSV

Merge pull request !156 from hanliyang/next_CSV-reuse-ASID
This commit is contained in:
刘诗 2024-05-11 07:12:15 +00:00 committed by Gitee
commit af8a5753e4
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
5 changed files with 186 additions and 8 deletions

View File

@ -154,4 +154,14 @@ config KVM_PROVE_MMU
config KVM_EXTERNAL_WRITE_TRACKING
bool
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

View File

@ -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)
{
}

View File

@ -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
/*

View File

@ -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 @@ again:
__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,7 +260,25 @@ 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);
@ -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 @@ out:
*/
sev_install_hooks();
/*
* 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)
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.
*/
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:
*

View File

@ -2301,6 +2301,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)