Skip to content

Commit 9926cfc

Browse files
Quentin PerretMarc Zyngier
authored andcommitted
KVM: arm64: Add helpers to pin memory shared with the hypervisor at EL2
Add helpers allowing the hypervisor to check whether a range of pages are currently shared by the host, and 'pin' them if so by blocking host unshare operations until the memory has been unpinned. This will allow the hypervisor to take references on host-provided data-structures (e.g. 'struct kvm') with the guarantee that these pages will remain in a stable state until the hypervisor decides to release them, for example during guest teardown. Tested-by: Vincent Donnefort <[email protected]> Signed-off-by: Quentin Perret <[email protected]> Signed-off-by: Will Deacon <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 43c1ff8 commit 9926cfc

File tree

3 files changed

+57
-1
lines changed

3 files changed

+57
-1
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ int host_stage2_set_owner_locked(phys_addr_t addr, u64 size, u8 owner_id);
6969
int kvm_host_prepare_stage2(void *pgt_pool_base);
7070
void handle_host_mem_abort(struct kvm_cpu_context *host_ctxt);
7171

72+
int hyp_pin_shared_mem(void *from, void *to);
73+
void hyp_unpin_shared_mem(void *from, void *to);
74+
7275
static __always_inline void __load_host_stage2(void)
7376
{
7477
if (static_branch_likely(&kvm_protected_mode_initialized))

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,15 @@ static inline void hyp_page_ref_inc(struct hyp_page *p)
5555
p->refcount++;
5656
}
5757

58-
static inline int hyp_page_ref_dec_and_test(struct hyp_page *p)
58+
static inline void hyp_page_ref_dec(struct hyp_page *p)
5959
{
6060
BUG_ON(!p->refcount);
6161
p->refcount--;
62+
}
63+
64+
static inline int hyp_page_ref_dec_and_test(struct hyp_page *p)
65+
{
66+
hyp_page_ref_dec(p);
6267
return (p->refcount == 0);
6368
}
6469

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

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,9 @@ static int hyp_ack_unshare(u64 addr, const struct pkvm_mem_transition *tx)
625625
{
626626
u64 size = tx->nr_pages * PAGE_SIZE;
627627

628+
if (tx->initiator.id == PKVM_ID_HOST && hyp_page_count((void *)addr))
629+
return -EBUSY;
630+
628631
if (__hyp_ack_skip_pgtable_check(tx))
629632
return 0;
630633

@@ -1038,3 +1041,48 @@ int __pkvm_hyp_donate_host(u64 pfn, u64 nr_pages)
10381041

10391042
return ret;
10401043
}
1044+
1045+
int hyp_pin_shared_mem(void *from, void *to)
1046+
{
1047+
u64 cur, start = ALIGN_DOWN((u64)from, PAGE_SIZE);
1048+
u64 end = PAGE_ALIGN((u64)to);
1049+
u64 size = end - start;
1050+
int ret;
1051+
1052+
host_lock_component();
1053+
hyp_lock_component();
1054+
1055+
ret = __host_check_page_state_range(__hyp_pa(start), size,
1056+
PKVM_PAGE_SHARED_OWNED);
1057+
if (ret)
1058+
goto unlock;
1059+
1060+
ret = __hyp_check_page_state_range(start, size,
1061+
PKVM_PAGE_SHARED_BORROWED);
1062+
if (ret)
1063+
goto unlock;
1064+
1065+
for (cur = start; cur < end; cur += PAGE_SIZE)
1066+
hyp_page_ref_inc(hyp_virt_to_page(cur));
1067+
1068+
unlock:
1069+
hyp_unlock_component();
1070+
host_unlock_component();
1071+
1072+
return ret;
1073+
}
1074+
1075+
void hyp_unpin_shared_mem(void *from, void *to)
1076+
{
1077+
u64 cur, start = ALIGN_DOWN((u64)from, PAGE_SIZE);
1078+
u64 end = PAGE_ALIGN((u64)to);
1079+
1080+
host_lock_component();
1081+
hyp_lock_component();
1082+
1083+
for (cur = start; cur < end; cur += PAGE_SIZE)
1084+
hyp_page_ref_dec(hyp_virt_to_page(cur));
1085+
1086+
hyp_unlock_component();
1087+
host_unlock_component();
1088+
}

0 commit comments

Comments
 (0)