* [PATCH 0/3] KVM: arm64: Simplify pKVM memory transitions
@ 2025-01-10 12:19 Quentin Perret
2025-01-10 12:19 ` [PATCH 1/3] KVM: arm64: Drop pkvm_mem_transition for FF-A Quentin Perret
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Quentin Perret @ 2025-01-10 12:19 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, Joey Gouly, Suzuki K Poulose,
Zenghui Yu, Catalin Marinas, Will Deacon
Cc: Fuad Tabba, Vincent Donnefort, linux-arm-kernel, kvmarm,
linux-kernel
Since its early days, pKVM has formalized memory 'transitions' (shares
and donations) using 'struct pkvm_mem_transition' and bunch of helpers
to manipulate it. The intention was for all transitions to use this
machinery to ensure we're checking things consistently. However, as
development progressed, it became clear that the rigidity of this model
made it really difficult to use in some use-cases which ended-up
side-stepping it entirely. That is the case for the
hyp_{un}pin_shared_mem() and host_{un}share_guest() paths upstream which
use lower level helpers directly, as well as for several other pKVM
features that should land upstream in the future (ex: when a guest
relinquishes a page during ballooning, when annotating a page that is
being DMA'd to, ...). On top of this, the pkvm_mem_transition machinery
requires a lot of boilerplate which makes the code hard to read, but
also adds layers of indirection that no compilers seems to see through,
hence leading to suboptimal generated code.
Given all the above, this series removes the pkvm_mem_transition
machinery from mem_protect.c, and converts all its users to use
__*_{check,set}_page_state_range() low-level helpers directly.
A few things to note:
- the existing helpers to request, ack, initiate and complete
transitions were mostly wrappers around
__*_{check,set}_page_state_range() anyways, so we're not losing that
much in terms of consistency
- the pkvm_mem_transition machinery did not suffice to avoid bugs such
as [1]. The pkvm selftest [2] should do a much better job at that
- see diffstat ;-)
This series depends on support for NP guest stage-2 for pKVM [3] as well
as the fix in [1]. I've pushed a branch with all the goodies applied [4]
if that can be useful.
Thanks,
Quentin
[1] https://lore.kernel.org/kvmarm/20241128154406.602875-1-qperret@google.com/
[2] https://lore.kernel.org/kvmarm/20241129125800.992468-1-qperret@google.com/
[3] https://lore.kernel.org/kvmarm/20241218194059.3670226-1-qperret@google.com/
[4] https://android-kvm.googlesource.com/linux/+/refs/heads/qperret/no-mem-tx
Quentin Perret (3):
KVM: arm64: Drop pkvm_mem_transition for FF-A
KVM: arm64: Drop pkvm_mem_transition for host/hyp sharing
KVM: arm64: Drop pkvm_mem_transition for host/hyp donations
arch/arm64/kvm/hyp/nvhe/mem_protect.c | 640 +++-----------------------
1 file changed, 76 insertions(+), 564 deletions(-)
--
2.47.1.688.g23fc6f90ad-goog
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/3] KVM: arm64: Drop pkvm_mem_transition for FF-A
2025-01-10 12:19 [PATCH 0/3] KVM: arm64: Simplify pKVM memory transitions Quentin Perret
@ 2025-01-10 12:19 ` Quentin Perret
2025-01-10 12:19 ` [PATCH 2/3] KVM: arm64: Drop pkvm_mem_transition for host/hyp sharing Quentin Perret
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Quentin Perret @ 2025-01-10 12:19 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, Joey Gouly, Suzuki K Poulose,
Zenghui Yu, Catalin Marinas, Will Deacon
Cc: Fuad Tabba, Vincent Donnefort, linux-arm-kernel, kvmarm,
linux-kernel
Simplify the __pkvm_host_{un}share_ffa() paths by using
{check,set}_page_state_range().
No functional changes intended.
Signed-off-by: Quentin Perret <qperret@google.com>
---
arch/arm64/kvm/hyp/nvhe/mem_protect.c | 36 ++++++++-------------------
1 file changed, 10 insertions(+), 26 deletions(-)
diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
index 392f036bc69e..3a3d9fcbc508 100644
--- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c
+++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
@@ -1324,22 +1324,14 @@ void hyp_unpin_shared_mem(void *from, void *to)
int __pkvm_host_share_ffa(u64 pfn, u64 nr_pages)
{
+ u64 phys = hyp_pfn_to_phys(pfn);
+ u64 size = PAGE_SIZE * nr_pages;
int ret;
- struct pkvm_mem_share share = {
- .tx = {
- .nr_pages = nr_pages,
- .initiator = {
- .id = PKVM_ID_HOST,
- .addr = hyp_pfn_to_phys(pfn),
- },
- .completer = {
- .id = PKVM_ID_FFA,
- },
- },
- };
host_lock_component();
- ret = do_share(&share);
+ ret = __host_check_page_state_range(phys, size, PKVM_PAGE_OWNED);
+ if (!ret)
+ ret = __host_set_page_state_range(phys, size, PKVM_PAGE_SHARED_OWNED);
host_unlock_component();
return ret;
@@ -1347,22 +1339,14 @@ int __pkvm_host_share_ffa(u64 pfn, u64 nr_pages)
int __pkvm_host_unshare_ffa(u64 pfn, u64 nr_pages)
{
+ u64 phys = hyp_pfn_to_phys(pfn);
+ u64 size = PAGE_SIZE * nr_pages;
int ret;
- struct pkvm_mem_share share = {
- .tx = {
- .nr_pages = nr_pages,
- .initiator = {
- .id = PKVM_ID_HOST,
- .addr = hyp_pfn_to_phys(pfn),
- },
- .completer = {
- .id = PKVM_ID_FFA,
- },
- },
- };
host_lock_component();
- ret = do_unshare(&share);
+ ret = __host_check_page_state_range(phys, size, PKVM_PAGE_SHARED_OWNED);
+ if (!ret)
+ ret = __host_set_page_state_range(phys, size, PKVM_PAGE_OWNED);
host_unlock_component();
return ret;
--
2.47.1.688.g23fc6f90ad-goog
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/3] KVM: arm64: Drop pkvm_mem_transition for host/hyp sharing
2025-01-10 12:19 [PATCH 0/3] KVM: arm64: Simplify pKVM memory transitions Quentin Perret
2025-01-10 12:19 ` [PATCH 1/3] KVM: arm64: Drop pkvm_mem_transition for FF-A Quentin Perret
@ 2025-01-10 12:19 ` Quentin Perret
2025-01-10 12:19 ` [PATCH 3/3] KVM: arm64: Drop pkvm_mem_transition for host/hyp donations Quentin Perret
2025-01-12 10:42 ` [PATCH 0/3] KVM: arm64: Simplify pKVM memory transitions Marc Zyngier
3 siblings, 0 replies; 5+ messages in thread
From: Quentin Perret @ 2025-01-10 12:19 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, Joey Gouly, Suzuki K Poulose,
Zenghui Yu, Catalin Marinas, Will Deacon
Cc: Fuad Tabba, Vincent Donnefort, linux-arm-kernel, kvmarm,
linux-kernel
Simplify the __pkvm_host_{un}share_hyp() paths by not using the
pkvm_mem_transition machinery. As there are the last users of the
do_share()/do_unshare(), remove all the now-unused code as well.
No functional changes intended.
Signed-off-by: Quentin Perret <qperret@google.com>
---
arch/arm64/kvm/hyp/nvhe/mem_protect.c | 319 +++-----------------------
1 file changed, 34 insertions(+), 285 deletions(-)
diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
index 3a3d9fcbc508..cd8d233b9527 100644
--- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c
+++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
@@ -685,36 +685,6 @@ static int host_request_owned_transition(u64 *completer_addr,
return __host_check_page_state_range(addr, size, PKVM_PAGE_OWNED);
}
-static int host_request_unshare(u64 *completer_addr,
- const struct pkvm_mem_transition *tx)
-{
- u64 size = tx->nr_pages * PAGE_SIZE;
- u64 addr = tx->initiator.addr;
-
- *completer_addr = tx->initiator.host.completer_addr;
- return __host_check_page_state_range(addr, size, PKVM_PAGE_SHARED_OWNED);
-}
-
-static int host_initiate_share(u64 *completer_addr,
- const struct pkvm_mem_transition *tx)
-{
- u64 size = tx->nr_pages * PAGE_SIZE;
- u64 addr = tx->initiator.addr;
-
- *completer_addr = tx->initiator.host.completer_addr;
- return __host_set_page_state_range(addr, size, PKVM_PAGE_SHARED_OWNED);
-}
-
-static int host_initiate_unshare(u64 *completer_addr,
- const struct pkvm_mem_transition *tx)
-{
- u64 size = tx->nr_pages * PAGE_SIZE;
- u64 addr = tx->initiator.addr;
-
- *completer_addr = tx->initiator.host.completer_addr;
- return __host_set_page_state_range(addr, size, PKVM_PAGE_OWNED);
-}
-
static int host_initiate_donation(u64 *completer_addr,
const struct pkvm_mem_transition *tx)
{
@@ -802,31 +772,6 @@ static bool __hyp_ack_skip_pgtable_check(const struct pkvm_mem_transition *tx)
tx->initiator.id != PKVM_ID_HOST);
}
-static int hyp_ack_share(u64 addr, const struct pkvm_mem_transition *tx,
- enum kvm_pgtable_prot perms)
-{
- u64 size = tx->nr_pages * PAGE_SIZE;
-
- if (perms != PAGE_HYP)
- return -EPERM;
-
- if (__hyp_ack_skip_pgtable_check(tx))
- return 0;
-
- return __hyp_check_page_state_range(addr, size, PKVM_NOPAGE);
-}
-
-static int hyp_ack_unshare(u64 addr, const struct pkvm_mem_transition *tx)
-{
- u64 size = tx->nr_pages * PAGE_SIZE;
-
- if (tx->initiator.id == PKVM_ID_HOST && hyp_page_count((void *)addr))
- return -EBUSY;
-
- return __hyp_check_page_state_range(addr, size,
- PKVM_PAGE_SHARED_BORROWED);
-}
-
static int hyp_ack_donation(u64 addr, const struct pkvm_mem_transition *tx)
{
u64 size = tx->nr_pages * PAGE_SIZE;
@@ -837,24 +782,6 @@ static int hyp_ack_donation(u64 addr, const struct pkvm_mem_transition *tx)
return __hyp_check_page_state_range(addr, size, PKVM_NOPAGE);
}
-static int hyp_complete_share(u64 addr, const struct pkvm_mem_transition *tx,
- enum kvm_pgtable_prot perms)
-{
- void *start = (void *)addr, *end = start + (tx->nr_pages * PAGE_SIZE);
- enum kvm_pgtable_prot prot;
-
- prot = pkvm_mkstate(perms, PKVM_PAGE_SHARED_BORROWED);
- return pkvm_create_mappings_locked(start, end, prot);
-}
-
-static int hyp_complete_unshare(u64 addr, const struct pkvm_mem_transition *tx)
-{
- u64 size = tx->nr_pages * PAGE_SIZE;
- int ret = kvm_pgtable_hyp_unmap(&pkvm_pgtable, addr, size);
-
- return (ret != size) ? -EFAULT : 0;
-}
-
static int hyp_complete_donation(u64 addr,
const struct pkvm_mem_transition *tx)
{
@@ -885,180 +812,6 @@ static int __guest_check_page_state_range(struct pkvm_hyp_vcpu *vcpu, u64 addr,
return check_page_state_range(&vm->pgt, addr, size, &d);
}
-static int check_share(struct pkvm_mem_share *share)
-{
- const struct pkvm_mem_transition *tx = &share->tx;
- u64 completer_addr;
- int ret;
-
- switch (tx->initiator.id) {
- case PKVM_ID_HOST:
- ret = host_request_owned_transition(&completer_addr, tx);
- break;
- default:
- ret = -EINVAL;
- }
-
- if (ret)
- return ret;
-
- switch (tx->completer.id) {
- case PKVM_ID_HYP:
- ret = hyp_ack_share(completer_addr, tx, share->completer_prot);
- break;
- case PKVM_ID_FFA:
- /*
- * We only check the host; the secure side will check the other
- * end when we forward the FFA call.
- */
- ret = 0;
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int __do_share(struct pkvm_mem_share *share)
-{
- const struct pkvm_mem_transition *tx = &share->tx;
- u64 completer_addr;
- int ret;
-
- switch (tx->initiator.id) {
- case PKVM_ID_HOST:
- ret = host_initiate_share(&completer_addr, tx);
- break;
- default:
- ret = -EINVAL;
- }
-
- if (ret)
- return ret;
-
- switch (tx->completer.id) {
- case PKVM_ID_HYP:
- ret = hyp_complete_share(completer_addr, tx, share->completer_prot);
- break;
- case PKVM_ID_FFA:
- /*
- * We're not responsible for any secure page-tables, so there's
- * nothing to do here.
- */
- ret = 0;
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-/*
- * do_share():
- *
- * The page owner grants access to another component with a given set
- * of permissions.
- *
- * Initiator: OWNED => SHARED_OWNED
- * Completer: NOPAGE => SHARED_BORROWED
- */
-static int do_share(struct pkvm_mem_share *share)
-{
- int ret;
-
- ret = check_share(share);
- if (ret)
- return ret;
-
- return WARN_ON(__do_share(share));
-}
-
-static int check_unshare(struct pkvm_mem_share *share)
-{
- const struct pkvm_mem_transition *tx = &share->tx;
- u64 completer_addr;
- int ret;
-
- switch (tx->initiator.id) {
- case PKVM_ID_HOST:
- ret = host_request_unshare(&completer_addr, tx);
- break;
- default:
- ret = -EINVAL;
- }
-
- if (ret)
- return ret;
-
- switch (tx->completer.id) {
- case PKVM_ID_HYP:
- ret = hyp_ack_unshare(completer_addr, tx);
- break;
- case PKVM_ID_FFA:
- /* See check_share() */
- ret = 0;
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int __do_unshare(struct pkvm_mem_share *share)
-{
- const struct pkvm_mem_transition *tx = &share->tx;
- u64 completer_addr;
- int ret;
-
- switch (tx->initiator.id) {
- case PKVM_ID_HOST:
- ret = host_initiate_unshare(&completer_addr, tx);
- break;
- default:
- ret = -EINVAL;
- }
-
- if (ret)
- return ret;
-
- switch (tx->completer.id) {
- case PKVM_ID_HYP:
- ret = hyp_complete_unshare(completer_addr, tx);
- break;
- case PKVM_ID_FFA:
- /* See __do_share() */
- ret = 0;
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-/*
- * do_unshare():
- *
- * The page owner revokes access from another component for a range of
- * pages which were previously shared using do_share().
- *
- * Initiator: SHARED_OWNED => OWNED
- * Completer: SHARED_BORROWED => NOPAGE
- */
-static int do_unshare(struct pkvm_mem_share *share)
-{
- int ret;
-
- ret = check_unshare(share);
- if (ret)
- return ret;
-
- return WARN_ON(__do_unshare(share));
-}
-
static int check_donation(struct pkvm_mem_donation *donation)
{
const struct pkvm_mem_transition *tx = &donation->tx;
@@ -1149,31 +902,29 @@ static int do_donate(struct pkvm_mem_donation *donation)
int __pkvm_host_share_hyp(u64 pfn)
{
+ u64 phys = hyp_pfn_to_phys(pfn);
+ void *virt = __hyp_va(phys);
+ enum kvm_pgtable_prot prot;
+ u64 size = PAGE_SIZE;
int ret;
- u64 host_addr = hyp_pfn_to_phys(pfn);
- u64 hyp_addr = (u64)__hyp_va(host_addr);
- struct pkvm_mem_share share = {
- .tx = {
- .nr_pages = 1,
- .initiator = {
- .id = PKVM_ID_HOST,
- .addr = host_addr,
- .host = {
- .completer_addr = hyp_addr,
- },
- },
- .completer = {
- .id = PKVM_ID_HYP,
- },
- },
- .completer_prot = PAGE_HYP,
- };
host_lock_component();
hyp_lock_component();
- ret = do_share(&share);
+ ret = __host_check_page_state_range(phys, size, PKVM_PAGE_OWNED);
+ if (ret)
+ goto unlock;
+ if (IS_ENABLED(CONFIG_NVHE_EL2_DEBUG)) {
+ ret = __hyp_check_page_state_range((u64)virt, size, PKVM_NOPAGE);
+ if (ret)
+ goto unlock;
+ }
+
+ prot = pkvm_mkstate(PAGE_HYP, PKVM_PAGE_SHARED_BORROWED);
+ WARN_ON(pkvm_create_mappings_locked(virt, virt + size, prot));
+ WARN_ON(__host_set_page_state_range(phys, size, PKVM_PAGE_SHARED_OWNED));
+unlock:
hyp_unlock_component();
host_unlock_component();
@@ -1182,31 +933,29 @@ int __pkvm_host_share_hyp(u64 pfn)
int __pkvm_host_unshare_hyp(u64 pfn)
{
+ u64 phys = hyp_pfn_to_phys(pfn);
+ u64 virt = (u64)__hyp_va(phys);
+ u64 size = PAGE_SIZE;
int ret;
- u64 host_addr = hyp_pfn_to_phys(pfn);
- u64 hyp_addr = (u64)__hyp_va(host_addr);
- struct pkvm_mem_share share = {
- .tx = {
- .nr_pages = 1,
- .initiator = {
- .id = PKVM_ID_HOST,
- .addr = host_addr,
- .host = {
- .completer_addr = hyp_addr,
- },
- },
- .completer = {
- .id = PKVM_ID_HYP,
- },
- },
- .completer_prot = PAGE_HYP,
- };
host_lock_component();
hyp_lock_component();
- ret = do_unshare(&share);
+ ret = __host_check_page_state_range(phys, size, PKVM_PAGE_SHARED_OWNED);
+ if (ret)
+ goto unlock;
+ ret = __hyp_check_page_state_range(virt, size, PKVM_PAGE_SHARED_BORROWED);
+ if (ret)
+ goto unlock;
+ if (hyp_page_count((void *)virt)) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ WARN_ON(kvm_pgtable_hyp_unmap(&pkvm_pgtable, virt, size) != size);
+ WARN_ON(__host_set_page_state_range(phys, size, PKVM_PAGE_OWNED));
+unlock:
hyp_unlock_component();
host_unlock_component();
--
2.47.1.688.g23fc6f90ad-goog
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/3] KVM: arm64: Drop pkvm_mem_transition for host/hyp donations
2025-01-10 12:19 [PATCH 0/3] KVM: arm64: Simplify pKVM memory transitions Quentin Perret
2025-01-10 12:19 ` [PATCH 1/3] KVM: arm64: Drop pkvm_mem_transition for FF-A Quentin Perret
2025-01-10 12:19 ` [PATCH 2/3] KVM: arm64: Drop pkvm_mem_transition for host/hyp sharing Quentin Perret
@ 2025-01-10 12:19 ` Quentin Perret
2025-01-12 10:42 ` [PATCH 0/3] KVM: arm64: Simplify pKVM memory transitions Marc Zyngier
3 siblings, 0 replies; 5+ messages in thread
From: Quentin Perret @ 2025-01-10 12:19 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, Joey Gouly, Suzuki K Poulose,
Zenghui Yu, Catalin Marinas, Will Deacon
Cc: Fuad Tabba, Vincent Donnefort, linux-arm-kernel, kvmarm,
linux-kernel
Simplify the __pkvm_host_donate_hyp() and pkvm_hyp_donate_host() paths
by not using the pkvm_mem_transition machinery. As the last users of
this, also remove all the now unused code.
No functional changes intended.
Signed-off-by: Quentin Perret <qperret@google.com>
---
arch/arm64/kvm/hyp/nvhe/mem_protect.c | 285 +++-----------------------
1 file changed, 32 insertions(+), 253 deletions(-)
diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
index cd8d233b9527..7ad7b133b81a 100644
--- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c
+++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
@@ -583,39 +583,6 @@ void handle_host_mem_abort(struct kvm_cpu_context *host_ctxt)
BUG_ON(ret && ret != -EAGAIN);
}
-struct pkvm_mem_transition {
- u64 nr_pages;
-
- struct {
- enum pkvm_component_id id;
- /* Address in the initiator's address space */
- u64 addr;
-
- union {
- struct {
- /* Address in the completer's address space */
- u64 completer_addr;
- } host;
- struct {
- u64 completer_addr;
- } hyp;
- };
- } initiator;
-
- struct {
- enum pkvm_component_id id;
- } completer;
-};
-
-struct pkvm_mem_share {
- const struct pkvm_mem_transition tx;
- const enum kvm_pgtable_prot completer_prot;
-};
-
-struct pkvm_mem_donation {
- const struct pkvm_mem_transition tx;
-};
-
struct check_walk_data {
enum pkvm_page_state desired;
enum pkvm_page_state (*get_page_state)(kvm_pte_t pte, u64 addr);
@@ -675,56 +642,6 @@ static int __host_set_page_state_range(u64 addr, u64 size,
return 0;
}
-static int host_request_owned_transition(u64 *completer_addr,
- const struct pkvm_mem_transition *tx)
-{
- u64 size = tx->nr_pages * PAGE_SIZE;
- u64 addr = tx->initiator.addr;
-
- *completer_addr = tx->initiator.host.completer_addr;
- return __host_check_page_state_range(addr, size, PKVM_PAGE_OWNED);
-}
-
-static int host_initiate_donation(u64 *completer_addr,
- const struct pkvm_mem_transition *tx)
-{
- u8 owner_id = tx->completer.id;
- u64 size = tx->nr_pages * PAGE_SIZE;
-
- *completer_addr = tx->initiator.host.completer_addr;
- return host_stage2_set_owner_locked(tx->initiator.addr, size, owner_id);
-}
-
-static bool __host_ack_skip_pgtable_check(const struct pkvm_mem_transition *tx)
-{
- return !(IS_ENABLED(CONFIG_NVHE_EL2_DEBUG) ||
- tx->initiator.id != PKVM_ID_HYP);
-}
-
-static int __host_ack_transition(u64 addr, const struct pkvm_mem_transition *tx,
- enum pkvm_page_state state)
-{
- u64 size = tx->nr_pages * PAGE_SIZE;
-
- if (__host_ack_skip_pgtable_check(tx))
- return 0;
-
- return __host_check_page_state_range(addr, size, state);
-}
-
-static int host_ack_donation(u64 addr, const struct pkvm_mem_transition *tx)
-{
- return __host_ack_transition(addr, tx, PKVM_NOPAGE);
-}
-
-static int host_complete_donation(u64 addr, const struct pkvm_mem_transition *tx)
-{
- u64 size = tx->nr_pages * PAGE_SIZE;
- u8 host_id = tx->completer.id;
-
- return host_stage2_set_owner_locked(addr, size, host_id);
-}
-
static enum pkvm_page_state hyp_get_page_state(kvm_pte_t pte, u64 addr)
{
if (!kvm_pte_valid(pte))
@@ -745,52 +662,6 @@ static int __hyp_check_page_state_range(u64 addr, u64 size,
return check_page_state_range(&pkvm_pgtable, addr, size, &d);
}
-static int hyp_request_donation(u64 *completer_addr,
- const struct pkvm_mem_transition *tx)
-{
- u64 size = tx->nr_pages * PAGE_SIZE;
- u64 addr = tx->initiator.addr;
-
- *completer_addr = tx->initiator.hyp.completer_addr;
- return __hyp_check_page_state_range(addr, size, PKVM_PAGE_OWNED);
-}
-
-static int hyp_initiate_donation(u64 *completer_addr,
- const struct pkvm_mem_transition *tx)
-{
- u64 size = tx->nr_pages * PAGE_SIZE;
- int ret;
-
- *completer_addr = tx->initiator.hyp.completer_addr;
- ret = kvm_pgtable_hyp_unmap(&pkvm_pgtable, tx->initiator.addr, size);
- return (ret != size) ? -EFAULT : 0;
-}
-
-static bool __hyp_ack_skip_pgtable_check(const struct pkvm_mem_transition *tx)
-{
- return !(IS_ENABLED(CONFIG_NVHE_EL2_DEBUG) ||
- tx->initiator.id != PKVM_ID_HOST);
-}
-
-static int hyp_ack_donation(u64 addr, const struct pkvm_mem_transition *tx)
-{
- u64 size = tx->nr_pages * PAGE_SIZE;
-
- if (__hyp_ack_skip_pgtable_check(tx))
- return 0;
-
- return __hyp_check_page_state_range(addr, size, PKVM_NOPAGE);
-}
-
-static int hyp_complete_donation(u64 addr,
- const struct pkvm_mem_transition *tx)
-{
- void *start = (void *)addr, *end = start + (tx->nr_pages * PAGE_SIZE);
- enum kvm_pgtable_prot prot = pkvm_mkstate(PAGE_HYP, PKVM_PAGE_OWNED);
-
- return pkvm_create_mappings_locked(start, end, prot);
-}
-
static enum pkvm_page_state guest_get_page_state(kvm_pte_t pte, u64 addr)
{
if (!kvm_pte_valid(pte))
@@ -812,94 +683,6 @@ static int __guest_check_page_state_range(struct pkvm_hyp_vcpu *vcpu, u64 addr,
return check_page_state_range(&vm->pgt, addr, size, &d);
}
-static int check_donation(struct pkvm_mem_donation *donation)
-{
- const struct pkvm_mem_transition *tx = &donation->tx;
- u64 completer_addr;
- int ret;
-
- switch (tx->initiator.id) {
- case PKVM_ID_HOST:
- ret = host_request_owned_transition(&completer_addr, tx);
- break;
- case PKVM_ID_HYP:
- ret = hyp_request_donation(&completer_addr, tx);
- break;
- default:
- ret = -EINVAL;
- }
-
- if (ret)
- return ret;
-
- switch (tx->completer.id) {
- case PKVM_ID_HOST:
- ret = host_ack_donation(completer_addr, tx);
- break;
- case PKVM_ID_HYP:
- ret = hyp_ack_donation(completer_addr, tx);
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int __do_donate(struct pkvm_mem_donation *donation)
-{
- const struct pkvm_mem_transition *tx = &donation->tx;
- u64 completer_addr;
- int ret;
-
- switch (tx->initiator.id) {
- case PKVM_ID_HOST:
- ret = host_initiate_donation(&completer_addr, tx);
- break;
- case PKVM_ID_HYP:
- ret = hyp_initiate_donation(&completer_addr, tx);
- break;
- default:
- ret = -EINVAL;
- }
-
- if (ret)
- return ret;
-
- switch (tx->completer.id) {
- case PKVM_ID_HOST:
- ret = host_complete_donation(completer_addr, tx);
- break;
- case PKVM_ID_HYP:
- ret = hyp_complete_donation(completer_addr, tx);
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-/*
- * do_donate():
- *
- * The page owner transfers ownership to another component, losing access
- * as a consequence.
- *
- * Initiator: OWNED => NOPAGE
- * Completer: NOPAGE => OWNED
- */
-static int do_donate(struct pkvm_mem_donation *donation)
-{
- int ret;
-
- ret = check_donation(donation);
- if (ret)
- return ret;
-
- return WARN_ON(__do_donate(donation));
-}
-
int __pkvm_host_share_hyp(u64 pfn)
{
u64 phys = hyp_pfn_to_phys(pfn);
@@ -964,30 +747,29 @@ int __pkvm_host_unshare_hyp(u64 pfn)
int __pkvm_host_donate_hyp(u64 pfn, u64 nr_pages)
{
+ u64 phys = hyp_pfn_to_phys(pfn);
+ u64 size = PAGE_SIZE * nr_pages;
+ void *virt = __hyp_va(phys);
+ enum kvm_pgtable_prot prot;
int ret;
- u64 host_addr = hyp_pfn_to_phys(pfn);
- u64 hyp_addr = (u64)__hyp_va(host_addr);
- struct pkvm_mem_donation donation = {
- .tx = {
- .nr_pages = nr_pages,
- .initiator = {
- .id = PKVM_ID_HOST,
- .addr = host_addr,
- .host = {
- .completer_addr = hyp_addr,
- },
- },
- .completer = {
- .id = PKVM_ID_HYP,
- },
- },
- };
host_lock_component();
hyp_lock_component();
- ret = do_donate(&donation);
+ ret = __host_check_page_state_range(phys, size, PKVM_PAGE_OWNED);
+ if (ret)
+ goto unlock;
+ if (IS_ENABLED(CONFIG_NVHE_EL2_DEBUG)) {
+ ret = __hyp_check_page_state_range((u64)virt, size, PKVM_NOPAGE);
+ if (ret)
+ goto unlock;
+ }
+ prot = pkvm_mkstate(PAGE_HYP, PKVM_PAGE_OWNED);
+ WARN_ON(pkvm_create_mappings_locked(virt, virt + size, prot));
+ WARN_ON(host_stage2_set_owner_locked(phys, size, PKVM_ID_HYP));
+
+unlock:
hyp_unlock_component();
host_unlock_component();
@@ -996,30 +778,27 @@ int __pkvm_host_donate_hyp(u64 pfn, u64 nr_pages)
int __pkvm_hyp_donate_host(u64 pfn, u64 nr_pages)
{
+ u64 phys = hyp_pfn_to_phys(pfn);
+ u64 size = PAGE_SIZE * nr_pages;
+ u64 virt = (u64)__hyp_va(phys);
int ret;
- u64 host_addr = hyp_pfn_to_phys(pfn);
- u64 hyp_addr = (u64)__hyp_va(host_addr);
- struct pkvm_mem_donation donation = {
- .tx = {
- .nr_pages = nr_pages,
- .initiator = {
- .id = PKVM_ID_HYP,
- .addr = hyp_addr,
- .hyp = {
- .completer_addr = host_addr,
- },
- },
- .completer = {
- .id = PKVM_ID_HOST,
- },
- },
- };
host_lock_component();
hyp_lock_component();
- ret = do_donate(&donation);
+ ret = __hyp_check_page_state_range(virt, size, PKVM_PAGE_OWNED);
+ if (ret)
+ goto unlock;
+ if (IS_ENABLED(CONFIG_NVHE_EL2_DEBUG)) {
+ ret = __host_check_page_state_range(phys, size, PKVM_NOPAGE);
+ if (ret)
+ goto unlock;
+ }
+ WARN_ON(kvm_pgtable_hyp_unmap(&pkvm_pgtable, virt, size) != size);
+ WARN_ON(host_stage2_set_owner_locked(phys, size, PKVM_ID_HOST));
+
+unlock:
hyp_unlock_component();
host_unlock_component();
--
2.47.1.688.g23fc6f90ad-goog
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 0/3] KVM: arm64: Simplify pKVM memory transitions
2025-01-10 12:19 [PATCH 0/3] KVM: arm64: Simplify pKVM memory transitions Quentin Perret
` (2 preceding siblings ...)
2025-01-10 12:19 ` [PATCH 3/3] KVM: arm64: Drop pkvm_mem_transition for host/hyp donations Quentin Perret
@ 2025-01-12 10:42 ` Marc Zyngier
3 siblings, 0 replies; 5+ messages in thread
From: Marc Zyngier @ 2025-01-12 10:42 UTC (permalink / raw)
To: Oliver Upton, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Catalin Marinas, Will Deacon, Quentin Perret
Cc: Fuad Tabba, Vincent Donnefort, linux-arm-kernel, kvmarm,
linux-kernel
On Fri, 10 Jan 2025 12:19:33 +0000, Quentin Perret wrote:
> Since its early days, pKVM has formalized memory 'transitions' (shares
> and donations) using 'struct pkvm_mem_transition' and bunch of helpers
> to manipulate it. The intention was for all transitions to use this
> machinery to ensure we're checking things consistently. However, as
> development progressed, it became clear that the rigidity of this model
> made it really difficult to use in some use-cases which ended-up
> side-stepping it entirely. That is the case for the
> hyp_{un}pin_shared_mem() and host_{un}share_guest() paths upstream which
> use lower level helpers directly, as well as for several other pKVM
> features that should land upstream in the future (ex: when a guest
> relinquishes a page during ballooning, when annotating a page that is
> being DMA'd to, ...). On top of this, the pkvm_mem_transition machinery
> requires a lot of boilerplate which makes the code hard to read, but
> also adds layers of indirection that no compilers seems to see through,
> hence leading to suboptimal generated code.
>
> [...]
Applied to next, thanks!
[1/3] KVM: arm64: Drop pkvm_mem_transition for FF-A
commit: ed2f80fd76bd2c6e00d2e90f78d21a3055ee3562
[2/3] KVM: arm64: Drop pkvm_mem_transition for host/hyp sharing
commit: d3b3473c15e4391673d8dca9c36dd5e9c3a8a4ac
[3/3] KVM: arm64: Drop pkvm_mem_transition for host/hyp donations
commit: 2d2aa2eb275fa6f80d68ed442c3328273bbbecba
Cheers,
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-01-12 10:42 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-10 12:19 [PATCH 0/3] KVM: arm64: Simplify pKVM memory transitions Quentin Perret
2025-01-10 12:19 ` [PATCH 1/3] KVM: arm64: Drop pkvm_mem_transition for FF-A Quentin Perret
2025-01-10 12:19 ` [PATCH 2/3] KVM: arm64: Drop pkvm_mem_transition for host/hyp sharing Quentin Perret
2025-01-10 12:19 ` [PATCH 3/3] KVM: arm64: Drop pkvm_mem_transition for host/hyp donations Quentin Perret
2025-01-12 10:42 ` [PATCH 0/3] KVM: arm64: Simplify pKVM memory transitions Marc Zyngier
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox