Skip to content

Commit a1ec5c7

Browse files
Fuad TabbaMarc Zyngier
authored andcommitted
KVM: arm64: Add infrastructure to create and track pKVM instances at EL2
Introduce a global table (and lock) to track pKVM instances at EL2, and provide hypercalls that can be used by the untrusted host to create and destroy pKVM VMs and their vCPUs. pKVM VM/vCPU state is directly accessible only by the trusted hypervisor (EL2). Each pKVM VM is directly associated with an untrusted host KVM instance, and is referenced by the host using an opaque handle. Future patches will provide hypercalls to allow the host to initialize/set/get pKVM VM/vCPU state using the opaque handle. Tested-by: Vincent Donnefort <[email protected]> Signed-off-by: Fuad Tabba <[email protected]> Co-developed-by: Will Deacon <[email protected]> Signed-off-by: Will Deacon <[email protected]> [maz: silence warning on unmap_donated_memory_noclear()] Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 5304002 commit a1ec5c7

File tree

12 files changed

+531
-0
lines changed

12 files changed

+531
-0
lines changed

arch/arm64/include/asm/kvm_asm.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ enum __kvm_host_smccc_func {
7676
__KVM_HOST_SMCCC_FUNC___vgic_v3_save_aprs,
7777
__KVM_HOST_SMCCC_FUNC___vgic_v3_restore_aprs,
7878
__KVM_HOST_SMCCC_FUNC___pkvm_vcpu_init_traps,
79+
__KVM_HOST_SMCCC_FUNC___pkvm_init_vm,
80+
__KVM_HOST_SMCCC_FUNC___pkvm_init_vcpu,
81+
__KVM_HOST_SMCCC_FUNC___pkvm_teardown_vm,
7982
};
8083

8184
#define DECLARE_KVM_VHE_SYM(sym) extern char sym[]

arch/arm64/include/asm/kvm_host.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ struct kvm_smccc_features {
115115
unsigned long vendor_hyp_bmap;
116116
};
117117

118+
typedef unsigned int pkvm_handle_t;
119+
118120
struct kvm_arch {
119121
struct kvm_s2_mmu mmu;
120122

@@ -166,6 +168,12 @@ struct kvm_arch {
166168

167169
/* Hypercall features firmware registers' descriptor */
168170
struct kvm_smccc_features smccc_feat;
171+
172+
/*
173+
* For an untrusted host VM, 'pkvm_handle' is used to lookup
174+
* the associated pKVM instance in the hypervisor.
175+
*/
176+
pkvm_handle_t pkvm_handle;
169177
};
170178

171179
struct kvm_vcpu_fault_info {

arch/arm64/include/asm/kvm_pgtable.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,14 @@ u64 kvm_pgtable_hyp_unmap(struct kvm_pgtable *pgt, u64 addr, u64 size);
296296
*/
297297
u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift);
298298

299+
/**
300+
* kvm_pgtable_stage2_pgd_size() - Helper to compute size of a stage-2 PGD
301+
* @vtcr: Content of the VTCR register.
302+
*
303+
* Return: the size (in bytes) of the stage-2 PGD
304+
*/
305+
size_t kvm_pgtable_stage2_pgd_size(u64 vtcr);
306+
299307
/**
300308
* __kvm_pgtable_stage2_init() - Initialise a guest stage-2 page-table.
301309
* @pgt: Uninitialised page-table structure to initialise.

arch/arm64/include/asm/kvm_pkvm.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
#include <linux/memblock.h>
1010
#include <asm/kvm_pgtable.h>
1111

12+
/* Maximum number of VMs that can co-exist under pKVM. */
13+
#define KVM_MAX_PVMS 255
14+
1215
#define HYP_MEMBLOCK_REGIONS 128
1316

1417
extern struct memblock_region kvm_nvhe_sym(hyp_memory)[];
@@ -40,6 +43,11 @@ static inline unsigned long hyp_vmemmap_pages(size_t vmemmap_entry_size)
4043
return res >> PAGE_SHIFT;
4144
}
4245

46+
static inline unsigned long hyp_vm_table_pages(void)
47+
{
48+
return PAGE_ALIGN(KVM_MAX_PVMS * sizeof(void *)) >> PAGE_SHIFT;
49+
}
50+
4351
static inline unsigned long __hyp_pgtable_max_pages(unsigned long nr_pages)
4452
{
4553
unsigned long total = 0, i;

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <asm/kvm_mmu.h>
1212
#include <asm/kvm_pgtable.h>
1313
#include <asm/virt.h>
14+
#include <nvhe/pkvm.h>
1415
#include <nvhe/spinlock.h>
1516

1617
/*
@@ -68,10 +69,12 @@ bool addr_is_memory(phys_addr_t phys);
6869
int host_stage2_idmap_locked(phys_addr_t addr, u64 size, enum kvm_pgtable_prot prot);
6970
int host_stage2_set_owner_locked(phys_addr_t addr, u64 size, u8 owner_id);
7071
int kvm_host_prepare_stage2(void *pgt_pool_base);
72+
int kvm_guest_prepare_stage2(struct pkvm_hyp_vm *vm, void *pgd);
7173
void handle_host_mem_abort(struct kvm_cpu_context *host_ctxt);
7274

7375
int hyp_pin_shared_mem(void *from, void *to);
7476
void hyp_unpin_shared_mem(void *from, void *to);
77+
void reclaim_guest_pages(struct pkvm_hyp_vm *vm);
7578

7679
static __always_inline void __load_host_stage2(void)
7780
{
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright (C) 2021 Google LLC
4+
* Author: Fuad Tabba <[email protected]>
5+
*/
6+
7+
#ifndef __ARM64_KVM_NVHE_PKVM_H__
8+
#define __ARM64_KVM_NVHE_PKVM_H__
9+
10+
#include <asm/kvm_pkvm.h>
11+
12+
/*
13+
* Holds the relevant data for maintaining the vcpu state completely at hyp.
14+
*/
15+
struct pkvm_hyp_vcpu {
16+
struct kvm_vcpu vcpu;
17+
18+
/* Backpointer to the host's (untrusted) vCPU instance. */
19+
struct kvm_vcpu *host_vcpu;
20+
};
21+
22+
/*
23+
* Holds the relevant data for running a protected vm.
24+
*/
25+
struct pkvm_hyp_vm {
26+
struct kvm kvm;
27+
28+
/* Backpointer to the host's (untrusted) KVM instance. */
29+
struct kvm *host_kvm;
30+
31+
/* The guest's stage-2 page-table managed by the hypervisor. */
32+
struct kvm_pgtable pgt;
33+
34+
/*
35+
* The number of vcpus initialized and ready to run.
36+
* Modifying this is protected by 'vm_table_lock'.
37+
*/
38+
unsigned int nr_vcpus;
39+
40+
/* Array of the hyp vCPU structures for this VM. */
41+
struct pkvm_hyp_vcpu *vcpus[];
42+
};
43+
44+
static inline struct pkvm_hyp_vm *
45+
pkvm_hyp_vcpu_to_hyp_vm(struct pkvm_hyp_vcpu *hyp_vcpu)
46+
{
47+
return container_of(hyp_vcpu->vcpu.kvm, struct pkvm_hyp_vm, kvm);
48+
}
49+
50+
void pkvm_hyp_vm_table_init(void *tbl);
51+
52+
int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva,
53+
unsigned long pgd_hva);
54+
int __pkvm_init_vcpu(pkvm_handle_t handle, struct kvm_vcpu *host_vcpu,
55+
unsigned long vcpu_hva);
56+
int __pkvm_teardown_vm(pkvm_handle_t handle);
57+
58+
#endif /* __ARM64_KVM_NVHE_PKVM_H__ */

arch/arm64/kvm/hyp/nvhe/hyp-main.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include <nvhe/mem_protect.h>
1717
#include <nvhe/mm.h>
18+
#include <nvhe/pkvm.h>
1819
#include <nvhe/trap_handler.h>
1920

2021
DEFINE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);
@@ -191,6 +192,33 @@ static void handle___pkvm_vcpu_init_traps(struct kvm_cpu_context *host_ctxt)
191192
__pkvm_vcpu_init_traps(kern_hyp_va(vcpu));
192193
}
193194

195+
static void handle___pkvm_init_vm(struct kvm_cpu_context *host_ctxt)
196+
{
197+
DECLARE_REG(struct kvm *, host_kvm, host_ctxt, 1);
198+
DECLARE_REG(unsigned long, vm_hva, host_ctxt, 2);
199+
DECLARE_REG(unsigned long, pgd_hva, host_ctxt, 3);
200+
201+
host_kvm = kern_hyp_va(host_kvm);
202+
cpu_reg(host_ctxt, 1) = __pkvm_init_vm(host_kvm, vm_hva, pgd_hva);
203+
}
204+
205+
static void handle___pkvm_init_vcpu(struct kvm_cpu_context *host_ctxt)
206+
{
207+
DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1);
208+
DECLARE_REG(struct kvm_vcpu *, host_vcpu, host_ctxt, 2);
209+
DECLARE_REG(unsigned long, vcpu_hva, host_ctxt, 3);
210+
211+
host_vcpu = kern_hyp_va(host_vcpu);
212+
cpu_reg(host_ctxt, 1) = __pkvm_init_vcpu(handle, host_vcpu, vcpu_hva);
213+
}
214+
215+
static void handle___pkvm_teardown_vm(struct kvm_cpu_context *host_ctxt)
216+
{
217+
DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1);
218+
219+
cpu_reg(host_ctxt, 1) = __pkvm_teardown_vm(handle);
220+
}
221+
194222
typedef void (*hcall_t)(struct kvm_cpu_context *);
195223

196224
#define HANDLE_FUNC(x) [__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
@@ -220,6 +248,9 @@ static const hcall_t host_hcall[] = {
220248
HANDLE_FUNC(__vgic_v3_save_aprs),
221249
HANDLE_FUNC(__vgic_v3_restore_aprs),
222250
HANDLE_FUNC(__pkvm_vcpu_init_traps),
251+
HANDLE_FUNC(__pkvm_init_vm),
252+
HANDLE_FUNC(__pkvm_init_vcpu),
253+
HANDLE_FUNC(__pkvm_teardown_vm),
223254
};
224255

225256
static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,20 @@ int kvm_host_prepare_stage2(void *pgt_pool_base)
141141
return 0;
142142
}
143143

144+
int kvm_guest_prepare_stage2(struct pkvm_hyp_vm *vm, void *pgd)
145+
{
146+
vm->pgt.pgd = pgd;
147+
return 0;
148+
}
149+
150+
void reclaim_guest_pages(struct pkvm_hyp_vm *vm)
151+
{
152+
unsigned long nr_pages;
153+
154+
nr_pages = kvm_pgtable_stage2_pgd_size(vm->kvm.arch.vtcr) >> PAGE_SHIFT;
155+
WARN_ON(__pkvm_hyp_donate_host(hyp_virt_to_pfn(vm->pgt.pgd), nr_pages));
156+
}
157+
144158
int __pkvm_prot_finalize(void)
145159
{
146160
struct kvm_s2_mmu *mmu = &host_mmu.arch.mmu;

0 commit comments

Comments
 (0)