Skip to content

Commit fe49fd9

Browse files
Marc Zyngieroupton
authored andcommitted
KVM: arm64: Move VTCR_EL2 into struct s2_mmu
We currently have a global VTCR_EL2 value for each guest, even if the guest uses NV. This implies that the guest's own S2 must fit in the host's. This is odd, for multiple reasons: - the PARange values and the number of IPA bits don't necessarily match: you can have 33 bits of IPA space, and yet you can only describe 32 or 36 bits of PARange - When userspace set the IPA space, it creates a contract with the kernel saying "this is the IPA space I'm prepared to handle". At no point does it constraint the guest's own IPA space as long as the guest doesn't try to use a [I]PA outside of the IPA space set by userspace - We don't even try to hide the value of ID_AA64MMFR0_EL1.PARange. And then there is the consequence of the above: if a guest tries to create a S2 that has for input address something that is larger than the IPA space defined by the host, we inject a fatal exception. This is no good. For all intent and purposes, a guest should be able to have the S2 it really wants, as long as the *output* address of that S2 isn't outside of the IPA space. For that, we need to have a per-s2_mmu VTCR_EL2 setting, which allows us to represent the full PARange. Move the vctr field into the s2_mmu structure, which has no impact whatsoever, except for NV. Note that once we are able to override ID_AA64MMFR0_EL1.PARange from userspace, we'll also be able to restrict the size of the shadow S2 that NV uses. Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20231012205108.3937270-1-maz@kernel.org Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
1 parent 934bf87 commit fe49fd9

File tree

9 files changed

+33
-24
lines changed

9 files changed

+33
-24
lines changed

arch/arm64/include/asm/kvm_host.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,16 @@ struct kvm_s2_mmu {
158158
phys_addr_t pgd_phys;
159159
struct kvm_pgtable *pgt;
160160

161+
/*
162+
* VTCR value used on the host. For a non-NV guest (or a NV
163+
* guest that runs in a context where its own S2 doesn't
164+
* apply), its T0SZ value reflects that of the IPA size.
165+
*
166+
* For a shadow S2 MMU, T0SZ reflects the PARange exposed to
167+
* the guest.
168+
*/
169+
u64 vtcr;
170+
161171
/* The last vcpu id that ran on each physical CPU */
162172
int __percpu *last_vcpu_ran;
163173

@@ -205,9 +215,6 @@ struct kvm_protected_vm {
205215
struct kvm_arch {
206216
struct kvm_s2_mmu mmu;
207217

208-
/* VTCR_EL2 value for this VM */
209-
u64 vtcr;
210-
211218
/* Interrupt controller */
212219
struct vgic_dist vgic;
213220

arch/arm64/include/asm/kvm_mmu.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@ static __always_inline unsigned long __kern_hyp_va(unsigned long v)
150150
*/
151151
#define KVM_PHYS_SHIFT (40)
152152

153-
#define kvm_phys_shift(kvm) VTCR_EL2_IPA(kvm->arch.vtcr)
154-
#define kvm_phys_size(kvm) (_AC(1, ULL) << kvm_phys_shift(kvm))
155-
#define kvm_phys_mask(kvm) (kvm_phys_size(kvm) - _AC(1, ULL))
153+
#define kvm_phys_shift(mmu) VTCR_EL2_IPA((mmu)->vtcr)
154+
#define kvm_phys_size(mmu) (_AC(1, ULL) << kvm_phys_shift(mmu))
155+
#define kvm_phys_mask(mmu) (kvm_phys_size(mmu) - _AC(1, ULL))
156156

157157
#include <asm/kvm_pgtable.h>
158158
#include <asm/stage2_pgtable.h>
@@ -299,7 +299,7 @@ static __always_inline u64 kvm_get_vttbr(struct kvm_s2_mmu *mmu)
299299
static __always_inline void __load_stage2(struct kvm_s2_mmu *mmu,
300300
struct kvm_arch *arch)
301301
{
302-
write_sysreg(arch->vtcr, vtcr_el2);
302+
write_sysreg(mmu->vtcr, vtcr_el2);
303303
write_sysreg(kvm_get_vttbr(mmu), vttbr_el2);
304304

305305
/*

arch/arm64/include/asm/stage2_pgtable.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@
2121
* (IPA_SHIFT - 4).
2222
*/
2323
#define stage2_pgtable_levels(ipa) ARM64_HW_PGTABLE_LEVELS((ipa) - 4)
24-
#define kvm_stage2_levels(kvm) VTCR_EL2_LVLS(kvm->arch.vtcr)
24+
#define kvm_stage2_levels(mmu) VTCR_EL2_LVLS((mmu)->vtcr)
2525

2626
/*
2727
* kvm_mmmu_cache_min_pages() is the number of pages required to install
2828
* a stage-2 translation. We pre-allocate the entry level page table at
2929
* the VM creation.
3030
*/
31-
#define kvm_mmu_cache_min_pages(kvm) (kvm_stage2_levels(kvm) - 1)
31+
#define kvm_mmu_cache_min_pages(mmu) (kvm_stage2_levels(mmu) - 1)
3232

3333
#endif /* __ARM64_S2_PGTABLE_H_ */

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ static void prepare_host_vtcr(void)
129129
parange = kvm_get_parange(id_aa64mmfr0_el1_sys_val);
130130
phys_shift = id_aa64mmfr0_parange_to_phys_shift(parange);
131131

132-
host_mmu.arch.vtcr = kvm_get_vtcr(id_aa64mmfr0_el1_sys_val,
133-
id_aa64mmfr1_el1_sys_val, phys_shift);
132+
host_mmu.arch.mmu.vtcr = kvm_get_vtcr(id_aa64mmfr0_el1_sys_val,
133+
id_aa64mmfr1_el1_sys_val, phys_shift);
134134
}
135135

136136
static bool host_stage2_force_pte_cb(u64 addr, u64 end, enum kvm_pgtable_prot prot);
@@ -235,7 +235,7 @@ int kvm_guest_prepare_stage2(struct pkvm_hyp_vm *vm, void *pgd)
235235
unsigned long nr_pages;
236236
int ret;
237237

238-
nr_pages = kvm_pgtable_stage2_pgd_size(vm->kvm.arch.vtcr) >> PAGE_SHIFT;
238+
nr_pages = kvm_pgtable_stage2_pgd_size(mmu->vtcr) >> PAGE_SHIFT;
239239
ret = hyp_pool_init(&vm->pool, hyp_virt_to_pfn(pgd), nr_pages, 0);
240240
if (ret)
241241
return ret;
@@ -295,7 +295,7 @@ int __pkvm_prot_finalize(void)
295295
return -EPERM;
296296

297297
params->vttbr = kvm_get_vttbr(mmu);
298-
params->vtcr = host_mmu.arch.vtcr;
298+
params->vtcr = mmu->vtcr;
299299
params->hcr_el2 |= HCR_VM;
300300

301301
/*

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ static void init_pkvm_hyp_vm(struct kvm *host_kvm, struct pkvm_hyp_vm *hyp_vm,
303303
{
304304
hyp_vm->host_kvm = host_kvm;
305305
hyp_vm->kvm.created_vcpus = nr_vcpus;
306-
hyp_vm->kvm.arch.vtcr = host_mmu.arch.vtcr;
306+
hyp_vm->kvm.arch.mmu.vtcr = host_mmu.arch.mmu.vtcr;
307307
}
308308

309309
static int init_pkvm_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu,
@@ -483,7 +483,7 @@ int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva,
483483
}
484484

485485
vm_size = pkvm_get_hyp_vm_size(nr_vcpus);
486-
pgd_size = kvm_pgtable_stage2_pgd_size(host_mmu.arch.vtcr);
486+
pgd_size = kvm_pgtable_stage2_pgd_size(host_mmu.arch.mmu.vtcr);
487487

488488
ret = -ENOMEM;
489489

arch/arm64/kvm/hyp/pgtable.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1511,7 +1511,7 @@ int __kvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2_mmu *mmu,
15111511
kvm_pgtable_force_pte_cb_t force_pte_cb)
15121512
{
15131513
size_t pgd_sz;
1514-
u64 vtcr = mmu->arch->vtcr;
1514+
u64 vtcr = mmu->vtcr;
15151515
u32 ia_bits = VTCR_EL2_IPA(vtcr);
15161516
u32 sl0 = FIELD_GET(VTCR_EL2_SL0_MASK, vtcr);
15171517
u32 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;

arch/arm64/kvm/mmu.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -892,7 +892,7 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t
892892

893893
mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
894894
mmfr1 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
895-
kvm->arch.vtcr = kvm_get_vtcr(mmfr0, mmfr1, phys_shift);
895+
mmu->vtcr = kvm_get_vtcr(mmfr0, mmfr1, phys_shift);
896896

897897
if (mmu->pgt != NULL) {
898898
kvm_err("kvm_arch already initialized?\n");
@@ -1067,7 +1067,8 @@ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
10671067
phys_addr_t addr;
10681068
int ret = 0;
10691069
struct kvm_mmu_memory_cache cache = { .gfp_zero = __GFP_ZERO };
1070-
struct kvm_pgtable *pgt = kvm->arch.mmu.pgt;
1070+
struct kvm_s2_mmu *mmu = &kvm->arch.mmu;
1071+
struct kvm_pgtable *pgt = mmu->pgt;
10711072
enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_DEVICE |
10721073
KVM_PGTABLE_PROT_R |
10731074
(writable ? KVM_PGTABLE_PROT_W : 0);
@@ -1080,7 +1081,7 @@ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
10801081

10811082
for (addr = guest_ipa; addr < guest_ipa + size; addr += PAGE_SIZE) {
10821083
ret = kvm_mmu_topup_memory_cache(&cache,
1083-
kvm_mmu_cache_min_pages(kvm));
1084+
kvm_mmu_cache_min_pages(mmu));
10841085
if (ret)
10851086
break;
10861087

@@ -1431,7 +1432,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
14311432
if (fault_status != ESR_ELx_FSC_PERM ||
14321433
(logging_active && write_fault)) {
14331434
ret = kvm_mmu_topup_memory_cache(memcache,
1434-
kvm_mmu_cache_min_pages(kvm));
1435+
kvm_mmu_cache_min_pages(vcpu->arch.hw_mmu));
14351436
if (ret)
14361437
return ret;
14371438
}
@@ -1747,7 +1748,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
17471748
}
17481749

17491750
/* Userspace should not be able to register out-of-bounds IPAs */
1750-
VM_BUG_ON(fault_ipa >= kvm_phys_size(vcpu->kvm));
1751+
VM_BUG_ON(fault_ipa >= kvm_phys_size(vcpu->arch.hw_mmu));
17511752

17521753
if (fault_status == ESR_ELx_FSC_ACCESS) {
17531754
handle_access_fault(vcpu, fault_ipa);
@@ -2021,7 +2022,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
20212022
* Prevent userspace from creating a memory region outside of the IPA
20222023
* space addressable by the KVM guest IPA space.
20232024
*/
2024-
if ((new->base_gfn + new->npages) > (kvm_phys_size(kvm) >> PAGE_SHIFT))
2025+
if ((new->base_gfn + new->npages) > (kvm_phys_size(&kvm->arch.mmu) >> PAGE_SHIFT))
20252026
return -EFAULT;
20262027

20272028
hva = new->userspace_addr;

arch/arm64/kvm/pkvm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ static int __pkvm_create_hyp_vm(struct kvm *host_kvm)
123123
if (host_kvm->created_vcpus < 1)
124124
return -EINVAL;
125125

126-
pgd_sz = kvm_pgtable_stage2_pgd_size(host_kvm->arch.vtcr);
126+
pgd_sz = kvm_pgtable_stage2_pgd_size(host_kvm->arch.mmu.vtcr);
127127

128128
/*
129129
* The PGD pages will be reclaimed using a hyp_memcache which implies

arch/arm64/kvm/vgic/vgic-kvm-device.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ int vgic_check_iorange(struct kvm *kvm, phys_addr_t ioaddr,
2727
if (addr + size < addr)
2828
return -EINVAL;
2929

30-
if (addr & ~kvm_phys_mask(kvm) || addr + size > kvm_phys_size(kvm))
30+
if (addr & ~kvm_phys_mask(&kvm->arch.mmu) ||
31+
(addr + size) > kvm_phys_size(&kvm->arch.mmu))
3132
return -E2BIG;
3233

3334
return 0;

0 commit comments

Comments
 (0)