KVM/arm64 fixes for 5.16, take #1
Subsystems (4)
Marc Zyngier
maintainercover KVM/arm64 fixes for 5.16, take #1
Paolo,
Here's the first set of fixes for 5.16. The main items are a fix for a host S2 issue for protected VM, as well as a correctness fix when extracting the exception class from assembly code. The rest is strictly cosmetic.
Please pull,
M.
The following changes since commit 5a2acbbb0179a7ffbb5440b9fa46689f619705ac:
Merge branch kvm/selftests/memslot into kvmarm-master/next (2021-10-21 11:40:03 +0100)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git tags/kvmarm-fixes-5.16-1
for you to fetch changes up to 50a8d3315960c74095c59e204db44abd937d4b5d:
KVM: arm64: Fix host stage-2 finalization (2021-11-08 18:07:48 +0000)
----------------------------------------------------------------
KVM/arm64 fixes for 5.16, take #1
- Fix the host S2 finalization by solely iterating over the memblocks instead of the whole IPA space
- Tighten the return value of kvm_vcpu_preferred_target() now that 32bit support is long gone
- Make sure the extraction of ESR_ELx.EC is limited to the architected bits
- Comment fixups
----------------------------------------------------------------
Mark Rutland (1):
KVM: arm64: Extract ESR_ELx.EC only
Quentin Perret (1):
KVM: arm64: Fix host stage-2 finalization
Randy Dunlap (1):
KVM: arm64: nvhe: Fix a non-kernel-doc comment
YueHaibing (1):
KVM: arm64: Change the return type of kvm_vcpu_preferred_target()
arch/arm64/include/asm/esr.h | 1 + arch/arm64/include/asm/kvm_host.h | 2 +- arch/arm64/kvm/arm.c | 5 +---- arch/arm64/kvm/guest.c | 7 +------ arch/arm64/kvm/hyp/hyp-entry.S | 2 +- arch/arm64/kvm/hyp/nvhe/host.S | 2 +- arch/arm64/kvm/hyp/nvhe/setup.c | 14 ++++++++++++-- arch/arm64/kvm/hyp/nvhe/sys_regs.c | 2 +- 8 files changed, 19 insertions(+), 16 deletions(-)
Marc Zyngier
maintainerPATCH 1/4 KVM: arm64: Extract ESR_ELx.EC only
From: Mark Rutland <[email protected]>
Since ARMv8.0 the upper 32 bits of ESR_ELx have been RES0, and recently some of the upper bits gained a meaning and can be non-zero. For example, when FEAT_LS64 is implemented, ESR_ELx[36:32] contain ISS2, which for an ST64BV or ST64BV0 can be non-zero. This can be seen in ARM DDI 0487G.b, page D13-3145, section D13.2.37.
Generally, we must not rely on RES0 bit remaining zero in future, and when extracting ESR_ELx.EC we must mask out all other bits.
All C code uses the ESR_ELx_EC() macro, which masks out the irrelevant bits, and therefore no alterations are required to C code to avoid consuming irrelevant bits.
In a couple of places the KVM assembly extracts ESR_ELx.EC using LSR on an X register, and so could in theory consume previously RES0 bits. In both cases this is for comparison with EC values ESR_ELx_EC_HVC32 and ESR_ELx_EC_HVC64, for which the upper bits of ESR_ELx must currently be zero, but this could change in future.
This patch adjusts the KVM vectors to use UBFX rather than LSR to extract ESR_ELx.EC, ensuring these are robust to future additions to ESR_ELx.
--- arch/arm64/include/asm/esr.h | 1 + arch/arm64/kvm/hyp/hyp-entry.S | 2 +- arch/arm64/kvm/hyp/nvhe/host.S | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-)
arch/arm64/include/asm/esr.h +1 -0
@@ -68,6 +68,7 @@#define ESR_ELx_EC_MAX (0x3F)#define ESR_ELx_EC_SHIFT (26) +#define ESR_ELx_EC_WIDTH (6)#define ESR_ELx_EC_MASK (UL(0x3F) << ESR_ELx_EC_SHIFT)#define ESR_ELx_EC (esr) (((esr) & ESR_ELx_EC_MASK) >> ESR_ELx_EC_SHIFT)
arch/arm64/kvm/hyp/hyp-entry.S +1 -1
@@ -44,7 +44,7 @@ el1_sync: // Guest trapped into EL2 mrs x0, esr_el2 - lsr x0, x0, #ESR_ELx_EC_SHIFT + ubfx x0, x0, #ESR_ELx_EC_SHIFT, #ESR_ELx_EC_WIDTH cmp x0, #ESR_ELx_EC_HVC64 ccmp x0, #ESR_ELx_EC_HVC32, #4, ne b.ne el1_trap
arch/arm64/kvm/hyp/nvhe/host.S +1 -1
@@ -141,7 +141,7 @@ SYM_FUNC_END(__host_hvc) .L__vect_start\@: stp x0, x1, [sp, #-16]! mrs x0, esr_el2 - lsr x0, x0, #ESR_ELx_EC_SHIFT + ubfx x0, x0, #ESR_ELx_EC_SHIFT, #ESR_ELx_EC_WIDTH cmp x0, #ESR_ELx_EC_HVC64 b.eq __host_hvc b __host_exit
Signature · 1 line
2.30.2
Marc Zyngier
maintainerPATCH 2/4 KVM: arm64: nvhe: Fix a non-kernel-doc comment
In reply to Marc ZyngierFrom: Randy Dunlap <[email protected]>
Do not use kernel-doc "/**" notation when the comment is not in kernel-doc format.
Fixes this docs build warning:
arch/arm64/kvm/hyp/nvhe/sys_regs.c:478: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst
* Handler for protected VM restricted exceptions.
--- arch/arm64/kvm/hyp/nvhe/sys_regs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/kvm/hyp/nvhe/sys_regs.c +1 -1
@@ -474,7 +474,7 @@ bool kvm_handle_pvm_sysreg(struct kvm_vcpu *vcpu, u64 *exit_code)return true; } -/** +/* * Handler for protected VM restricted exceptions. * * Inject an undefined exception into the guest and return true to indicate that
Signature · 1 line
2.30.2
Marc Zyngier
maintainerPATCH 3/4 KVM: arm64: Change the return type of kvm_vcpu_preferred_target()
In reply to Marc ZyngierFrom: YueHaibing <[email protected]>
kvm_vcpu_preferred_target() always return 0 because kvm_target_cpu() never returns a negative error code.
--- arch/arm64/include/asm/kvm_host.h | 2 +- arch/arm64/kvm/arm.c | 5 +---- arch/arm64/kvm/guest.c | 7 +------ 3 files changed, 3 insertions(+), 11 deletions(-)
arch/arm64/include/asm/kvm_host.h +1 -1
@@ -584,7 +584,7 @@ struct kvm_vcpu_stat {u64 exits; }; -int kvm_vcpu_preferred_target (struct kvm_vcpu_init *init); +void kvm_vcpu_preferred_target (struct kvm_vcpu_init *init);unsigned long kvm_arm_num_regs (struct kvm_vcpu *vcpu);int kvm_arm_copy_reg_indices (struct kvm_vcpu *vcpu,u64 __user *indices);int kvm_arm_get_reg (struct kvm_vcpu *vcpu,const struct kvm_one_reg *reg);
arch/arm64/kvm/arm.c +1 -4
@@ -1397,12 +1397,9 @@ long kvm_arch_vm_ioctl(struct file *filp,return kvm_vm_ioctl_set_device_addr (kvm, &dev_addr); }case KVM_ARM_PREFERRED_TARGET : { -int err;struct kvm_vcpu_init init; - err =kvm_vcpu_preferred_target (&init); -if (err) -return err; +kvm_vcpu_preferred_target (&init);if (copy_to_user (argp, &init,sizeof (init)))return -EFAULT ;
arch/arm64/kvm/guest.c +1 -6
@@ -869,13 +869,10 @@ u32 __attribute_const__ kvm_target_cpu(void)return KVM_ARM_TARGET_GENERIC_V8 ; } -int kvm_vcpu_preferred_target (struct kvm_vcpu_init *init) +void kvm_vcpu_preferred_target (struct kvm_vcpu_init *init) {u32 target =kvm_target_cpu (); -if (target <0 ) -return -ENODEV ; -memset (init,0 ,sizeof (*init));/*
@@ -885,8 +882,6 @@ int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init)* target type. */ init->target = (__u32 )target; - -return 0 ; }int kvm_arch_vcpu_ioctl_get_fpu (struct kvm_vcpu *vcpu,struct kvm_fpu *fpu)
Signature · 1 line
2.30.2
Marc Zyngier
maintainerPATCH 4/4 KVM: arm64: Fix host stage-2 finalization
In reply to Marc ZyngierFrom: Quentin Perret <[email protected]>
We currently walk the hypervisor stage-1 page-table towards the end of hyp init in nVHE protected mode and adjust the host page ownership attributes in its stage-2 in order to get a consistent state from both point of views. The walk is done on the entire hyp VA space, and expects to only ever find page-level mappings. While this expectation is reasonable in the half of hyp VA space that maps memory with a fixed offset (see the loop in pkvm_create_mappings_locked()), it can be incorrect in the other half where nothing prevents the usage of block mappings. For instance, on systems where memory is physically aligned at an address that happens to maps to a PMD aligned VA in the hyp_vmemmap, kvm_pgtable_hyp_map() will install block mappings when backing the hyp_vmemmap, which will later cause finalize_host_mappings() to fail. Furthermore, it should be noted that all pages backing the hyp_vmemmap are also mapped in the 'fixed offset range' of the hypervisor, which implies that finalize_host_mappings() will walk both aliases and update the host stage-2 attributes twice. The order in which this happens is unpredictable, though, since the hyp VA layout is highly dependent on the position of the idmap page, hence resulting in a fragile mess at best.
In order to fix all of this, let's restrict the finalization walk to only cover memory regions in the 'fixed-offset range' of the hyp VA space and nothing else. This not only fixes a correctness issue, but will also result in a slighlty faster hyp initialization overall.
--- arch/arm64/kvm/hyp/nvhe/setup.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
arch/arm64/kvm/hyp/nvhe/setup.c +12 -2
@@ -178,7 +178,7 @@ static int finalize_host_mappings_walker(u64 addr, u64 end, u32 level, phys =kvm_pte_to_phys (pte);if (!addr_is_memory (phys)) -return 0 ; +return -EINVAL ;/* * Adjust the host stage-2 mappings to match the ownership attributes
@@ -207,8 +207,18 @@ static int finalize_host_mappings(void) .cb = finalize_host_mappings_walker, .flags = KVM_PGTABLE_WALK_LEAF, }; +int i, ret; + +for (i =0 ; i < hyp_memblock_nr; i++) { +struct memblock_region *reg = &hyp_memory[i]; +u64 start = (u64 )hyp_phys_to_virt (reg->base); + + ret =kvm_pgtable_walk (&pkvm_pgtable, start, reg->size, &walker); +if (ret) +return ret; + } -return kvm_pgtable_walk (&pkvm_pgtable,0 ,BIT (pkvm_pgtable.ia_bits), &walker); +return 0 ; }void __noreturn __pkvm_init_finalise (void )
Signature · 1 line
2.30.2