arm64: mm: extend linear region for 52-bit VA configurations
authorArd Biesheuvel <ardb@kernel.org>
Thu, 8 Oct 2020 15:36:00 +0000 (17:36 +0200)
committerCatalin Marinas <catalin.marinas@arm.com>
Mon, 9 Nov 2020 17:15:37 +0000 (17:15 +0000)
For historical reasons, the arm64 kernel VA space is configured as two
equally sized halves, i.e., on a 48-bit VA build, the VA space is split
into a 47-bit vmalloc region and a 47-bit linear region.

When support for 52-bit virtual addressing was added, this equal split
was kept, resulting in a substantial waste of virtual address space in
the linear region:

                           48-bit VA                     52-bit VA
  0xffff_ffff_ffff_ffff +-------------+               +-------------+
                        |   vmalloc   |               |   vmalloc   |
  0xffff_8000_0000_0000 +-------------+ _PAGE_END(48) +-------------+
                        |   linear    |               :             :
  0xffff_0000_0000_0000 +-------------+               :             :
                        :             :               :             :
                        :             :               :             :
                        :             :               :             :
                        :             :               :  currently  :
                        :  unusable   :               :             :
                        :             :               :   unused    :
                        :     by      :               :             :
                        :             :               :             :
                        :  hardware   :               :             :
                        :             :               :             :
  0xfff8_0000_0000_0000 :             : _PAGE_END(52) +-------------+
                        :             :               |             |
                        :             :               |             |
                        :             :               |             |
                        :             :               |             |
                        :             :               |             |
                        :  unusable   :               |             |
                        :             :               |   linear    |
                        :     by      :               |             |
                        :             :               |   region    |
                        :  hardware   :               |             |
                        :             :               |             |
                        :             :               |             |
                        :             :               |             |
                        :             :               |             |
                        :             :               |             |
                        :             :               |             |
  0xfff0_0000_0000_0000 +-------------+  PAGE_OFFSET  +-------------+

As illustrated above, the 52-bit VA kernel uses 47 bits for the vmalloc
space (as before), to ensure that a single 64k granule kernel image can
support any 64k granule capable system, regardless of whether it supports
the 52-bit virtual addressing extension. However, due to the fact that
the VA space is still split in equal halves, the linear region is only
2^51 bytes in size, wasting almost half of the 52-bit VA space.

Let's fix this, by abandoning the equal split, and simply assigning all
VA space outside of the vmalloc region to the linear region.

The KASAN shadow region is reconfigured so that it ends at the start of
the vmalloc region, and grows downwards. That way, the arrangement of
the vmalloc space (which contains kernel mappings, modules, BPF region,
the vmemmap array etc) is identical between non-KASAN and KASAN builds,
which aids debugging.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Steve Capper <steve.capper@arm.com>
Link: https://lore.kernel.org/r/20201008153602.9467-3-ardb@kernel.org
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Documentation/arm64/kasan-offsets.sh
Documentation/arm64/memory.rst
arch/arm64/Kconfig
arch/arm64/include/asm/memory.h
arch/arm64/mm/init.c

index 2b7a021..2dc5f9e 100644 (file)
@@ -1,12 +1,11 @@
 #!/bin/sh
 
 # Print out the KASAN_SHADOW_OFFSETS required to place the KASAN SHADOW
-# start address at the mid-point of the kernel VA space
+# start address at the top of the linear region
 
 print_kasan_offset () {
        printf "%02d\t" $1
        printf "0x%08x00000000\n" $(( (0xffffffff & (-1 << ($1 - 1 - 32))) \
-                       + (1 << ($1 - 32 - $2)) \
                        - (1 << (64 - 32 - $2)) ))
 }
 
index cf03b32..ee51eb6 100644 (file)
@@ -32,10 +32,10 @@ AArch64 Linux memory layout with 4KB pages + 4 levels (48-bit)::
   -----------------------------------------------------------------------
   0000000000000000     0000ffffffffffff         256TB          user
   ffff000000000000     ffff7fffffffffff         128TB          kernel logical memory map
-  ffff800000000000     ffff9fffffffffff          32TB          kasan shadow region
-  ffffa00000000000     ffffa00007ffffff         128MB          bpf jit region
-  ffffa00008000000     ffffa0000fffffff         128MB          modules
-  ffffa00010000000     fffffdffbffeffff         ~93TB          vmalloc
+[ ffff600000000000     ffff7fffffffffff ]        32TB          [ kasan shadow region ]
+  ffff800000000000     ffff800007ffffff         128MB          bpf jit region
+  ffff800008000000     ffff80000fffffff         128MB          modules
+  ffff800010000000     fffffdffbffeffff         125TB          vmalloc
   fffffdffbfff0000     fffffdfffe5f8fff        ~998MB          [guard region]
   fffffdfffe5f9000     fffffdfffe9fffff        4124KB          fixed mappings
   fffffdfffea00000     fffffdfffebfffff           2MB          [guard region]
@@ -50,12 +50,11 @@ AArch64 Linux memory layout with 64KB pages + 3 levels (52-bit with HW support):
   Start                        End                     Size            Use
   -----------------------------------------------------------------------
   0000000000000000     000fffffffffffff           4PB          user
-  fff0000000000000     fff7ffffffffffff           2PB          kernel logical memory map
-  fff8000000000000     fffd9fffffffffff        1440TB          [gap]
-  fffda00000000000     ffff9fffffffffff         512TB          kasan shadow region
-  ffffa00000000000     ffffa00007ffffff         128MB          bpf jit region
-  ffffa00008000000     ffffa0000fffffff         128MB          modules
-  ffffa00010000000     fffff81ffffeffff         ~88TB          vmalloc
+  fff0000000000000     ffff7fffffffffff          ~4PB          kernel logical memory map
+[ fffd800000000000     ffff7fffffffffff ]       512TB          [ kasan shadow region ]
+  ffff800000000000     ffff800007ffffff         128MB          bpf jit region
+  ffff800008000000     ffff80000fffffff         128MB          modules
+  ffff800010000000     fffff81ffffeffff         120TB          vmalloc
   fffff81fffff0000     fffffc1ffe58ffff          ~3TB          [guard region]
   fffffc1ffe590000     fffffc1ffe9fffff        4544KB          fixed mappings
   fffffc1ffea00000     fffffc1ffebfffff           2MB          [guard region]
index 1515f6f..c6092cb 100644 (file)
@@ -331,16 +331,16 @@ config BROKEN_GAS_INST
 config KASAN_SHADOW_OFFSET
        hex
        depends on KASAN
-       default 0xdfffa00000000000 if (ARM64_VA_BITS_48 || ARM64_VA_BITS_52) && !KASAN_SW_TAGS
-       default 0xdfffd00000000000 if ARM64_VA_BITS_47 && !KASAN_SW_TAGS
-       default 0xdffffe8000000000 if ARM64_VA_BITS_42 && !KASAN_SW_TAGS
-       default 0xdfffffd000000000 if ARM64_VA_BITS_39 && !KASAN_SW_TAGS
-       default 0xdffffffa00000000 if ARM64_VA_BITS_36 && !KASAN_SW_TAGS
-       default 0xefff900000000000 if (ARM64_VA_BITS_48 || ARM64_VA_BITS_52) && KASAN_SW_TAGS
-       default 0xefffc80000000000 if ARM64_VA_BITS_47 && KASAN_SW_TAGS
-       default 0xeffffe4000000000 if ARM64_VA_BITS_42 && KASAN_SW_TAGS
-       default 0xefffffc800000000 if ARM64_VA_BITS_39 && KASAN_SW_TAGS
-       default 0xeffffff900000000 if ARM64_VA_BITS_36 && KASAN_SW_TAGS
+       default 0xdfff800000000000 if (ARM64_VA_BITS_48 || ARM64_VA_BITS_52) && !KASAN_SW_TAGS
+       default 0xdfffc00000000000 if ARM64_VA_BITS_47 && !KASAN_SW_TAGS
+       default 0xdffffe0000000000 if ARM64_VA_BITS_42 && !KASAN_SW_TAGS
+       default 0xdfffffc000000000 if ARM64_VA_BITS_39 && !KASAN_SW_TAGS
+       default 0xdffffff800000000 if ARM64_VA_BITS_36 && !KASAN_SW_TAGS
+       default 0xefff800000000000 if (ARM64_VA_BITS_48 || ARM64_VA_BITS_52) && KASAN_SW_TAGS
+       default 0xefffc00000000000 if ARM64_VA_BITS_47 && KASAN_SW_TAGS
+       default 0xeffffe0000000000 if ARM64_VA_BITS_42 && KASAN_SW_TAGS
+       default 0xefffffc000000000 if ARM64_VA_BITS_39 && KASAN_SW_TAGS
+       default 0xeffffff800000000 if ARM64_VA_BITS_36 && KASAN_SW_TAGS
        default 0xffffffffffffffff
 
 source "arch/arm64/Kconfig.platforms"
index cd61239..8e89f9b 100644 (file)
@@ -44,7 +44,7 @@
 #define _PAGE_OFFSET(va)       (-(UL(1) << (va)))
 #define PAGE_OFFSET            (_PAGE_OFFSET(VA_BITS))
 #define KIMAGE_VADDR           (MODULES_END)
-#define BPF_JIT_REGION_START   (KASAN_SHADOW_END)
+#define BPF_JIT_REGION_START   (_PAGE_END(VA_BITS_MIN))
 #define BPF_JIT_REGION_SIZE    (SZ_128M)
 #define BPF_JIT_REGION_END     (BPF_JIT_REGION_START + BPF_JIT_REGION_SIZE)
 #define MODULES_END            (MODULES_VADDR + MODULES_VSIZE)
 #define KASAN_SHADOW_OFFSET    _AC(CONFIG_KASAN_SHADOW_OFFSET, UL)
 #define KASAN_SHADOW_END       ((UL(1) << (64 - KASAN_SHADOW_SCALE_SHIFT)) \
                                        + KASAN_SHADOW_OFFSET)
+#define PAGE_END               (KASAN_SHADOW_END - (1UL << (vabits_actual - KASAN_SHADOW_SCALE_SHIFT)))
 #define KASAN_THREAD_SHIFT     1
 #else
 #define KASAN_THREAD_SHIFT     0
-#define KASAN_SHADOW_END       (_PAGE_END(VA_BITS_MIN))
+#define PAGE_END               (_PAGE_END(VA_BITS_MIN))
 #endif /* CONFIG_KASAN */
 
 #define MIN_THREAD_SHIFT       (14 + KASAN_THREAD_SHIFT)
 #include <asm/bug.h>
 
 extern u64                     vabits_actual;
-#define PAGE_END               (_PAGE_END(vabits_actual))
 
 extern s64                     memstart_addr;
 /* PHYS_OFFSET - the physical address of the start of memory. */
@@ -238,11 +238,9 @@ static inline const void *__tag_set(const void *addr, u8 tag)
 
 
 /*
- * The linear kernel range starts at the bottom of the virtual address
- * space. Testing the top bit for the start of the region is a
- * sufficient check and avoids having to worry about the tag.
+ * The linear kernel range starts at the bottom of the virtual address space.
  */
-#define __is_lm_address(addr)  (!(((u64)addr) & BIT(vabits_actual - 1)))
+#define __is_lm_address(addr)  (((u64)(addr) & ~PAGE_OFFSET) < (PAGE_END - PAGE_OFFSET))
 
 #define __lm_to_phys(addr)     (((addr) & ~PAGE_OFFSET) + PHYS_OFFSET)
 #define __kimg_to_phys(addr)   ((addr) - kimage_voffset)
index 0955406..7e15d92 100644 (file)
@@ -269,7 +269,7 @@ static void __init fdt_enforce_memory_region(void)
 
 void __init arm64_memblock_init(void)
 {
-       const s64 linear_region_size = BIT(vabits_actual - 1);
+       const s64 linear_region_size = PAGE_END - _PAGE_OFFSET(vabits_actual);
 
        /* Handle linux,usable-memory-range property */
        fdt_enforce_memory_region();