Skip to content

Commit f28f1d0

Browse files
vdonnefortMarc Zyngier
authored andcommitted
KVM: arm64: Add a range to __pkvm_host_unshare_guest()
In preparation for supporting stage-2 huge mappings for np-guest. Add a nr_pages argument to the __pkvm_host_unshare_guest hypercall. This range supports only two values: 1 or PMD_SIZE / PAGE_SIZE (that is 512 on a 4K-pages system). Signed-off-by: Vincent Donnefort <vdonnefort@google.com> Link: https://lore.kernel.org/r/20250521124834.1070650-5-vdonnefort@google.com Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent 4274385 commit f28f1d0

File tree

4 files changed

+35
-29
lines changed

4 files changed

+35
-29
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +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, u64 nr_pages, 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);
44+
int __pkvm_host_unshare_guest(u64 gfn, u64 nr_pages, struct pkvm_hyp_vm *hyp_vm);
4545
int __pkvm_host_relax_perms_guest(u64 gfn, struct pkvm_hyp_vcpu *vcpu, enum kvm_pgtable_prot prot);
4646
int __pkvm_host_wrprotect_guest(u64 gfn, struct pkvm_hyp_vm *hyp_vm);
4747
int __pkvm_host_test_clear_young_guest(u64 gfn, bool mkold, struct pkvm_hyp_vm *vm);

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ static void handle___pkvm_host_unshare_guest(struct kvm_cpu_context *host_ctxt)
270270
{
271271
DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1);
272272
DECLARE_REG(u64, gfn, host_ctxt, 2);
273+
DECLARE_REG(u64, nr_pages, host_ctxt, 3);
273274
struct pkvm_hyp_vm *hyp_vm;
274275
int ret = -EINVAL;
275276

@@ -280,7 +281,7 @@ static void handle___pkvm_host_unshare_guest(struct kvm_cpu_context *host_ctxt)
280281
if (!hyp_vm)
281282
goto out;
282283

283-
ret = __pkvm_host_unshare_guest(gfn, hyp_vm);
284+
ret = __pkvm_host_unshare_guest(gfn, nr_pages, hyp_vm);
284285
put_pkvm_hyp_vm(hyp_vm);
285286
out:
286287
cpu_reg(host_ctxt, 1) = ret;

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

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -980,10 +980,9 @@ int __pkvm_host_share_guest(u64 pfn, u64 gfn, u64 nr_pages, struct pkvm_hyp_vcpu
980980
return ret;
981981
}
982982

983-
static int __check_host_shared_guest(struct pkvm_hyp_vm *vm, u64 *__phys, u64 ipa)
983+
static int __check_host_shared_guest(struct pkvm_hyp_vm *vm, u64 *__phys, u64 ipa, u64 size)
984984
{
985985
enum pkvm_page_state state;
986-
struct hyp_page *page;
987986
kvm_pte_t pte;
988987
u64 phys;
989988
s8 level;
@@ -994,51 +993,57 @@ static int __check_host_shared_guest(struct pkvm_hyp_vm *vm, u64 *__phys, u64 ip
994993
return ret;
995994
if (!kvm_pte_valid(pte))
996995
return -ENOENT;
997-
if (level != KVM_PGTABLE_LAST_LEVEL)
996+
if (kvm_granule_size(level) != size)
998997
return -E2BIG;
999998

1000999
state = guest_get_page_state(pte, ipa);
10011000
if (state != PKVM_PAGE_SHARED_BORROWED)
10021001
return -EPERM;
10031002

10041003
phys = kvm_pte_to_phys(pte);
1005-
ret = check_range_allowed_memory(phys, phys + PAGE_SIZE);
1004+
ret = check_range_allowed_memory(phys, phys + size);
10061005
if (WARN_ON(ret))
10071006
return ret;
10081007

1009-
page = hyp_phys_to_page(phys);
1010-
if (get_host_state(page) != PKVM_PAGE_SHARED_OWNED)
1011-
return -EPERM;
1012-
if (WARN_ON(!page->host_share_guest_count))
1013-
return -EINVAL;
1008+
for_each_hyp_page(page, phys, size) {
1009+
if (get_host_state(page) != PKVM_PAGE_SHARED_OWNED)
1010+
return -EPERM;
1011+
if (WARN_ON(!page->host_share_guest_count))
1012+
return -EINVAL;
1013+
}
10141014

10151015
*__phys = phys;
10161016

10171017
return 0;
10181018
}
10191019

1020-
int __pkvm_host_unshare_guest(u64 gfn, struct pkvm_hyp_vm *vm)
1020+
int __pkvm_host_unshare_guest(u64 gfn, u64 nr_pages, struct pkvm_hyp_vm *vm)
10211021
{
10221022
u64 ipa = hyp_pfn_to_phys(gfn);
1023-
struct hyp_page *page;
1024-
u64 phys;
1023+
u64 size, phys;
10251024
int ret;
10261025

1026+
ret = __guest_check_transition_size(0, ipa, nr_pages, &size);
1027+
if (ret)
1028+
return ret;
1029+
10271030
host_lock_component();
10281031
guest_lock_component(vm);
10291032

1030-
ret = __check_host_shared_guest(vm, &phys, ipa);
1033+
ret = __check_host_shared_guest(vm, &phys, ipa, size);
10311034
if (ret)
10321035
goto unlock;
10331036

1034-
ret = kvm_pgtable_stage2_unmap(&vm->pgt, ipa, PAGE_SIZE);
1037+
ret = kvm_pgtable_stage2_unmap(&vm->pgt, ipa, size);
10351038
if (ret)
10361039
goto unlock;
10371040

1038-
page = hyp_phys_to_page(phys);
1039-
page->host_share_guest_count--;
1040-
if (!page->host_share_guest_count)
1041-
WARN_ON(__host_set_page_state_range(phys, PAGE_SIZE, PKVM_PAGE_OWNED));
1041+
for_each_hyp_page(page, phys, size) {
1042+
/* __check_host_shared_guest() protects against underflow */
1043+
page->host_share_guest_count--;
1044+
if (!page->host_share_guest_count)
1045+
set_host_state(page, PKVM_PAGE_OWNED);
1046+
}
10421047

10431048
unlock:
10441049
guest_unlock_component(vm);
@@ -1058,7 +1063,7 @@ static void assert_host_shared_guest(struct pkvm_hyp_vm *vm, u64 ipa)
10581063
host_lock_component();
10591064
guest_lock_component(vm);
10601065

1061-
ret = __check_host_shared_guest(vm, &phys, ipa);
1066+
ret = __check_host_shared_guest(vm, &phys, ipa, PAGE_SIZE);
10621067

10631068
guest_unlock_component(vm);
10641069
host_unlock_component();
@@ -1245,15 +1250,15 @@ void pkvm_ownership_selftest(void *base)
12451250
assert_transition_res(-EPERM, __pkvm_host_unshare_ffa, pfn, 1);
12461251
assert_transition_res(-EPERM, hyp_pin_shared_mem, virt, virt + size);
12471252
assert_transition_res(-EPERM, __pkvm_host_share_guest, pfn, gfn, 1, vcpu, prot);
1248-
assert_transition_res(-ENOENT, __pkvm_host_unshare_guest, gfn, vm);
1253+
assert_transition_res(-ENOENT, __pkvm_host_unshare_guest, gfn, 1, vm);
12491254

12501255
selftest_state.host = PKVM_PAGE_OWNED;
12511256
selftest_state.hyp = PKVM_NOPAGE;
12521257
assert_transition_res(0, __pkvm_hyp_donate_host, pfn, 1);
12531258
assert_transition_res(-EPERM, __pkvm_hyp_donate_host, pfn, 1);
12541259
assert_transition_res(-EPERM, __pkvm_host_unshare_hyp, pfn);
12551260
assert_transition_res(-EPERM, __pkvm_host_unshare_ffa, pfn, 1);
1256-
assert_transition_res(-ENOENT, __pkvm_host_unshare_guest, gfn, vm);
1261+
assert_transition_res(-ENOENT, __pkvm_host_unshare_guest, gfn, 1, vm);
12571262
assert_transition_res(-EPERM, hyp_pin_shared_mem, virt, virt + size);
12581263

12591264
selftest_state.host = PKVM_PAGE_SHARED_OWNED;
@@ -1264,7 +1269,7 @@ void pkvm_ownership_selftest(void *base)
12641269
assert_transition_res(-EPERM, __pkvm_host_share_ffa, pfn, 1);
12651270
assert_transition_res(-EPERM, __pkvm_hyp_donate_host, pfn, 1);
12661271
assert_transition_res(-EPERM, __pkvm_host_share_guest, pfn, gfn, 1, vcpu, prot);
1267-
assert_transition_res(-ENOENT, __pkvm_host_unshare_guest, gfn, vm);
1272+
assert_transition_res(-ENOENT, __pkvm_host_unshare_guest, gfn, 1, vm);
12681273

12691274
assert_transition_res(0, hyp_pin_shared_mem, virt, virt + size);
12701275
assert_transition_res(0, hyp_pin_shared_mem, virt, virt + size);
@@ -1276,7 +1281,7 @@ void pkvm_ownership_selftest(void *base)
12761281
assert_transition_res(-EPERM, __pkvm_host_share_ffa, pfn, 1);
12771282
assert_transition_res(-EPERM, __pkvm_hyp_donate_host, pfn, 1);
12781283
assert_transition_res(-EPERM, __pkvm_host_share_guest, pfn, gfn, 1, vcpu, prot);
1279-
assert_transition_res(-ENOENT, __pkvm_host_unshare_guest, gfn, vm);
1284+
assert_transition_res(-ENOENT, __pkvm_host_unshare_guest, gfn, 1, vm);
12801285

12811286
hyp_unpin_shared_mem(virt, virt + size);
12821287
assert_page_state();
@@ -1295,7 +1300,7 @@ void pkvm_ownership_selftest(void *base)
12951300
assert_transition_res(-EPERM, __pkvm_host_unshare_hyp, pfn);
12961301
assert_transition_res(-EPERM, __pkvm_hyp_donate_host, pfn, 1);
12971302
assert_transition_res(-EPERM, __pkvm_host_share_guest, pfn, gfn, 1, vcpu, prot);
1298-
assert_transition_res(-ENOENT, __pkvm_host_unshare_guest, gfn, vm);
1303+
assert_transition_res(-ENOENT, __pkvm_host_unshare_guest, gfn, 1, vm);
12991304
assert_transition_res(-EPERM, hyp_pin_shared_mem, virt, virt + size);
13001305

13011306
selftest_state.host = PKVM_PAGE_OWNED;
@@ -1319,11 +1324,11 @@ void pkvm_ownership_selftest(void *base)
13191324
WARN_ON(hyp_virt_to_page(virt)->host_share_guest_count != 2);
13201325

13211326
selftest_state.guest[0] = PKVM_NOPAGE;
1322-
assert_transition_res(0, __pkvm_host_unshare_guest, gfn, vm);
1327+
assert_transition_res(0, __pkvm_host_unshare_guest, gfn, 1, vm);
13231328

13241329
selftest_state.guest[1] = PKVM_NOPAGE;
13251330
selftest_state.host = PKVM_PAGE_OWNED;
1326-
assert_transition_res(0, __pkvm_host_unshare_guest, gfn + 1, vm);
1331+
assert_transition_res(0, __pkvm_host_unshare_guest, gfn + 1, 1, vm);
13271332

13281333
selftest_state.host = PKVM_NOPAGE;
13291334
selftest_state.hyp = PKVM_PAGE_OWNED;

arch/arm64/kvm/pkvm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ int pkvm_pgtable_stage2_unmap(struct kvm_pgtable *pgt, u64 addr, u64 size)
390390

391391
lockdep_assert_held_write(&kvm->mmu_lock);
392392
for_each_mapping_in_range_safe(pgt, addr, addr + size, mapping) {
393-
ret = kvm_call_hyp_nvhe(__pkvm_host_unshare_guest, handle, mapping->gfn);
393+
ret = kvm_call_hyp_nvhe(__pkvm_host_unshare_guest, handle, mapping->gfn, 1);
394394
if (WARN_ON(ret))
395395
break;
396396
rb_erase(&mapping->node, &pgt->pkvm_mappings);

0 commit comments

Comments
 (0)