Skip to content

Commit 72db3d3

Browse files
Quentin PerretMarc Zyngier
authored andcommitted
KVM: arm64: Introduce __pkvm_host_unshare_guest()
In preparation for letting the host unmap pages from non-protected guests, introduce a new hypercall implementing the host-unshare-guest transition. Tested-by: Fuad Tabba <[email protected]> Reviewed-by: Fuad Tabba <[email protected]> Signed-off-by: Quentin Perret <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Marc Zyngier <[email protected]>
1 parent d0bd3e6 commit 72db3d3

File tree

6 files changed

+108
-0
lines changed

6 files changed

+108
-0
lines changed

arch/arm64/include/asm/kvm_asm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ enum __kvm_host_smccc_func {
6666
__KVM_HOST_SMCCC_FUNC___pkvm_host_share_hyp,
6767
__KVM_HOST_SMCCC_FUNC___pkvm_host_unshare_hyp,
6868
__KVM_HOST_SMCCC_FUNC___pkvm_host_share_guest,
69+
__KVM_HOST_SMCCC_FUNC___pkvm_host_unshare_guest,
6970
__KVM_HOST_SMCCC_FUNC___kvm_adjust_pc,
7071
__KVM_HOST_SMCCC_FUNC___kvm_vcpu_run,
7172
__KVM_HOST_SMCCC_FUNC___kvm_flush_vm_context,

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ int __pkvm_host_share_ffa(u64 pfn, u64 nr_pages);
4141
int __pkvm_host_unshare_ffa(u64 pfn, u64 nr_pages);
4242
int __pkvm_host_share_guest(u64 pfn, u64 gfn, struct pkvm_hyp_vcpu *vcpu,
4343
enum kvm_pgtable_prot prot);
44+
int __pkvm_host_unshare_guest(u64 gfn, struct pkvm_hyp_vm *hyp_vm);
4445

4546
bool addr_is_memory(phys_addr_t phys);
4647
int host_stage2_idmap_locked(phys_addr_t addr, u64 size, enum kvm_pgtable_prot prot);

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ static inline bool pkvm_hyp_vcpu_is_protected(struct pkvm_hyp_vcpu *hyp_vcpu)
6464
return vcpu_is_protected(&hyp_vcpu->vcpu);
6565
}
6666

67+
static inline bool pkvm_hyp_vm_is_protected(struct pkvm_hyp_vm *hyp_vm)
68+
{
69+
return kvm_vm_is_protected(&hyp_vm->kvm);
70+
}
71+
6772
void pkvm_hyp_vm_table_init(void *tbl);
6873

6974
int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva,
@@ -78,6 +83,7 @@ void pkvm_put_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu);
7883
struct pkvm_hyp_vcpu *pkvm_get_loaded_hyp_vcpu(void);
7984

8085
struct pkvm_hyp_vm *get_pkvm_hyp_vm(pkvm_handle_t handle);
86+
struct pkvm_hyp_vm *get_np_pkvm_hyp_vm(pkvm_handle_t handle);
8187
void put_pkvm_hyp_vm(struct pkvm_hyp_vm *hyp_vm);
8288

8389
#endif /* __ARM64_KVM_NVHE_PKVM_H__ */

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,26 @@ static void handle___pkvm_host_share_guest(struct kvm_cpu_context *host_ctxt)
244244
cpu_reg(host_ctxt, 1) = ret;
245245
}
246246

247+
static void handle___pkvm_host_unshare_guest(struct kvm_cpu_context *host_ctxt)
248+
{
249+
DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1);
250+
DECLARE_REG(u64, gfn, host_ctxt, 2);
251+
struct pkvm_hyp_vm *hyp_vm;
252+
int ret = -EINVAL;
253+
254+
if (!is_protected_kvm_enabled())
255+
goto out;
256+
257+
hyp_vm = get_np_pkvm_hyp_vm(handle);
258+
if (!hyp_vm)
259+
goto out;
260+
261+
ret = __pkvm_host_unshare_guest(gfn, hyp_vm);
262+
put_pkvm_hyp_vm(hyp_vm);
263+
out:
264+
cpu_reg(host_ctxt, 1) = ret;
265+
}
266+
247267
static void handle___kvm_adjust_pc(struct kvm_cpu_context *host_ctxt)
248268
{
249269
DECLARE_REG(struct kvm_vcpu *, vcpu, host_ctxt, 1);
@@ -454,6 +474,7 @@ static const hcall_t host_hcall[] = {
454474
HANDLE_FUNC(__pkvm_host_share_hyp),
455475
HANDLE_FUNC(__pkvm_host_unshare_hyp),
456476
HANDLE_FUNC(__pkvm_host_share_guest),
477+
HANDLE_FUNC(__pkvm_host_unshare_guest),
457478
HANDLE_FUNC(__kvm_adjust_pc),
458479
HANDLE_FUNC(__kvm_vcpu_run),
459480
HANDLE_FUNC(__kvm_flush_vm_context),

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

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,3 +1421,70 @@ int __pkvm_host_share_guest(u64 pfn, u64 gfn, struct pkvm_hyp_vcpu *vcpu,
14211421

14221422
return ret;
14231423
}
1424+
1425+
static int __check_host_shared_guest(struct pkvm_hyp_vm *vm, u64 *__phys, u64 ipa)
1426+
{
1427+
enum pkvm_page_state state;
1428+
struct hyp_page *page;
1429+
kvm_pte_t pte;
1430+
u64 phys;
1431+
s8 level;
1432+
int ret;
1433+
1434+
ret = kvm_pgtable_get_leaf(&vm->pgt, ipa, &pte, &level);
1435+
if (ret)
1436+
return ret;
1437+
if (level != KVM_PGTABLE_LAST_LEVEL)
1438+
return -E2BIG;
1439+
if (!kvm_pte_valid(pte))
1440+
return -ENOENT;
1441+
1442+
state = guest_get_page_state(pte, ipa);
1443+
if (state != PKVM_PAGE_SHARED_BORROWED)
1444+
return -EPERM;
1445+
1446+
phys = kvm_pte_to_phys(pte);
1447+
ret = check_range_allowed_memory(phys, phys + PAGE_SIZE);
1448+
if (WARN_ON(ret))
1449+
return ret;
1450+
1451+
page = hyp_phys_to_page(phys);
1452+
if (page->host_state != PKVM_PAGE_SHARED_OWNED)
1453+
return -EPERM;
1454+
if (WARN_ON(!page->host_share_guest_count))
1455+
return -EINVAL;
1456+
1457+
*__phys = phys;
1458+
1459+
return 0;
1460+
}
1461+
1462+
int __pkvm_host_unshare_guest(u64 gfn, struct pkvm_hyp_vm *vm)
1463+
{
1464+
u64 ipa = hyp_pfn_to_phys(gfn);
1465+
struct hyp_page *page;
1466+
u64 phys;
1467+
int ret;
1468+
1469+
host_lock_component();
1470+
guest_lock_component(vm);
1471+
1472+
ret = __check_host_shared_guest(vm, &phys, ipa);
1473+
if (ret)
1474+
goto unlock;
1475+
1476+
ret = kvm_pgtable_stage2_unmap(&vm->pgt, ipa, PAGE_SIZE);
1477+
if (ret)
1478+
goto unlock;
1479+
1480+
page = hyp_phys_to_page(phys);
1481+
page->host_share_guest_count--;
1482+
if (!page->host_share_guest_count)
1483+
WARN_ON(__host_set_page_state_range(phys, PAGE_SIZE, PKVM_PAGE_OWNED));
1484+
1485+
unlock:
1486+
guest_unlock_component(vm);
1487+
host_unlock_component();
1488+
1489+
return ret;
1490+
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,18 @@ void put_pkvm_hyp_vm(struct pkvm_hyp_vm *hyp_vm)
376376
hyp_spin_unlock(&vm_table_lock);
377377
}
378378

379+
struct pkvm_hyp_vm *get_np_pkvm_hyp_vm(pkvm_handle_t handle)
380+
{
381+
struct pkvm_hyp_vm *hyp_vm = get_pkvm_hyp_vm(handle);
382+
383+
if (hyp_vm && pkvm_hyp_vm_is_protected(hyp_vm)) {
384+
put_pkvm_hyp_vm(hyp_vm);
385+
hyp_vm = NULL;
386+
}
387+
388+
return hyp_vm;
389+
}
390+
379391
static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struct kvm *host_kvm)
380392
{
381393
struct kvm *kvm = &hyp_vm->kvm;

0 commit comments

Comments
 (0)