Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 27c52b4

Browse files
committed
ANDROID: KVM: arm64: Add a range to the guest MMIO guard hypercalls
Extend the guest MMIO guard HVCs with a nr_pages argument. Contrary to the memshare, legacy kernel didn't enforce arg2 and arg3 to 0. We have then to bring a new set of HVCs. The range version of those HVCs is advertised in the meminfo HVC. Bug: 278749606 Bug: 243642516 Change-Id: Ic56aa7f0049dadaa72b5b5e65c00c6bafe5a40b9 Signed-off-by: Vincent Donnefort <[email protected]>
1 parent 5b0ab75 commit 27c52b4

File tree

4 files changed

+123
-36
lines changed

4 files changed

+123
-36
lines changed

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,10 @@ int __pkvm_guest_share_host(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa,
5454
u64 nr_pages, u64 *nr_shared);
5555
int __pkvm_guest_unshare_host(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa,
5656
u64 nr_pages, u64 *nr_unshared);
57-
int __pkvm_install_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa);
58-
int __pkvm_remove_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa);
57+
int __pkvm_install_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa,
58+
u64 nr_pages, u64 *nr_guarded);
59+
int __pkvm_remove_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa,
60+
u64 nr_pages, u64 *nr_unguarded);
5961
bool __pkvm_check_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu);
6062
int __pkvm_guest_relinquish_to_host(struct pkvm_hyp_vcpu *vcpu,
6163
u64 ipa, u64 *ppa);

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

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2495,60 +2495,94 @@ static bool __check_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa)
24952495
pte == KVM_INVALID_PTE_MMIO_NOTE);
24962496
}
24972497

2498-
int __pkvm_install_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa)
2498+
int __pkvm_install_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa,
2499+
u64 nr_pages, u64 *nr_guarded)
24992500
{
2501+
struct guest_request_walker_data data = GUEST_WALKER_DATA_INIT(PKVM_NOPAGE);
25002502
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
2501-
kvm_pte_t pte;
2502-
u32 level;
2503+
struct kvm_pgtable_walker walker = {
2504+
.cb = guest_request_walker,
2505+
.flags = KVM_PGTABLE_WALK_LEAF,
2506+
.arg = (void *)&data,
2507+
};
2508+
u64 size = nr_pages * PAGE_SIZE;
25032509
int ret;
25042510

25052511
if (!test_bit(KVM_ARCH_FLAG_MMIO_GUARD, &vm->kvm.arch.flags))
25062512
return -EINVAL;
25072513

2508-
if (ipa & ~PAGE_MASK)
2514+
if (!PAGE_ALIGNED(ipa) || !PAGE_ALIGNED(size) || !size)
25092515
return -EINVAL;
25102516

25112517
guest_lock_component(vm);
25122518

2513-
ret = kvm_pgtable_get_leaf(&vm->pgt, ipa, &pte, &level);
2514-
if (ret)
2515-
goto unlock;
2516-
2517-
if (pte && BIT(ARM64_HW_PGTABLE_LEVEL_SHIFT(level)) == PAGE_SIZE) {
2518-
/*
2519-
* Already flagged as MMIO, let's accept it, and fail
2520-
* otherwise
2521-
*/
2522-
if (pte != KVM_INVALID_PTE_MMIO_NOTE)
2523-
ret = -EBUSY;
2524-
2519+
/* Check we either have NOMAP or NOMAP|MMIO in this range */
2520+
data.desired_mask = ~PKVM_MMIO;
2521+
ret = kvm_pgtable_walk(&vm->pgt, ipa, size, &walker);
2522+
/* Walker reached data.max_ptes */
2523+
if (ret == -E2BIG)
2524+
ret = 0;
2525+
else if (ret)
25252526
goto unlock;
2526-
}
25272527

2528-
ret = kvm_pgtable_stage2_annotate(&vm->pgt, ipa, PAGE_SIZE,
2528+
/*
2529+
* Intersection between the requested region and what has been verified
2530+
*/
2531+
size = min(data.size - (ipa - data.ipa_start), size);
2532+
ret = kvm_pgtable_stage2_annotate(&vm->pgt, ipa, size,
25292533
&hyp_vcpu->vcpu.arch.stage2_mc,
25302534
KVM_INVALID_PTE_MMIO_NOTE);
2531-
2535+
if (nr_guarded)
2536+
*nr_guarded = size >> PAGE_SHIFT;
25322537
unlock:
25332538
guest_unlock_component(vm);
25342539
return ret;
25352540
}
25362541

2537-
int __pkvm_remove_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa)
2542+
int __pkvm_remove_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa,
2543+
u64 nr_pages, u64 *nr_unguarded)
25382544
{
25392545
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
2546+
struct guest_request_walker_data data =
2547+
GUEST_WALKER_DATA_INIT(PKVM_NOPAGE | PKVM_MMIO);
2548+
struct kvm_pgtable_walker walker = {
2549+
.cb = guest_request_walker,
2550+
.flags = KVM_PGTABLE_WALK_LEAF,
2551+
.arg = (void *)&data,
2552+
};
2553+
u64 size = nr_pages * PAGE_SIZE;
2554+
int ret;
25402555

25412556
if (!test_bit(KVM_ARCH_FLAG_MMIO_GUARD, &vm->kvm.arch.flags))
25422557
return -EINVAL;
25432558

2559+
if (!PAGE_ALIGNED(ipa) || !PAGE_ALIGNED(size) || !size)
2560+
return -EINVAL;
2561+
25442562
guest_lock_component(vm);
25452563

2546-
if (__check_ioguard_page(hyp_vcpu, ipa))
2547-
WARN_ON(kvm_pgtable_stage2_unmap(&vm->pgt,
2548-
ALIGN_DOWN(ipa, PAGE_SIZE), PAGE_SIZE));
2564+
ret = kvm_pgtable_walk(&vm->pgt, ipa, size, &walker);
2565+
/* Walker reached data.max_ptes */
2566+
if (ret == -E2BIG)
2567+
ret = 0;
2568+
else if (ret)
2569+
goto unlock;
2570+
2571+
/*
2572+
* Ioguard is using annotation which has force_pte on.
2573+
* We shouldn't get any block mapping
2574+
*/
2575+
WARN_ON(data.ipa_start != ipa);
2576+
WARN_ON(data.size > size);
2577+
2578+
ret = kvm_pgtable_stage2_unmap(&vm->pgt, data.ipa_start, data.size);
25492579

25502580
guest_unlock_component(vm);
2551-
return 0;
2581+
2582+
if (nr_unguarded)
2583+
*nr_unguarded = data.size >> PAGE_SHIFT;
2584+
unlock:
2585+
return WARN_ON(ret);
25522586
}
25532587

25542588
bool __pkvm_check_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu)

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

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,20 +1525,57 @@ static bool pkvm_memunshare_call(struct pkvm_hyp_vcpu *hyp_vcpu)
15251525
return true;
15261526
}
15271527

1528-
static bool pkvm_install_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu, u64 *exit_code)
1528+
static bool pkvm_install_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu,
1529+
u64 *exit_code)
15291530
{
1530-
u64 retval = SMCCC_RET_SUCCESS;
15311531
u64 ipa = smccc_get_arg1(&hyp_vcpu->vcpu);
1532-
int ret;
1532+
u64 nr_pages = smccc_get_arg2(&hyp_vcpu->vcpu);
1533+
u32 fn = smccc_get_function(&hyp_vcpu->vcpu);
1534+
u64 retval = SMCCC_RET_SUCCESS;
1535+
u64 nr_guarded = 0;
1536+
int ret = -EINVAL;
1537+
1538+
/* Legacy non-range version, arg2|arg3 might be garbage */
1539+
if (fn == ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_MAP_FUNC_ID)
1540+
nr_pages = 1;
1541+
else if (smccc_get_arg3(&hyp_vcpu->vcpu))
1542+
goto out_guest_err;
15331543

1534-
ret = __pkvm_install_ioguard_page(hyp_vcpu, ipa);
1544+
ret = __pkvm_install_ioguard_page(hyp_vcpu, ipa, nr_pages, &nr_guarded);
15351545
if (ret == -ENOMEM && !pkvm_handle_empty_memcache(hyp_vcpu, exit_code))
15361546
return false;
15371547

1548+
out_guest_err:
15381549
if (ret)
15391550
retval = SMCCC_RET_INVALID_PARAMETER;
15401551

1541-
smccc_set_retval(&hyp_vcpu->vcpu, retval, 0, 0, 0);
1552+
smccc_set_retval(&hyp_vcpu->vcpu, retval, nr_guarded, 0, 0);
1553+
return true;
1554+
}
1555+
1556+
static bool pkvm_remove_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu,
1557+
u64 *exit_code)
1558+
{
1559+
u64 ipa = smccc_get_arg1(&hyp_vcpu->vcpu);
1560+
u64 nr_pages = smccc_get_arg2(&hyp_vcpu->vcpu);
1561+
u32 fn = smccc_get_function(&hyp_vcpu->vcpu);
1562+
u64 retval = SMCCC_RET_SUCCESS;
1563+
u64 nr_unguarded = 0;
1564+
int ret = -EINVAL;
1565+
1566+
/* Legacy non-range version, arg2|arg3 might be garbage */
1567+
if (fn == ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_UNMAP_FUNC_ID)
1568+
nr_pages = 1;
1569+
else if (smccc_get_arg3(&hyp_vcpu->vcpu))
1570+
goto out_guest_err;
1571+
1572+
ret = __pkvm_remove_ioguard_page(hyp_vcpu, ipa, nr_pages, &nr_unguarded);
1573+
1574+
out_guest_err:
1575+
if (ret)
1576+
retval = SMCCC_RET_INVALID_PARAMETER;
1577+
1578+
smccc_set_retval(&hyp_vcpu->vcpu, retval, nr_unguarded, 0, 0);
15421579
return true;
15431580
}
15441581

@@ -1653,20 +1690,20 @@ bool kvm_handle_pvm_hvc64(struct kvm_vcpu *vcpu, u64 *exit_code)
16531690
val[0] |= BIT(ARM_SMCCC_KVM_FUNC_MMIO_GUARD_ENROLL);
16541691
val[0] |= BIT(ARM_SMCCC_KVM_FUNC_MMIO_GUARD_MAP);
16551692
val[0] |= BIT(ARM_SMCCC_KVM_FUNC_MMIO_GUARD_UNMAP);
1693+
val[0] |= BIT(ARM_SMCCC_KVM_FUNC_MMIO_RGUARD_MAP);
1694+
val[0] |= BIT(ARM_SMCCC_KVM_FUNC_MMIO_RGUARD_UNMAP);
16561695
val[0] |= BIT(ARM_SMCCC_KVM_FUNC_MEM_RELINQUISH);
16571696
break;
16581697
case ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_ENROLL_FUNC_ID:
16591698
set_bit(KVM_ARCH_FLAG_MMIO_GUARD, &vcpu->kvm->arch.flags);
16601699
val[0] = SMCCC_RET_SUCCESS;
16611700
break;
16621701
case ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_MAP_FUNC_ID:
1702+
case ARM_SMCCC_VENDOR_HYP_KVM_MMIO_RGUARD_MAP_FUNC_ID:
16631703
return pkvm_install_ioguard_page(hyp_vcpu, exit_code);
16641704
case ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_UNMAP_FUNC_ID:
1665-
if (__pkvm_remove_ioguard_page(hyp_vcpu, vcpu_get_reg(vcpu, 1)))
1666-
val[0] = SMCCC_RET_INVALID_PARAMETER;
1667-
else
1668-
val[0] = SMCCC_RET_SUCCESS;
1669-
break;
1705+
case ARM_SMCCC_VENDOR_HYP_KVM_MMIO_RGUARD_UNMAP_FUNC_ID:
1706+
return pkvm_remove_ioguard_page(hyp_vcpu, exit_code);
16701707
case ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_INFO_FUNC_ID:
16711708
case ARM_SMCCC_VENDOR_HYP_KVM_HYP_MEMINFO_FUNC_ID:
16721709
return pkvm_meminfo_call(hyp_vcpu);

include/linux/arm-smccc.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@
123123
#define ARM_SMCCC_KVM_FUNC_MMIO_GUARD_MAP 7
124124
#define ARM_SMCCC_KVM_FUNC_MMIO_GUARD_UNMAP 8
125125
#define ARM_SMCCC_KVM_FUNC_MEM_RELINQUISH 9
126+
#define ARM_SMCCC_KVM_FUNC_MMIO_RGUARD_MAP 10
127+
#define ARM_SMCCC_KVM_FUNC_MMIO_RGUARD_UNMAP 11
126128
#define ARM_SMCCC_KVM_FUNC_FEATURES_2 127
127129
#define ARM_SMCCC_KVM_NUM_FUNCS 128
128130

@@ -199,6 +201,18 @@
199201
ARM_SMCCC_OWNER_VENDOR_HYP, \
200202
ARM_SMCCC_KVM_FUNC_MMIO_GUARD_UNMAP)
201203

204+
#define ARM_SMCCC_VENDOR_HYP_KVM_MMIO_RGUARD_MAP_FUNC_ID \
205+
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
206+
ARM_SMCCC_SMC_64, \
207+
ARM_SMCCC_OWNER_VENDOR_HYP, \
208+
ARM_SMCCC_KVM_FUNC_MMIO_RGUARD_MAP)
209+
210+
#define ARM_SMCCC_VENDOR_HYP_KVM_MMIO_RGUARD_UNMAP_FUNC_ID \
211+
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
212+
ARM_SMCCC_SMC_64, \
213+
ARM_SMCCC_OWNER_VENDOR_HYP, \
214+
ARM_SMCCC_KVM_FUNC_MMIO_RGUARD_UNMAP)
215+
202216
/* Paravirtualised time calls (defined by ARM DEN0057A) */
203217
#define ARM_SMCCC_HV_PV_TIME_FEATURES \
204218
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \

0 commit comments

Comments
 (0)