diff mbox series

[8/9] arm64: mm: Logic to make offset_ttbr1 conditional

Message ID 20190218170245.14915-9-steve.capper@arm.com (mailing list archive)
State New, archived
Headers show
Series 52-bit kernel + user VAs | expand

Commit Message

Steve Capper Feb. 18, 2019, 5:02 p.m. UTC
When running with a 52-bit userspace VA and a 48-bit kernel VA we offset
ttbr1_el1 to allow the kernel pagetables with a 52-bit PTRS_PER_PGD to
be used for both userspace and kernel.

Moving on to a 52-bit kernel VA we no longer require this offset to
ttbr1_el1 should we be running on a system with HW support for 52-bit
VAs.

This patch introduces alternative logic to offset_ttbr1 and expands out
the very early case in head.S. We need to use the alternative framework
as offset_ttbr1 is used in places in the kernel where it is not possible
to safely adrp address kernel constants (such as the kpti paths); thus
code patching is the safer route.

Signed-off-by: Steve Capper <steve.capper@arm.com>
---
 arch/arm64/include/asm/assembler.h | 10 +++++++++-
 arch/arm64/include/asm/cpucaps.h   |  3 ++-
 arch/arm64/kernel/cpufeature.c     | 18 ++++++++++++++++++
 arch/arm64/kernel/head.S           | 14 +++++++++++++-
 arch/arm64/kernel/hibernate-asm.S  |  1 +
 5 files changed, 43 insertions(+), 3 deletions(-)

Comments

Bhupesh Sharma April 3, 2019, 11:26 a.m. UTC | #1
Hi Steve,

On 02/18/2019 10:32 PM, Steve Capper wrote:
> When running with a 52-bit userspace VA and a 48-bit kernel VA we offset
> ttbr1_el1 to allow the kernel pagetables with a 52-bit PTRS_PER_PGD to
> be used for both userspace and kernel.
> 
> Moving on to a 52-bit kernel VA we no longer require this offset to
> ttbr1_el1 should we be running on a system with HW support for 52-bit
> VAs.
> 
> This patch introduces alternative logic to offset_ttbr1 and expands out
> the very early case in head.S. We need to use the alternative framework
> as offset_ttbr1 is used in places in the kernel where it is not possible
> to safely adrp address kernel constants (such as the kpti paths); thus
> code patching is the safer route.
> 
> Signed-off-by: Steve Capper <steve.capper@arm.com>
> ---
>   arch/arm64/include/asm/assembler.h | 10 +++++++++-
>   arch/arm64/include/asm/cpucaps.h   |  3 ++-
>   arch/arm64/kernel/cpufeature.c     | 18 ++++++++++++++++++
>   arch/arm64/kernel/head.S           | 14 +++++++++++++-
>   arch/arm64/kernel/hibernate-asm.S  |  1 +
>   5 files changed, 43 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
> index 4feb6119c3c9..58ed5d086e1e 100644
> --- a/arch/arm64/include/asm/assembler.h
> +++ b/arch/arm64/include/asm/assembler.h
> @@ -551,6 +551,14 @@ USER(\label, ic	ivau, \tmp2)			// invalidate I line PoU
>   	.macro	offset_ttbr1, ttbr
>   #ifdef CONFIG_ARM64_USER_VA_BITS_52
>   	orr	\ttbr, \ttbr, #TTBR1_BADDR_4852_OFFSET
> +#endif
> +
> +#ifdef CONFIG_ARM64_USER_KERNEL_VA_BITS_52
> +alternative_if_not ARM64_HAS_52BIT_VA
> +	orr	\ttbr, \ttbr, #TTBR1_BADDR_4852_OFFSET
> +alternative_else
> +	nop
> +alternative_endif
>   #endif
>   	.endm
>   
> @@ -560,7 +568,7 @@ USER(\label, ic	ivau, \tmp2)			// invalidate I line PoU
>    * to be nop'ed out when dealing with 52-bit kernel VAs.
>    */
>   	.macro	restore_ttbr1, ttbr
> -#ifdef CONFIG_ARM64_USER_VA_BITS_52
> +#if defined(CONFIG_ARM64_USER_VA_BITS_52) || defined(CONFIG_ARM64_KERNEL_VA_BITS_52)
>   	bic	\ttbr, \ttbr, #TTBR1_BADDR_4852_OFFSET
>   #endif
>   	.endm
> diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
> index 82e9099834ae..d71aecb6d6db 100644
> --- a/arch/arm64/include/asm/cpucaps.h
> +++ b/arch/arm64/include/asm/cpucaps.h
> @@ -60,7 +60,8 @@
>   #define ARM64_HAS_ADDRESS_AUTH_IMP_DEF		39
>   #define ARM64_HAS_GENERIC_AUTH_ARCH		40
>   #define ARM64_HAS_GENERIC_AUTH_IMP_DEF		41
> +#define ARM64_HAS_52BIT_VA			42
>   
> -#define ARM64_NCAPS				42
> +#define ARM64_NCAPS				43
>   
>   #endif /* __ASM_CPUCAPS_H */
> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index f6d84e2c92fe..2e150c564f2a 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -944,6 +944,16 @@ has_useable_cnp(const struct arm64_cpu_capabilities *entry, int scope)
>   	return has_cpuid_feature(entry, scope);
>   }
>   
> +#ifdef CONFIG_ARM64_USER_KERNEL_VA_BITS_52
> +extern u64 vabits_actual;
> +static bool __maybe_unused
> +has_52bit_kernel_va(const struct arm64_cpu_capabilities *entry, int scope)
> +{
> +	return vabits_actual == 52;
> +}
> +
> +#endif /* CONFIG_ARM64_USER_KERNEL_VA_BITS_52 */
> +
>   #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
>   static int __kpti_forced; /* 0: not forced, >0: forced on, <0: forced off */
>   
> @@ -1480,6 +1490,14 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
>   		.matches = has_cpuid_feature,
>   	},
>   #endif /* CONFIG_ARM64_PTR_AUTH */
> +#ifdef CONFIG_ARM64_USER_KERNEL_VA_BITS_52
> +	{
> +		.desc = "52-bit kernel VA",
> +		.capability = ARM64_HAS_52BIT_VA,
> +		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
> +		.matches = has_52bit_kernel_va,
> +	},
> +#endif /* CONFIG_ARM64_USER_KERNEL_VA_BITS_52 */
>   	{},
>   };

Right, so now the question is how do we export the 52-bit VA properties 
(that we select in the kernel) to user-space. There are two things to 
consider:

a). CPUs which support ARMv8.2-LVA + newer kernels which export 52-bit 
address capabilities:

- Right now, neither the cpu-feature-registers interface (see [1]) nor 
the HWCAPS interface (see [2]), provide a mechanism to export these 
properties to the user-space.

- I had shared a patch in the past for enabling atleast LVA and LPA 
extension bits to be exported via the cpu-feature-registers interface 
(See: 
http://lists.infradead.org/pipermail/kexec/2019-January/022371.html), 
but we didn't make much progress on the same.

May be Suzuki (in Cc), will have more comments on the same.

[1]. 
https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt
[2]. https://www.kernel.org/doc/Documentation/arm64/elf_hwcaps.txt

b). CPUs which do not support ARMv8.2-LVA + newer kernels which export 
52-bit address capabilities:

- Right now, for older CPUs running with kernels with 
CONFIG_ARM64_USER_KERNEL_VA_BITS_52=y, if we have:

VA_BITS = 52,
VA_BITS_ACTUAL = vabits_actual = 48,
VA_BITS_MIN = min (48, VA_BITS) = 48.

Now, we need to make user-space aware of the VA_BITS_ACTUAL value, so 
that it can process virtual addresses. Let's consider two different 
use-cases which are normally used to debug live-kernel or debug crashes 
(via kdump):

- Calculating 'vaddr_to_paddr' for a given vaddr (provided to user-space 
for e.g from /proc/kcore file).

A). An essential part of the calculation is to know if the provided 
vaddr lies in the linear map range. In kernel, we use the following 
computation to determine whether an address lies in the linear map range:

#define __is_lm_address(addr)	(!((addr) & BIT(VA_BITS_ACTUAL - 1)))

A similar check is performed in user-space utilities while performing 
live debugging to determine paddr value for a given vaddr (for 
performing a page-table walk).

So, we need a mechanism to have the VA_BITS_ACTUAL value in user-space.
Reading kernel CONFIG flags, vmlinux information and /proc/kallsyms is 
not a portable approach for all user-space use-cases, hence we need a 
standard method of exporting this information to user-space.

May be something like a 
'/sys/devices/system/cpu/addressing-capabilities' node? (similar to 
'/sys/devices/system/cpu/vulnerabilities' we added for sideband 
vulnerabilities).

I understand that it may be difficult to standardize a 'sysfs' 
placeholder for different archs for addressing ranges, but I am just 
thinking out loud here.

May be something like:

+ssize_t cpu_show_address_capabilities(struct device *dev, struct 
device_attribute *attr,
+			    char *buf)
+{
+	return sprintf(buf, "va_bits_actual: %ld\n", vabits_actual);
+}

and more..

See 
<https://github.com/torvalds/linux/blob/master/arch/x86/kernel/cpu/bugs.c#L1188> 
for an example.

B). Debugging a crash dump obtained on one arm64 system (say a 
reporter's machine with VA_BITS_ACTUAL = 48) on another arm64 system 
(say the maintainer's machine with VA_BITS_ACTUAL = 52)

So, we again need a mechanism to have the VA_BITS_ACTUAL value in crash 
vmcore dump'ed on the reporter's machine.

Note, that reading kernel CONFIG flags, vmlinux information or 
/proc/kallsyms on the maintainer's machine will not help in such cases 
as they can be different from the configuration on the reporter's machine.

In such case, it is _mandatory_ to have VA_BITS_ACTUAL information 
exported in vmcoreinfo. Also since commit 23c85094fe18 ("proc/kcore: add 
vmcoreinfo note to /proc/kcore"), we have the same information available 
in kcore.

So, it would make sense to have the following patch for exporting 
VA_BITS_ACTUAL information in vmcoreinfo. I would suggest that we have 
the same added in the re-worked version v2 of the patchset so that the 
user-space works as expected:

----------------------------x

 From 0a4f30357932bf2addd1dda66acde8c26ecd3f75 Mon Sep 17 00:00:00 2001
From: Bhupesh Sharma <bhsharma@redhat.com>
Date: Wed, 3 Apr 2019 16:27:10 +0530
Subject: [PATCH] arm64/crash_core: Export VA_BITS_ACTUAL in vmcoreinfo

VA_BITS_ACTUAL indicates the actual VA_BITS detected at boot time which
is required for determining 52-bit kernel address support at boot time.

User-space utilities like makedumpfile and crash-utility, need to
read/write this value from/to vmcoreinfo for determining if a virtual
address lies in the linear map range.

The user-space computation for determining whether an address lies in
the linear map range is the same as we have in kernel-space:

   #define __is_lm_address(addr)	(!((addr) & BIT(VA_BITS_ACTUAL - 1)))

Signed-off-by: Bhupesh Sharma <bhsharma@redhat.com>
---
  Documentation/kdump/vmcoreinfo.txt | 7 +++++++
  arch/arm64/kernel/crash_core.c     | 1 +
  2 files changed, 8 insertions(+)

diff --git a/Documentation/kdump/vmcoreinfo.txt 
b/Documentation/kdump/vmcoreinfo.txt
index bb94a4bd597a..a23ae95e3a93 100644
--- a/Documentation/kdump/vmcoreinfo.txt
+++ b/Documentation/kdump/vmcoreinfo.txt
@@ -376,6 +376,13 @@ VA_BITS
  The maximum number of bits for virtual addresses. Used to compute the
  virtual memory ranges.

+VA_BITS_ACTUAL
+--------------
+
+Indicates the actual VA_BITS detected at boot time, i.e. the maximum
+number of bits for virtual addresses. Required for determing 52-bit kernel
+address support at boot time.
+
  kimage_voffset
  --------------

diff --git a/arch/arm64/kernel/crash_core.c b/arch/arm64/kernel/crash_core.c
index ca4c3e12d8c5..1cde442ce8b2 100644
--- a/arch/arm64/kernel/crash_core.c
+++ b/arch/arm64/kernel/crash_core.c
@@ -10,6 +10,7 @@
  void arch_crash_save_vmcoreinfo(void)
  {
  	VMCOREINFO_NUMBER(VA_BITS);
+	VMCOREINFO_NUMBER(VA_BITS_ACTUAL);
  	/* Please note VMCOREINFO_NUMBER() uses "%d", not "%x" */
  	vmcoreinfo_append_str("NUMBER(kimage_voffset)=0x%llx\n",
  						kimage_voffset);
diff mbox series

Patch

diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 4feb6119c3c9..58ed5d086e1e 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -551,6 +551,14 @@  USER(\label, ic	ivau, \tmp2)			// invalidate I line PoU
 	.macro	offset_ttbr1, ttbr
 #ifdef CONFIG_ARM64_USER_VA_BITS_52
 	orr	\ttbr, \ttbr, #TTBR1_BADDR_4852_OFFSET
+#endif
+
+#ifdef CONFIG_ARM64_USER_KERNEL_VA_BITS_52
+alternative_if_not ARM64_HAS_52BIT_VA
+	orr	\ttbr, \ttbr, #TTBR1_BADDR_4852_OFFSET
+alternative_else
+	nop
+alternative_endif
 #endif
 	.endm
 
@@ -560,7 +568,7 @@  USER(\label, ic	ivau, \tmp2)			// invalidate I line PoU
  * to be nop'ed out when dealing with 52-bit kernel VAs.
  */
 	.macro	restore_ttbr1, ttbr
-#ifdef CONFIG_ARM64_USER_VA_BITS_52
+#if defined(CONFIG_ARM64_USER_VA_BITS_52) || defined(CONFIG_ARM64_KERNEL_VA_BITS_52)
 	bic	\ttbr, \ttbr, #TTBR1_BADDR_4852_OFFSET
 #endif
 	.endm
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index 82e9099834ae..d71aecb6d6db 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -60,7 +60,8 @@ 
 #define ARM64_HAS_ADDRESS_AUTH_IMP_DEF		39
 #define ARM64_HAS_GENERIC_AUTH_ARCH		40
 #define ARM64_HAS_GENERIC_AUTH_IMP_DEF		41
+#define ARM64_HAS_52BIT_VA			42
 
-#define ARM64_NCAPS				42
+#define ARM64_NCAPS				43
 
 #endif /* __ASM_CPUCAPS_H */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index f6d84e2c92fe..2e150c564f2a 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -944,6 +944,16 @@  has_useable_cnp(const struct arm64_cpu_capabilities *entry, int scope)
 	return has_cpuid_feature(entry, scope);
 }
 
+#ifdef CONFIG_ARM64_USER_KERNEL_VA_BITS_52
+extern u64 vabits_actual;
+static bool __maybe_unused
+has_52bit_kernel_va(const struct arm64_cpu_capabilities *entry, int scope)
+{
+	return vabits_actual == 52;
+}
+
+#endif /* CONFIG_ARM64_USER_KERNEL_VA_BITS_52 */
+
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
 static int __kpti_forced; /* 0: not forced, >0: forced on, <0: forced off */
 
@@ -1480,6 +1490,14 @@  static const struct arm64_cpu_capabilities arm64_features[] = {
 		.matches = has_cpuid_feature,
 	},
 #endif /* CONFIG_ARM64_PTR_AUTH */
+#ifdef CONFIG_ARM64_USER_KERNEL_VA_BITS_52
+	{
+		.desc = "52-bit kernel VA",
+		.capability = ARM64_HAS_52BIT_VA,
+		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+		.matches = has_52bit_kernel_va,
+	},
+#endif /* CONFIG_ARM64_USER_KERNEL_VA_BITS_52 */
 	{},
 };
 
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 68c391b26858..4877b82d2091 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -789,7 +789,19 @@  ENTRY(__enable_mmu)
 	phys_to_ttbr x1, x1
 	phys_to_ttbr x2, x2
 	msr	ttbr0_el1, x2			// load TTBR0
-	offset_ttbr1 x1
+
+#if defined(CONFIG_ARM64_USER_VA_BITS_52)
+	orr     x1, x1, #TTBR1_BADDR_4852_OFFSET
+#endif
+
+#if defined(CONFIG_ARM64_USER_KERNEL_VA_BITS_52)
+	ldr_l	x3, vabits_actual
+	cmp	x3, #52
+	b.eq	1f
+	orr     x1, x1, #TTBR1_BADDR_4852_OFFSET
+1:
+#endif
+
 	msr	ttbr1_el1, x1			// load TTBR1
 	isb
 	msr	sctlr_el1, x0
diff --git a/arch/arm64/kernel/hibernate-asm.S b/arch/arm64/kernel/hibernate-asm.S
index fe36d85c60bd..d32725a2b77f 100644
--- a/arch/arm64/kernel/hibernate-asm.S
+++ b/arch/arm64/kernel/hibernate-asm.S
@@ -19,6 +19,7 @@ 
 #include <linux/linkage.h>
 #include <linux/errno.h>
 
+#include <asm/alternative.h>
 #include <asm/asm-offsets.h>
 #include <asm/assembler.h>
 #include <asm/cputype.h>