Skip to content

Commit c9a3bf1

Browse files
committed
Support the COVH promote_to_tvm() ABI which causes a TVM to be created in a
single-step. Preload VM pages into memory, fill the NACL shared memory with boot vcpu state, and reflect the promote_to_tvm() call to the TSM. Support CoVE implementations that do not support dynamic page conversion. A TSM that does not support dynamic page conversion does not require the donation of pages to store VCPU state in confidential memory. Signed-off-by: Wojciech Ozga <woz@zurich.ibm.com>
1 parent 1910bf1 commit c9a3bf1

File tree

11 files changed

+218
-29
lines changed

11 files changed

+218
-29
lines changed

arch/riscv/include/asm/kvm_cove.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,10 @@ int kvm_riscv_cove_init(void);
134134

135135
/* TVM related functions */
136136
void kvm_riscv_cove_vm_destroy(struct kvm *kvm);
137-
int kvm_riscv_cove_vm_init(struct kvm *kvm);
137+
int kvm_riscv_cove_vm_single_step_init(struct kvm_vcpu *vcpu,
138+
unsigned long fdt_address,
139+
unsigned long tap_addr);
140+
int kvm_riscv_cove_vm_multi_step_init(struct kvm *kvm);
138141

139142
/* TVM VCPU related functions */
140143
void kvm_riscv_cove_vcpu_destroy(struct kvm_vcpu *vcpu);
@@ -168,7 +171,13 @@ static inline int kvm_riscv_cove_hardware_enable(void) {return 0; }
168171

169172
/* TVM related functions */
170173
static inline void kvm_riscv_cove_vm_destroy(struct kvm *kvm) {}
171-
static inline int kvm_riscv_cove_vm_init(struct kvm *kvm) {return -1; }
174+
static inline int kvm_riscv_cove_vm_single_step_init(struct kvm_vcpu *vcpu,
175+
unsigned long fdt_address,
176+
unsigned long tap_addr)
177+
{
178+
return -1;
179+
}
180+
static inline int kvm_riscv_cove_vm_multi_step_init(struct kvm *kvm) {return -1; }
172181

173182
/* TVM VCPU related functions */
174183
static inline void kvm_riscv_cove_vcpu_destroy(struct kvm_vcpu *vcpu) {}

arch/riscv/include/asm/kvm_cove_sbi.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ int sbi_covh_tvm_demote_page(unsigned long tvmid,
7878
int sbi_covh_tvm_remove_pages(unsigned long tvmid,
7979
unsigned long tvm_base_page_addr,
8080
unsigned long len);
81+
int sbi_covh_tsm_promote_to_tvm(unsigned long fdt_address,
82+
unsigned long tap_addr,
83+
unsigned long sepc,
84+
unsigned long *tvmid);
8185

8286
/* Functions related to CoVE Interrupt Management(COVI) Extension */
8387
int sbi_covi_tvm_aia_init(unsigned long tvm_gid, struct sbi_cove_tvm_aia_params *tvm_aia_params);

arch/riscv/include/asm/kvm_vcpu_sbi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_experimental;
6868
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_vendor;
6969
#ifdef CONFIG_RISCV_COVE_HOST
7070
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_covg;
71+
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_covh;
7172
#endif
7273

7374
#endif /* __RISCV_KVM_VCPU_SBI_H__ */

arch/riscv/include/uapi/asm/kvm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ enum KVM_RISCV_SBI_EXT_ID {
149149
KVM_RISCV_SBI_EXT_VENDOR,
150150
KVM_RISCV_SBI_EXT_DBCN,
151151
KVM_RISCV_SBI_EXT_COVG,
152+
KVM_RISCV_SBI_EXT_COVH,
152153
KVM_RISCV_SBI_EXT_MAX,
153154
};
154155

arch/riscv/kvm/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@ kvm-y += aia.o
3131
kvm-y += aia_device.o
3232
kvm-y += aia_aplic.o
3333
kvm-y += aia_imsic.o
34-
kvm-$(CONFIG_RISCV_COVE_HOST) += cove_sbi.o cove.o vcpu_sbi_covg.o
34+
kvm-$(CONFIG_RISCV_COVE_HOST) += cove_sbi.o cove.o vcpu_sbi_covg.o vcpu_sbi_covh.o

arch/riscv/kvm/cove.c

Lines changed: 81 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -628,12 +628,12 @@ void kvm_riscv_cove_vcpu_destroy(struct kvm_vcpu *vcpu)
628628

629629
int kvm_riscv_cove_vcpu_init(struct kvm_vcpu *vcpu)
630630
{
631-
int rc;
632-
struct kvm *kvm;
633631
struct kvm_cove_tvm_vcpu_context *tvcpuc;
634632
struct kvm_cove_tvm_context *tvmc;
635-
struct page *vcpus_page;
636633
unsigned long vcpus_phys_addr;
634+
struct page *vcpus_page;
635+
struct kvm *kvm;
636+
int rc;
637637

638638
if (!vcpu)
639639
return -EINVAL;
@@ -654,36 +654,38 @@ int kvm_riscv_cove_vcpu_init(struct kvm_vcpu *vcpu)
654654
if (!tvcpuc)
655655
return -ENOMEM;
656656

657-
vcpus_page = alloc_pages(GFP_KERNEL | __GFP_ZERO,
658-
get_order_num_pages(tinfo.tvcpu_pages_needed));
659-
if (!vcpus_page) {
660-
rc = -ENOMEM;
661-
goto alloc_page_failed;
662-
}
663-
664657
tvcpuc->vcpu = vcpu;
665658
tvcpuc->vcpu_state.npages = tinfo.tvcpu_pages_needed;
666-
tvcpuc->vcpu_state.page = vcpus_page;
667-
vcpus_phys_addr = page_to_phys(vcpus_page);
668659

669-
rc = cove_convert_pages(vcpus_phys_addr, tvcpuc->vcpu_state.npages, true);
670-
if (rc)
671-
goto convert_failed;
660+
if (tinfo.tvcpu_pages_needed > 0) {
661+
vcpus_page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order_num_pages(tinfo.tvcpu_pages_needed));
662+
if (!vcpus_page) {
663+
rc = -ENOMEM;
664+
goto alloc_page_failed;
665+
}
666+
tvcpuc->vcpu_state.page = vcpus_page;
667+
vcpus_phys_addr = page_to_phys(vcpus_page);
672668

673-
rc = sbi_covh_create_tvm_vcpu(tvmc->tvm_guest_id, vcpu->vcpu_idx, vcpus_phys_addr);
674-
if (rc)
675-
goto vcpu_create_failed;
669+
rc = cove_convert_pages(vcpus_phys_addr, tvcpuc->vcpu_state.npages, true);
670+
if (rc)
671+
goto convert_failed;
676672

673+
rc = sbi_covh_create_tvm_vcpu(tvmc->tvm_guest_id, vcpu->vcpu_idx, vcpus_phys_addr);
674+
if (rc)
675+
goto vcpu_create_failed;
676+
}
677677
vcpu->arch.tc = tvcpuc;
678678

679679
return 0;
680680

681681
vcpu_create_failed:
682682
/* Reclaim all the pages or return to the confidential page pool */
683-
sbi_covh_tsm_reclaim_pages(vcpus_phys_addr, tvcpuc->vcpu_state.npages);
683+
if (tinfo.tvcpu_pages_needed > 0)
684+
sbi_covh_tsm_reclaim_pages(vcpus_phys_addr, tvcpuc->vcpu_state.npages);
684685

685686
convert_failed:
686-
__free_pages(vcpus_page, get_order_num_pages(tinfo.tvcpu_pages_needed));
687+
if (tinfo.tvcpu_pages_needed > 0)
688+
__free_pages(vcpus_page, get_order_num_pages(tinfo.tvcpu_pages_needed));
687689

688690
alloc_page_failed:
689691
kfree(tvcpuc);
@@ -877,7 +879,7 @@ void kvm_riscv_cove_vm_destroy(struct kvm *kvm)
877879
kvm_err("Memory reclaim failed with rc %d\n", rc);
878880
}
879881

880-
int kvm_riscv_cove_vm_init(struct kvm *kvm)
882+
int kvm_riscv_cove_vm_multi_step_init(struct kvm *kvm)
881883
{
882884
struct kvm_cove_tvm_context *tvmc;
883885
struct page *tvms_page, *pgt_page;
@@ -980,6 +982,64 @@ int kvm_riscv_cove_vm_init(struct kvm *kvm)
980982
return rc;
981983
}
982984

985+
int kvm_riscv_cove_vm_single_step_init(struct kvm_vcpu *vcpu, unsigned long fdt_address,
986+
unsigned long tap_addr)
987+
{
988+
struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
989+
unsigned long tvm_gid, target_vcpuid;
990+
struct kvm_cove_tvm_context *tvmc;
991+
struct kvm_vcpu *target_vcpu;
992+
struct kvm *kvm = vcpu->kvm;
993+
void *nshmem = nacl_shmem();
994+
int rc = 0, gpr_id, offset;
995+
996+
tvmc = kzalloc(sizeof(*tvmc), GFP_KERNEL);
997+
if (!tvmc)
998+
return -ENOMEM;
999+
1000+
for (gpr_id = 1; gpr_id < 32; gpr_id++) {
1001+
offset = KVM_ARCH_GUEST_ZERO + gpr_id * sizeof(unsigned long);
1002+
nacl_shmem_gpr_write_cove(nshmem, offset,
1003+
((unsigned long *)cp)[gpr_id]);
1004+
}
1005+
kvm_arch_vcpu_load(vcpu, smp_processor_id());
1006+
rc = sbi_covh_tsm_promote_to_tvm(fdt_address, tap_addr, cp->sepc, &tvm_gid);
1007+
if (rc)
1008+
goto done;
1009+
1010+
INIT_LIST_HEAD(&tvmc->measured_pages);
1011+
INIT_LIST_HEAD(&tvmc->zero_pages);
1012+
INIT_LIST_HEAD(&tvmc->shared_pages);
1013+
INIT_LIST_HEAD(&tvmc->reclaim_pending_pages);
1014+
1015+
tvmc->tvm_guest_id = tvm_gid;
1016+
tvmc->kvm = kvm;
1017+
kvm->arch.tvmc = tvmc;
1018+
1019+
kvm_for_each_vcpu(target_vcpuid, target_vcpu, kvm) {
1020+
rc = kvm_riscv_cove_vcpu_init(target_vcpu);
1021+
if (rc)
1022+
goto vcpus_allocated;
1023+
1024+
target_vcpu->requests = 0;
1025+
if (target_vcpu->vcpu_idx != 0)
1026+
kvm_riscv_vcpu_power_off(target_vcpu);
1027+
}
1028+
1029+
tvmc->finalized_done = true;
1030+
kvm_info("Guest VM creation successful with guest id %lx\n", tvm_gid);
1031+
return 0;
1032+
1033+
vcpus_allocated:
1034+
kvm_for_each_vcpu(target_vcpuid, target_vcpu, kvm)
1035+
if (target_vcpu->arch.tc)
1036+
kfree(target_vcpu->arch.tc);
1037+
1038+
done:
1039+
kfree(tvmc);
1040+
return rc;
1041+
}
1042+
9831043
int kvm_riscv_cove_init(void)
9841044
{
9851045
int rc;

arch/riscv/kvm/cove_sbi.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,3 +488,23 @@ int sbi_covh_tvm_remove_pages(unsigned long tvmid,
488488

489489
return 0;
490490
}
491+
492+
int sbi_covh_tsm_promote_to_tvm(unsigned long fdt_address,
493+
unsigned long tap_addr,
494+
unsigned long sepc,
495+
unsigned long *tvmid)
496+
{
497+
struct sbiret ret;
498+
int rc = 0;
499+
500+
ret = sbi_ecall(SBI_EXT_COVH, SBI_EXT_COVH_PROMOTE_TO_TVM, fdt_address,
501+
tap_addr, sepc, 0, 0, 0);
502+
if (ret.error) {
503+
rc = sbi_err_map_linux_errno(ret.error);
504+
goto done;
505+
}
506+
507+
*tvmid = ret.value;
508+
done:
509+
return rc;
510+
}

arch/riscv/kvm/main.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ int kvm_arch_hardware_enable(void)
3232

3333
/*
3434
* We just need to invoke aia enable for CoVE if host is in VS mode and TSM
35-
* supports AIA (COVI extension). However, if the host is running in HS mode,
36-
* we need to initialize other CSRs as well for legacy VMs.
35+
* supports AIA (COVI extension). However, if the host is running in HS
36+
* mode, we need to initialize other CSRs as well for legacy VMs.
3737
*/
38-
if (unlikely(kvm_riscv_cove_enabled()) && likely(kvm_riscv_covi_available()))
38+
if (unlikely(kvm_riscv_cove_enabled()) && kvm_riscv_covi_available())
3939
goto enable_aia;
4040

4141
hedeleg = 0;

arch/riscv/kvm/vcpu_sbi.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ static const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_covg = {
4040
.extid_end = -1UL,
4141
.handler = NULL,
4242
};
43+
static const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_covh = {
44+
.extid_start = -1UL,
45+
.extid_end = -1UL,
46+
.handler = NULL,
47+
};
4348
#endif
4449

4550
struct kvm_riscv_sbi_extension_entry {
@@ -96,6 +101,10 @@ static const struct kvm_riscv_sbi_extension_entry sbi_ext[] = {
96101
.dis_idx = KVM_RISCV_SBI_EXT_COVG,
97102
.ext_ptr = &vcpu_sbi_ext_covg,
98103
},
104+
{
105+
.dis_idx = KVM_RISCV_SBI_EXT_COVH,
106+
.ext_ptr = &vcpu_sbi_ext_covh,
107+
},
99108
};
100109

101110
void kvm_riscv_vcpu_sbi_forward(struct kvm_vcpu *vcpu, struct kvm_run *run)

arch/riscv/kvm/vcpu_sbi_covh.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (c) 2024 IBM.
4+
*
5+
* Authors:
6+
* Wojciech Ozga <woz@zurich.ibm.com>
7+
*/
8+
9+
#include <linux/errno.h>
10+
#include <linux/err.h>
11+
#include <linux/kvm_host.h>
12+
#include <linux/list.h>
13+
#include <linux/mm.h>
14+
#include <linux/spinlock.h>
15+
#include <asm/csr.h>
16+
#include <asm/sbi.h>
17+
#include <asm/kvm_vcpu_sbi.h>
18+
#include <asm/kvm_cove.h>
19+
#include <asm/kvm_cove_sbi.h>
20+
#include <asm/kvm_nacl.h>
21+
#include <linux/rbtree.h>
22+
#include <linux/pgtable.h>
23+
24+
static int preload_pages(struct kvm_vcpu *vcpu) {
25+
unsigned long hva, fault_addr, page;
26+
struct kvm_memory_slot *memslot;
27+
bool writable;
28+
29+
memslot = search_memslots(kvm_memslots(vcpu->kvm),
30+
kernel_map.phys_addr, true);
31+
if (memslot) {
32+
for (page = 0; page < memslot->npages; page++) {
33+
fault_addr = gfn_to_gpa(memslot->base_gfn) +
34+
page * PAGE_SIZE;
35+
hva = gfn_to_hva_memslot_prot(memslot,
36+
gpa_to_gfn(fault_addr),
37+
&writable);
38+
if (!kvm_is_error_hva(hva))
39+
kvm_riscv_gstage_map(vcpu, memslot, fault_addr,
40+
hva, NULL);
41+
}
42+
}
43+
44+
return 0;
45+
}
46+
47+
static int kvm_riscv_cove_promote_to_tvm(struct kvm_vcpu *vcpu,
48+
unsigned long fdt_address,
49+
unsigned long tap_addr) {
50+
int rc;
51+
52+
preload_pages(vcpu);
53+
rc = kvm_riscv_cove_vm_single_step_init(vcpu, fdt_address, tap_addr);
54+
if (rc)
55+
goto done;
56+
57+
vcpu->kvm->arch.vm_type = KVM_VM_TYPE_RISCV_COVE;
58+
done:
59+
return rc;
60+
}
61+
62+
static int kvm_sbi_ext_covh_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
63+
struct kvm_vcpu_sbi_return *retdata)
64+
{
65+
struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
66+
unsigned long funcid = cp->a6;
67+
int ret;
68+
69+
switch (funcid) {
70+
case SBI_EXT_COVH_PROMOTE_TO_TVM:
71+
ret = kvm_riscv_cove_promote_to_tvm(vcpu, cp->a0, cp->a1);
72+
return 0;
73+
74+
default:
75+
kvm_err("%s: Unsupported guest SBI %ld.\n", __func__, funcid);
76+
retdata->err_val = SBI_ERR_NOT_SUPPORTED;
77+
return -EOPNOTSUPP;
78+
}
79+
}
80+
81+
const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_covh = {
82+
.extid_start = SBI_EXT_COVH,
83+
.extid_end = SBI_EXT_COVH,
84+
.handler = kvm_sbi_ext_covh_handler,
85+
};

0 commit comments

Comments
 (0)