Skip to contentSkip to conversation

arm64: mm: optimize VA space organization for 52-bit

PATCH Applied Ard Biesheuvel 6 participants 26 messages Oct 8, 2020 – Nov 10, 2020

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

v2 cover arm64: mm: optimize VA space organization for 52-bit

This series reorganizes the kernel VA space slightly so that 52-bit VA configurations can use more virtual address space, i.e., the usable linear address space almost doubles, from 2^51 to 2^52-2^47.

Patch #1 merges the physvirt_offset and memstart_addr variables, both of which represent translations between the physical address space and the linear region, and there is no need for having both. This fixes a bug too, as the two values were not properly kept in sync when booting with KASLR enabled.

Patch #2 updates the definitions for the boundaries of the linear space, so that 52-bit VA builds use all available space for the linear region.

Patches #3 and #4 simplify the way the vmemmap region is configured, and unify the 48-bit/4k and 52-bit/64k layouts.

Changes since v1:
- drop incorrect use of untagged_addr() from #2
- add patches #3 and #4

Not boot tested yet on a 52-bit VA capable system.

Cc Steve Capper <[email protected]>
Cc Anshuman Khandual <[email protected]>

Ard Biesheuvel (4):
arm64: mm: use single quantity to represent the PA to VA translation
arm64: mm: extend linear region for 52-bit VA configurations
arm64: mm: make vmemmap region a projection of the linear region
arm64: mm: tidy up top of kernel VA space

 Documentation/arm64/kasan-offsets.sh |  3 +-
 Documentation/arm64/memory.rst       | 45 +++++++++-----------
 arch/arm64/Kconfig                   | 20 ++++-----
 arch/arm64/include/asm/memory.h      | 35 +++++++--------
 arch/arm64/include/asm/pgtable.h     |  6 +--
 arch/arm64/mm/init.c                 | 34 ++++++---------
 6 files changed, 63 insertions(+), 80 deletions(-)
Signature · 7 lines
2.17.1


_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
#1 lore raw

PATCH v2 1/4 arm64: mm: use single quantity to represent the PA to VA translation

On arm64, the global variable memstart_addr represents the physical address of PAGE_OFFSET, and so physical to virtual translations or vice versa used to come down to simple additions or subtractions involving the values of PAGE_OFFSET and memstart_addr.

When support for 52-bit virtual addressing was introduced, we had to deal with PAGE_OFFSET potentially being outside of the region that can be covered by the virtual range (as the 52-bit VA capable build needs to be able to run on systems that are only 48-bit VA capable), and for this reason, another translation was introduced, and recorded in the global variable physvirt_offset.

However, if we go back to the original definition of memstart_addr, i.e., the physical address of PAGE_OFFSET, it turns out that there is no need for two separate translations: instead, we can simply subtract the size of the unaddressable VA space from memstart_addr to make the available physical memory appear in the 48-bit addressable VA region.

This simplifies things, but also fixes a bug on KASLR builds, which may update memstart_addr later on in arm64_memblock_init(), but fails to update vmemmap and physvirt_offset accordingly.

Fixes 5383cc6efed13 ("arm64: mm: Introduce vabits_actual")
---
 arch/arm64/include/asm/memory.h  |  5 ++--
 arch/arm64/include/asm/pgtable.h |  4 +--
 arch/arm64/mm/init.c             | 30 +++++++-------------
 3 files changed, 14 insertions(+), 25 deletions(-)
arch/arm64/include/asm/memory.h +2 -3
index afa722504bfd..1ded73189874 100644
@@ -164,7 +164,6 @@
 extern u64			vabits_actual;
 #define PAGE_END		(_PAGE_END(vabits_actual))
 
-extern s64			physvirt_offset;
 extern s64			memstart_addr;
 /* PHYS_OFFSET - the physical address of the start of memory. */
 #define PHYS_OFFSET		({ VM_BUG_ON(memstart_addr & 1); memstart_addr; })
@@ -240,7 +239,7 @@ static inline const void *__tag_set(const void *addr, u8 tag)
  */
 #define __is_lm_address(addr)	(!(((u64)addr) & BIT(vabits_actual - 1)))
 
-#define __lm_to_phys(addr)	(((addr) + physvirt_offset))
+#define __lm_to_phys(addr)	(((addr) & ~PAGE_OFFSET) + PHYS_OFFSET)
 #define __kimg_to_phys(addr)	((addr) - kimage_voffset)
 
 #define __virt_to_phys_nodebug(x) ({					\
@@ -258,7 +257,7 @@ extern phys_addr_t __phys_addr_symbol(unsigned long x);
 #define __phys_addr_symbol(x)	__pa_symbol_nodebug(x)
 #endif /* CONFIG_DEBUG_VIRTUAL */
 
-#define __phys_to_virt(x)	((unsigned long)((x) - physvirt_offset))
+#define __phys_to_virt(x)	((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET)
 #define __phys_to_kimg(x)	((unsigned long)((x) + kimage_voffset))
 
 /*
arch/arm64/include/asm/pgtable.h +2 -2
index d5d3fbe73953..88233d42d9c2 100644
@@ -23,6 +23,8 @@
 #define VMALLOC_START		(MODULES_END)
 #define VMALLOC_END		(- PUD_SIZE - VMEMMAP_SIZE - SZ_64K)
 
+#define vmemmap			((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT))
+
 #define FIRST_USER_ADDRESS	0UL
 
 #ifndef __ASSEMBLY__
@@ -33,8 +35,6 @@
 #include <linux/mm_types.h>
 #include <linux/sched.h>
 
-extern struct page *vmemmap;
-
 extern void __pte_error(const char *file, int line, unsigned long val);
 extern void __pmd_error(const char *file, int line, unsigned long val);
 extern void __pud_error(const char *file, int line, unsigned long val);
arch/arm64/mm/init.c +10 -20
index 481d22c32a2e..324f0e0894f6 100644
@@ -54,12 +54,6 @@
 s64 memstart_addr __ro_after_init = -1;
 EXPORT_SYMBOL(memstart_addr);
 
-s64 physvirt_offset __ro_after_init;
-EXPORT_SYMBOL(physvirt_offset);
-
-struct page *vmemmap __ro_after_init;
-EXPORT_SYMBOL(vmemmap);
-
 /*
  * We create both ZONE_DMA and ZONE_DMA32. ZONE_DMA covers the first 1G of
  * memory as some devices, namely the Raspberry Pi 4, have peripherals with
@@ -290,20 +284,6 @@ void __init arm64_memblock_init(void)
 	memstart_addr = round_down(memblock_start_of_DRAM(),
 				   ARM64_MEMSTART_ALIGN);
 
-	physvirt_offset = PHYS_OFFSET - PAGE_OFFSET;
-
-	vmemmap = ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT));
-
-	/*
-	 * If we are running with a 52-bit kernel VA config on a system that
-	 * does not support it, we have to offset our vmemmap and physvirt_offset
-	 * s.t. we avoid the 52-bit portion of the direct linear map
-	 */
-	if (IS_ENABLED(CONFIG_ARM64_VA_BITS_52) && (vabits_actual != 52)) {
-		vmemmap += (_PAGE_OFFSET(48) - _PAGE_OFFSET(52)) >> PAGE_SHIFT;
-		physvirt_offset = PHYS_OFFSET - _PAGE_OFFSET(48);
-	}
-
 	/*
 	 * Remove the memory that we will not be able to cover with the
 	 * linear mapping. Take care not to clip the kernel which may be
@@ -318,6 +298,16 @@ void __init arm64_memblock_init(void)
 		memblock_remove(0, memstart_addr);
 	}
 
+	/*
+	 * If we are running with a 52-bit kernel VA config on a system that
+	 * does not support it, we have to place the available physical
+	 * memory in the 48-bit addressable part of the linear region, i.e.,
+	 * we have to move it upward. Since memstart_addr represents the
+	 * physical address of PAGE_OFFSET, we have to *subtract* from it.
+	 */
+	if (IS_ENABLED(CONFIG_ARM64_VA_BITS_52) && (vabits_actual != 52))
+		memstart_addr -= _PAGE_OFFSET(48) - _PAGE_OFFSET(52);
+
 	/*
 	 * Apply the memory limit if it was set. Since the kernel may be loaded
 	 * high up in memory, add back the kernel region that must be accessible
Signature · 7 lines
2.17.1


_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Reviewed-by on v2 1/4
#2 lore raw

RE: [PATCH v2 1/4] arm64: mm: use single quantity to represent the PA to VA translation

Hi Ard,

Quoted 18 lines · Ard Biesheuvel

On arm64, the global variable memstart_addr represents the physical address of PAGE_OFFSET, and so physical to virtual translations or vice versa used to come down to simple additions or subtractions involving the values of PAGE_OFFSET and memstart_addr.

When support for 52-bit virtual addressing was introduced, we had to deal with PAGE_OFFSET potentially being outside of the region that can be covered by the virtual range (as the 52-bit VA capable build needs to be able to run on systems that are only 48-bit VA capable), and for this reason, another translation was introduced, and recorded in the global variable physvirt_offset.

However, if we go back to the original definition of memstart_addr, i.e., the physical address of PAGE_OFFSET, it turns out that there is no need for two separate translations: instead, we can simply subtract the size of the unaddressable VA space from memstart_addr to make the available physical memory appear in the 48-bit addressable VA region.

Quoted 4 lines

This simplifies things, but also fixes a bug on KASLR builds, which may update memstart_addr later on in arm64_memblock_init(), but fails to update vmemmap and physvirt_offset accordingly.

Apologies, I didn't spot that before.

Quoted 2 lines
Fixes 5383cc6efed13 ("arm64: mm: Introduce vabits_actual")

Thanks for this. It is much better to modify memstart_addr rather than introducing needless complexity.

Cheers,
--
Steve

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Reviewed-by on v2 1/4
#3 lore raw

Re: [PATCH v2 1/4] arm64: mm: use single quantity to represent the PA to VA translation

In reply to Ard Biesheuvel

Hi Ard,

Quoted 18 lines · Ard Biesheuvel

On arm64, the global variable memstart_addr represents the physical address of PAGE_OFFSET, and so physical to virtual translations or vice versa used to come down to simple additions or subtractions involving the values of PAGE_OFFSET and memstart_addr.

When support for 52-bit virtual addressing was introduced, we had to deal with PAGE_OFFSET potentially being outside of the region that can be covered by the virtual range (as the 52-bit VA capable build needs to be able to run on systems that are only 48-bit VA capable), and for this reason, another translation was introduced, and recorded in the global variable physvirt_offset.

However, if we go back to the original definition of memstart_addr, i.e., the physical address of PAGE_OFFSET, it turns out that there is no need for two separate translations: instead, we can simply subtract the size of the unaddressable VA space from memstart_addr to make the available physical memory appear in the 48-bit addressable VA region.

Quoted 4 lines

This simplifies things, but also fixes a bug on KASLR builds, which may update memstart_addr later on in arm64_memblock_init(), but fails to update vmemmap and physvirt_offset accordingly.

Apologies, I didn't spot that before.

Quoted 2 lines
Fixes 5383cc6efed13 ("arm64: mm: Introduce vabits_actual")

Thanks for this. It is much better to modify memstart_addr rather than introducing needless complexity.

Cheers,
--
Steve

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

maintainer
#4 lore raw

Re: [PATCH v2 1/4] arm64: mm: use single quantity to represent the PA to VA translation

In reply to Ard Biesheuvel
Quoted 22 lines · Ard Biesheuvel

On arm64, the global variable memstart_addr represents the physical address of PAGE_OFFSET, and so physical to virtual translations or vice versa used to come down to simple additions or subtractions involving the values of PAGE_OFFSET and memstart_addr.

When support for 52-bit virtual addressing was introduced, we had to deal with PAGE_OFFSET potentially being outside of the region that can be covered by the virtual range (as the 52-bit VA capable build needs to be able to run on systems that are only 48-bit VA capable), and for this reason, another translation was introduced, and recorded in the global variable physvirt_offset.

However, if we go back to the original definition of memstart_addr, i.e., the physical address of PAGE_OFFSET, it turns out that there is no need for two separate translations: instead, we can simply subtract the size of the unaddressable VA space from memstart_addr to make the available physical memory appear in the 48-bit addressable VA region.

This simplifies things, but also fixes a bug on KASLR builds, which may update memstart_addr later on in arm64_memblock_init(), but fails to update vmemmap and physvirt_offset accordingly.

Quoted 7 lines
Fixes 5383cc6efed13 ("arm64: mm: Introduce vabits_actual")
---
 arch/arm64/include/asm/memory.h  |  5 ++--
 arch/arm64/include/asm/pgtable.h |  4 +--
 arch/arm64/mm/init.c             | 30 +++++++-------------
 3 files changed, 14 insertions(+), 25 deletions(-)

I'll pick this one patch up for 5.10, thanks.

Will

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#5 lore raw

PATCH v2 2/4 arm64: mm: extend linear region for 52-bit VA configurations

In reply to Ard Biesheuvel

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.

---
 Documentation/arm64/kasan-offsets.sh |  3 +--
 Documentation/arm64/memory.rst       | 19 +++++++++----------
 arch/arm64/Kconfig                   | 20 ++++++++++----------
 arch/arm64/include/asm/memory.h      | 12 +++++-------
 arch/arm64/mm/init.c                 |  2 +-
 5 files changed, 26 insertions(+), 30 deletions(-)
Documentation/arm64/kasan-offsets.sh +1 -2
index 2b7a021db363..2dc5f9e18039 100644
@@ -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)) ))
 }
 
Documentation/arm64/memory.rst +9 -10
index cf03b3290800..ee51eb66a578 100644
@@ -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]
arch/arm64/Kconfig +10 -10
index 6d232837cbee..896a46a71d23 100644
@@ -321,16 +321,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"
arch/arm64/include/asm/memory.h +5 -7
index 1ded73189874..58932f434433 100644
@@ -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)
@@ -76,10 +76,11 @@
 #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)
@@ -162,7 +163,6 @@
 #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. */
@@ -233,11 +233,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)
arch/arm64/mm/init.c +1 -1
index 324f0e0894f6..9090779dd3cd 100644
@@ -270,7 +270,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();
Signature · 7 lines
2.17.1


_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
#6 lore raw

Re: [PATCH v2 2/4] arm64: mm: extend linear region for 52-bit VA configurations

Hi Ard,

One comment below...

Quoted 68 lines · Ard Biesheuvel

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.

---
  Documentation/arm64/kasan-offsets.sh |  3 +--
  Documentation/arm64/memory.rst       | 19 +++++++++----------
  arch/arm64/Kconfig                   | 20 ++++++++++----------
  arch/arm64/include/asm/memory.h      | 12 +++++-------
  arch/arm64/mm/init.c                 |  2 +-
  5 files changed, 26 insertions(+), 30 deletions(-)

[...]

Documentation/arm64/memory.rst AArch64 Linux memory layout with 4KB pages + 4 levels (48-bit):: · line 35

Quoted 13 lines
Documentation/arm64/memory.rst +1 -4
index cf03b3290800..ee51eb66a578 100644
@@ -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 ]

We have the KASAN shadow region intersecting with the kernel logical memory map now. Could this present a problem if both the KASAN and phys_to_virt paths land on the same VA? Or is that not possible? (Also what about smaller VA sizes?)

If it is a problem, could carving out the appropriate memblocks (and warning the user) be a way forward?

Cheers,
--
Steve

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#7 lore raw

Re: [PATCH v2 2/4] arm64: mm: extend linear region for 52-bit VA configurations

Quoted 96 lines · Steve Capper

Hi Ard,

One comment below...

Quoted 68 lines · Ard Biesheuvel

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.

---
  Documentation/arm64/kasan-offsets.sh |  3 +--
  Documentation/arm64/memory.rst       | 19 +++++++++----------
  arch/arm64/Kconfig                   | 20 ++++++++++----------
  arch/arm64/include/asm/memory.h      | 12 +++++-------
  arch/arm64/mm/init.c                 |  2 +-
  5 files changed, 26 insertions(+), 30 deletions(-)

[...]

Documentation/arm64/memory.rst AArch64 Linux memory layout with 4KB pages + 4 levels (48-bit):: · line 35

Quoted 13 lines
Documentation/arm64/memory.rst +1 -4
index cf03b3290800..ee51eb66a578 100644
@@ -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 ]

We have the KASAN shadow region intersecting with the kernel logical memory map now. Could this present a problem if both the KASAN and phys_to_virt paths land on the same VA? Or is that not possible? (Also what about smaller VA sizes?)

Quoted 3 lines

If it is a problem, could carving out the appropriate memblocks (and warning the user) be a way forward?

Hi Steve,

This is currently taken into account in arm64_memblock_init():

const s64 linear_region_size = PAGE_END - _PAGE_OFFSET(vabits_actual);

When CONFIG_KASAN=y, PAGE_END is #defined as

(KASAN_SHADOW_END - (1UL << (vabits_actual - KASAN_SHADOW_SCALE_SHIFT)))

and so the linear region ends where the KASAN shadow region starts. So even if the static definitions overlap, the shared region will not be used for mapping memory if it is needed for allocating shadow pages.

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Reviewed-by
#8 lore raw

Re: [PATCH v2 2/4] arm64: mm: extend linear region for 52-bit VA configurations

Quoted 107 lines · Ard Biesheuvel
Quoted 96 lines · Steve Capper

Hi Ard,

One comment below...

Quoted 68 lines · Ard Biesheuvel

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.

---
   Documentation/arm64/kasan-offsets.sh |  3 +--
   Documentation/arm64/memory.rst       | 19 +++++++++----------
   arch/arm64/Kconfig                   | 20 ++++++++++----------
   arch/arm64/include/asm/memory.h      | 12 +++++-------
   arch/arm64/mm/init.c                 |  2 +-
   5 files changed, 26 insertions(+), 30 deletions(-)

[...]

Documentation/arm64/memory.rst AArch64 Linux memory layout with 4KB pages + 4 levels (48-bit):: · line 35

Quoted 13 lines
Documentation/arm64/memory.rst +1 -4
index cf03b3290800..ee51eb66a578 100644
@@ -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 ]

We have the KASAN shadow region intersecting with the kernel logical memory map now. Could this present a problem if both the KASAN and phys_to_virt paths land on the same VA? Or is that not possible? (Also what about smaller VA sizes?)

Quoted 3 lines

If it is a problem, could carving out the appropriate memblocks (and warning the user) be a way forward?

Hi Steve,

This is currently taken into account in arm64_memblock_init():

const s64 linear_region_size = PAGE_END - _PAGE_OFFSET(vabits_actual);

Quoted 8 lines

When CONFIG_KASAN=y, PAGE_END is #defined as

(KASAN_SHADOW_END - (1UL << (vabits_actual - KASAN_SHADOW_SCALE_SHIFT)))

and so the linear region ends where the KASAN shadow region starts. So even if the static definitions overlap, the shared region will not be used for mapping memory if it is needed for allocating shadow pages.

Ahhh, yes, thanks that will prevent the intersection from occurring.

This looks good to me, feel free to add:

Cheers,
--
Steve

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#9 lore raw

Re: [PATCH v2 2/4] arm64: mm: extend linear region for 52-bit VA configurations

In reply to Ard Biesheuvel
Quoted 43 lines · Ard Biesheuvel

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  +-------------+
Quoted 6 lines

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.

Right, that is a huge wastage. Increasing the linear mapping will definitely help in getting more memory used on the system. But now do we have enough vmemmap range to support this enlarged linear mapping ?

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#10 lore raw

Re: [PATCH v2 2/4] arm64: mm: extend linear region for 52-bit VA configurations

Quoted 54 lines · Anshuman Khandual
Quoted 43 lines · Ard Biesheuvel

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  +-------------+
Quoted 6 lines

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.

Quoted 3 lines

Right, that is a huge wastage. Increasing the linear mapping will definitely help in getting more memory used on the system. But now do we have enough vmemmap range to support this enlarged linear mapping ?

Yes.

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#11 lore raw

PATCH v2 3/4 arm64: mm: make vmemmap region a projection of the linear region

In reply to Ard Biesheuvel

Now that we have reverted the introduction of the vmemmap struct page pointer and the separate physvirt_offset, we can simplify things further, and place the vmemmap region in the VA space in such a way that virtual to page translations and vice versa can be implemented using a single arithmetic shift.

One happy coincidence resulting from this is that the 48-bit/4k and 52-bit/64k configurations (which are assumed to be the two most prevalent) end up with the same placement of the vmemmap region. In a subsequent patch, we will take advantage of this, and unify the memory maps even more.

---
 Documentation/arm64/memory.rst  | 30 ++++++++++----------
 arch/arm64/include/asm/memory.h | 14 ++++-----
 arch/arm64/mm/init.c            |  2 ++
 3 files changed, 23 insertions(+), 23 deletions(-)
Documentation/arm64/memory.rst +15 -15
index ee51eb66a578..476edb6015b2 100644
@@ -35,14 +35,14 @@ AArch64 Linux memory layout with 4KB pages + 4 levels (48-bit)::
 [ 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]
-  fffffdfffec00000	fffffdffffbfffff	  16MB		PCI I/O space
-  fffffdffffc00000	fffffdffffdfffff	   2MB		[guard region]
-  fffffdffffe00000	ffffffffffdfffff	   2TB		vmemmap
-  ffffffffffe00000	ffffffffffffffff	   2MB		[guard region]
+  ffff800010000000	fffffbffbffeffff	 123TB		vmalloc
+  fffffbffbfff0000	fffffbfffe7f8fff	~998MB		[guard region]
+  fffffbfffe7f9000	fffffbfffebfffff	4124KB		fixed mappings
+  fffffbfffec00000	fffffbfffedfffff	   2MB		[guard region]
+  fffffbfffee00000	fffffbffffdfffff	  16MB		PCI I/O space
+  fffffbffffe00000	fffffbffffffffff	   2MB		[guard region]
+  fffffc0000000000	fffffdffffffffff	   2TB		vmemmap
+  fffffe0000000000	ffffffffffffffff	   2TB		[guard region]
 
 
 AArch64 Linux memory layout with 64KB pages + 3 levels (52-bit with HW support)::
@@ -55,13 +55,13 @@ AArch64 Linux memory layout with 64KB pages + 3 levels (52-bit with HW support):
   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]
-  fffffc1ffec00000	fffffc1fffbfffff	  16MB		PCI I/O space
-  fffffc1fffc00000	fffffc1fffdfffff	   2MB		[guard region]
-  fffffc1fffe00000	ffffffffffdfffff	3968GB		vmemmap
-  ffffffffffe00000	ffffffffffffffff	   2MB		[guard region]
+  fffff81fffff0000	fffffbfffe38ffff	  ~3TB		[guard region]
+  fffffbfffe390000	fffffbfffebfffff	4544KB		fixed mappings
+  fffffbfffec00000	fffffbfffedfffff	   2MB		[guard region]
+  fffffbfffee00000	fffffbffffdfffff	  16MB		PCI I/O space
+  fffffbffffe00000	fffffbffffffffff	   2MB		[guard region]
+  fffffc0000000000	ffffffdfffffffff	  ~4TB		vmemmap
+  ffffffe000000000	ffffffffffffffff	 128GB		[guard region]
 
 
 Translation table lookup with 4KB pages::
arch/arm64/include/asm/memory.h +6 -8
index 58932f434433..39ea35f7e34e 100644
@@ -30,8 +30,8 @@
  * keep a constant PAGE_OFFSET and "fallback" to using the higher end
  * of the VMEMMAP where 52-bit support is not available in hardware.
  */
-#define VMEMMAP_SIZE ((_PAGE_END(VA_BITS_MIN) - PAGE_OFFSET) \
-			>> (PAGE_SHIFT - STRUCT_PAGE_MAX_SHIFT))
+#define VMEMMAP_SHIFT	(PAGE_SHIFT - STRUCT_PAGE_MAX_SHIFT)
+#define VMEMMAP_SIZE	((_PAGE_END(VA_BITS_MIN) - PAGE_OFFSET) >> VMEMMAP_SHIFT)
 
 /*
  * PAGE_OFFSET - the virtual address of the start of the linear map, at the
@@ -50,7 +50,7 @@
 #define MODULES_END		(MODULES_VADDR + MODULES_VSIZE)
 #define MODULES_VADDR		(BPF_JIT_REGION_END)
 #define MODULES_VSIZE		(SZ_128M)
-#define VMEMMAP_START		(-VMEMMAP_SIZE - SZ_2M)
+#define VMEMMAP_START		(-(UL(1) << (VA_BITS - VMEMMAP_SHIFT)))
 #define VMEMMAP_END		(VMEMMAP_START + VMEMMAP_SIZE)
 #define PCI_IO_END		(VMEMMAP_START - SZ_2M)
 #define PCI_IO_START		(PCI_IO_END - PCI_IO_SIZE)
@@ -303,15 +303,13 @@ static inline void *phys_to_virt(phys_addr_t x)
 #else
 #define page_to_virt(x)	({						\
 	__typeof__(x) __page = x;					\
-	u64 __idx = ((u64)__page - VMEMMAP_START) / sizeof(struct page);\
-	u64 __addr = PAGE_OFFSET + (__idx * PAGE_SIZE);			\
+	u64 __addr = (u64)__page << VMEMMAP_SHIFT;			\
 	(void *)__tag_set((const void *)__addr, page_kasan_tag(__page));\
 })
 
 #define virt_to_page(x)	({						\
-	u64 __idx = (__tag_reset((u64)x) - PAGE_OFFSET) / PAGE_SIZE;	\
-	u64 __addr = VMEMMAP_START + (__idx * sizeof(struct page));	\
-	(struct page *)__addr;						\
+	u64 __addr = __tag_reset((u64)(x)) & PAGE_MASK;			\
+	(struct page *)((s64)__addr >> VMEMMAP_SHIFT);			\
 })
 #endif /* !CONFIG_SPARSEMEM_VMEMMAP || CONFIG_DEBUG_VIRTUAL */
 
arch/arm64/mm/init.c +2 -0
index 9090779dd3cd..f0599ae73b8d 100644
@@ -504,6 +504,8 @@ static void __init free_unused_memmap(void)
  */
 void __init mem_init(void)
 {
+	BUILD_BUG_ON(!is_power_of_2(sizeof(struct page)));
+
 	if (swiotlb_force == SWIOTLB_FORCE ||
 	    max_pfn > PFN_DOWN(arm64_dma_phys_limit ? : arm64_dma32_phys_limit))
 		swiotlb_init(1);
Signature · 7 lines
2.17.1


_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Reviewed-by on v2 3/4
#12 lore raw

Re: [PATCH v2 3/4] arm64: mm: make vmemmap region a projection of the linear region

Quoted 6 lines · Ard Biesheuvel

Now that we have reverted the introduction of the vmemmap struct page pointer and the separate physvirt_offset, we can simplify things further, and place the vmemmap region in the VA space in such a way that virtual to page translations and vice versa can be implemented using a single arithmetic shift.

Quoted 7 lines

One happy coincidence resulting from this is that the 48-bit/4k and 52-bit/64k configurations (which are assumed to be the two most prevalent) end up with the same placement of the vmemmap region. In a subsequent patch, we will take advantage of this, and unify the memory maps even more.

Cheers,
--
Steve

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#13 lore raw

Re: [PATCH v2 3/4] arm64: mm: make vmemmap region a projection of the linear region

In reply to Ard Biesheuvel

Hi Ard,

Quoted 6 lines · Ard Biesheuvel

Now that we have reverted the introduction of the vmemmap struct page pointer and the separate physvirt_offset, we can simplify things further, and place the vmemmap region in the VA space in such a way that virtual to page translations and vice versa can be implemented using a single arithmetic shift.

Quoted 7 lines

One happy coincidence resulting from this is that the 48-bit/4k and 52-bit/64k configurations (which are assumed to be the two most prevalent) end up with the same placement of the vmemmap region. In a subsequent patch, we will take advantage of this, and unify the memory maps even more.

This is now commit 8c96400d6a39be76 ("arm64: mm: make vmemmap region a projection of the linear region") in arm64/for-next/core.

arch/arm64/mm/init.c static void __init free_unused_memmap(void) · line 507

Quoted 7 lines
arch/arm64/mm/init.c +1 -0
@@ -504,6 +504,8 @@ static void __init free_unused_memmap(void)
  */
 void __init mem_init(void)
 {
+       BUILD_BUG_ON(!is_power_of_2(sizeof(struct page)));

This check is triggering for me.

If CONFIG_MEMCG=n, sizeof(struct page) = 56.

If CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y, this is mitigated by the explicit alignment:

    #ifdef CONFIG_HAVE_ALIGNED_STRUCT_PAGE
    #define _struct_page_alignment  __aligned(2 * sizeof(unsigned long))
    #else
    #define _struct_page_alignment
    #endif

    struct page { ... } _struct_page_alignment;

However, HAVE_ALIGNED_STRUCT_PAGE is selected only if SLUB, while my .config is using SLAB.

Gr{oetje,eeting}s,

Geert

Signature · 10 lines
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
#14 lore raw

Re: [PATCH v2 3/4] arm64: mm: make vmemmap region a projection of the linear region

Quoted 44 lines · Geert Uytterhoeven

Hi Ard,

Quoted 6 lines · Ard Biesheuvel

Now that we have reverted the introduction of the vmemmap struct page pointer and the separate physvirt_offset, we can simplify things further, and place the vmemmap region in the VA space in such a way that virtual to page translations and vice versa can be implemented using a single arithmetic shift.

Quoted 7 lines

One happy coincidence resulting from this is that the 48-bit/4k and 52-bit/64k configurations (which are assumed to be the two most prevalent) end up with the same placement of the vmemmap region. In a subsequent patch, we will take advantage of this, and unify the memory maps even more.

This is now commit 8c96400d6a39be76 ("arm64: mm: make vmemmap region a projection of the linear region") in arm64/for-next/core.

arch/arm64/mm/init.c static void __init free_unused_memmap(void) · line 507

Quoted 7 lines
arch/arm64/mm/init.c +1 -0
@@ -504,6 +504,8 @@ static void __init free_unused_memmap(void)
  */
 void __init mem_init(void)
 {
+       BUILD_BUG_ON(!is_power_of_2(sizeof(struct page)));

This check is triggering for me.

If CONFIG_MEMCG=n, sizeof(struct page) = 56.

If CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y, this is mitigated by the explicit alignment:

    #ifdef CONFIG_HAVE_ALIGNED_STRUCT_PAGE
    #define _struct_page_alignment  __aligned(2 * sizeof(unsigned long))
    #else
    #define _struct_page_alignment
    #endif

    struct page { ... } _struct_page_alignment;
Quoted 3 lines

However, HAVE_ALIGNED_STRUCT_PAGE is selected only if SLUB, while my .config is using SLAB.

Thanks for the report. I will look into this.

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#15 lore raw

Re: [PATCH v2 3/4] arm64: mm: make vmemmap region a projection of the linear region

Quoted 44 lines · Ard Biesheuvel
Quoted 42 lines · Geert Uytterhoeven

Hi Ard,

Quoted 6 lines · Ard Biesheuvel

Now that we have reverted the introduction of the vmemmap struct page pointer and the separate physvirt_offset, we can simplify things further, and place the vmemmap region in the VA space in such a way that virtual to page translations and vice versa can be implemented using a single arithmetic shift.

Quoted 7 lines

One happy coincidence resulting from this is that the 48-bit/4k and 52-bit/64k configurations (which are assumed to be the two most prevalent) end up with the same placement of the vmemmap region. In a subsequent patch, we will take advantage of this, and unify the memory maps even more.

This is now commit 8c96400d6a39be76 ("arm64: mm: make vmemmap region a projection of the linear region") in arm64/for-next/core.

arch/arm64/mm/init.c static void __init free_unused_memmap(void) · line 507

Quoted 7 lines
arch/arm64/mm/init.c +1 -0
@@ -504,6 +504,8 @@ static void __init free_unused_memmap(void)
  */
 void __init mem_init(void)
 {
+       BUILD_BUG_ON(!is_power_of_2(sizeof(struct page)));

This check is triggering for me.

If CONFIG_MEMCG=n, sizeof(struct page) = 56.

If CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y, this is mitigated by the explicit alignment:

    #ifdef CONFIG_HAVE_ALIGNED_STRUCT_PAGE
    #define _struct_page_alignment  __aligned(2 * sizeof(unsigned long))
    #else
    #define _struct_page_alignment
    #endif
Quoted 7 lines
Quoted 5 lines
    struct page { ... } _struct_page_alignment;

However, HAVE_ALIGNED_STRUCT_PAGE is selected only if SLUB, while my .config is using SLAB.

Thanks for the report. I will look into this.

OK, so we can obviously fix this easily by setting CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y unconditionally instead of only 'if SLUB'. The question is whether that is likely to lead to any performance regressions.

So first of all, having a smaller struct page means we can fit more of them into memory. On a 4k pages config with SPARSEMEM_VMEMMAP enabled (which allocates struct pages in 2M blocks), every 2M block can cover 146 MB of DRAM instead of 128 MB. I'm not sure what kind of DRAM arrangement would be needed to take advantage of this in practice, though.

Another aspect is D-cache utilization: cache lines are typically 64 bytes on arm64, and while we can improve Dcache utilization in theory (by virtue of the smaller size), the random access nature of struct pages may well result in the opposite, given that 3 out of 4 struct pages now straddle two cachelines.

Given the above, and given the purpose of this patch series, which was to tidy up and unify different configurations, in order to reduce the size of the validation matrix, I think it would be reasonable to simply set CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y for arm64 in all cases.

Signature · 6 lines
Ard.

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
#16 lore raw

Re: [PATCH v2 3/4] arm64: mm: make vmemmap region a projection of the linear region

Hi Ard,

Quoted 54 lines · Ard Biesheuvel
Quoted 40 lines · Ard Biesheuvel
Quoted 39 lines · Geert Uytterhoeven
Quoted 6 lines · Ard Biesheuvel

Now that we have reverted the introduction of the vmemmap struct page pointer and the separate physvirt_offset, we can simplify things further, and place the vmemmap region in the VA space in such a way that virtual to page translations and vice versa can be implemented using a single arithmetic shift.

Quoted 7 lines

One happy coincidence resulting from this is that the 48-bit/4k and 52-bit/64k configurations (which are assumed to be the two most prevalent) end up with the same placement of the vmemmap region. In a subsequent patch, we will take advantage of this, and unify the memory maps even more.

This is now commit 8c96400d6a39be76 ("arm64: mm: make vmemmap region a projection of the linear region") in arm64/for-next/core.

arch/arm64/mm/init.c static void __init free_unused_memmap(void) · line 507

Quoted 7 lines
arch/arm64/mm/init.c +1 -0
@@ -504,6 +504,8 @@ static void __init free_unused_memmap(void)
  */
 void __init mem_init(void)
 {
+       BUILD_BUG_ON(!is_power_of_2(sizeof(struct page)));

This check is triggering for me.

If CONFIG_MEMCG=n, sizeof(struct page) = 56.

If CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y, this is mitigated by the explicit alignment:

    #ifdef CONFIG_HAVE_ALIGNED_STRUCT_PAGE
    #define _struct_page_alignment  __aligned(2 * sizeof(unsigned long))
    #else
    #define _struct_page_alignment
    #endif
Quoted 7 lines
Quoted 5 lines
    struct page { ... } _struct_page_alignment;

However, HAVE_ALIGNED_STRUCT_PAGE is selected only if SLUB, while my .config is using SLAB.

Thanks for the report. I will look into this.

OK, so we can obviously fix this easily by setting CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y unconditionally instead of only 'if SLUB'. The question is whether that is likely to lead to any performance regressions.

Quoted 6 lines

So first of all, having a smaller struct page means we can fit more of them into memory. On a 4k pages config with SPARSEMEM_VMEMMAP enabled (which allocates struct pages in 2M blocks), every 2M block can cover 146 MB of DRAM instead of 128 MB. I'm not sure what kind of DRAM arrangement would be needed to take advantage of this in practice, though.

So this starts making a difference only for systems with more than 1 GiB RAM, where we can probably afford losing 2 MiB.

Quoted 10 lines

Another aspect is D-cache utilization: cache lines are typically 64 bytes on arm64, and while we can improve Dcache utilization in theory (by virtue of the smaller size), the random access nature of struct pages may well result in the opposite, given that 3 out of 4 struct pages now straddle two cachelines.

Given the above, and given the purpose of this patch series, which was to tidy up and unify different configurations, in order to reduce the size of the validation matrix, I think it would be reasonable to simply set CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y for arm64 in all cases.

Thanks, sounds reasonable to me.

Gr{oetje,eeting}s,

Geert

Signature · 10 lines
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
maintainer
#17 lore raw

Re: [PATCH v2 3/4] arm64: mm: make vmemmap region a projection of the linear region

In reply to Ard Biesheuvel
Quoted 47 lines · Ard Biesheuvel
Quoted 46 lines · Ard Biesheuvel
Quoted 44 lines · Geert Uytterhoeven
Quoted 6 lines · Ard Biesheuvel

Now that we have reverted the introduction of the vmemmap struct page pointer and the separate physvirt_offset, we can simplify things further, and place the vmemmap region in the VA space in such a way that virtual to page translations and vice versa can be implemented using a single arithmetic shift.

Quoted 7 lines

One happy coincidence resulting from this is that the 48-bit/4k and 52-bit/64k configurations (which are assumed to be the two most prevalent) end up with the same placement of the vmemmap region. In a subsequent patch, we will take advantage of this, and unify the memory maps even more.

This is now commit 8c96400d6a39be76 ("arm64: mm: make vmemmap region a projection of the linear region") in arm64/for-next/core.

arch/arm64/mm/init.c static void __init free_unused_memmap(void) · line 507

Quoted 7 lines
arch/arm64/mm/init.c +1 -0
@@ -504,6 +504,8 @@ static void __init free_unused_memmap(void)
  */
 void __init mem_init(void)
 {
+       BUILD_BUG_ON(!is_power_of_2(sizeof(struct page)));

This check is triggering for me.

If CONFIG_MEMCG=n, sizeof(struct page) = 56.

If CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y, this is mitigated by the explicit alignment:

    #ifdef CONFIG_HAVE_ALIGNED_STRUCT_PAGE
    #define _struct_page_alignment  __aligned(2 * sizeof(unsigned long))
    #else
    #define _struct_page_alignment
    #endif

    struct page { ... } _struct_page_alignment;

However, HAVE_ALIGNED_STRUCT_PAGE is selected only if SLUB, while my .config is using SLAB.

Quoted 6 lines
Quoted 1 line

Thanks for the report. I will look into this.

OK, so we can obviously fix this easily by setting CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y unconditionally instead of only 'if SLUB'. The question is whether that is likely to lead to any performance regressions.

I'm not sure I understand. The mem_init() bug triggers if sizeof(struct page) is not a power of 2. HAVE_ALIGNED_STRUCT_PAGE forces the page alignment to 16 bytes but, for example, a 48-byte structure is not a power of 2.

Signature · 6 lines
Catalin

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
#18 lore raw

Re: [PATCH v2 3/4] arm64: mm: make vmemmap region a projection of the linear region

Quoted 56 lines · Catalin Marinas
Quoted 47 lines · Ard Biesheuvel
Quoted 46 lines · Ard Biesheuvel
Quoted 44 lines · Geert Uytterhoeven
Quoted 6 lines · Ard Biesheuvel

Now that we have reverted the introduction of the vmemmap struct page pointer and the separate physvirt_offset, we can simplify things further, and place the vmemmap region in the VA space in such a way that virtual to page translations and vice versa can be implemented using a single arithmetic shift.

Quoted 7 lines

One happy coincidence resulting from this is that the 48-bit/4k and 52-bit/64k configurations (which are assumed to be the two most prevalent) end up with the same placement of the vmemmap region. In a subsequent patch, we will take advantage of this, and unify the memory maps even more.

This is now commit 8c96400d6a39be76 ("arm64: mm: make vmemmap region a projection of the linear region") in arm64/for-next/core.

arch/arm64/mm/init.c static void __init free_unused_memmap(void) · line 507

Quoted 7 lines
arch/arm64/mm/init.c +1 -0
@@ -504,6 +504,8 @@ static void __init free_unused_memmap(void)
  */
 void __init mem_init(void)
 {
+       BUILD_BUG_ON(!is_power_of_2(sizeof(struct page)));

This check is triggering for me.

If CONFIG_MEMCG=n, sizeof(struct page) = 56.

If CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y, this is mitigated by the explicit alignment:

    #ifdef CONFIG_HAVE_ALIGNED_STRUCT_PAGE
    #define _struct_page_alignment  __aligned(2 * sizeof(unsigned long))
    #else
    #define _struct_page_alignment
    #endif

    struct page { ... } _struct_page_alignment;

However, HAVE_ALIGNED_STRUCT_PAGE is selected only if SLUB, while my .config is using SLAB.

Quoted 6 lines
Quoted 1 line

Thanks for the report. I will look into this.

OK, so we can obviously fix this easily by setting CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y unconditionally instead of only 'if SLUB'. The question is whether that is likely to lead to any performance regressions.

Quoted 5 lines

I'm not sure I understand. The mem_init() bug triggers if sizeof(struct page) is not a power of 2. HAVE_ALIGNED_STRUCT_PAGE forces the page alignment to 16 bytes but, for example, a 48-byte structure is not a power of 2.

True, but looking at include/linux/mm_types.h, I don't see how that would happen.

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

maintainer
#19 lore raw

Re: [PATCH v2 3/4] arm64: mm: make vmemmap region a projection of the linear region

Quoted 39 lines · Ard Biesheuvel
Quoted 38 lines · Catalin Marinas
Quoted 36 lines · Ard Biesheuvel
Quoted 23 lines · Ard Biesheuvel
Quoted 22 lines · Geert Uytterhoeven

arch/arm64/mm/init.c static void __init free_unused_memmap(void) · line 507

Quoted 7 lines · Ard Biesheuvel
arch/arm64/mm/init.c +1 -0
@@ -504,6 +504,8 @@ static void __init free_unused_memmap(void)
  */
 void __init mem_init(void)
 {
+       BUILD_BUG_ON(!is_power_of_2(sizeof(struct page)));

This check is triggering for me.

If CONFIG_MEMCG=n, sizeof(struct page) = 56.

If CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y, this is mitigated by the explicit alignment:

    #ifdef CONFIG_HAVE_ALIGNED_STRUCT_PAGE
    #define _struct_page_alignment  __aligned(2 * sizeof(unsigned long))
    #else
    #define _struct_page_alignment
    #endif
Quoted 7 lines
Quoted 5 lines
    struct page { ... } _struct_page_alignment;

However, HAVE_ALIGNED_STRUCT_PAGE is selected only if SLUB, while my .config is using SLAB.

Thanks for the report. I will look into this.

OK, so we can obviously fix this easily by setting CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y unconditionally instead of only 'if SLUB'. The question is whether that is likely to lead to any performance regressions.

Quoted 7 lines
Quoted 4 lines

I'm not sure I understand. The mem_init() bug triggers if sizeof(struct page) is not a power of 2. HAVE_ALIGNED_STRUCT_PAGE forces the page alignment to 16 bytes but, for example, a 48-byte structure is not a power of 2.

True, but looking at include/linux/mm_types.h, I don't see how that would happen.

Not with 48 and probably won't ever go beyond 64 for "production" builds. But say someone wants to experiment with some debug data in struct page and adds a long. The structure (I think 64 now with MEMCG=y) becomes 72, force-aligned to 80. That triggers the build-bug.

Anyway, I don't mind the forced alignment, only that the build-bug you added has a different requirement than what HAVE_ALIGNED_STRUCT_PAGE provides (power of 2 vs 16-byte aligned).

AFAICT, VMEMMAP_START is a compile-time value, PAGE_OFFSET is also compile-time, so can we not revert to the original virt_to_page and page_to_virt macros? They'd not be as efficient but it may not matter much (and if the struct size is a power of 2, the compiler should change the division/multiplication by shifts).

Signature · 6 lines
Catalin

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
#20 lore raw

Re: [PATCH v2 3/4] arm64: mm: make vmemmap region a projection of the linear region

Quoted 58 lines · Catalin Marinas
Quoted 39 lines · Ard Biesheuvel
Quoted 38 lines · Catalin Marinas
Quoted 36 lines · Ard Biesheuvel
Quoted 23 lines · Ard Biesheuvel
Quoted 22 lines · Geert Uytterhoeven

arch/arm64/mm/init.c static void __init free_unused_memmap(void) · line 507

Quoted 7 lines · Ard Biesheuvel
arch/arm64/mm/init.c +1 -0
@@ -504,6 +504,8 @@ static void __init free_unused_memmap(void)
  */
 void __init mem_init(void)
 {
+       BUILD_BUG_ON(!is_power_of_2(sizeof(struct page)));

This check is triggering for me.

If CONFIG_MEMCG=n, sizeof(struct page) = 56.

If CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y, this is mitigated by the explicit alignment:

    #ifdef CONFIG_HAVE_ALIGNED_STRUCT_PAGE
    #define _struct_page_alignment  __aligned(2 * sizeof(unsigned long))
    #else
    #define _struct_page_alignment
    #endif
Quoted 7 lines
Quoted 5 lines
    struct page { ... } _struct_page_alignment;

However, HAVE_ALIGNED_STRUCT_PAGE is selected only if SLUB, while my .config is using SLAB.

Thanks for the report. I will look into this.

OK, so we can obviously fix this easily by setting CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y unconditionally instead of only 'if SLUB'. The question is whether that is likely to lead to any performance regressions.

Quoted 7 lines
Quoted 4 lines

I'm not sure I understand. The mem_init() bug triggers if sizeof(struct page) is not a power of 2. HAVE_ALIGNED_STRUCT_PAGE forces the page alignment to 16 bytes but, for example, a 48-byte structure is not a power of 2.

True, but looking at include/linux/mm_types.h, I don't see how that would happen.

Not with 48 and probably won't ever go beyond 64 for "production" builds. But say someone wants to experiment with some debug data in struct page and adds a long. The structure (I think 64 now with MEMCG=y) becomes 72, force-aligned to 80. That triggers the build-bug.

Anyway, I don't mind the forced alignment, only that the build-bug you added has a different requirement than what HAVE_ALIGNED_STRUCT_PAGE provides (power of 2 vs 16-byte aligned).

Quoted 6 lines

AFAICT, VMEMMAP_START is a compile-time value, PAGE_OFFSET is also compile-time, so can we not revert to the original virt_to_page and page_to_virt macros? They'd not be as efficient but it may not matter much (and if the struct size is a power of 2, the compiler should change the division/multiplication by shifts).

Works for me. I'll go and code that up.

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#21 lore raw

PATCH v2 4/4 arm64: mm: tidy up top of kernel VA space

In reply to Ard Biesheuvel

Tidy up the way the top of the kernel VA space is organized, by mirroring the 256 MB region we have below the vmalloc space, and populating it top down with the PCI I/O space, some guard regions, and the fixmap region. The latter region is itself populated top down, and today only covers about 4 MB, and so 224 MB is ample, and no guard region is therefore required.

The resulting layout is identical between 48-bit/4k and 52-bit/64k configurations.

---
 Documentation/arm64/memory.rst   | 22 +++++++++-----------
 arch/arm64/include/asm/memory.h  |  4 ++--
 arch/arm64/include/asm/pgtable.h |  2 +-
 3 files changed, 13 insertions(+), 15 deletions(-)
Documentation/arm64/memory.rst +10 -12
index 476edb6015b2..f4d24753e0e7 100644
@@ -35,12 +35,11 @@ AArch64 Linux memory layout with 4KB pages + 4 levels (48-bit)::
 [ ffff600000000000	ffff7fffffffffff ]	  32TB		[ kasan shadow region ]
   ffff800000000000	ffff800007ffffff	 128MB		bpf jit region
   ffff800008000000	ffff80000fffffff	 128MB		modules
-  ffff800010000000	fffffbffbffeffff	 123TB		vmalloc
-  fffffbffbfff0000	fffffbfffe7f8fff	~998MB		[guard region]
-  fffffbfffe7f9000	fffffbfffebfffff	4124KB		fixed mappings
-  fffffbfffec00000	fffffbfffedfffff	   2MB		[guard region]
-  fffffbfffee00000	fffffbffffdfffff	  16MB		PCI I/O space
-  fffffbffffe00000	fffffbffffffffff	   2MB		[guard region]
+  ffff800010000000	fffffbffefffffff	 124TB		vmalloc
+  fffffbfff0000000	fffffbfffdffffff	 224MB		fixed mappings (top down)
+  fffffbfffe000000	fffffbfffe7fffff	   8MB		[guard region]
+  fffffbfffe800000	fffffbffff7fffff	  16MB		PCI I/O space
+  fffffbffff800000	fffffbffffffffff	   8MB		[guard region]
   fffffc0000000000	fffffdffffffffff	   2TB		vmemmap
   fffffe0000000000	ffffffffffffffff	   2TB		[guard region]
 
@@ -54,12 +53,11 @@ AArch64 Linux memory layout with 64KB pages + 3 levels (52-bit with HW support):
 [ fffd800000000000	ffff7fffffffffff ]	 512TB		[ kasan shadow region ]
   ffff800000000000	ffff800007ffffff	 128MB		bpf jit region
   ffff800008000000	ffff80000fffffff	 128MB		modules
-  ffff800010000000	fffff81ffffeffff	 120TB		vmalloc
-  fffff81fffff0000	fffffbfffe38ffff	  ~3TB		[guard region]
-  fffffbfffe390000	fffffbfffebfffff	4544KB		fixed mappings
-  fffffbfffec00000	fffffbfffedfffff	   2MB		[guard region]
-  fffffbfffee00000	fffffbffffdfffff	  16MB		PCI I/O space
-  fffffbffffe00000	fffffbffffffffff	   2MB		[guard region]
+  ffff800010000000	fffffbffefffffff	 124TB		vmalloc
+  fffffbfff0000000	fffffbfffdffffff	 224MB		fixed mappings (top down)
+  fffffbfffe000000	fffffbfffe7fffff	   8MB		[guard region]
+  fffffbfffe800000	fffffbffff7fffff	  16MB		PCI I/O space
+  fffffbffff800000	fffffbffffffffff	   8MB		[guard region]
   fffffc0000000000	ffffffdfffffffff	  ~4TB		vmemmap
   ffffffe000000000	ffffffffffffffff	 128GB		[guard region]
 
arch/arm64/include/asm/memory.h +2 -2
index 39ea35f7e34e..3a32bc9136eb 100644
@@ -52,9 +52,9 @@
 #define MODULES_VSIZE		(SZ_128M)
 #define VMEMMAP_START		(-(UL(1) << (VA_BITS - VMEMMAP_SHIFT)))
 #define VMEMMAP_END		(VMEMMAP_START + VMEMMAP_SIZE)
-#define PCI_IO_END		(VMEMMAP_START - SZ_2M)
+#define PCI_IO_END		(VMEMMAP_START - SZ_8M)
 #define PCI_IO_START		(PCI_IO_END - PCI_IO_SIZE)
-#define FIXADDR_TOP		(PCI_IO_START - SZ_2M)
+#define FIXADDR_TOP		(VMEMMAP_START - SZ_32M)
 
 #if VA_BITS > 48
 #define VA_BITS_MIN		(48)
arch/arm64/include/asm/pgtable.h +1 -1
index 88233d42d9c2..5a3bf92c85e7 100644
@@ -21,7 +21,7 @@
  *	and fixed mappings
  */
 #define VMALLOC_START		(MODULES_END)
-#define VMALLOC_END		(- PUD_SIZE - VMEMMAP_SIZE - SZ_64K)
+#define VMALLOC_END		(VMEMMAP_START - SZ_256M)
 
 #define vmemmap			((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT))
 
Signature · 7 lines
2.17.1


_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Reviewed-by on v2 4/4
#22 lore raw

Re: [PATCH v2 4/4] arm64: mm: tidy up top of kernel VA space

Quoted 9 lines · Ard Biesheuvel

Tidy up the way the top of the kernel VA space is organized, by mirroring the 256 MB region we have below the vmalloc space, and populating it top down with the PCI I/O space, some guard regions, and the fixmap region. The latter region is itself populated top down, and today only covers about 4 MB, and so 224 MB is ample, and no guard region is therefore required.

The resulting layout is identical between 48-bit/4k and 52-bit/64k configurations.

Nice! :-)

Quoted 2 lines

Cheers,
--
Steve

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#23 lore raw
In reply to Ard Biesheuvel
Quoted 14 lines · Ard Biesheuvel

This series reorganizes the kernel VA space slightly so that 52-bit VA configurations can use more virtual address space, i.e., the usable linear address space almost doubles, from 2^51 to 2^52-2^47.

Patch #1 merges the physvirt_offset and memstart_addr variables, both of which represent translations between the physical address space and the linear region, and there is no need for having both. This fixes a bug too, as the two values were not properly kept in sync when booting with KASLR enabled.

Patch #2 updates the definitions for the boundaries of the linear space, so that 52-bit VA builds use all available space for the linear region.

Quoted 9 lines

Patches #3 and #4 simplify the way the vmemmap region is configured, and unify the 48-bit/4k and 52-bit/64k layouts.

Changes since v1:
- drop incorrect use of untagged_addr() from #2
- add patches #3 and #4

Not boot tested yet on a 52-bit VA capable system.

Boot tested now on FVP Base with and without LVA support enabled.

Quoted 17 lines
Cc Steve Capper <[email protected]>
Cc Anshuman Khandual <[email protected]>

Ard Biesheuvel (4):
arm64: mm: use single quantity to represent the PA to VA translation
arm64: mm: extend linear region for 52-bit VA configurations
arm64: mm: make vmemmap region a projection of the linear region
arm64: mm: tidy up top of kernel VA space

 Documentation/arm64/kasan-offsets.sh |  3 +-
 Documentation/arm64/memory.rst       | 45 +++++++++-----------
 arch/arm64/Kconfig                   | 20 ++++-----
 arch/arm64/include/asm/memory.h      | 35 +++++++--------
 arch/arm64/include/asm/pgtable.h     |  6 +--
 arch/arm64/mm/init.c                 | 34 ++++++---------
 6 files changed, 63 insertions(+), 80 deletions(-)
Quoted 3 lines

--
2.17.1

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

maintainer
#24 lore raw
In reply to Ard Biesheuvel
Quoted 11 lines · Ard Biesheuvel

This series reorganizes the kernel VA space slightly so that 52-bit VA configurations can use more virtual address space, i.e., the usable linear address space almost doubles, from 2^51 to 2^52-2^47.

Patch #1 merges the physvirt_offset and memstart_addr variables, both of which represent translations between the physical address space and the linear region, and there is no need for having both. This fixes a bug too, as the two values were not properly kept in sync when booting with KASLR enabled.

[...]

Applied the first patch to arm64 (for-next/core), thanks!

[1/1] arm64: mm: use single quantity to represent the PA to VA translation

      https://git.kernel.org/arm64/c/7bc1a0f9e176

Cheers,

Signature · 10 lines
Will

https://fixes.arm64.dev
https://next.arm64.dev
https://will.arm64.dev

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
maintainer Applied
#25 lore raw
In reply to Ard Biesheuvel
Quoted 11 lines · Ard Biesheuvel

This series reorganizes the kernel VA space slightly so that 52-bit VA configurations can use more virtual address space, i.e., the usable linear address space almost doubles, from 2^51 to 2^52-2^47.

Patch #1 merges the physvirt_offset and memstart_addr variables, both of which represent translations between the physical address space and the linear region, and there is no need for having both. This fixes a bug too, as the two values were not properly kept in sync when booting with KASLR enabled.

[...]

Applied to arm64 (for-next/va-refactor), thanks!

[2/4] arm64: mm: extend linear region for 52-bit VA configurations

      https://git.kernel.org/arm64/c/f4693c2716b3
[3/4] arm64: mm: make vmemmap region a projection of the linear region
      https://git.kernel.org/arm64/c/8c96400d6a39
[4/4] arm64: mm: tidy up top of kernel VA space
      https://git.kernel.org/arm64/c/9ad7c6d5e75b
Signature · 7 lines
Catalin


_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel