| From bb0dfd4b244b7529acec055e2e8d5020500a0406 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 26 Aug 2021 18:56:13 +0200 |
| Subject: arm64: mm: limit linear region to 51 bits for KVM in nVHE mode |
| |
| From: Ard Biesheuvel <ardb@kernel.org> |
| |
| [ Upstream commit 88053ec8cb1b91df566353cd3116470193797e00 ] |
| |
| KVM in nVHE mode divides up its VA space into two equal halves, and |
| picks the half that does not conflict with the HYP ID map to map its |
| linear region. This worked fine when the kernel's linear map itself was |
| guaranteed to cover precisely as many bits of VA space, but this was |
| changed by commit f4693c2716b35d08 ("arm64: mm: extend linear region for |
| 52-bit VA configurations"). |
| |
| The result is that, depending on the placement of the ID map, kernel-VA |
| to hyp-VA translations may produce addresses that either conflict with |
| other HYP mappings (including the ID map itself) or generate addresses |
| outside of the 52-bit addressable range, neither of which is likely to |
| lead to anything useful. |
| |
| Given that 52-bit capable cores are guaranteed to implement VHE, this |
| only affects configurations such as pKVM where we opt into non-VHE mode |
| even if the hardware is VHE capable. So just for these configurations, |
| let's limit the kernel linear map to 51 bits and work around the |
| problem. |
| |
| Fixes: f4693c2716b3 ("arm64: mm: extend linear region for 52-bit VA configurations") |
| Signed-off-by: Ard Biesheuvel <ardb@kernel.org> |
| Link: https://lore.kernel.org/r/20210826165613.60774-1-ardb@kernel.org |
| Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| arch/arm64/mm/init.c | 16 +++++++++++++++- |
| 1 file changed, 15 insertions(+), 1 deletion(-) |
| |
| diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c |
| index 1fdb7bb7c198..0ad4afc9359b 100644 |
| --- a/arch/arm64/mm/init.c |
| +++ b/arch/arm64/mm/init.c |
| @@ -319,7 +319,21 @@ static void __init fdt_enforce_memory_region(void) |
| |
| void __init arm64_memblock_init(void) |
| { |
| - const s64 linear_region_size = PAGE_END - _PAGE_OFFSET(vabits_actual); |
| + s64 linear_region_size = PAGE_END - _PAGE_OFFSET(vabits_actual); |
| + |
| + /* |
| + * Corner case: 52-bit VA capable systems running KVM in nVHE mode may |
| + * be limited in their ability to support a linear map that exceeds 51 |
| + * bits of VA space, depending on the placement of the ID map. Given |
| + * that the placement of the ID map may be randomized, let's simply |
| + * limit the kernel's linear map to 51 bits as well if we detect this |
| + * configuration. |
| + */ |
| + if (IS_ENABLED(CONFIG_KVM) && vabits_actual == 52 && |
| + is_hyp_mode_available() && !is_kernel_in_hyp_mode()) { |
| + pr_info("Capping linear region to 51 bits for KVM in nVHE mode on LVA capable hardware.\n"); |
| + linear_region_size = min_t(u64, linear_region_size, BIT(51)); |
| + } |
| |
| /* Handle linux,usable-memory-range property */ |
| fdt_enforce_memory_region(); |
| -- |
| 2.33.0 |
| |