KVM: SVM: Add support for different CSV guests to reuse the same ASID
Upstream: no If user want to reuse one ASID for many CSV guests, he should provide a label (i.e. userid) and the length of the label when launch CSV guest. The reference count of the ASID will be increased if user launch a CSV guest with the label correspond to the ASID. When a CSV guest which launch with a label is destroyed, the reference count of the ASID correspond to the label will be decreased, and the ASID is freed only if the reference count becomes zero. The codes for reuse ASID is not compatible with CONFIG_CGROUP_MISC, we introduce CONFIG_KVM_SUPPORTS_CSV_REUSE_ASID that depends on !CGROUP_MISC, the code take effect only when CONFIG_KVM_SUPPORTS_CSV_REUSE_ASID=y. Signed-off-by: hanliyang <hanliyang@hygon.cn>
This commit is contained in:
parent
d0eb7cacd6
commit
079cc16170
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
/*
|
||||
|
|
|
@ -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(¶ms, 0, sizeof(params));
|
||||
|
||||
if (argp->data &&
|
||||
copy_from_user(¶ms,
|
||||
(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:
|
||||
*
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue