Skip to content

Commit 1eab115

Browse files
Fuad Tabbaoupton
authored andcommitted
KVM: arm64: Create each pKVM hyp vcpu after its corresponding host vcpu
Instead of creating and initializing _all_ hyp vcpus in pKVM when the first host vcpu runs for the first time, initialize _each_ hyp vcpu in conjunction with its corresponding host vcpu. Some of the host vcpu state (e.g., system registers and traps values) is not initialized until the first time the host vcpu is run. Therefore, initializing a hyp vcpu before its corresponding host vcpu has run for the first time might not view the complete host state of these vcpus. Additionally, this behavior is inline with non-protected modes. Acked-by: Will Deacon <will@kernel.org> Reviewed-by: Marc Zyngier <maz@kernel.org> Signed-off-by: Fuad Tabba <tabba@google.com> Link: https://lore.kernel.org/r/20250314111832.4137161-5-tabba@google.com Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
1 parent 8b21fb4 commit 1eab115

File tree

6 files changed

+54
-42
lines changed

6 files changed

+54
-42
lines changed

arch/arm64/include/asm/kvm_host.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,8 @@ struct kvm_vcpu_arch {
873873
#define VCPU_INITIALIZED __vcpu_single_flag(cflags, BIT(0))
874874
/* SVE config completed */
875875
#define VCPU_SVE_FINALIZED __vcpu_single_flag(cflags, BIT(1))
876+
/* pKVM VCPU setup completed */
877+
#define VCPU_PKVM_FINALIZED __vcpu_single_flag(cflags, BIT(2))
876878

877879
/* Exception pending */
878880
#define PENDING_EXCEPTION __vcpu_single_flag(iflags, BIT(0))

arch/arm64/include/asm/kvm_pkvm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
int pkvm_init_host_vm(struct kvm *kvm);
2020
int pkvm_create_hyp_vm(struct kvm *kvm);
2121
void pkvm_destroy_hyp_vm(struct kvm *kvm);
22+
int pkvm_create_hyp_vcpu(struct kvm_vcpu *vcpu);
2223

2324
/*
2425
* This functions as an allow-list of protected VM capabilities.

arch/arm64/kvm/arm.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,10 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
833833
ret = pkvm_create_hyp_vm(kvm);
834834
if (ret)
835835
return ret;
836+
837+
ret = pkvm_create_hyp_vcpu(vcpu);
838+
if (ret)
839+
return ret;
836840
}
837841

838842
mutex_lock(&kvm->arch.config_lock);

arch/arm64/kvm/hyp/include/nvhe/pkvm.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,6 @@ struct pkvm_hyp_vm {
4343
struct hyp_pool pool;
4444
hyp_spinlock_t lock;
4545

46-
/*
47-
* The number of vcpus initialized and ready to run.
48-
* Modifying this is protected by 'vm_table_lock'.
49-
*/
50-
unsigned int nr_vcpus;
51-
5246
/* Array of the hyp vCPU structures for this VM. */
5347
struct pkvm_hyp_vcpu *vcpus[];
5448
};

arch/arm64/kvm/hyp/nvhe/pkvm.c

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -245,10 +245,12 @@ struct pkvm_hyp_vcpu *pkvm_load_hyp_vcpu(pkvm_handle_t handle,
245245

246246
hyp_spin_lock(&vm_table_lock);
247247
hyp_vm = get_vm_by_handle(handle);
248-
if (!hyp_vm || hyp_vm->nr_vcpus <= vcpu_idx)
248+
if (!hyp_vm || hyp_vm->kvm.created_vcpus <= vcpu_idx)
249249
goto unlock;
250250

251251
hyp_vcpu = hyp_vm->vcpus[vcpu_idx];
252+
if (!hyp_vcpu)
253+
goto unlock;
252254

253255
/* Ensure vcpu isn't loaded on more than one cpu simultaneously. */
254256
if (unlikely(hyp_vcpu->loaded_hyp_vcpu)) {
@@ -367,8 +369,14 @@ static void unpin_host_vcpus(struct pkvm_hyp_vcpu *hyp_vcpus[],
367369
{
368370
int i;
369371

370-
for (i = 0; i < nr_vcpus; i++)
371-
unpin_host_vcpu(hyp_vcpus[i]->host_vcpu);
372+
for (i = 0; i < nr_vcpus; i++) {
373+
struct pkvm_hyp_vcpu *hyp_vcpu = hyp_vcpus[i];
374+
375+
if (!hyp_vcpu)
376+
continue;
377+
378+
unpin_host_vcpu(hyp_vcpu->host_vcpu);
379+
}
372380
}
373381

374382
static void init_pkvm_hyp_vm(struct kvm *host_kvm, struct pkvm_hyp_vm *hyp_vm,
@@ -392,24 +400,18 @@ static void pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *
392400

393401
static int init_pkvm_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu,
394402
struct pkvm_hyp_vm *hyp_vm,
395-
struct kvm_vcpu *host_vcpu,
396-
unsigned int vcpu_idx)
403+
struct kvm_vcpu *host_vcpu)
397404
{
398405
int ret = 0;
399406

400407
if (hyp_pin_shared_mem(host_vcpu, host_vcpu + 1))
401408
return -EBUSY;
402409

403-
if (host_vcpu->vcpu_idx != vcpu_idx) {
404-
ret = -EINVAL;
405-
goto done;
406-
}
407-
408410
hyp_vcpu->host_vcpu = host_vcpu;
409411

410412
hyp_vcpu->vcpu.kvm = &hyp_vm->kvm;
411413
hyp_vcpu->vcpu.vcpu_id = READ_ONCE(host_vcpu->vcpu_id);
412-
hyp_vcpu->vcpu.vcpu_idx = vcpu_idx;
414+
hyp_vcpu->vcpu.vcpu_idx = READ_ONCE(host_vcpu->vcpu_idx);
413415

414416
hyp_vcpu->vcpu.arch.hw_mmu = &hyp_vm->kvm.arch.mmu;
415417
hyp_vcpu->vcpu.arch.cflags = READ_ONCE(host_vcpu->arch.cflags);
@@ -647,27 +649,28 @@ int __pkvm_init_vcpu(pkvm_handle_t handle, struct kvm_vcpu *host_vcpu,
647649
goto unlock;
648650
}
649651

650-
idx = hyp_vm->nr_vcpus;
652+
ret = init_pkvm_hyp_vcpu(hyp_vcpu, hyp_vm, host_vcpu);
653+
if (ret)
654+
goto unlock;
655+
656+
idx = hyp_vcpu->vcpu.vcpu_idx;
651657
if (idx >= hyp_vm->kvm.created_vcpus) {
652658
ret = -EINVAL;
653659
goto unlock;
654660
}
655661

656-
ret = init_pkvm_hyp_vcpu(hyp_vcpu, hyp_vm, host_vcpu, idx);
657-
if (ret)
662+
if (hyp_vm->vcpus[idx]) {
663+
ret = -EINVAL;
658664
goto unlock;
665+
}
659666

660667
hyp_vm->vcpus[idx] = hyp_vcpu;
661-
hyp_vm->nr_vcpus++;
662668
unlock:
663669
hyp_spin_unlock(&vm_table_lock);
664670

665-
if (ret) {
671+
if (ret)
666672
unmap_donated_memory(hyp_vcpu, sizeof(*hyp_vcpu));
667-
return ret;
668-
}
669-
670-
return 0;
673+
return ret;
671674
}
672675

673676
static void
@@ -714,11 +717,17 @@ int __pkvm_teardown_vm(pkvm_handle_t handle)
714717
mc = &host_kvm->arch.pkvm.teardown_mc;
715718
stage2_mc = &host_kvm->arch.pkvm.stage2_teardown_mc;
716719
reclaim_pgtable_pages(hyp_vm, stage2_mc);
717-
unpin_host_vcpus(hyp_vm->vcpus, hyp_vm->nr_vcpus);
720+
unpin_host_vcpus(hyp_vm->vcpus, hyp_vm->kvm.created_vcpus);
718721

719-
for (idx = 0; idx < hyp_vm->nr_vcpus; ++idx) {
722+
/* Push the metadata pages to the teardown memcache */
723+
for (idx = 0; idx < hyp_vm->kvm.created_vcpus; ++idx) {
720724
struct pkvm_hyp_vcpu *hyp_vcpu = hyp_vm->vcpus[idx];
721-
struct kvm_hyp_memcache *vcpu_mc = &hyp_vcpu->vcpu.arch.pkvm_memcache;
725+
struct kvm_hyp_memcache *vcpu_mc;
726+
727+
if (!hyp_vcpu)
728+
continue;
729+
730+
vcpu_mc = &hyp_vcpu->vcpu.arch.pkvm_memcache;
722731

723732
while (vcpu_mc->nr_pages) {
724733
void *addr = pop_hyp_memcache(vcpu_mc, hyp_phys_to_virt);

arch/arm64/kvm/pkvm.c

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@ static int __pkvm_create_hyp_vcpu(struct kvm_vcpu *vcpu)
128128
return -ENOMEM;
129129

130130
ret = kvm_call_hyp_nvhe(__pkvm_init_vcpu, handle, vcpu, hyp_vcpu);
131-
if (ret)
131+
if (!ret)
132+
vcpu_set_flag(vcpu, VCPU_PKVM_FINALIZED);
133+
else
132134
free_pages_exact(hyp_vcpu, hyp_vcpu_sz);
133135

134136
return ret;
@@ -147,9 +149,7 @@ static int __pkvm_create_hyp_vcpu(struct kvm_vcpu *vcpu)
147149
static int __pkvm_create_hyp_vm(struct kvm *host_kvm)
148150
{
149151
size_t pgd_sz, hyp_vm_sz;
150-
struct kvm_vcpu *host_vcpu;
151152
void *pgd, *hyp_vm;
152-
unsigned long idx;
153153
int ret;
154154

155155
if (host_kvm->created_vcpus < 1)
@@ -185,17 +185,7 @@ static int __pkvm_create_hyp_vm(struct kvm *host_kvm)
185185
host_kvm->arch.pkvm.stage2_teardown_mc.flags |= HYP_MEMCACHE_ACCOUNT_STAGE2;
186186
kvm_account_pgtable_pages(pgd, pgd_sz / PAGE_SIZE);
187187

188-
kvm_for_each_vcpu(idx, host_vcpu, host_kvm) {
189-
ret = __pkvm_create_hyp_vcpu(host_vcpu);
190-
if (ret)
191-
goto destroy_vm;
192-
}
193-
194188
return 0;
195-
196-
destroy_vm:
197-
__pkvm_destroy_hyp_vm(host_kvm);
198-
return ret;
199189
free_vm:
200190
free_pages_exact(hyp_vm, hyp_vm_sz);
201191
free_pgd:
@@ -215,6 +205,18 @@ int pkvm_create_hyp_vm(struct kvm *host_kvm)
215205
return ret;
216206
}
217207

208+
int pkvm_create_hyp_vcpu(struct kvm_vcpu *vcpu)
209+
{
210+
int ret = 0;
211+
212+
mutex_lock(&vcpu->kvm->arch.config_lock);
213+
if (!vcpu_get_flag(vcpu, VCPU_PKVM_FINALIZED))
214+
ret = __pkvm_create_hyp_vcpu(vcpu);
215+
mutex_unlock(&vcpu->kvm->arch.config_lock);
216+
217+
return ret;
218+
}
219+
218220
void pkvm_destroy_hyp_vm(struct kvm *host_kvm)
219221
{
220222
mutex_lock(&host_kvm->arch.config_lock);

0 commit comments

Comments
 (0)