@@ -52,6 +52,9 @@ static struct pkvm_vm_ref {
5252 */
5353size_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+
5558static 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+
232272static 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+
393476void 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