Skip to content

Commit 4274385

Browse files
vdonnefortMarc Zyngier
authored andcommitted
KVM: arm64: Add a range to __pkvm_host_share_guest()
In preparation for supporting stage-2 huge mappings for np-guest. Add a nr_pages argument to the __pkvm_host_share_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-4-vdonnefort@google.com Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent 3db771f commit 4274385

File tree

4 files changed

+61
-34
lines changed

4 files changed

+61
-34
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
@@ -39,7 +39,7 @@ int __pkvm_host_donate_hyp(u64 pfn, u64 nr_pages);
3939
int __pkvm_hyp_donate_host(u64 pfn, u64 nr_pages);
4040
int __pkvm_host_share_ffa(u64 pfn, u64 nr_pages);
4141
int __pkvm_host_unshare_ffa(u64 pfn, u64 nr_pages);
42-
int __pkvm_host_share_guest(u64 pfn, u64 gfn, struct pkvm_hyp_vcpu *vcpu,
42+
int __pkvm_host_share_guest(u64 pfn, u64 gfn, u64 nr_pages, struct pkvm_hyp_vcpu *vcpu,
4343
enum kvm_pgtable_prot prot);
4444
int __pkvm_host_unshare_guest(u64 gfn, 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);

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ static void handle___pkvm_host_share_guest(struct kvm_cpu_context *host_ctxt)
245245
{
246246
DECLARE_REG(u64, pfn, host_ctxt, 1);
247247
DECLARE_REG(u64, gfn, host_ctxt, 2);
248-
DECLARE_REG(enum kvm_pgtable_prot, prot, host_ctxt, 3);
248+
DECLARE_REG(u64, nr_pages, host_ctxt, 3);
249+
DECLARE_REG(enum kvm_pgtable_prot, prot, host_ctxt, 4);
249250
struct pkvm_hyp_vcpu *hyp_vcpu;
250251
int ret = -EINVAL;
251252

@@ -260,7 +261,7 @@ static void handle___pkvm_host_share_guest(struct kvm_cpu_context *host_ctxt)
260261
if (ret)
261262
goto out;
262263

263-
ret = __pkvm_host_share_guest(pfn, gfn, hyp_vcpu, prot);
264+
ret = __pkvm_host_share_guest(pfn, gfn, nr_pages, hyp_vcpu, prot);
264265
out:
265266
cpu_reg(host_ctxt, 1) = ret;
266267
}

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

Lines changed: 56 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -695,10 +695,9 @@ static enum pkvm_page_state guest_get_page_state(kvm_pte_t pte, u64 addr)
695695
return pkvm_getstate(kvm_pgtable_stage2_pte_prot(pte));
696696
}
697697

698-
static int __guest_check_page_state_range(struct pkvm_hyp_vcpu *vcpu, u64 addr,
698+
static int __guest_check_page_state_range(struct pkvm_hyp_vm *vm, u64 addr,
699699
u64 size, enum pkvm_page_state state)
700700
{
701-
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(vcpu);
702701
struct check_walk_data d = {
703702
.desired = state,
704703
.get_page_state = guest_get_page_state,
@@ -907,48 +906,72 @@ int __pkvm_host_unshare_ffa(u64 pfn, u64 nr_pages)
907906
return ret;
908907
}
909908

910-
int __pkvm_host_share_guest(u64 pfn, u64 gfn, struct pkvm_hyp_vcpu *vcpu,
909+
static int __guest_check_transition_size(u64 phys, u64 ipa, u64 nr_pages, u64 *size)
910+
{
911+
if (nr_pages == 1) {
912+
*size = PAGE_SIZE;
913+
return 0;
914+
}
915+
916+
return -EINVAL;
917+
}
918+
919+
int __pkvm_host_share_guest(u64 pfn, u64 gfn, u64 nr_pages, struct pkvm_hyp_vcpu *vcpu,
911920
enum kvm_pgtable_prot prot)
912921
{
913922
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(vcpu);
914923
u64 phys = hyp_pfn_to_phys(pfn);
915924
u64 ipa = hyp_pfn_to_phys(gfn);
916-
struct hyp_page *page;
925+
u64 size;
917926
int ret;
918927

919928
if (prot & ~KVM_PGTABLE_PROT_RWX)
920929
return -EINVAL;
921930

922-
ret = check_range_allowed_memory(phys, phys + PAGE_SIZE);
931+
ret = __guest_check_transition_size(phys, ipa, nr_pages, &size);
932+
if (ret)
933+
return ret;
934+
935+
ret = check_range_allowed_memory(phys, phys + size);
923936
if (ret)
924937
return ret;
925938

926939
host_lock_component();
927940
guest_lock_component(vm);
928941

929-
ret = __guest_check_page_state_range(vcpu, ipa, PAGE_SIZE, PKVM_NOPAGE);
942+
ret = __guest_check_page_state_range(vm, ipa, size, PKVM_NOPAGE);
930943
if (ret)
931944
goto unlock;
932945

933-
page = hyp_phys_to_page(phys);
934-
switch (get_host_state(page)) {
935-
case PKVM_PAGE_OWNED:
936-
WARN_ON(__host_set_page_state_range(phys, PAGE_SIZE, PKVM_PAGE_SHARED_OWNED));
937-
break;
938-
case PKVM_PAGE_SHARED_OWNED:
939-
if (page->host_share_guest_count)
940-
break;
941-
/* Only host to np-guest multi-sharing is tolerated */
942-
fallthrough;
943-
default:
944-
ret = -EPERM;
945-
goto unlock;
946+
for_each_hyp_page(page, phys, size) {
947+
switch (get_host_state(page)) {
948+
case PKVM_PAGE_OWNED:
949+
continue;
950+
case PKVM_PAGE_SHARED_OWNED:
951+
if (page->host_share_guest_count == U32_MAX) {
952+
ret = -EBUSY;
953+
goto unlock;
954+
}
955+
956+
/* Only host to np-guest multi-sharing is tolerated */
957+
if (page->host_share_guest_count)
958+
continue;
959+
960+
fallthrough;
961+
default:
962+
ret = -EPERM;
963+
goto unlock;
964+
}
946965
}
947966

948-
WARN_ON(kvm_pgtable_stage2_map(&vm->pgt, ipa, PAGE_SIZE, phys,
967+
for_each_hyp_page(page, phys, size) {
968+
set_host_state(page, PKVM_PAGE_SHARED_OWNED);
969+
page->host_share_guest_count++;
970+
}
971+
972+
WARN_ON(kvm_pgtable_stage2_map(&vm->pgt, ipa, size, phys,
949973
pkvm_mkstate(prot, PKVM_PAGE_SHARED_BORROWED),
950974
&vcpu->vcpu.arch.pkvm_memcache, 0));
951-
page->host_share_guest_count++;
952975

953976
unlock:
954977
guest_unlock_component(vm);
@@ -1169,6 +1192,9 @@ static void assert_page_state(void)
11691192
struct pkvm_hyp_vcpu *vcpu = &selftest_vcpu;
11701193
u64 phys = hyp_virt_to_phys(virt);
11711194
u64 ipa[2] = { selftest_ipa(), selftest_ipa() + PAGE_SIZE };
1195+
struct pkvm_hyp_vm *vm;
1196+
1197+
vm = pkvm_hyp_vcpu_to_hyp_vm(vcpu);
11721198

11731199
host_lock_component();
11741200
WARN_ON(__host_check_page_state_range(phys, size, selftest_state.host));
@@ -1179,8 +1205,8 @@ static void assert_page_state(void)
11791205
hyp_unlock_component();
11801206

11811207
guest_lock_component(&selftest_vm);
1182-
WARN_ON(__guest_check_page_state_range(vcpu, ipa[0], size, selftest_state.guest[0]));
1183-
WARN_ON(__guest_check_page_state_range(vcpu, ipa[1], size, selftest_state.guest[1]));
1208+
WARN_ON(__guest_check_page_state_range(vm, ipa[0], size, selftest_state.guest[0]));
1209+
WARN_ON(__guest_check_page_state_range(vm, ipa[1], size, selftest_state.guest[1]));
11841210
guest_unlock_component(&selftest_vm);
11851211
}
11861212

@@ -1218,7 +1244,7 @@ void pkvm_ownership_selftest(void *base)
12181244
assert_transition_res(-EPERM, __pkvm_host_share_ffa, pfn, 1);
12191245
assert_transition_res(-EPERM, __pkvm_host_unshare_ffa, pfn, 1);
12201246
assert_transition_res(-EPERM, hyp_pin_shared_mem, virt, virt + size);
1221-
assert_transition_res(-EPERM, __pkvm_host_share_guest, pfn, gfn, vcpu, prot);
1247+
assert_transition_res(-EPERM, __pkvm_host_share_guest, pfn, gfn, 1, vcpu, prot);
12221248
assert_transition_res(-ENOENT, __pkvm_host_unshare_guest, gfn, vm);
12231249

12241250
selftest_state.host = PKVM_PAGE_OWNED;
@@ -1237,7 +1263,7 @@ void pkvm_ownership_selftest(void *base)
12371263
assert_transition_res(-EPERM, __pkvm_host_donate_hyp, pfn, 1);
12381264
assert_transition_res(-EPERM, __pkvm_host_share_ffa, pfn, 1);
12391265
assert_transition_res(-EPERM, __pkvm_hyp_donate_host, pfn, 1);
1240-
assert_transition_res(-EPERM, __pkvm_host_share_guest, pfn, gfn, vcpu, prot);
1266+
assert_transition_res(-EPERM, __pkvm_host_share_guest, pfn, gfn, 1, vcpu, prot);
12411267
assert_transition_res(-ENOENT, __pkvm_host_unshare_guest, gfn, vm);
12421268

12431269
assert_transition_res(0, hyp_pin_shared_mem, virt, virt + size);
@@ -1249,7 +1275,7 @@ void pkvm_ownership_selftest(void *base)
12491275
assert_transition_res(-EPERM, __pkvm_host_donate_hyp, pfn, 1);
12501276
assert_transition_res(-EPERM, __pkvm_host_share_ffa, pfn, 1);
12511277
assert_transition_res(-EPERM, __pkvm_hyp_donate_host, pfn, 1);
1252-
assert_transition_res(-EPERM, __pkvm_host_share_guest, pfn, gfn, vcpu, prot);
1278+
assert_transition_res(-EPERM, __pkvm_host_share_guest, pfn, gfn, 1, vcpu, prot);
12531279
assert_transition_res(-ENOENT, __pkvm_host_unshare_guest, gfn, vm);
12541280

12551281
hyp_unpin_shared_mem(virt, virt + size);
@@ -1268,7 +1294,7 @@ void pkvm_ownership_selftest(void *base)
12681294
assert_transition_res(-EPERM, __pkvm_host_share_hyp, pfn);
12691295
assert_transition_res(-EPERM, __pkvm_host_unshare_hyp, pfn);
12701296
assert_transition_res(-EPERM, __pkvm_hyp_donate_host, pfn, 1);
1271-
assert_transition_res(-EPERM, __pkvm_host_share_guest, pfn, gfn, vcpu, prot);
1297+
assert_transition_res(-EPERM, __pkvm_host_share_guest, pfn, gfn, 1, vcpu, prot);
12721298
assert_transition_res(-ENOENT, __pkvm_host_unshare_guest, gfn, vm);
12731299
assert_transition_res(-EPERM, hyp_pin_shared_mem, virt, virt + size);
12741300

@@ -1279,8 +1305,8 @@ void pkvm_ownership_selftest(void *base)
12791305

12801306
selftest_state.host = PKVM_PAGE_SHARED_OWNED;
12811307
selftest_state.guest[0] = PKVM_PAGE_SHARED_BORROWED;
1282-
assert_transition_res(0, __pkvm_host_share_guest, pfn, gfn, vcpu, prot);
1283-
assert_transition_res(-EPERM, __pkvm_host_share_guest, pfn, gfn, vcpu, prot);
1308+
assert_transition_res(0, __pkvm_host_share_guest, pfn, gfn, 1, vcpu, prot);
1309+
assert_transition_res(-EPERM, __pkvm_host_share_guest, pfn, gfn, 1, vcpu, prot);
12841310
assert_transition_res(-EPERM, __pkvm_host_share_ffa, pfn, 1);
12851311
assert_transition_res(-EPERM, __pkvm_host_donate_hyp, pfn, 1);
12861312
assert_transition_res(-EPERM, __pkvm_host_share_hyp, pfn);
@@ -1289,7 +1315,7 @@ void pkvm_ownership_selftest(void *base)
12891315
assert_transition_res(-EPERM, hyp_pin_shared_mem, virt, virt + size);
12901316

12911317
selftest_state.guest[1] = PKVM_PAGE_SHARED_BORROWED;
1292-
assert_transition_res(0, __pkvm_host_share_guest, pfn, gfn + 1, vcpu, prot);
1318+
assert_transition_res(0, __pkvm_host_share_guest, pfn, gfn + 1, 1, vcpu, prot);
12931319
WARN_ON(hyp_virt_to_page(virt)->host_share_guest_count != 2);
12941320

12951321
selftest_state.guest[0] = PKVM_NOPAGE;

arch/arm64/kvm/pkvm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ int pkvm_pgtable_stage2_map(struct kvm_pgtable *pgt, u64 addr, u64 size,
366366
return -EINVAL;
367367

368368
lockdep_assert_held_write(&kvm->mmu_lock);
369-
ret = kvm_call_hyp_nvhe(__pkvm_host_share_guest, pfn, gfn, prot);
369+
ret = kvm_call_hyp_nvhe(__pkvm_host_share_guest, pfn, gfn, 1, prot);
370370
if (ret) {
371371
/* Is the gfn already mapped due to a racing vCPU? */
372372
if (ret == -EPERM)

0 commit comments

Comments
 (0)