Skip to content

Commit 25c9c7b

Browse files
committed
pKVM: x86: Add vcpu_free PV interface
Add vcpu_free PV interface for host to release a vCPU from a guest VM. This interface cleans up the operations done when creating a vCPU, which includes detaching the pkvm_vcpu structure, cleaning up vendor resources, unsharing the host's kvm_vcpu structure and tearing down the donated memory pages. The physical address and size of the torn-down memory pages are stored in a pkvm_memcache structure and returned for the host to reclaim. Signed-off-by: Chuanxiao Dong <[email protected]>
1 parent d1f700a commit 25c9c7b

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

arch/x86/include/asm/kvm_pkvm.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ union pkvm_hc_data {
6666
struct {
6767
struct pkvm_memcache memcache;
6868
} vm_destroy;
69+
struct {
70+
struct pkvm_memcache memcache;
71+
} vcpu_free;
6972
struct {
7073
u64 data[PKVM_HC_DATA_MAX_NUM];
7174
} raw;

arch/x86/include/asm/pkvm_hypercalls.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ PKVM_HC(enable_virtualization_cpu)
2020
PKVM_HC(vm_init)
2121
PKVM_HC_OUT(vm_destroy)
2222
PKVM_HC(vcpu_create)
23+
PKVM_HC_OUT(vcpu_free)
2324

2425
#undef PKVM_HC
2526
#undef PKVM_HC_OUT

arch/x86/kvm/pkvm/pkvm.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ static struct pkvm_vm_ref {
5252
*/
5353
size_t kvm_vcpu_sz = sizeof(struct kvm_vcpu);
5454

55+
static int __pkvm_vcpu_free(struct pkvm_vm *pkvm_vm, int vcpu_handle,
56+
struct pkvm_memcache *mc);
57+
5558
static int pkvm_enable_virtualization_cpu(void)
5659
{
5760
kvm_user_return_msr_cpu_online();
@@ -191,12 +194,21 @@ static void pkvm_vm_destroy(int vm_handle, struct pkvm_memcache *mc)
191194
{
192195
struct pkvm_vm *pkvm_vm = free_pkvm_vm_handle(vm_handle);
193196
unsigned long shared_kvm_pa;
197+
int i;
194198

195199
if (!pkvm_vm)
196200
return;
197201

198202
memset(mc, 0, sizeof(*mc));
199203

204+
/*
205+
* Normally all the created pkvm_vcpus should have been freed already
206+
* by the vcpu_free PV interface. In case any pkvm_vcpu is still not
207+
* freed, try to free it here.
208+
*/
209+
for (i = 0; i < pkvm_vm->kvm.created_vcpus; i++)
210+
__pkvm_vcpu_free(pkvm_vm, i, mc);
211+
200212
shared_kvm_pa = __pkvm_pa(pkvm_vm->shared_kvm);
201213

202214
kvm_x86_call(vm_destroy)(&pkvm_vm->kvm);
@@ -229,6 +241,34 @@ static int attach_pkvm_vcpu_to_vm(struct pkvm_vm *pkvm_vm, struct pkvm_vcpu *pkv
229241
return vcpu_handle;
230242
}
231243

244+
static struct pkvm_vcpu *detach_pkvm_vcpu_from_vm(struct pkvm_vm *pkvm_vm, int vcpu_handle)
245+
{
246+
int refcount = atomic_cmpxchg(&pkvm_vm->vcpu_refs[vcpu_handle], 1, 0);
247+
struct pkvm_vcpu *pkvm_vcpu;
248+
249+
if (refcount > 1) {
250+
/* The pkvm_vcpu is in use and cannot be detached. */
251+
pkvm_err("VM%d vcpu%d is busy, refcount %d\n",
252+
pkvm_vm->kvm.arch.pkvm.handle,
253+
vcpu_handle, refcount);
254+
return NULL;
255+
} else if (refcount == 0) {
256+
/* No pkvm_vcpu is attached. */
257+
return NULL;
258+
}
259+
260+
BUG_ON(refcount != 1);
261+
262+
pkvm_spin_lock(&pkvm_vm->lock);
263+
264+
pkvm_vcpu = pkvm_vm->vcpus[vcpu_handle];
265+
pkvm_vm->vcpus[vcpu_handle] = NULL;
266+
267+
pkvm_spin_unlock(&pkvm_vm->lock);
268+
269+
return pkvm_vcpu;
270+
}
271+
232272
static int setup_vcpu_lapic(struct kvm_vcpu *vcpu)
233273
{
234274
struct kvm_lapic *apic = vcpu->arch.apic, *shared_apic;
@@ -390,6 +430,49 @@ static int pkvm_vcpu_create(int vm_handle, phys_addr_t host_vcpu_pa,
390430
return ret;
391431
}
392432

433+
static int __pkvm_vcpu_free(struct pkvm_vm *pkvm_vm, int vcpu_handle,
434+
struct pkvm_memcache *mc)
435+
{
436+
struct pkvm_vcpu *pkvm_vcpu = detach_pkvm_vcpu_from_vm(pkvm_vm, vcpu_handle);
437+
unsigned long shared_vcpu_pa;
438+
struct fpstate *fps;
439+
440+
if (!pkvm_vcpu)
441+
return -EINVAL;
442+
443+
shared_vcpu_pa = __pkvm_pa(pkvm_vcpu->shared_vcpu);
444+
445+
__vcpu_free(&pkvm_vcpu->vcpu);
446+
447+
fps = pkvm_vcpu->vcpu.arch.guest_fpu.fpstate;
448+
teardown_donated_memory(mc, fps, fps->size);
449+
teardown_donated_memory(mc, pkvm_vcpu, pkvm_vcpu->size);
450+
451+
pkvm_host_unshare_hyp(shared_vcpu_pa, kvm_vcpu_sz);
452+
453+
return 0;
454+
}
455+
456+
static int pkvm_vcpu_free(int vm_handle, int vcpu_handle, struct pkvm_memcache *mc)
457+
{
458+
struct pkvm_vm *pkvm_vm;
459+
int ret;
460+
461+
if (vcpu_handle < 0 || vcpu_handle >= KVM_MAX_VCPUS)
462+
return -EINVAL;
463+
464+
pkvm_vm = pkvm_get_vm(vm_handle);
465+
if (!pkvm_vm)
466+
return -EINVAL;
467+
468+
memset(mc, 0, sizeof(*mc));
469+
470+
ret = __pkvm_vcpu_free(pkvm_vm, array_index_nospec(vcpu_handle, KVM_MAX_VCPUS), mc);
471+
472+
pkvm_put_vm(pkvm_vm);
473+
return ret;
474+
}
475+
393476
void pkvm_handle_host_hypercall(struct kvm_vcpu *vcpu)
394477
{
395478
enum pkvm_hc hc = pkvm_hc(vcpu);
@@ -428,6 +511,10 @@ void pkvm_handle_host_hypercall(struct kvm_vcpu *vcpu)
428511
pkvm_host_gpa_to_phys(pkvm_hc_input3(vcpu)),
429512
pkvm_host_gpa_to_phys(pkvm_hc_input4(vcpu)));
430513
break;
514+
case __pkvm__vcpu_free:
515+
ret = pkvm_vcpu_free(pkvm_hc_input1(vcpu), pkvm_hc_input2(vcpu),
516+
&out.vcpu_free.memcache);
517+
break;
431518
default:
432519
ret = -EINVAL;
433520
break;

0 commit comments

Comments
 (0)