From cb7c716999a60df4044c2254f8a961e68375419f Mon Sep 17 00:00:00 2001 From: Pablo Greco Date: Feb 26 2020 17:17:51 +0000 Subject: aarch64 kvm fixes --- diff --git a/SOURCES/0001-arm64-kvm-Fix-IDMAP-overlap-with-HYP-VA.patch b/SOURCES/0001-arm64-kvm-Fix-IDMAP-overlap-with-HYP-VA.patch new file mode 100644 index 0000000..405c9f5 --- /dev/null +++ b/SOURCES/0001-arm64-kvm-Fix-IDMAP-overlap-with-HYP-VA.patch @@ -0,0 +1,258 @@ +From 5b7a08e0ea5bb51f886f2f5e2373de2bf5981dd2 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Thu, 28 Nov 2019 20:58:05 +0100 +Subject: [PATCH 1/2] arm64: KVM: Invoke compute_layout() before alternatives + are applied + +compute_layout() is invoked as part of an alternative fixup under +stop_machine(). This function invokes get_random_long() which acquires a +sleeping lock on -RT which can not be acquired in this context. + +Rename compute_layout() to kvm_compute_layout() and invoke it before +stop_machine() applies the alternatives. Add a __init prefix to +kvm_compute_layout() because the caller has it, too (and so the code can be +discarded after boot). + +Reviewed-by: James Morse +Acked-by: Marc Zyngier +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Catalin Marinas +--- + arch/arm64/include/asm/kvm_mmu.h | 1 + + arch/arm64/kernel/smp.c | 4 ++++ + arch/arm64/kvm/va_layout.c | 8 +------- + 3 files changed, 6 insertions(+), 7 deletions(-) + +diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h +index befe37d..53d846f 100644 +--- a/arch/arm64/include/asm/kvm_mmu.h ++++ b/arch/arm64/include/asm/kvm_mmu.h +@@ -91,6 +91,7 @@ + + void kvm_update_va_mask(struct alt_instr *alt, + __le32 *origptr, __le32 *updptr, int nr_inst); ++void kvm_compute_layout(void); + + static inline unsigned long __kern_hyp_va(unsigned long v) + { +diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c +index dc9fe87..02d41ea 100644 +--- a/arch/arm64/kernel/smp.c ++++ b/arch/arm64/kernel/smp.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -39,6 +40,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -408,6 +410,8 @@ static void __init hyp_mode_check(void) + "CPU: CPUs started in inconsistent modes"); + else + pr_info("CPU: All CPU(s) started at EL1\n"); ++ if (IS_ENABLED(CONFIG_KVM_ARM_HOST)) ++ kvm_compute_layout(); + } + + void __init smp_cpus_done(unsigned int max_cpus) +diff --git a/arch/arm64/kvm/va_layout.c b/arch/arm64/kvm/va_layout.c +index 2cf7d4b..dab1fea 100644 +--- a/arch/arm64/kvm/va_layout.c ++++ b/arch/arm64/kvm/va_layout.c +@@ -22,7 +22,7 @@ + static u64 tag_val; + static u64 va_mask; + +-static void compute_layout(void) ++__init void kvm_compute_layout(void) + { + phys_addr_t idmap_addr = __pa_symbol(__hyp_idmap_text_start); + u64 hyp_va_msb; +@@ -110,9 +110,6 @@ void __init kvm_update_va_mask(struct alt_instr *alt, + + BUG_ON(nr_inst != 5); + +- if (!has_vhe() && !va_mask) +- compute_layout(); +- + for (i = 0; i < nr_inst; i++) { + u32 rd, rn, insn, oinsn; + +@@ -156,9 +153,6 @@ void kvm_patch_vector_branch(struct alt_instr *alt, + return; + } + +- if (!va_mask) +- compute_layout(); +- + /* + * Compute HYP VA by using the same computation as kern_hyp_va() + */ +-- +1.8.3.1 + + +From d2d093ca412b7fd66acd745d00e3ebd4764fe127 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Sat, 28 Dec 2019 11:57:14 +0000 +Subject: [PATCH 2/2] arm64: kvm: Fix IDMAP overlap with HYP VA + +Booting 5.4 on LX2160A reveals that KVM is non-functional: + +kvm: Limiting the IPA size due to kernel Virtual Address limit +kvm [1]: IPA Size Limit: 43bits +kvm [1]: IDMAP intersecting with HYP VA, unable to continue +kvm [1]: error initializing Hyp mode: -22 + +Debugging shows: + +kvm [1]: IDMAP page: 81a26000 +kvm [1]: HYP VA range: 0:22ffffffff + +as RAM is located at: + +80000000-fbdfffff : System RAM +2080000000-237fffffff : System RAM + +Comparing this with the same kernel on Armada 8040 shows: + +kvm: Limiting the IPA size due to kernel Virtual Address limit +kvm [1]: IPA Size Limit: 43bits +kvm [1]: IDMAP page: 2a26000 +kvm [1]: HYP VA range: 4800000000:493fffffff +... +kvm [1]: Hyp mode initialized successfully + +which indicates that hyp_va_msb is set, and is always set to the +opposite value of the idmap page to avoid the overlap. This does not +happen with the LX2160A. + +Further debugging shows vabits_actual = 39, kva_msb = 38 on LX2160A and +kva_msb = 33 on Armada 8040. Looking at the bit layout of the HYP VA, +there is still one bit available for hyp_va_msb. Set this bit +appropriately. This allows KVM to be functional on the LX2160A, but +without any HYP VA randomisation: + +kvm: Limiting the IPA size due to kernel Virtual Address limit +kvm [1]: IPA Size Limit: 43bits +kvm [1]: IDMAP page: 81a24000 +kvm [1]: HYP VA range: 4000000000:62ffffffff +... +kvm [1]: Hyp mode initialized successfully + +Fixes: ed57cac83e05 ("arm64: KVM: Introduce EL2 VA randomisation") +Signed-off-by: Russell King +[maz: small additional cleanups, preserved case where the tag + is legitimately 0 and we can just use the mask, Fixes tag] +Signed-off-by: Marc Zyngier +Link: https://lore.kernel.org/r/E1ilAiY-0000MA-RG@rmk-PC.armlinux.org.uk +--- + arch/arm64/kvm/va_layout.c | 56 +++++++++++++++++++++------------------------- + 1 file changed, 25 insertions(+), 31 deletions(-) + +diff --git a/arch/arm64/kvm/va_layout.c b/arch/arm64/kvm/va_layout.c +index dab1fea..a4f48c1 100644 +--- a/arch/arm64/kvm/va_layout.c ++++ b/arch/arm64/kvm/va_layout.c +@@ -13,52 +13,46 @@ + #include + + /* +- * The LSB of the random hyp VA tag or 0 if no randomization is used. ++ * The LSB of the HYP VA tag + */ + static u8 tag_lsb; + /* +- * The random hyp VA tag value with the region bit if hyp randomization is used ++ * The HYP VA tag value with the region bit + */ + static u64 tag_val; + static u64 va_mask; + ++/* ++ * We want to generate a hyp VA with the following format (with V == ++ * vabits_actual): ++ * ++ * 63 ... V | V-1 | V-2 .. tag_lsb | tag_lsb - 1 .. 0 ++ * --------------------------------------------------------- ++ * | 0000000 | hyp_va_msb | random tag | kern linear VA | ++ * |--------- tag_val -----------|----- va_mask ---| ++ * ++ * which does not conflict with the idmap regions. ++ */ + __init void kvm_compute_layout(void) + { + phys_addr_t idmap_addr = __pa_symbol(__hyp_idmap_text_start); + u64 hyp_va_msb; +- int kva_msb; + + /* Where is my RAM region? */ + hyp_va_msb = idmap_addr & BIT(vabits_actual - 1); + hyp_va_msb ^= BIT(vabits_actual - 1); + +- kva_msb = fls64((u64)phys_to_virt(memblock_start_of_DRAM()) ^ ++ tag_lsb = fls64((u64)phys_to_virt(memblock_start_of_DRAM()) ^ + (u64)(high_memory - 1)); + +- if (kva_msb == (vabits_actual - 1)) { +- /* +- * No space in the address, let's compute the mask so +- * that it covers (vabits_actual - 1) bits, and the region +- * bit. The tag stays set to zero. +- */ +- va_mask = BIT(vabits_actual - 1) - 1; +- va_mask |= hyp_va_msb; +- } else { +- /* +- * We do have some free bits to insert a random tag. +- * Hyp VAs are now created from kernel linear map VAs +- * using the following formula (with V == vabits_actual): +- * +- * 63 ... V | V-1 | V-2 .. tag_lsb | tag_lsb - 1 .. 0 +- * --------------------------------------------------------- +- * | 0000000 | hyp_va_msb | random tag | kern linear VA | +- */ +- tag_lsb = kva_msb; +- va_mask = GENMASK_ULL(tag_lsb - 1, 0); +- tag_val = get_random_long() & GENMASK_ULL(vabits_actual - 2, tag_lsb); +- tag_val |= hyp_va_msb; +- tag_val >>= tag_lsb; ++ va_mask = GENMASK_ULL(tag_lsb - 1, 0); ++ tag_val = hyp_va_msb; ++ ++ if (tag_lsb != (vabits_actual - 1)) { ++ /* We have some free bits to insert a random tag. */ ++ tag_val |= get_random_long() & GENMASK_ULL(vabits_actual - 2, tag_lsb); + } ++ tag_val >>= tag_lsb; + } + + static u32 compute_instruction(int n, u32 rd, u32 rn) +@@ -117,11 +111,11 @@ void __init kvm_update_va_mask(struct alt_instr *alt, + * VHE doesn't need any address translation, let's NOP + * everything. + * +- * Alternatively, if we don't have any spare bits in +- * the address, NOP everything after masking that +- * kernel VA. ++ * Alternatively, if the tag is zero (because the layout ++ * dictates it and we don't have any spare bits in the ++ * address), NOP everything after masking the kernel VA. + */ +- if (has_vhe() || (!tag_lsb && i > 0)) { ++ if (has_vhe() || (!tag_val && i > 0)) { + updptr[i] = cpu_to_le32(aarch64_insn_gen_nop()); + continue; + } +-- +1.8.3.1 + diff --git a/SPECS/kernel.spec b/SPECS/kernel.spec index d24e73e..056e047 100644 --- a/SPECS/kernel.spec +++ b/SPECS/kernel.spec @@ -866,6 +866,9 @@ Patch601: alsa-5.6.patch # This is already in 5.5 rhbz 1794369 Patch603: 0001-e1000e-Add-support-for-Comet-Lake.patch +#KVM fix +Patch700: 0001-arm64-kvm-Fix-IDMAP-overlap-with-HYP-VA.patch + #CentOS Patch9999: 0001-Fix-mt7615.patch # END OF PATCH DEFINITIONS @@ -2909,3 +2912,4 @@ fi - Import headers and tools from Fedora - Fix BR foor CentOS 7 - aarch64 mmap fixes +- aarch64 kvm fixes