Skip to content

Commit 1ee3210

Browse files
willdeaconMarc Zyngier
authored andcommitted
KVM: arm64: Implement __pkvm_host_share_hyp() using do_share()
__pkvm_host_share_hyp() shares memory between the host and the hypervisor so implement it as an invocation of the new do_share() mechanism. Note that double-sharing is no longer permitted (as this allows us to reduce the number of page-table walks significantly), but is thankfully no longer relied upon by the host. Signed-off-by: Will Deacon <[email protected]> Signed-off-by: Quentin Perret <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent e82edcc commit 1ee3210

File tree

1 file changed

+33
-88
lines changed

1 file changed

+33
-88
lines changed

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

Lines changed: 33 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -370,94 +370,6 @@ static int host_stage2_idmap(u64 addr)
370370
return ret;
371371
}
372372

373-
static inline bool check_prot(enum kvm_pgtable_prot prot,
374-
enum kvm_pgtable_prot required,
375-
enum kvm_pgtable_prot denied)
376-
{
377-
return (prot & (required | denied)) == required;
378-
}
379-
380-
int __pkvm_host_share_hyp(u64 pfn)
381-
{
382-
phys_addr_t addr = hyp_pfn_to_phys(pfn);
383-
enum kvm_pgtable_prot prot, cur;
384-
void *virt = __hyp_va(addr);
385-
enum pkvm_page_state state;
386-
kvm_pte_t pte;
387-
int ret;
388-
389-
if (!addr_is_memory(addr))
390-
return -EINVAL;
391-
392-
host_lock_component();
393-
hyp_lock_component();
394-
395-
ret = kvm_pgtable_get_leaf(&host_kvm.pgt, addr, &pte, NULL);
396-
if (ret)
397-
goto unlock;
398-
if (!pte)
399-
goto map_shared;
400-
401-
/*
402-
* Check attributes in the host stage-2 PTE. We need the page to be:
403-
* - mapped RWX as we're sharing memory;
404-
* - not borrowed, as that implies absence of ownership.
405-
* Otherwise, we can't let it got through
406-
*/
407-
cur = kvm_pgtable_stage2_pte_prot(pte);
408-
prot = pkvm_mkstate(0, PKVM_PAGE_SHARED_BORROWED);
409-
if (!check_prot(cur, PKVM_HOST_MEM_PROT, prot)) {
410-
ret = -EPERM;
411-
goto unlock;
412-
}
413-
414-
state = pkvm_getstate(cur);
415-
if (state == PKVM_PAGE_OWNED)
416-
goto map_shared;
417-
418-
/*
419-
* Tolerate double-sharing the same page, but this requires
420-
* cross-checking the hypervisor stage-1.
421-
*/
422-
if (state != PKVM_PAGE_SHARED_OWNED) {
423-
ret = -EPERM;
424-
goto unlock;
425-
}
426-
427-
ret = kvm_pgtable_get_leaf(&pkvm_pgtable, (u64)virt, &pte, NULL);
428-
if (ret)
429-
goto unlock;
430-
431-
/*
432-
* If the page has been shared with the hypervisor, it must be
433-
* already mapped as SHARED_BORROWED in its stage-1.
434-
*/
435-
cur = kvm_pgtable_hyp_pte_prot(pte);
436-
prot = pkvm_mkstate(PAGE_HYP, PKVM_PAGE_SHARED_BORROWED);
437-
if (!check_prot(cur, prot, ~prot))
438-
ret = -EPERM;
439-
goto unlock;
440-
441-
map_shared:
442-
/*
443-
* If the page is not yet shared, adjust mappings in both page-tables
444-
* while both locks are held.
445-
*/
446-
prot = pkvm_mkstate(PAGE_HYP, PKVM_PAGE_SHARED_BORROWED);
447-
ret = pkvm_create_mappings_locked(virt, virt + PAGE_SIZE, prot);
448-
BUG_ON(ret);
449-
450-
prot = pkvm_mkstate(PKVM_HOST_MEM_PROT, PKVM_PAGE_SHARED_OWNED);
451-
ret = host_stage2_idmap_locked(addr, PAGE_SIZE, prot);
452-
BUG_ON(ret);
453-
454-
unlock:
455-
hyp_unlock_component();
456-
host_unlock_component();
457-
458-
return ret;
459-
}
460-
461373
void handle_host_mem_abort(struct kvm_cpu_context *host_ctxt)
462374
{
463375
struct kvm_vcpu_fault_info fault;
@@ -708,3 +620,36 @@ static int do_share(struct pkvm_mem_share *share)
708620

709621
return WARN_ON(__do_share(share));
710622
}
623+
624+
int __pkvm_host_share_hyp(u64 pfn)
625+
{
626+
int ret;
627+
u64 host_addr = hyp_pfn_to_phys(pfn);
628+
u64 hyp_addr = (u64)__hyp_va(host_addr);
629+
struct pkvm_mem_share share = {
630+
.tx = {
631+
.nr_pages = 1,
632+
.initiator = {
633+
.id = PKVM_ID_HOST,
634+
.addr = host_addr,
635+
.host = {
636+
.completer_addr = hyp_addr,
637+
},
638+
},
639+
.completer = {
640+
.id = PKVM_ID_HYP,
641+
},
642+
},
643+
.completer_prot = PAGE_HYP,
644+
};
645+
646+
host_lock_component();
647+
hyp_lock_component();
648+
649+
ret = do_share(&share);
650+
651+
hyp_unlock_component();
652+
host_unlock_component();
653+
654+
return ret;
655+
}

0 commit comments

Comments
 (0)