Commit 0238d3c7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux

Pull arm64 updates from Will Deacon:
 "The changes are a real mixed bag this time around.

  The only scary looking one from the diffstat is the uapi change to
  asm-generic/mman-common.h, but this has been acked by Arnd and is
  actually just adding a pair of comments in an attempt to prevent
  allocation of some PROT values which tend to get used for
  arch-specific purposes. We'll be using them for Branch Target
  Identification (a CFI-like hardening feature), which is currently
  under review on the mailing list.

  New architecture features:

   - Support for Armv8.5 E0PD, which benefits KASLR in the same way as
     KPTI but without the overhead. This allows KPTI to be disabled on
     CPUs that are not affected by Meltdown, even is KASLR is enabled.

   - Initial support for the Armv8.5 RNG instructions, which claim to
     provide access to a high bandwidth, cryptographically secure
     hardware random number generator. As well as exposing these to
     userspace, we also use them as part of the KASLR seed and to seed
     the crng once all CPUs have come online.

   - Advertise a bunch of new instructions to userspace, including
     support for Data Gathering Hint, Matrix Multiply and 16-bit
     floating point.

  Kexec:

   - Cleanups in preparation for relocating with the MMU enabled

   - Support for loading crash dump kernels with kexec_file_load()

  Perf and PMU drivers:

   - Cleanups and non-critical fixes for a couple of system PMU drivers

  FPU-less (aka broken) CPU support:

   - Considerable fixes to support CPUs without the FP/SIMD extensions,
     including their presence in heterogeneous systems. Good luck
     finding a 64-bit userspace that handles this.

  Modern assembly function annotations:

   - Start migrating our use of ENTRY() and ENDPROC() over to the
     new-fangled SYM_{CODE,FUNC}_{START,END} macros, which are intended
     to aid debuggers

  Kbuild:

   - Cleanup detection of LSE support in the assembler by introducing
     'as-instr'

   - Remove compressed Image files when building clean targets

  IP checksumming:

   - Implement optimised IPv4 checksumming routine when hardware offload
     is not in use. An IPv6 version is in the works, pending testing.

  Hardware errata:

   - Work around Cortex-A55 erratum #1530923

  Shadow call stack:

   - Work around some issues with Clang's integrated assembler not
     liking our perfectly reasonable assembly code

   - Avoid allocating the X18 register, so that it can be used to hold
     the shadow call stack pointer in future

  ACPI:

   - Fix ID count checking in IORT code. This may regress broken
     firmware that happened to work with the old implementation, in
     which case we'll have to revert it and try something else

   - Fix DAIF corruption on return from GHES handler with pseudo-NMIs

  Miscellaneous:

   - Whitelist some CPUs that are unaffected by Spectre-v2

   - Reduce frequency of ASID rollover when KPTI is compiled in but
     inactive

   - Reserve a couple of arch-specific PROT flags that are already used
     by Sparc and PowerPC and are planned for later use with BTI on
     arm64

   - Preparatory cleanup of our entry assembly code in preparation for
     moving more of it into C later on

   - Refactoring and cleanup"

* tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: (73 commits)
  arm64: acpi: fix DAIF manipulation with pNMI
  arm64: kconfig: Fix alignment of E0PD help text
  arm64: Use v8.5-RNG entropy for KASLR seed
  arm64: Implement archrandom.h for ARMv8.5-RNG
  arm64: kbuild: remove compressed images on 'make ARCH=arm64 (dist)clean'
  arm64: entry: Avoid empty alternatives entries
  arm64: Kconfig: select HAVE_FUTEX_CMPXCHG
  arm64: csum: Fix pathological zero-length calls
  arm64: entry: cleanup sp_el0 manipulation
  arm64: entry: cleanup el0 svc handler naming
  arm64: entry: mark all entry code as notrace
  arm64: assembler: remove smp_dmb macro
  arm64: assembler: remove inherit_daif macro
  ACPI/IORT: Fix 'Number of IDs' handling in iort_id_map()
  mm: Reserve asm-generic prot flags 0x10 and 0x20 for arch use
  arm64: Use macros instead of hard-coded constants for MAIR_EL1
  arm64: Add KRYO{3,4}XX CPU cores to spectre-v2 safe list
  arm64: kernel: avoid x18 in __cpu_soft_restart
  arm64: kvm: stop treating register x18 as caller save
  arm64/lib: copy_page: avoid x18 register in assembler code
  ...
parents d5226fa6 e533dbe9
...@@ -117,6 +117,8 @@ infrastructure: ...@@ -117,6 +117,8 @@ infrastructure:
+------------------------------+---------+---------+ +------------------------------+---------+---------+
| Name | bits | visible | | Name | bits | visible |
+------------------------------+---------+---------+ +------------------------------+---------+---------+
| RNDR | [63-60] | y |
+------------------------------+---------+---------+
| TS | [55-52] | y | | TS | [55-52] | y |
+------------------------------+---------+---------+ +------------------------------+---------+---------+
| FHM | [51-48] | y | | FHM | [51-48] | y |
...@@ -200,6 +202,12 @@ infrastructure: ...@@ -200,6 +202,12 @@ infrastructure:
+------------------------------+---------+---------+ +------------------------------+---------+---------+
| Name | bits | visible | | Name | bits | visible |
+------------------------------+---------+---------+ +------------------------------+---------+---------+
| I8MM | [55-52] | y |
+------------------------------+---------+---------+
| DGH | [51-48] | y |
+------------------------------+---------+---------+
| BF16 | [47-44] | y |
+------------------------------+---------+---------+
| SB | [39-36] | y | | SB | [39-36] | y |
+------------------------------+---------+---------+ +------------------------------+---------+---------+
| FRINTTS | [35-32] | y | | FRINTTS | [35-32] | y |
...@@ -234,10 +242,18 @@ infrastructure: ...@@ -234,10 +242,18 @@ infrastructure:
+------------------------------+---------+---------+ +------------------------------+---------+---------+
| Name | bits | visible | | Name | bits | visible |
+------------------------------+---------+---------+ +------------------------------+---------+---------+
| F64MM | [59-56] | y |
+------------------------------+---------+---------+
| F32MM | [55-52] | y |
+------------------------------+---------+---------+
| I8MM | [47-44] | y |
+------------------------------+---------+---------+
| SM4 | [43-40] | y | | SM4 | [43-40] | y |
+------------------------------+---------+---------+ +------------------------------+---------+---------+
| SHA3 | [35-32] | y | | SHA3 | [35-32] | y |
+------------------------------+---------+---------+ +------------------------------+---------+---------+
| BF16 | [23-20] | y |
+------------------------------+---------+---------+
| BitPerm | [19-16] | y | | BitPerm | [19-16] | y |
+------------------------------+---------+---------+ +------------------------------+---------+---------+
| AES | [7-4] | y | | AES | [7-4] | y |
......
...@@ -204,6 +204,37 @@ HWCAP2_FRINT ...@@ -204,6 +204,37 @@ HWCAP2_FRINT
Functionality implied by ID_AA64ISAR1_EL1.FRINTTS == 0b0001. Functionality implied by ID_AA64ISAR1_EL1.FRINTTS == 0b0001.
HWCAP2_SVEI8MM
Functionality implied by ID_AA64ZFR0_EL1.I8MM == 0b0001.
HWCAP2_SVEF32MM
Functionality implied by ID_AA64ZFR0_EL1.F32MM == 0b0001.
HWCAP2_SVEF64MM
Functionality implied by ID_AA64ZFR0_EL1.F64MM == 0b0001.
HWCAP2_SVEBF16
Functionality implied by ID_AA64ZFR0_EL1.BF16 == 0b0001.
HWCAP2_I8MM
Functionality implied by ID_AA64ISAR1_EL1.I8MM == 0b0001.
HWCAP2_BF16
Functionality implied by ID_AA64ISAR1_EL1.BF16 == 0b0001.
HWCAP2_DGH
Functionality implied by ID_AA64ISAR1_EL1.DGH == 0b0001.
HWCAP2_RNG
Functionality implied by ID_AA64ISAR0_EL1.RNDR == 0b0001.
4. Unused AT_HWCAP bits 4. Unused AT_HWCAP bits
----------------------- -----------------------
......
...@@ -88,6 +88,8 @@ stable kernels. ...@@ -88,6 +88,8 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+ +----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-A76 | #1463225 | ARM64_ERRATUM_1463225 | | ARM | Cortex-A76 | #1463225 | ARM64_ERRATUM_1463225 |
+----------------+-----------------+-----------------+-----------------------------+ +----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-A55 | #1530923 | ARM64_ERRATUM_1530923 |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Neoverse-N1 | #1188873,1418040| ARM64_ERRATUM_1418040 | | ARM | Neoverse-N1 | #1188873,1418040| ARM64_ERRATUM_1418040 |
+----------------+-----------------+-----------------+-----------------------------+ +----------------+-----------------+-----------------+-----------------------------+
| ARM | Neoverse-N1 | #1349291 | N/A | | ARM | Neoverse-N1 | #1349291 | N/A |
......
...@@ -162,6 +162,7 @@ config ARM64 ...@@ -162,6 +162,7 @@ config ARM64
select HAVE_PERF_USER_STACK_DUMP select HAVE_PERF_USER_STACK_DUMP
select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_FUNCTION_ARG_ACCESS_API select HAVE_FUNCTION_ARG_ACCESS_API
select HAVE_FUTEX_CMPXCHG if FUTEX
select HAVE_RCU_TABLE_FREE select HAVE_RCU_TABLE_FREE
select HAVE_RSEQ select HAVE_RSEQ
select HAVE_STACKPROTECTOR select HAVE_STACKPROTECTOR
...@@ -302,6 +303,9 @@ config ARCH_SUPPORTS_UPROBES ...@@ -302,6 +303,9 @@ config ARCH_SUPPORTS_UPROBES
config ARCH_PROC_KCORE_TEXT config ARCH_PROC_KCORE_TEXT
def_bool y def_bool y
config BROKEN_GAS_INST
def_bool !$(as-instr,1:\n.inst 0\n.rept . - 1b\n\nnop\n.endr\n)
config KASAN_SHADOW_OFFSET config KASAN_SHADOW_OFFSET
hex hex
depends on KASAN depends on KASAN
...@@ -515,9 +519,13 @@ config ARM64_ERRATUM_1418040 ...@@ -515,9 +519,13 @@ config ARM64_ERRATUM_1418040
If unsure, say Y. If unsure, say Y.
config ARM64_WORKAROUND_SPECULATIVE_AT_VHE
bool
config ARM64_ERRATUM_1165522 config ARM64_ERRATUM_1165522
bool "Cortex-A76: Speculative AT instruction using out-of-context translation regime could cause subsequent request to generate an incorrect translation" bool "Cortex-A76: Speculative AT instruction using out-of-context translation regime could cause subsequent request to generate an incorrect translation"
default y default y
select ARM64_WORKAROUND_SPECULATIVE_AT_VHE
help help
This option adds a workaround for ARM Cortex-A76 erratum 1165522. This option adds a workaround for ARM Cortex-A76 erratum 1165522.
...@@ -527,6 +535,19 @@ config ARM64_ERRATUM_1165522 ...@@ -527,6 +535,19 @@ config ARM64_ERRATUM_1165522
If unsure, say Y. If unsure, say Y.
config ARM64_ERRATUM_1530923
bool "Cortex-A55: Speculative AT instruction using out-of-context translation regime could cause subsequent request to generate an incorrect translation"
default y
select ARM64_WORKAROUND_SPECULATIVE_AT_VHE
help
This option adds a workaround for ARM Cortex-A55 erratum 1530923.
Affected Cortex-A55 cores (r0p0, r0p1, r1p0, r2p0) could end-up with
corrupted TLBs by speculating an AT instruction during a guest
context switch.
If unsure, say Y.
config ARM64_ERRATUM_1286807 config ARM64_ERRATUM_1286807
bool "Cortex-A76: Modification of the translation table for a virtual address might lead to read-after-read ordering violation" bool "Cortex-A76: Modification of the translation table for a virtual address might lead to read-after-read ordering violation"
default y default y
...@@ -543,9 +564,13 @@ config ARM64_ERRATUM_1286807 ...@@ -543,9 +564,13 @@ config ARM64_ERRATUM_1286807
invalidated has been observed by other observers. The invalidated has been observed by other observers. The
workaround repeats the TLBI+DSB operation. workaround repeats the TLBI+DSB operation.
config ARM64_WORKAROUND_SPECULATIVE_AT_NVHE
bool
config ARM64_ERRATUM_1319367 config ARM64_ERRATUM_1319367
bool "Cortex-A57/A72: Speculative AT instruction using out-of-context translation regime could cause subsequent request to generate an incorrect translation" bool "Cortex-A57/A72: Speculative AT instruction using out-of-context translation regime could cause subsequent request to generate an incorrect translation"
default y default y
select ARM64_WORKAROUND_SPECULATIVE_AT_NVHE
help help
This option adds work arounds for ARM Cortex-A57 erratum 1319537 This option adds work arounds for ARM Cortex-A57 erratum 1319537
and A72 erratum 1319367 and A72 erratum 1319367
...@@ -1364,6 +1389,11 @@ config ARM64_PAN ...@@ -1364,6 +1389,11 @@ config ARM64_PAN
instruction if the cpu does not implement the feature. instruction if the cpu does not implement the feature.
config ARM64_LSE_ATOMICS config ARM64_LSE_ATOMICS
bool
default ARM64_USE_LSE_ATOMICS
depends on $(as-instr,.arch_extension lse)
config ARM64_USE_LSE_ATOMICS
bool "Atomic instructions" bool "Atomic instructions"
depends on JUMP_LABEL depends on JUMP_LABEL
default y default y
...@@ -1485,6 +1515,30 @@ config ARM64_PTR_AUTH ...@@ -1485,6 +1515,30 @@ config ARM64_PTR_AUTH
endmenu endmenu
menu "ARMv8.5 architectural features"
config ARM64_E0PD
bool "Enable support for E0PD"
default y
help
E0PD (part of the ARMv8.5 extensions) allows us to ensure
that EL0 accesses made via TTBR1 always fault in constant time,
providing similar benefits to KASLR as those provided by KPTI, but
with lower overhead and without disrupting legitimate access to
kernel memory such as SPE.
This option enables E0PD for TTBR1 where available.
config ARCH_RANDOM
bool "Enable support for random number generation"
default y
help
Random number generation (part of the ARMv8.5 Extensions)
provides a high bandwidth, cryptographically secure
hardware random number generator.
endmenu
config ARM64_SVE config ARM64_SVE
bool "ARM Scalable Vector Extension support" bool "ARM Scalable Vector Extension support"
default y default y
...@@ -1545,7 +1599,7 @@ config ARM64_MODULE_PLTS ...@@ -1545,7 +1599,7 @@ config ARM64_MODULE_PLTS
config ARM64_PSEUDO_NMI config ARM64_PSEUDO_NMI
bool "Support for NMI-like interrupts" bool "Support for NMI-like interrupts"
select CONFIG_ARM_GIC_V3 select ARM_GIC_V3
help help
Adds support for mimicking Non-Maskable Interrupts through the use of Adds support for mimicking Non-Maskable Interrupts through the use of
GIC interrupt priority. This support requires version 3 or later of GIC interrupt priority. This support requires version 3 or later of
......
...@@ -30,11 +30,8 @@ LDFLAGS_vmlinux += --fix-cortex-a53-843419 ...@@ -30,11 +30,8 @@ LDFLAGS_vmlinux += --fix-cortex-a53-843419
endif endif
endif endif
# Check for binutils support for specific extensions ifeq ($(CONFIG_ARM64_USE_LSE_ATOMICS), y)
lseinstr := $(call as-instr,.arch_extension lse,-DCONFIG_AS_LSE=1) ifneq ($(CONFIG_ARM64_LSE_ATOMICS), y)
ifeq ($(CONFIG_ARM64_LSE_ATOMICS), y)
ifeq ($(lseinstr),)
$(warning LSE atomics not supported by binutils) $(warning LSE atomics not supported by binutils)
endif endif
endif endif
...@@ -45,19 +42,15 @@ cc_has_k_constraint := $(call try-run,echo \ ...@@ -45,19 +42,15 @@ cc_has_k_constraint := $(call try-run,echo \
return 0; \ return 0; \
}' | $(CC) -S -x c -o "$$TMP" -,,-DCONFIG_CC_HAS_K_CONSTRAINT=1) }' | $(CC) -S -x c -o "$$TMP" -,,-DCONFIG_CC_HAS_K_CONSTRAINT=1)
ifeq ($(CONFIG_ARM64), y) ifeq ($(CONFIG_BROKEN_GAS_INST),y)
brokengasinst := $(call as-instr,1:\n.inst 0\n.rept . - 1b\n\nnop\n.endr\n,,-DCONFIG_BROKEN_GAS_INST=1)
ifneq ($(brokengasinst),)
$(warning Detected assembler with broken .inst; disassembly will be unreliable) $(warning Detected assembler with broken .inst; disassembly will be unreliable)
endif
endif endif
KBUILD_CFLAGS += -mgeneral-regs-only $(lseinstr) $(brokengasinst) \ KBUILD_CFLAGS += -mgeneral-regs-only \
$(compat_vdso) $(cc_has_k_constraint) $(compat_vdso) $(cc_has_k_constraint)
KBUILD_CFLAGS += -fno-asynchronous-unwind-tables KBUILD_CFLAGS += -fno-asynchronous-unwind-tables
KBUILD_CFLAGS += $(call cc-disable-warning, psabi) KBUILD_CFLAGS += $(call cc-disable-warning, psabi)
KBUILD_AFLAGS += $(lseinstr) $(brokengasinst) $(compat_vdso) KBUILD_AFLAGS += $(compat_vdso)
KBUILD_CFLAGS += $(call cc-option,-mabi=lp64) KBUILD_CFLAGS += $(call cc-option,-mabi=lp64)
KBUILD_AFLAGS += $(call cc-option,-mabi=lp64) KBUILD_AFLAGS += $(call cc-option,-mabi=lp64)
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
OBJCOPYFLAGS_Image :=-O binary -R .note -R .note.gnu.build-id -R .comment -S OBJCOPYFLAGS_Image :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
targets := Image Image.gz targets := Image Image.bz2 Image.gz Image.lz4 Image.lzma Image.lzo
$(obj)/Image: vmlinux FORCE $(obj)/Image: vmlinux FORCE
$(call if_changed,objcopy) $(call if_changed,objcopy)
......
...@@ -35,13 +35,16 @@ void apply_alternatives_module(void *start, size_t length); ...@@ -35,13 +35,16 @@ void apply_alternatives_module(void *start, size_t length);
static inline void apply_alternatives_module(void *start, size_t length) { } static inline void apply_alternatives_module(void *start, size_t length) { }
#endif #endif
#define ALTINSTR_ENTRY(feature,cb) \ #define ALTINSTR_ENTRY(feature) \
" .word 661b - .\n" /* label */ \ " .word 661b - .\n" /* label */ \
" .if " __stringify(cb) " == 0\n" \
" .word 663f - .\n" /* new instruction */ \ " .word 663f - .\n" /* new instruction */ \
" .else\n" \ " .hword " __stringify(feature) "\n" /* feature bit */ \
" .byte 662b-661b\n" /* source len */ \
" .byte 664f-663f\n" /* replacement len */
#define ALTINSTR_ENTRY_CB(feature, cb) \
" .word 661b - .\n" /* label */ \
" .word " __stringify(cb) "- .\n" /* callback */ \ " .word " __stringify(cb) "- .\n" /* callback */ \
" .endif\n" \
" .hword " __stringify(feature) "\n" /* feature bit */ \ " .hword " __stringify(feature) "\n" /* feature bit */ \
" .byte 662b-661b\n" /* source len */ \ " .byte 662b-661b\n" /* source len */ \
" .byte 664f-663f\n" /* replacement len */ " .byte 664f-663f\n" /* replacement len */
...@@ -62,15 +65,14 @@ static inline void apply_alternatives_module(void *start, size_t length) { } ...@@ -62,15 +65,14 @@ static inline void apply_alternatives_module(void *start, size_t length) { }
* *
* Alternatives with callbacks do not generate replacement instructions. * Alternatives with callbacks do not generate replacement instructions.
*/ */
#define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled, cb) \ #define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled) \
".if "__stringify(cfg_enabled)" == 1\n" \ ".if "__stringify(cfg_enabled)" == 1\n" \
"661:\n\t" \ "661:\n\t" \
oldinstr "\n" \ oldinstr "\n" \
"662:\n" \ "662:\n" \
".pushsection .altinstructions,\"a\"\n" \ ".pushsection .altinstructions,\"a\"\n" \
ALTINSTR_ENTRY(feature,cb) \ ALTINSTR_ENTRY(feature) \
".popsection\n" \ ".popsection\n" \
" .if " __stringify(cb) " == 0\n" \
".pushsection .altinstr_replacement, \"a\"\n" \ ".pushsection .altinstr_replacement, \"a\"\n" \
"663:\n\t" \ "663:\n\t" \
newinstr "\n" \ newinstr "\n" \
...@@ -78,17 +80,25 @@ static inline void apply_alternatives_module(void *start, size_t length) { } ...@@ -78,17 +80,25 @@ static inline void apply_alternatives_module(void *start, size_t length) { }
".popsection\n\t" \ ".popsection\n\t" \
".org . - (664b-663b) + (662b-661b)\n\t" \ ".org . - (664b-663b) + (662b-661b)\n\t" \
".org . - (662b-661b) + (664b-663b)\n" \ ".org . - (662b-661b) + (664b-663b)\n" \
".else\n\t" \ ".endif\n"
#define __ALTERNATIVE_CFG_CB(oldinstr, feature, cfg_enabled, cb) \
".if "__stringify(cfg_enabled)" == 1\n" \
"661:\n\t" \
oldinstr "\n" \
"662:\n" \
".pushsection .altinstructions,\"a\"\n" \
ALTINSTR_ENTRY_CB(feature, cb) \
".popsection\n" \
"663:\n\t" \ "663:\n\t" \
"664:\n\t" \ "664:\n\t" \
".endif\n" \
".endif\n" ".endif\n"
#define _ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg, ...) \ #define _ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg, ...) \
__ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg), 0) __ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg))
#define ALTERNATIVE_CB(oldinstr, cb) \ #define ALTERNATIVE_CB(oldinstr, cb) \
__ALTERNATIVE_CFG(oldinstr, "NOT_AN_INSTRUCTION", ARM64_CB_PATCH, 1, cb) __ALTERNATIVE_CFG_CB(oldinstr, ARM64_CB_PATCH, 1, cb)
#else #else
#include <asm/assembler.h> #include <asm/assembler.h>
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_ARCHRANDOM_H
#define _ASM_ARCHRANDOM_H
#ifdef CONFIG_ARCH_RANDOM
#include <linux/random.h>
#include <asm/cpufeature.h>
static inline bool __arm64_rndr(unsigned long *v)
{
bool ok;
/*
* Reads of RNDR set PSTATE.NZCV to 0b0000 on success,
* and set PSTATE.NZCV to 0b0100 otherwise.
*/
asm volatile(
__mrs_s("%0", SYS_RNDR_EL0) "\n"
" cset %w1, ne\n"
: "=r" (*v), "=r" (ok)
:
: "cc");
return ok;
}
static inline bool __must_check arch_get_random_long(unsigned long *v)
{
return false;
}
static inline bool __must_check arch_get_random_int(unsigned int *v)
{
return false;
}
static inline bool __must_check arch_get_random_seed_long(unsigned long *v)
{
/*
* Only support the generic interface after we have detected
* the system wide capability, avoiding complexity with the
* cpufeature code and with potential scheduling between CPUs
* with and without the feature.
*/
if (!cpus_have_const_cap(ARM64_HAS_RNG))
return false;
return __arm64_rndr(v);
}
static inline bool __must_check arch_get_random_seed_int(unsigned int *v)
{
unsigned long val;
bool ok = arch_get_random_seed_long(&val);
*v = val;
return ok;
}
static inline bool __init __early_cpu_has_rndr(void)
{
/* Open code as we run prior to the first call to cpufeature. */
unsigned long ftr = read_sysreg_s(SYS_ID_AA64ISAR0_EL1);
return (ftr >> ID_AA64ISAR0_RNDR_SHIFT) & 0xf;
}
#else
static inline bool __arm64_rndr(unsigned long *v) { return false; }
static inline bool __init __early_cpu_has_rndr(void) { return false; }
#endif /* CONFIG_ARCH_RANDOM */
#endif /* _ASM_ARCHRANDOM_H */
...@@ -40,12 +40,6 @@ ...@@ -40,12 +40,6 @@
msr daif, \flags msr daif, \flags
.endm .endm
/* Only on aarch64 pstate, PSR_D_BIT is different for aarch32 */
.macro inherit_daif, pstate:req, tmp:req
and \tmp, \pstate, #(PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)
msr daif, \tmp
.endm
/* IRQ is the lowest priority flag, unconditionally unmask the rest. */ /* IRQ is the lowest priority flag, unconditionally unmask the rest. */
.macro enable_da_f .macro enable_da_f
msr daifclr, #(8 | 4 | 1) msr daifclr, #(8 | 4 | 1)
...@@ -85,13 +79,6 @@ ...@@ -85,13 +79,6 @@
9990: 9990:
.endm .endm
/*
* SMP data memory barrier
*/
.macro smp_dmb, opt
dmb \opt
.endm
/* /*
* RAS Error Synchronization barrier * RAS Error Synchronization barrier
*/ */
...@@ -461,17 +448,6 @@ USER(\label, ic ivau, \tmp2) // invalidate I line PoU ...@@ -461,17 +448,6 @@ USER(\label, ic ivau, \tmp2) // invalidate I line PoU
b.ne 9998b b.ne 9998b
.endm .endm
/*
* Annotate a function as position independent, i.e., safe to be called before
* the kernel virtual mapping is activated.
*/
#define ENDPIPROC(x) \
.globl __pi_##x; \
.type __pi_##x, %function; \
.set __pi_##x, x; \
.size __pi_##x, . - x; \
ENDPROC(x)
/* /*
* Annotate a function as being unsuitable for kprobes. * Annotate a function as being unsuitable for kprobes.
*/ */
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include <linux/stringify.h> #include <linux/stringify.h>
#if IS_ENABLED(CONFIG_ARM64_LSE_ATOMICS) && IS_ENABLED(CONFIG_AS_LSE) #ifdef CONFIG_ARM64_LSE_ATOMICS
#define __LL_SC_FALLBACK(asm_ops) \ #define __LL_SC_FALLBACK(asm_ops) \
" b 3f\n" \ " b 3f\n" \
" .subsection 1\n" \ " .subsection 1\n" \
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
static inline void __lse_atomic_##op(int i, atomic_t *v) \ static inline void __lse_atomic_##op(int i, atomic_t *v) \
{ \ { \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" " #asm_op " %w[i], %[v]\n" \ " " #asm_op " %w[i], %[v]\n" \
: [i] "+r" (i), [v] "+Q" (v->counter) \ : [i] "+r" (i), [v] "+Q" (v->counter) \
: "r" (v)); \ : "r" (v)); \
...@@ -30,6 +31,7 @@ ATOMIC_OP(add, stadd) ...@@ -30,6 +31,7 @@ ATOMIC_OP(add, stadd)
static inline int __lse_atomic_fetch_##op##name(int i, atomic_t *v) \ static inline int __lse_atomic_fetch_##op##name(int i, atomic_t *v) \
{ \ { \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" " #asm_op #mb " %w[i], %w[i], %[v]" \ " " #asm_op #mb " %w[i], %w[i], %[v]" \
: [i] "+r" (i), [v] "+Q" (v->counter) \ : [i] "+r" (i), [v] "+Q" (v->counter) \
: "r" (v) \ : "r" (v) \
...@@ -58,6 +60,7 @@ static inline int __lse_atomic_add_return##name(int i, atomic_t *v) \ ...@@ -58,6 +60,7 @@ static inline int __lse_atomic_add_return##name(int i, atomic_t *v) \
u32 tmp; \ u32 tmp; \
\ \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" ldadd" #mb " %w[i], %w[tmp], %[v]\n" \ " ldadd" #mb " %w[i], %w[tmp], %[v]\n" \
" add %w[i], %w[i], %w[tmp]" \ " add %w[i], %w[i], %w[tmp]" \
: [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp) \ : [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp) \
...@@ -77,6 +80,7 @@ ATOMIC_OP_ADD_RETURN( , al, "memory") ...@@ -77,6 +80,7 @@ ATOMIC_OP_ADD_RETURN( , al, "memory")
static inline void __lse_atomic_and(int i, atomic_t *v) static inline void __lse_atomic_and(int i, atomic_t *v)
{ {
asm volatile( asm volatile(
__LSE_PREAMBLE
" mvn %w[i], %w[i]\n" " mvn %w[i], %w[i]\n"
" stclr %w[i], %[v]" " stclr %w[i], %[v]"
: [i] "+&r" (i), [v] "+Q" (v->counter) : [i] "+&r" (i), [v] "+Q" (v->counter)
...@@ -87,6 +91,7 @@ static inline void __lse_atomic_and(int i, atomic_t *v) ...@@ -87,6 +91,7 @@ static inline void __lse_atomic_and(int i, atomic_t *v)
static inline int __lse_atomic_fetch_and##name(int i, atomic_t *v) \ static inline int __lse_atomic_fetch_and##name(int i, atomic_t *v) \
{ \ { \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" mvn %w[i], %w[i]\n" \ " mvn %w[i], %w[i]\n" \
" ldclr" #mb " %w[i], %w[i], %[v]" \ " ldclr" #mb " %w[i], %w[i], %[v]" \
: [i] "+&r" (i), [v] "+Q" (v->counter) \ : [i] "+&r" (i), [v] "+Q" (v->counter) \
...@@ -106,6 +111,7 @@ ATOMIC_FETCH_OP_AND( , al, "memory") ...@@ -106,6 +111,7 @@ ATOMIC_FETCH_OP_AND( , al, "memory")
static inline void __lse_atomic_sub(int i, atomic_t *v) static inline void __lse_atomic_sub(int i, atomic_t *v)
{ {
asm volatile( asm volatile(
__LSE_PREAMBLE
" neg %w[i], %w[i]\n" " neg %w[i], %w[i]\n"
" stadd %w[i], %[v]" " stadd %w[i], %[v]"
: [i] "+&r" (i), [v] "+Q" (v->counter) : [i] "+&r" (i), [v] "+Q" (v->counter)
...@@ -118,6 +124,7 @@ static inline int __lse_atomic_sub_return##name(int i, atomic_t *v) \ ...@@ -118,6 +124,7 @@ static inline int __lse_atomic_sub_return##name(int i, atomic_t *v) \
u32 tmp; \ u32 tmp; \
\ \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" neg %w[i], %w[i]\n" \ " neg %w[i], %w[i]\n" \
" ldadd" #mb " %w[i], %w[tmp], %[v]\n" \ " ldadd" #mb " %w[i], %w[tmp], %[v]\n" \
" add %w[i], %w[i], %w[tmp]" \ " add %w[i], %w[i], %w[tmp]" \
...@@ -139,6 +146,7 @@ ATOMIC_OP_SUB_RETURN( , al, "memory") ...@@ -139,6 +146,7 @@ ATOMIC_OP_SUB_RETURN( , al, "memory")
static inline int __lse_atomic_fetch_sub##name(int i, atomic_t *v) \ static inline int __lse_atomic_fetch_sub##name(int i, atomic_t *v) \
{ \ { \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" neg %w[i], %w[i]\n" \ " neg %w[i], %w[i]\n" \
" ldadd" #mb " %w[i], %w[i], %[v]" \ " ldadd" #mb " %w[i], %w[i], %[v]" \
: [i] "+&r" (i), [v] "+Q" (v->counter) \ : [i] "+&r" (i), [v] "+Q" (v->counter) \
...@@ -159,6 +167,7 @@ ATOMIC_FETCH_OP_SUB( , al, "memory") ...@@ -159,6 +167,7 @@ ATOMIC_FETCH_OP_SUB( , al, "memory")
static inline void __lse_atomic64_##op(s64 i, atomic64_t *v) \ static inline void __lse_atomic64_##op(s64 i, atomic64_t *v) \
{ \ { \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" " #asm_op " %[i], %[v]\n" \ " " #asm_op " %[i], %[v]\n" \
: [i] "+r" (i), [v] "+Q" (v->counter) \ : [i] "+r" (i), [v] "+Q" (v->counter) \
: "r" (v)); \ : "r" (v)); \
...@@ -175,6 +184,7 @@ ATOMIC64_OP(add, stadd) ...@@ -175,6 +184,7 @@ ATOMIC64_OP(add, stadd)
static inline long __lse_atomic64_fetch_##op##name(s64 i, atomic64_t *v)\ static inline long __lse_atomic64_fetch_##op##name(s64 i, atomic64_t *v)\
{ \ { \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" " #asm_op #mb " %[i], %[i], %[v]" \ " " #asm_op #mb " %[i], %[i], %[v]" \
: [i] "+r" (i), [v] "+Q" (v->counter) \ : [i] "+r" (i), [v] "+Q" (v->counter) \
: "r" (v) \ : "r" (v) \
...@@ -203,6 +213,7 @@ static inline long __lse_atomic64_add_return##name(s64 i, atomic64_t *v)\ ...@@ -203,6 +213,7 @@ static inline long __lse_atomic64_add_return##name(s64 i, atomic64_t *v)\
unsigned long tmp; \ unsigned long tmp; \
\ \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" ldadd" #mb " %[i], %x[tmp], %[v]\n" \ " ldadd" #mb " %[i], %x[tmp], %[v]\n" \
" add %[i], %[i], %x[tmp]" \ " add %[i], %[i], %x[tmp]" \
: [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp) \ : [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp) \
...@@ -222,6 +233,7 @@ ATOMIC64_OP_ADD_RETURN( , al, "memory") ...@@ -222,6 +233,7 @@ ATOMIC64_OP_ADD_RETURN( , al, "memory")
static inline void __lse_atomic64_and(s64 i, atomic64_t *v) static inline void __lse_atomic64_and(s64 i, atomic64_t *v)
{ {
asm volatile( asm volatile(
__LSE_PREAMBLE
" mvn %[i], %[i]\n" " mvn %[i], %[i]\n"
" stclr %[i], %[v]" " stclr %[i], %[v]"
: [i] "+&r" (i), [v] "+Q" (v->counter) : [i] "+&r" (i), [v] "+Q" (v->counter)
...@@ -232,6 +244,7 @@ static inline void __lse_atomic64_and(s64 i, atomic64_t *v) ...@@ -232,6 +244,7 @@ static inline void __lse_atomic64_and(s64 i, atomic64_t *v)
static inline long __lse_atomic64_fetch_and##name(s64 i, atomic64_t *v) \ static inline long __lse_atomic64_fetch_and##name(s64 i, atomic64_t *v) \
{ \ { \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" mvn %[i], %[i]\n" \ " mvn %[i], %[i]\n" \
" ldclr" #mb " %[i], %[i], %[v]" \ " ldclr" #mb " %[i], %[i], %[v]" \
: [i] "+&r" (i), [v] "+Q" (v->counter) \ : [i] "+&r" (i), [v] "+Q" (v->counter) \
...@@ -251,6 +264,7 @@ ATOMIC64_FETCH_OP_AND( , al, "memory") ...@@ -251,6 +264,7 @@ ATOMIC64_FETCH_OP_AND( , al, "memory")
static inline void __lse_atomic64_sub(s64 i, atomic64_t *v) static inline void __lse_atomic64_sub(s64 i, atomic64_t *v)
{ {
asm volatile( asm volatile(
__LSE_PREAMBLE
" neg %[i], %[i]\n" " neg %[i], %[i]\n"
" stadd %[i], %[v]" " stadd %[i], %[v]"
: [i] "+&r" (i), [v] "+Q" (v->counter) : [i] "+&r" (i), [v] "+Q" (v->counter)
...@@ -263,6 +277,7 @@ static inline long __lse_atomic64_sub_return##name(s64 i, atomic64_t *v) \ ...@@ -263,6 +277,7 @@ static inline long __lse_atomic64_sub_return##name(s64 i, atomic64_t *v) \
unsigned long tmp; \ unsigned long tmp; \
\ \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" neg %[i], %[i]\n" \ " neg %[i], %[i]\n" \
" ldadd" #mb " %[i], %x[tmp], %[v]\n" \ " ldadd" #mb " %[i], %x[tmp], %[v]\n" \
" add %[i], %[i], %x[tmp]" \ " add %[i], %[i], %x[tmp]" \
...@@ -284,6 +299,7 @@ ATOMIC64_OP_SUB_RETURN( , al, "memory") ...@@ -284,6 +299,7 @@ ATOMIC64_OP_SUB_RETURN( , al, "memory")
static inline long __lse_atomic64_fetch_sub##name(s64 i, atomic64_t *v) \ static inline long __lse_atomic64_fetch_sub##name(s64 i, atomic64_t *v) \
{ \ { \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" neg %[i], %[i]\n" \ " neg %[i], %[i]\n" \
" ldadd" #mb " %[i], %[i], %[v]" \ " ldadd" #mb " %[i], %[i], %[v]" \
: [i] "+&r" (i), [v] "+Q" (v->counter) \ : [i] "+&r" (i), [v] "+Q" (v->counter) \
...@@ -305,6 +321,7 @@ static inline s64 __lse_atomic64_dec_if_positive(atomic64_t *v) ...@@ -305,6 +321,7 @@ static inline s64 __lse_atomic64_dec_if_positive(atomic64_t *v)
unsigned long tmp; unsigned long tmp;
asm volatile( asm volatile(
__LSE_PREAMBLE
"1: ldr %x[tmp], %[v]\n" "1: ldr %x[tmp], %[v]\n"
" subs %[ret], %x[tmp], #1\n" " subs %[ret], %x[tmp], #1\n"
" b.lt 2f\n" " b.lt 2f\n"
...@@ -332,6 +349,7 @@ __lse__cmpxchg_case_##name##sz(volatile void *ptr, \ ...@@ -332,6 +349,7 @@ __lse__cmpxchg_case_##name##sz(volatile void *ptr, \
unsigned long tmp; \ unsigned long tmp; \
\ \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" mov %" #w "[tmp], %" #w "[old]\n" \ " mov %" #w "[tmp], %" #w "[old]\n" \
" cas" #mb #sfx "\t%" #w "[tmp], %" #w "[new], %[v]\n" \ " cas" #mb #sfx "\t%" #w "[tmp], %" #w "[new], %[v]\n" \
" mov %" #w "[ret], %" #w "[tmp]" \ " mov %" #w "[ret], %" #w "[tmp]" \
...@@ -379,6 +397,7 @@ __lse__cmpxchg_double##name(unsigned long old1, \ ...@@ -379,6 +397,7 @@ __lse__cmpxchg_double##name(unsigned long old1, \
register unsigned long x4 asm ("x4") = (unsigned long)ptr; \ register unsigned long x4 asm ("x4") = (unsigned long)ptr; \
\ \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" casp" #mb "\t%[old1], %[old2], %[new1], %[new2], %[v]\n"\ " casp" #mb "\t%[old1], %[old2], %[new1], %[new2], %[v]\n"\
" eor %[old1], %[old1], %[oldval1]\n" \ " eor %[old1], %[old1], %[oldval1]\n" \
" eor %[old2], %[old2], %[oldval2]\n" \ " eor %[old2], %[old2], %[oldval2]\n" \
......
...@@ -35,6 +35,9 @@ static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) ...@@ -35,6 +35,9 @@ static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
} }
#define ip_fast_csum ip_fast_csum #define ip_fast_csum ip_fast_csum
extern unsigned int do_csum(const unsigned char *buff, int len);
#define do_csum do_csum
#include <asm-generic/checksum.h> #include <asm-generic/checksum.h>
#endif /* __ASM_CHECKSUM_H */ #endif /* __ASM_CHECKSUM_H */
...@@ -39,6 +39,7 @@ struct cpuinfo_arm64 { ...@@ -39,6 +39,7 @@ struct cpuinfo_arm64 {
u32 reg_id_isar3; u32 reg_id_isar3;
u32 reg_id_isar4; u32 reg_id_isar4;
u32 reg_id_isar5; u32 reg_id_isar5;
u32 reg_id_isar6;
u32 reg_id_mmfr0; u32 reg_id_mmfr0;
u32 reg_id_mmfr1; u32 reg_id_mmfr1;
u32 reg_id_mmfr2; u32 reg_id_mmfr2;
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
#define ARM64_SSBS 34 #define ARM64_SSBS 34
#define ARM64_WORKAROUND_1418040 35 #define ARM64_WORKAROUND_1418040 35
#define ARM64_HAS_SB 36 #define ARM64_HAS_SB 36
#define ARM64_WORKAROUND_1165522 37 #define ARM64_WORKAROUND_SPECULATIVE_AT_VHE 37
#define ARM64_HAS_ADDRESS_AUTH_ARCH 38 #define ARM64_HAS_ADDRESS_AUTH_ARCH 38
#define ARM64_HAS_ADDRESS_AUTH_IMP_DEF 39 #define ARM64_HAS_ADDRESS_AUTH_IMP_DEF 39
#define ARM64_HAS_GENERIC_AUTH_ARCH 40 #define ARM64_HAS_GENERIC_AUTH_ARCH 40
...@@ -55,8 +55,10 @@ ...@@ -55,8 +55,10 @@
#define ARM64_WORKAROUND_CAVIUM_TX2_219_TVM 45 #define ARM64_WORKAROUND_CAVIUM_TX2_219_TVM 45
#define ARM64_WORKAROUND_CAVIUM_TX2_219_PRFM 46 #define ARM64_WORKAROUND_CAVIUM_TX2_219_PRFM 46
#define ARM64_WORKAROUND_1542419 47 #define ARM64_WORKAROUND_1542419 47
#define ARM64_WORKAROUND_1319367 48 #define ARM64_WORKAROUND_SPECULATIVE_AT_NVHE 48
#define ARM64_HAS_E0PD 49
#define ARM64_HAS_RNG 50
#define ARM64_NCAPS 49 #define ARM64_NCAPS 51
#endif /* __ASM_CPUCAPS_H */ #endif /* __ASM_CPUCAPS_H */
...@@ -613,6 +613,11 @@ static inline bool system_has_prio_mask_debugging(void) ...@@ -613,6 +613,11 @@ static inline bool system_has_prio_mask_debugging(void)
system_uses_irq_prio_masking(); system_uses_irq_prio_masking();
} }
static inline bool system_capabilities_finalized(void)
{
return static_branch_likely(&arm64_const_caps_ready);
}
#define ARM64_BP_HARDEN_UNKNOWN -1 #define ARM64_BP_HARDEN_UNKNOWN -1
#define ARM64_BP_HARDEN_WA_NEEDED 0 #define ARM64_BP_HARDEN_WA_NEEDED 0
#define ARM64_BP_HARDEN_NOT_REQUIRED 1 #define ARM64_BP_HARDEN_NOT_REQUIRED 1
......
...@@ -85,6 +85,8 @@ ...@@ -85,6 +85,8 @@
#define QCOM_CPU_PART_FALKOR_V1 0x800 #define QCOM_CPU_PART_FALKOR_V1 0x800
#define QCOM_CPU_PART_FALKOR 0xC00 #define QCOM_CPU_PART_FALKOR 0xC00
#define QCOM_CPU_PART_KRYO 0x200 #define QCOM_CPU_PART_KRYO 0x200
#define QCOM_CPU_PART_KRYO_3XX_SILVER 0x803
#define QCOM_CPU_PART_KRYO_4XX_SILVER 0x805
#define NVIDIA_CPU_PART_DENVER 0x003 #define NVIDIA_CPU_PART_DENVER 0x003
#define NVIDIA_CPU_PART_CARMEL 0x004 #define NVIDIA_CPU_PART_CARMEL 0x004
...@@ -111,6 +113,8 @@ ...@@ -111,6 +113,8 @@
#define MIDR_QCOM_FALKOR_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR_V1) #define MIDR_QCOM_FALKOR_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR_V1)
#define MIDR_QCOM_FALKOR MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR) #define MIDR_QCOM_FALKOR MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR)
#define MIDR_QCOM_KRYO MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO) #define MIDR_QCOM_KRYO MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO)
#define MIDR_QCOM_KRYO_3XX_SILVER MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_3XX_SILVER)
#define MIDR_QCOM_KRYO_4XX_SILVER MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_4XX_SILVER)
#define MIDR_NVIDIA_DENVER MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_DENVER) #define MIDR_NVIDIA_DENVER MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_DENVER)
#define MIDR_NVIDIA_CARMEL MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_CARMEL) #define MIDR_NVIDIA_CARMEL MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_CARMEL)
#define MIDR_FUJITSU_A64FX MIDR_CPU_MODEL(ARM_CPU_IMP_FUJITSU, FUJITSU_CPU_PART_A64FX) #define MIDR_FUJITSU_A64FX MIDR_CPU_MODEL(ARM_CPU_IMP_FUJITSU, FUJITSU_CPU_PART_A64FX)
......
...@@ -38,7 +38,7 @@ static inline void local_daif_mask(void) ...@@ -38,7 +38,7 @@ static inline void local_daif_mask(void)
trace_hardirqs_off(); trace_hardirqs_off();
} }
static inline unsigned long local_daif_save(void) static inline unsigned long local_daif_save_flags(void)
{ {
unsigned long flags; unsigned long flags;
...@@ -50,6 +50,15 @@ static inline unsigned long local_daif_save(void) ...@@ -50,6 +50,15 @@ static inline unsigned long local_daif_save(void)
flags |= PSR_I_BIT; flags |= PSR_I_BIT;
} }
return flags;
}
static inline unsigned long local_daif_save(void)
{
unsigned long flags;
flags = local_daif_save_flags();
local_daif_mask(); local_daif_mask();
return flags; return flags;
......
...@@ -45,8 +45,8 @@ void do_sysinstr(unsigned int esr, struct pt_regs *regs); ...@@ -45,8 +45,8 @@ void do_sysinstr(unsigned int esr, struct pt_regs *regs);
void do_sp_pc_abort(unsigned long addr, unsigned int esr, struct pt_regs *regs); void do_sp_pc_abort(unsigned long addr, unsigned int esr, struct pt_regs *regs);
void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr); void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr);
void do_cp15instr(unsigned int esr, struct pt_regs *regs); void do_cp15instr(unsigned int esr, struct pt_regs *regs);
void el0_svc_handler(struct pt_regs *regs); void do_el0_svc(struct pt_regs *regs);
void el0_svc_compat_handler(struct pt_regs *regs); void do_el0_svc_compat(struct pt_regs *regs);
void do_el0_ia_bp_hardening(unsigned long addr, unsigned int esr, void do_el0_ia_bp_hardening(unsigned long addr, unsigned int esr,
struct pt_regs *regs); struct pt_regs *regs);
......
...@@ -86,6 +86,14 @@ ...@@ -86,6 +86,14 @@
#define KERNEL_HWCAP_SVESM4 __khwcap2_feature(SVESM4) #define KERNEL_HWCAP_SVESM4 __khwcap2_feature(SVESM4)
#define KERNEL_HWCAP_FLAGM2 __khwcap2_feature(FLAGM2) #define KERNEL_HWCAP_FLAGM2 __khwcap2_feature(FLAGM2)
#define KERNEL_HWCAP_FRINT __khwcap2_feature(FRINT) #define KERNEL_HWCAP_FRINT __khwcap2_feature(FRINT)
#define KERNEL_HWCAP_SVEI8MM __khwcap2_feature(SVEI8MM)
#define KERNEL_HWCAP_SVEF32MM __khwcap2_feature(SVEF32MM)
#define KERNEL_HWCAP_SVEF64MM __khwcap2_feature(SVEF64MM)
#define KERNEL_HWCAP_SVEBF16 __khwcap2_feature(SVEBF16)
#define KERNEL_HWCAP_I8MM __khwcap2_feature(I8MM)
#define KERNEL_HWCAP_BF16 __khwcap2_feature(BF16)
#define KERNEL_HWCAP_DGH __khwcap2_feature(DGH)
#define KERNEL_HWCAP_RNG __khwcap2_feature(RNG)
/* /*
* This yields a mask that user programs can use to figure out what * This yields a mask that user programs can use to figure out what
......
...@@ -96,6 +96,10 @@ static inline void crash_post_resume(void) {} ...@@ -96,6 +96,10 @@ static inline void crash_post_resume(void) {}
struct kimage_arch { struct kimage_arch {
void *dtb; void *dtb;
unsigned long dtb_mem; unsigned long dtb_mem;
/* Core ELF header buffer */
void *elf_headers;
unsigned long elf_headers_mem;
unsigned long elf_headers_sz;
}; };
extern const struct kexec_file_ops kexec_image_ops; extern const struct kexec_file_ops kexec_image_ops;
......
...@@ -547,7 +547,7 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr, ...@@ -547,7 +547,7 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
* wrong, and hyp will crash and burn when it uses any * wrong, and hyp will crash and burn when it uses any
* cpus_have_const_cap() wrapper. * cpus_have_const_cap() wrapper.
*/ */
BUG_ON(!static_branch_likely(&arm64_const_caps_ready)); BUG_ON(!system_capabilities_finalized());
__kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr, tpidr_el2); __kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr, tpidr_el2);
/* /*
...@@ -571,7 +571,7 @@ static inline bool kvm_arch_requires_vhe(void) ...@@ -571,7 +571,7 @@ static inline bool kvm_arch_requires_vhe(void)
return true; return true;
/* Some implementations have defects that confine them to VHE */ /* Some implementations have defects that confine them to VHE */
if (cpus_have_cap(ARM64_WORKAROUND_1165522)) if (cpus_have_cap(ARM64_WORKAROUND_SPECULATIVE_AT_VHE))
return true; return true;
return false; return false;
......
...@@ -91,11 +91,11 @@ static __always_inline void __hyp_text __load_guest_stage2(struct kvm *kvm) ...@@ -91,11 +91,11 @@ static __always_inline void __hyp_text __load_guest_stage2(struct kvm *kvm)
write_sysreg(kvm_get_vttbr(kvm), vttbr_el2); write_sysreg(kvm_get_vttbr(kvm), vttbr_el2);
/* /*
* ARM erratum 1165522 requires the actual execution of the above * ARM errata 1165522 and 1530923 require the actual execution of the
* before we can switch to the EL1/EL0 translation regime used by * above before we can switch to the EL1/EL0 translation regime used by
* the guest. * the guest.
*/ */
asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_1165522)); asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_SPECULATIVE_AT_VHE));
} }
#endif /* __ARM64_KVM_HYP_H__ */ #endif /* __ARM64_KVM_HYP_H__ */
......
...@@ -4,4 +4,20 @@ ...@@ -4,4 +4,20 @@
#define __ALIGN .align 2 #define __ALIGN .align 2
#define __ALIGN_STR ".align 2" #define __ALIGN_STR ".align 2"
/*
* Annotate a function as position independent, i.e., safe to be called before
* the kernel virtual mapping is activated.
*/
#define SYM_FUNC_START_PI(x) \
SYM_FUNC_START_ALIAS(__pi_##x); \
SYM_FUNC_START(x)
#define SYM_FUNC_START_WEAK_PI(x) \
SYM_FUNC_START_ALIAS(__pi_##x); \
SYM_FUNC_START_WEAK(x)
#define SYM_FUNC_END_PI(x) \
SYM_FUNC_END(x); \
SYM_FUNC_END_ALIAS(__pi_##x)
#endif #endif
...@@ -4,7 +4,9 @@ ...@@ -4,7 +4,9 @@
#include <asm/atomic_ll_sc.h> #include <asm/atomic_ll_sc.h>
#if defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS) #ifdef CONFIG_ARM64_LSE_ATOMICS
#define __LSE_PREAMBLE ".arch armv8-a+lse\n"
#include <linux/compiler_types.h> #include <linux/compiler_types.h>
#include <linux/export.h> #include <linux/export.h>
...@@ -14,8 +16,6 @@ ...@@ -14,8 +16,6 @@
#include <asm/atomic_lse.h> #include <asm/atomic_lse.h>
#include <asm/cpucaps.h> #include <asm/cpucaps.h>
__asm__(".arch_extension lse");
extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS]; extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS];
extern struct static_key_false arm64_const_caps_ready; extern struct static_key_false arm64_const_caps_ready;
...@@ -34,9 +34,9 @@ static inline bool system_uses_lse_atomics(void) ...@@ -34,9 +34,9 @@ static inline bool system_uses_lse_atomics(void)
/* In-line patching at runtime */ /* In-line patching at runtime */
#define ARM64_LSE_ATOMIC_INSN(llsc, lse) \ #define ARM64_LSE_ATOMIC_INSN(llsc, lse) \
ALTERNATIVE(llsc, lse, ARM64_HAS_LSE_ATOMICS) ALTERNATIVE(llsc, __LSE_PREAMBLE lse, ARM64_HAS_LSE_ATOMICS)
#else /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */ #else /* CONFIG_ARM64_LSE_ATOMICS */
static inline bool system_uses_lse_atomics(void) { return false; } static inline bool system_uses_lse_atomics(void) { return false; }
...@@ -44,5 +44,5 @@ static inline bool system_uses_lse_atomics(void) { return false; } ...@@ -44,5 +44,5 @@ static inline bool system_uses_lse_atomics(void) { return false; }
#define ARM64_LSE_ATOMIC_INSN(llsc, lse) llsc #define ARM64_LSE_ATOMIC_INSN(llsc, lse) llsc
#endif /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */ #endif /* CONFIG_ARM64_LSE_ATOMICS */
#endif /* __ASM_LSE_H */ #endif /* __ASM_LSE_H */
...@@ -29,52 +29,11 @@ typedef struct { ...@@ -29,52 +29,11 @@ typedef struct {
*/ */
#define ASID(mm) ((mm)->context.id.counter & 0xffff) #define ASID(mm) ((mm)->context.id.counter & 0xffff)
static inline bool arm64_kernel_unmapped_at_el0(void) extern bool arm64_use_ng_mappings;
{
return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0) &&
cpus_have_const_cap(ARM64_UNMAP_KERNEL_AT_EL0);
}
static inline bool arm64_kernel_use_ng_mappings(void) static inline bool arm64_kernel_unmapped_at_el0(void)
{ {
bool tx1_bug; return arm64_use_ng_mappings;
/* What's a kpti? Use global mappings if we don't know. */
if (!IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0))
return false;
/*
* Note: this function is called before the CPU capabilities have
* been configured, so our early mappings will be global. If we
* later determine that kpti is required, then
* kpti_install_ng_mappings() will make them non-global.
*/
if (arm64_kernel_unmapped_at_el0())
return true;
if (!IS_ENABLED(CONFIG_RANDOMIZE_BASE))
return false;
/*
* KASLR is enabled so we're going to be enabling kpti on non-broken
* CPUs regardless of their susceptibility to Meltdown. Rather
* than force everybody to go through the G -> nG dance later on,
* just put down non-global mappings from the beginning.
*/
if (!IS_ENABLED(CONFIG_CAVIUM_ERRATUM_27456)) {
tx1_bug = false;
#ifndef MODULE
} else if (!static_branch_likely(&arm64_const_caps_ready)) {
extern const struct midr_range cavium_erratum_27456_cpus[];
tx1_bug = is_midr_in_range_list(read_cpuid_id(),
cavium_erratum_27456_cpus);
#endif
} else {
tx1_bug = __cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_27456);
}
return !tx1_bug && kaslr_offset() > 0;
} }
typedef void (*bp_hardening_cb_t)(void); typedef void (*bp_hardening_cb_t)(void);
...@@ -128,6 +87,7 @@ extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, ...@@ -128,6 +87,7 @@ extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
pgprot_t prot, bool page_mappings_only); pgprot_t prot, bool page_mappings_only);
extern void *fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot); extern void *fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot);
extern void mark_linear_text_alias_ro(void); extern void mark_linear_text_alias_ro(void);
extern bool kaslr_requires_kpti(void);
#define INIT_MM_CONTEXT(name) \ #define INIT_MM_CONTEXT(name) \
.pgd = init_pg_dir, .pgd = init_pg_dir,
......
...@@ -110,6 +110,7 @@ ...@@ -110,6 +110,7 @@
#define PUD_TABLE_BIT (_AT(pudval_t, 1) << 1) #define PUD_TABLE_BIT (_AT(pudval_t, 1) << 1)
#define PUD_TYPE_MASK (_AT(pudval_t, 3) << 0) #define PUD_TYPE_MASK (_AT(pudval_t, 3) << 0)
#define PUD_TYPE_SECT (_AT(pudval_t, 1) << 0) #define PUD_TYPE_SECT (_AT(pudval_t, 1) << 0)
#define PUD_SECT_RDONLY (_AT(pudval_t, 1) << 7) /* AP[2] */
/* /*
* Level 2 descriptor (PMD). * Level 2 descriptor (PMD).
...@@ -292,6 +293,8 @@ ...@@ -292,6 +293,8 @@
#define TCR_HD (UL(1) << 40) #define TCR_HD (UL(1) << 40)
#define TCR_NFD0 (UL(1) << 53) #define TCR_NFD0 (UL(1) << 53)
#define TCR_NFD1 (UL(1) << 54) #define TCR_NFD1 (UL(1) << 54)
#define TCR_E0PD0 (UL(1) << 55)
#define TCR_E0PD1 (UL(1) << 56)
/* /*
* TTBR. * TTBR.
......
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
#define _PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) #define _PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
#define _PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) #define _PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
#define PTE_MAYBE_NG (arm64_kernel_use_ng_mappings() ? PTE_NG : 0) #define PTE_MAYBE_NG (arm64_kernel_unmapped_at_el0() ? PTE_NG : 0)
#define PMD_MAYBE_NG (arm64_kernel_use_ng_mappings() ? PMD_SECT_NG : 0) #define PMD_MAYBE_NG (arm64_kernel_unmapped_at_el0() ? PMD_SECT_NG : 0)
#define PROT_DEFAULT (_PROT_DEFAULT | PTE_MAYBE_NG) #define PROT_DEFAULT (_PROT_DEFAULT | PTE_MAYBE_NG)
#define PROT_SECT_DEFAULT (_PROT_SECT_DEFAULT | PMD_MAYBE_NG) #define PROT_SECT_DEFAULT (_PROT_SECT_DEFAULT | PMD_MAYBE_NG)
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <asm-generic/sections.h> #include <asm-generic/sections.h>
extern char __alt_instructions[], __alt_instructions_end[]; extern char __alt_instructions[], __alt_instructions_end[];
extern char __exception_text_start[], __exception_text_end[];
extern char __hibernate_exit_text_start[], __hibernate_exit_text_end[]; extern char __hibernate_exit_text_start[], __hibernate_exit_text_end[];
extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[]; extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[];
extern char __hyp_text_start[], __hyp_text_end[]; extern char __hyp_text_start[], __hyp_text_end[];
......
...@@ -26,6 +26,8 @@ DECLARE_PER_CPU(bool, fpsimd_context_busy); ...@@ -26,6 +26,8 @@ DECLARE_PER_CPU(bool, fpsimd_context_busy);
static __must_check inline bool may_use_simd(void) static __must_check inline bool may_use_simd(void)
{ {
/* /*
* We must make sure that the SVE has been initialized properly
* before using the SIMD in kernel.
* fpsimd_context_busy is only set while preemption is disabled, * fpsimd_context_busy is only set while preemption is disabled,
* and is clear whenever preemption is enabled. Since * and is clear whenever preemption is enabled. Since
* this_cpu_read() is atomic w.r.t. preemption, fpsimd_context_busy * this_cpu_read() is atomic w.r.t. preemption, fpsimd_context_busy
...@@ -33,7 +35,9 @@ static __must_check inline bool may_use_simd(void) ...@@ -33,7 +35,9 @@ static __must_check inline bool may_use_simd(void)
* migrated, and if it's clear we cannot be migrated to a CPU * migrated, and if it's clear we cannot be migrated to a CPU
* where it is set. * where it is set.
*/ */
return !in_irq() && !irqs_disabled() && !in_nmi() && return !WARN_ON(!system_capabilities_finalized()) &&
system_supports_fpsimd() &&
!in_irq() && !irqs_disabled() && !in_nmi() &&
!this_cpu_read(fpsimd_context_busy); !this_cpu_read(fpsimd_context_busy);
} }
......
...@@ -146,6 +146,7 @@ ...@@ -146,6 +146,7 @@
#define SYS_ID_ISAR4_EL1 sys_reg(3, 0, 0, 2, 4) #define SYS_ID_ISAR4_EL1 sys_reg(3, 0, 0, 2, 4)
#define SYS_ID_ISAR5_EL1 sys_reg(3, 0, 0, 2, 5) #define SYS_ID_ISAR5_EL1 sys_reg(3, 0, 0, 2, 5)
#define SYS_ID_MMFR4_EL1 sys_reg(3, 0, 0, 2, 6) #define SYS_ID_MMFR4_EL1 sys_reg(3, 0, 0, 2, 6)
#define SYS_ID_ISAR6_EL1 sys_reg(3, 0, 0, 2, 7)
#define SYS_MVFR0_EL1 sys_reg(3, 0, 0, 3, 0) #define SYS_MVFR0_EL1 sys_reg(3, 0, 0, 3, 0)
#define SYS_MVFR1_EL1 sys_reg(3, 0, 0, 3, 1) #define SYS_MVFR1_EL1 sys_reg(3, 0, 0, 3, 1)
...@@ -365,6 +366,9 @@ ...@@ -365,6 +366,9 @@
#define SYS_CTR_EL0 sys_reg(3, 3, 0, 0, 1) #define SYS_CTR_EL0 sys_reg(3, 3, 0, 0, 1)
#define SYS_DCZID_EL0 sys_reg(3, 3, 0, 0, 7) #define SYS_DCZID_EL0 sys_reg(3, 3, 0, 0, 7)
#define SYS_RNDR_EL0 sys_reg(3, 3, 2, 4, 0)
#define SYS_RNDRRS_EL0 sys_reg(3, 3, 2, 4, 1)
#define SYS_PMCR_EL0 sys_reg(3, 3, 9, 12, 0) #define SYS_PMCR_EL0 sys_reg(3, 3, 9, 12, 0)
#define SYS_PMCNTENSET_EL0 sys_reg(3, 3, 9, 12, 1) #define SYS_PMCNTENSET_EL0 sys_reg(3, 3, 9, 12, 1)
#define SYS_PMCNTENCLR_EL0 sys_reg(3, 3, 9, 12, 2) #define SYS_PMCNTENCLR_EL0 sys_reg(3, 3, 9, 12, 2)
...@@ -538,7 +542,20 @@ ...@@ -538,7 +542,20 @@
SCTLR_EL1_NTWE | SCTLR_ELx_IESB | SCTLR_EL1_SPAN |\ SCTLR_EL1_NTWE | SCTLR_ELx_IESB | SCTLR_EL1_SPAN |\
ENDIAN_SET_EL1 | SCTLR_EL1_UCI | SCTLR_EL1_RES1) ENDIAN_SET_EL1 | SCTLR_EL1_UCI | SCTLR_EL1_RES1)
/* MAIR_ELx memory attributes (used by Linux) */
#define MAIR_ATTR_DEVICE_nGnRnE UL(0x00)
#define MAIR_ATTR_DEVICE_nGnRE UL(0x04)
#define MAIR_ATTR_DEVICE_GRE UL(0x0c)
#define MAIR_ATTR_NORMAL_NC UL(0x44)
#define MAIR_ATTR_NORMAL_WT UL(0xbb)
#define MAIR_ATTR_NORMAL UL(0xff)
#define MAIR_ATTR_MASK UL(0xff)
/* Position the attr at the correct index */
#define MAIR_ATTRIDX(attr, idx) ((attr) << ((idx) * 8))
/* id_aa64isar0 */ /* id_aa64isar0 */
#define ID_AA64ISAR0_RNDR_SHIFT 60
#define ID_AA64ISAR0_TS_SHIFT 52 #define ID_AA64ISAR0_TS_SHIFT 52
#define ID_AA64ISAR0_FHM_SHIFT 48 #define ID_AA64ISAR0_FHM_SHIFT 48
#define ID_AA64ISAR0_DP_SHIFT 44 #define ID_AA64ISAR0_DP_SHIFT 44
...@@ -553,6 +570,10 @@ ...@@ -553,6 +570,10 @@
#define ID_AA64ISAR0_AES_SHIFT 4 #define ID_AA64ISAR0_AES_SHIFT 4
/* id_aa64isar1 */ /* id_aa64isar1 */
#define ID_AA64ISAR1_I8MM_SHIFT 52
#define ID_AA64ISAR1_DGH_SHIFT 48
#define ID_AA64ISAR1_BF16_SHIFT 44
#define ID_AA64ISAR1_SPECRES_SHIFT 40
#define ID_AA64ISAR1_SB_SHIFT 36 #define ID_AA64ISAR1_SB_SHIFT 36
#define ID_AA64ISAR1_FRINTTS_SHIFT 32 #define ID_AA64ISAR1_FRINTTS_SHIFT 32
#define ID_AA64ISAR1_GPI_SHIFT 28 #define ID_AA64ISAR1_GPI_SHIFT 28
...@@ -605,12 +626,20 @@ ...@@ -605,12 +626,20 @@
#define ID_AA64PFR1_SSBS_PSTATE_INSNS 2 #define ID_AA64PFR1_SSBS_PSTATE_INSNS 2
/* id_aa64zfr0 */ /* id_aa64zfr0 */
#define ID_AA64ZFR0_F64MM_SHIFT 56
#define ID_AA64ZFR0_F32MM_SHIFT 52
#define ID_AA64ZFR0_I8MM_SHIFT 44
#define ID_AA64ZFR0_SM4_SHIFT 40 #define ID_AA64ZFR0_SM4_SHIFT 40
#define ID_AA64ZFR0_SHA3_SHIFT 32 #define ID_AA64ZFR0_SHA3_SHIFT 32
#define ID_AA64ZFR0_BF16_SHIFT 20
#define ID_AA64ZFR0_BITPERM_SHIFT 16 #define ID_AA64ZFR0_BITPERM_SHIFT 16
#define ID_AA64ZFR0_AES_SHIFT 4 #define ID_AA64ZFR0_AES_SHIFT 4
#define ID_AA64ZFR0_SVEVER_SHIFT 0 #define ID_AA64ZFR0_SVEVER_SHIFT 0
#define ID_AA64ZFR0_F64MM 0x1
#define ID_AA64ZFR0_F32MM 0x1
#define ID_AA64ZFR0_I8MM 0x1
#define ID_AA64ZFR0_BF16 0x1
#define ID_AA64ZFR0_SM4 0x1 #define ID_AA64ZFR0_SM4 0x1
#define ID_AA64ZFR0_SHA3 0x1 #define ID_AA64ZFR0_SHA3 0x1
#define ID_AA64ZFR0_BITPERM 0x1 #define ID_AA64ZFR0_BITPERM 0x1
...@@ -655,6 +684,7 @@ ...@@ -655,6 +684,7 @@
#define ID_AA64MMFR1_VMIDBITS_16 2 #define ID_AA64MMFR1_VMIDBITS_16 2
/* id_aa64mmfr2 */ /* id_aa64mmfr2 */
#define ID_AA64MMFR2_E0PD_SHIFT 60
#define ID_AA64MMFR2_FWB_SHIFT 40 #define ID_AA64MMFR2_FWB_SHIFT 40
#define ID_AA64MMFR2_AT_SHIFT 32 #define ID_AA64MMFR2_AT_SHIFT 32
#define ID_AA64MMFR2_LVA_SHIFT 16 #define ID_AA64MMFR2_LVA_SHIFT 16
...@@ -679,6 +709,14 @@ ...@@ -679,6 +709,14 @@
#define ID_ISAR5_AES_SHIFT 4 #define ID_ISAR5_AES_SHIFT 4
#define ID_ISAR5_SEVL_SHIFT 0 #define ID_ISAR5_SEVL_SHIFT 0
#define ID_ISAR6_I8MM_SHIFT 24
#define ID_ISAR6_BF16_SHIFT 20
#define ID_ISAR6_SPECRES_SHIFT 16
#define ID_ISAR6_SB_SHIFT 12
#define ID_ISAR6_FHM_SHIFT 8
#define ID_ISAR6_DP_SHIFT 4
#define ID_ISAR6_JSCVT_SHIFT 0
#define MVFR0_FPROUND_SHIFT 28 #define MVFR0_FPROUND_SHIFT 28
#define MVFR0_FPSHVEC_SHIFT 24 #define MVFR0_FPSHVEC_SHIFT 24
#define MVFR0_FPSQRT_SHIFT 20 #define MVFR0_FPSQRT_SHIFT 20
......
...@@ -65,5 +65,13 @@ ...@@ -65,5 +65,13 @@
#define HWCAP2_SVESM4 (1 << 6) #define HWCAP2_SVESM4 (1 << 6)
#define HWCAP2_FLAGM2 (1 << 7) #define HWCAP2_FLAGM2 (1 << 7)
#define HWCAP2_FRINT (1 << 8) #define HWCAP2_FRINT (1 << 8)
#define HWCAP2_SVEI8MM (1 << 9)
#define HWCAP2_SVEF32MM (1 << 10)
#define HWCAP2_SVEF64MM (1 << 11)
#define HWCAP2_SVEBF16 (1 << 12)
#define HWCAP2_I8MM (1 << 13)
#define HWCAP2_BF16 (1 << 14)
#define HWCAP2_DGH (1 << 15)
#define HWCAP2_RNG (1 << 16)
#endif /* _UAPI__ASM_HWCAP_H */ #endif /* _UAPI__ASM_HWCAP_H */
...@@ -274,7 +274,7 @@ int apei_claim_sea(struct pt_regs *regs) ...@@ -274,7 +274,7 @@ int apei_claim_sea(struct pt_regs *regs)
if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES)) if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
return err; return err;
current_flags = arch_local_save_flags(); current_flags = local_daif_save_flags();
/* /*
* SEA can interrupt SError, mask it and describe this as an NMI so * SEA can interrupt SError, mask it and describe this as an NMI so
......
...@@ -618,7 +618,8 @@ static struct insn_emulation_ops setend_ops = { ...@@ -618,7 +618,8 @@ static struct insn_emulation_ops setend_ops = {
}; };
/* /*
* Invoked as late_initcall, since not needed before init spawned. * Invoked as core_initcall, which guarantees that the instruction
* emulation is ready for userspace.
*/ */
static int __init armv8_deprecated_init(void) static int __init armv8_deprecated_init(void)
{ {
......
...@@ -42,11 +42,11 @@ ENTRY(__cpu_soft_restart) ...@@ -42,11 +42,11 @@ ENTRY(__cpu_soft_restart)
mov x0, #HVC_SOFT_RESTART mov x0, #HVC_SOFT_RESTART
hvc #0 // no return hvc #0 // no return
1: mov x18, x1 // entry 1: mov x8, x1 // entry
mov x0, x2 // arg0 mov x0, x2 // arg0
mov x1, x3 // arg1 mov x1, x3 // arg1
mov x2, x4 // arg2 mov x2, x4 // arg2
br x18 br x8
ENDPROC(__cpu_soft_restart) ENDPROC(__cpu_soft_restart)
.popsection .popsection
...@@ -548,6 +548,8 @@ static const struct midr_range spectre_v2_safe_list[] = { ...@@ -548,6 +548,8 @@ static const struct midr_range spectre_v2_safe_list[] = {
MIDR_ALL_VERSIONS(MIDR_CORTEX_A55), MIDR_ALL_VERSIONS(MIDR_CORTEX_A55),
MIDR_ALL_VERSIONS(MIDR_BRAHMA_B53), MIDR_ALL_VERSIONS(MIDR_BRAHMA_B53),
MIDR_ALL_VERSIONS(MIDR_HISI_TSV110), MIDR_ALL_VERSIONS(MIDR_HISI_TSV110),
MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_3XX_SILVER),
MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_SILVER),
{ /* sentinel */ } { /* sentinel */ }
}; };
...@@ -757,6 +759,20 @@ static const struct arm64_cpu_capabilities erratum_843419_list[] = { ...@@ -757,6 +759,20 @@ static const struct arm64_cpu_capabilities erratum_843419_list[] = {
}; };
#endif #endif
#ifdef CONFIG_ARM64_WORKAROUND_SPECULATIVE_AT_VHE
static const struct midr_range erratum_speculative_at_vhe_list[] = {
#ifdef CONFIG_ARM64_ERRATUM_1165522
/* Cortex A76 r0p0 to r2p0 */
MIDR_RANGE(MIDR_CORTEX_A76, 0, 0, 2, 0),
#endif
#ifdef CONFIG_ARM64_ERRATUM_1530923
/* Cortex A55 r0p0 to r2p0 */
MIDR_RANGE(MIDR_CORTEX_A55, 0, 0, 2, 0),
#endif
{},
};
#endif
const struct arm64_cpu_capabilities arm64_errata[] = { const struct arm64_cpu_capabilities arm64_errata[] = {
#ifdef CONFIG_ARM64_WORKAROUND_CLEAN_CACHE #ifdef CONFIG_ARM64_WORKAROUND_CLEAN_CACHE
{ {
...@@ -883,12 +899,11 @@ const struct arm64_cpu_capabilities arm64_errata[] = { ...@@ -883,12 +899,11 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
ERRATA_MIDR_RANGE_LIST(erratum_1418040_list), ERRATA_MIDR_RANGE_LIST(erratum_1418040_list),
}, },
#endif #endif
#ifdef CONFIG_ARM64_ERRATUM_1165522 #ifdef CONFIG_ARM64_WORKAROUND_SPECULATIVE_AT_VHE
{ {
/* Cortex-A76 r0p0 to r2p0 */ .desc = "ARM errata 1165522, 1530923",
.desc = "ARM erratum 1165522", .capability = ARM64_WORKAROUND_SPECULATIVE_AT_VHE,
.capability = ARM64_WORKAROUND_1165522, ERRATA_MIDR_RANGE_LIST(erratum_speculative_at_vhe_list),
ERRATA_MIDR_RANGE(MIDR_CORTEX_A76, 0, 0, 2, 0),
}, },
#endif #endif
#ifdef CONFIG_ARM64_ERRATUM_1463225 #ifdef CONFIG_ARM64_ERRATUM_1463225
...@@ -925,7 +940,7 @@ const struct arm64_cpu_capabilities arm64_errata[] = { ...@@ -925,7 +940,7 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
#ifdef CONFIG_ARM64_ERRATUM_1319367 #ifdef CONFIG_ARM64_ERRATUM_1319367
{ {
.desc = "ARM erratum 1319367", .desc = "ARM erratum 1319367",
.capability = ARM64_WORKAROUND_1319367, .capability = ARM64_WORKAROUND_SPECULATIVE_AT_NVHE,
ERRATA_MIDR_RANGE_LIST(ca57_a72), ERRATA_MIDR_RANGE_LIST(ca57_a72),
}, },
#endif #endif
......
This diff is collapsed.
...@@ -84,6 +84,14 @@ static const char *const hwcap_str[] = { ...@@ -84,6 +84,14 @@ static const char *const hwcap_str[] = {
"svesm4", "svesm4",
"flagm2", "flagm2",
"frint", "frint",
"svei8mm",
"svef32mm",
"svef64mm",
"svebf16",
"i8mm",
"bf16",
"dgh",
"rng",
NULL NULL
}; };
...@@ -360,6 +368,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) ...@@ -360,6 +368,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1); info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1); info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1); info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
info->reg_id_isar6 = read_cpuid(ID_ISAR6_EL1);
info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1); info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1); info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1); info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
......
...@@ -36,14 +36,14 @@ static void notrace el1_pc(struct pt_regs *regs, unsigned long esr) ...@@ -36,14 +36,14 @@ static void notrace el1_pc(struct pt_regs *regs, unsigned long esr)
} }
NOKPROBE_SYMBOL(el1_pc); NOKPROBE_SYMBOL(el1_pc);
static void el1_undef(struct pt_regs *regs) static void notrace el1_undef(struct pt_regs *regs)
{ {
local_daif_inherit(regs); local_daif_inherit(regs);
do_undefinstr(regs); do_undefinstr(regs);
} }
NOKPROBE_SYMBOL(el1_undef); NOKPROBE_SYMBOL(el1_undef);
static void el1_inv(struct pt_regs *regs, unsigned long esr) static void notrace el1_inv(struct pt_regs *regs, unsigned long esr)
{ {
local_daif_inherit(regs); local_daif_inherit(regs);
bad_mode(regs, 0, esr); bad_mode(regs, 0, esr);
...@@ -215,7 +215,7 @@ static void notrace el0_svc(struct pt_regs *regs) ...@@ -215,7 +215,7 @@ static void notrace el0_svc(struct pt_regs *regs)
if (system_uses_irq_prio_masking()) if (system_uses_irq_prio_masking())
gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET); gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET);
el0_svc_handler(regs); do_el0_svc(regs);
} }
NOKPROBE_SYMBOL(el0_svc); NOKPROBE_SYMBOL(el0_svc);
...@@ -281,7 +281,7 @@ static void notrace el0_svc_compat(struct pt_regs *regs) ...@@ -281,7 +281,7 @@ static void notrace el0_svc_compat(struct pt_regs *regs)
if (system_uses_irq_prio_masking()) if (system_uses_irq_prio_masking())
gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET); gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET);
el0_svc_compat_handler(regs); do_el0_svc_compat(regs);
} }
NOKPROBE_SYMBOL(el0_svc_compat); NOKPROBE_SYMBOL(el0_svc_compat);
......
...@@ -60,16 +60,16 @@ ...@@ -60,16 +60,16 @@
.macro kernel_ventry, el, label, regsize = 64 .macro kernel_ventry, el, label, regsize = 64
.align 7 .align 7
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
alternative_if ARM64_UNMAP_KERNEL_AT_EL0
.if \el == 0 .if \el == 0
alternative_if ARM64_UNMAP_KERNEL_AT_EL0
.if \regsize == 64 .if \regsize == 64
mrs x30, tpidrro_el0 mrs x30, tpidrro_el0
msr tpidrro_el0, xzr msr tpidrro_el0, xzr
.else .else
mov x30, xzr mov x30, xzr
.endif .endif
.endif
alternative_else_nop_endif alternative_else_nop_endif
.endif
#endif #endif
sub sp, sp, #S_FRAME_SIZE sub sp, sp, #S_FRAME_SIZE
...@@ -167,9 +167,13 @@ alternative_cb_end ...@@ -167,9 +167,13 @@ alternative_cb_end
.if \el == 0 .if \el == 0
clear_gp_regs clear_gp_regs
mrs x21, sp_el0 mrs x21, sp_el0
ldr_this_cpu tsk, __entry_task, x20 // Ensure MDSCR_EL1.SS is clear, ldr_this_cpu tsk, __entry_task, x20
ldr x19, [tsk, #TSK_TI_FLAGS] // since we can unmask debug msr sp_el0, tsk
disable_step_tsk x19, x20 // exceptions when scheduling.
// Ensure MDSCR_EL1.SS is clear, since we can unmask debug exceptions
// when scheduling.
ldr x19, [tsk, #TSK_TI_FLAGS]
disable_step_tsk x19, x20
apply_ssbd 1, x22, x23 apply_ssbd 1, x22, x23
...@@ -232,13 +236,6 @@ alternative_else_nop_endif ...@@ -232,13 +236,6 @@ alternative_else_nop_endif
str w21, [sp, #S_SYSCALLNO] str w21, [sp, #S_SYSCALLNO]
.endif .endif
/*
* Set sp_el0 to current thread_info.
*/
.if \el == 0
msr sp_el0, tsk
.endif
/* Save pmr */ /* Save pmr */
alternative_if ARM64_HAS_IRQ_PRIO_MASKING alternative_if ARM64_HAS_IRQ_PRIO_MASKING
mrs_s x20, SYS_ICC_PMR_EL1 mrs_s x20, SYS_ICC_PMR_EL1
...@@ -653,6 +650,7 @@ el0_sync: ...@@ -653,6 +650,7 @@ el0_sync:
mov x0, sp mov x0, sp
bl el0_sync_handler bl el0_sync_handler
b ret_to_user b ret_to_user
ENDPROC(el0_sync)
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.align 6 .align 6
...@@ -661,16 +659,18 @@ el0_sync_compat: ...@@ -661,16 +659,18 @@ el0_sync_compat:
mov x0, sp mov x0, sp
bl el0_sync_compat_handler bl el0_sync_compat_handler
b ret_to_user b ret_to_user
ENDPROC(el0_sync) ENDPROC(el0_sync_compat)
.align 6 .align 6
el0_irq_compat: el0_irq_compat:
kernel_entry 0, 32 kernel_entry 0, 32
b el0_irq_naked b el0_irq_naked
ENDPROC(el0_irq_compat)
el0_error_compat: el0_error_compat:
kernel_entry 0, 32 kernel_entry 0, 32
b el0_error_naked b el0_error_naked
ENDPROC(el0_error_compat)
#endif #endif
.align 6 .align 6
......
...@@ -269,6 +269,7 @@ static void sve_free(struct task_struct *task) ...@@ -269,6 +269,7 @@ static void sve_free(struct task_struct *task)
*/ */
static void task_fpsimd_load(void) static void task_fpsimd_load(void)
{ {
WARN_ON(!system_supports_fpsimd());
WARN_ON(!have_cpu_fpsimd_context()); WARN_ON(!have_cpu_fpsimd_context());
if (system_supports_sve() && test_thread_flag(TIF_SVE)) if (system_supports_sve() && test_thread_flag(TIF_SVE))
...@@ -289,6 +290,7 @@ static void fpsimd_save(void) ...@@ -289,6 +290,7 @@ static void fpsimd_save(void)
this_cpu_ptr(&fpsimd_last_state); this_cpu_ptr(&fpsimd_last_state);
/* set by fpsimd_bind_task_to_cpu() or fpsimd_bind_state_to_cpu() */ /* set by fpsimd_bind_task_to_cpu() or fpsimd_bind_state_to_cpu() */
WARN_ON(!system_supports_fpsimd());
WARN_ON(!have_cpu_fpsimd_context()); WARN_ON(!have_cpu_fpsimd_context());
if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) { if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) {
...@@ -1092,6 +1094,7 @@ void fpsimd_bind_task_to_cpu(void) ...@@ -1092,6 +1094,7 @@ void fpsimd_bind_task_to_cpu(void)
struct fpsimd_last_state_struct *last = struct fpsimd_last_state_struct *last =
this_cpu_ptr(&fpsimd_last_state); this_cpu_ptr(&fpsimd_last_state);
WARN_ON(!system_supports_fpsimd());
last->st = &current->thread.uw.fpsimd_state; last->st = &current->thread.uw.fpsimd_state;
last->sve_state = current->thread.sve_state; last->sve_state = current->thread.sve_state;
last->sve_vl = current->thread.sve_vl; last->sve_vl = current->thread.sve_vl;
...@@ -1114,6 +1117,7 @@ void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st, void *sve_state, ...@@ -1114,6 +1117,7 @@ void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st, void *sve_state,
struct fpsimd_last_state_struct *last = struct fpsimd_last_state_struct *last =
this_cpu_ptr(&fpsimd_last_state); this_cpu_ptr(&fpsimd_last_state);
WARN_ON(!system_supports_fpsimd());
WARN_ON(!in_softirq() && !irqs_disabled()); WARN_ON(!in_softirq() && !irqs_disabled());
last->st = st; last->st = st;
...@@ -1128,8 +1132,19 @@ void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st, void *sve_state, ...@@ -1128,8 +1132,19 @@ void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st, void *sve_state,
*/ */
void fpsimd_restore_current_state(void) void fpsimd_restore_current_state(void)
{ {
if (!system_supports_fpsimd()) /*
* For the tasks that were created before we detected the absence of
* FP/SIMD, the TIF_FOREIGN_FPSTATE could be set via fpsimd_thread_switch(),
* e.g, init. This could be then inherited by the children processes.
* If we later detect that the system doesn't support FP/SIMD,
* we must clear the flag for all the tasks to indicate that the
* FPSTATE is clean (as we can't have one) to avoid looping for ever in
* do_notify_resume().
*/
if (!system_supports_fpsimd()) {
clear_thread_flag(TIF_FOREIGN_FPSTATE);
return; return;
}
get_cpu_fpsimd_context(); get_cpu_fpsimd_context();
...@@ -1148,7 +1163,7 @@ void fpsimd_restore_current_state(void) ...@@ -1148,7 +1163,7 @@ void fpsimd_restore_current_state(void)
*/ */
void fpsimd_update_current_state(struct user_fpsimd_state const *state) void fpsimd_update_current_state(struct user_fpsimd_state const *state)
{ {
if (!system_supports_fpsimd()) if (WARN_ON(!system_supports_fpsimd()))
return; return;
get_cpu_fpsimd_context(); get_cpu_fpsimd_context();
...@@ -1179,7 +1194,13 @@ void fpsimd_update_current_state(struct user_fpsimd_state const *state) ...@@ -1179,7 +1194,13 @@ void fpsimd_update_current_state(struct user_fpsimd_state const *state)
void fpsimd_flush_task_state(struct task_struct *t) void fpsimd_flush_task_state(struct task_struct *t)
{ {
t->thread.fpsimd_cpu = NR_CPUS; t->thread.fpsimd_cpu = NR_CPUS;
/*
* If we don't support fpsimd, bail out after we have
* reset the fpsimd_cpu for this task and clear the
* FPSTATE.
*/
if (!system_supports_fpsimd())
return;
barrier(); barrier();
set_tsk_thread_flag(t, TIF_FOREIGN_FPSTATE); set_tsk_thread_flag(t, TIF_FOREIGN_FPSTATE);
...@@ -1193,6 +1214,7 @@ void fpsimd_flush_task_state(struct task_struct *t) ...@@ -1193,6 +1214,7 @@ void fpsimd_flush_task_state(struct task_struct *t)
*/ */
static void fpsimd_flush_cpu_state(void) static void fpsimd_flush_cpu_state(void)
{ {
WARN_ON(!system_supports_fpsimd());
__this_cpu_write(fpsimd_last_state.st, NULL); __this_cpu_write(fpsimd_last_state.st, NULL);
set_thread_flag(TIF_FOREIGN_FPSTATE); set_thread_flag(TIF_FOREIGN_FPSTATE);
} }
...@@ -1203,6 +1225,8 @@ static void fpsimd_flush_cpu_state(void) ...@@ -1203,6 +1225,8 @@ static void fpsimd_flush_cpu_state(void)
*/ */
void fpsimd_save_and_flush_cpu_state(void) void fpsimd_save_and_flush_cpu_state(void)
{ {
if (!system_supports_fpsimd())
return;
WARN_ON(preemptible()); WARN_ON(preemptible());
__get_cpu_fpsimd_context(); __get_cpu_fpsimd_context();
fpsimd_save(); fpsimd_save();
......
...@@ -182,78 +182,79 @@ int arch_hibernation_header_restore(void *addr) ...@@ -182,78 +182,79 @@ int arch_hibernation_header_restore(void *addr)
} }
EXPORT_SYMBOL(arch_hibernation_header_restore); EXPORT_SYMBOL(arch_hibernation_header_restore);
/* static int trans_pgd_map_page(pgd_t *trans_pgd, void *page,
* Copies length bytes, starting at src_start into an new page,
* perform cache maintentance, then maps it at the specified address low
* address as executable.
*
* This is used by hibernate to copy the code it needs to execute when
* overwriting the kernel text. This function generates a new set of page
* tables, which it loads into ttbr0.
*
* Length is provided as we probably only want 4K of data, even on a 64K
* page system.
*/
static int create_safe_exec_page(void *src_start, size_t length,
unsigned long dst_addr, unsigned long dst_addr,
phys_addr_t *phys_dst_addr, pgprot_t pgprot)
void *(*allocator)(gfp_t mask),
gfp_t mask)
{ {
int rc = 0;
pgd_t *trans_pgd;
pgd_t *pgdp; pgd_t *pgdp;
pud_t *pudp; pud_t *pudp;
pmd_t *pmdp; pmd_t *pmdp;
pte_t *ptep; pte_t *ptep;
unsigned long dst = (unsigned long)allocator(mask);
if (!dst) {
rc = -ENOMEM;
goto out;
}
memcpy((void *)dst, src_start, length);
__flush_icache_range(dst, dst + length);
trans_pgd = allocator(mask);
if (!trans_pgd) {
rc = -ENOMEM;
goto out;
}
pgdp = pgd_offset_raw(trans_pgd, dst_addr); pgdp = pgd_offset_raw(trans_pgd, dst_addr);
if (pgd_none(READ_ONCE(*pgdp))) { if (pgd_none(READ_ONCE(*pgdp))) {
pudp = allocator(mask); pudp = (void *)get_safe_page(GFP_ATOMIC);
if (!pudp) { if (!pudp)
rc = -ENOMEM; return -ENOMEM;
goto out;
}
pgd_populate(&init_mm, pgdp, pudp); pgd_populate(&init_mm, pgdp, pudp);
} }
pudp = pud_offset(pgdp, dst_addr); pudp = pud_offset(pgdp, dst_addr);
if (pud_none(READ_ONCE(*pudp))) { if (pud_none(READ_ONCE(*pudp))) {
pmdp = allocator(mask); pmdp = (void *)get_safe_page(GFP_ATOMIC);
if (!pmdp) { if (!pmdp)
rc = -ENOMEM; return -ENOMEM;
goto out;
}
pud_populate(&init_mm, pudp, pmdp); pud_populate(&init_mm, pudp, pmdp);
} }
pmdp = pmd_offset(pudp, dst_addr); pmdp = pmd_offset(pudp, dst_addr);
if (pmd_none(READ_ONCE(*pmdp))) { if (pmd_none(READ_ONCE(*pmdp))) {
ptep = allocator(mask); ptep = (void *)get_safe_page(GFP_ATOMIC);
if (!ptep) { if (!ptep)
rc = -ENOMEM; return -ENOMEM;
goto out;
}
pmd_populate_kernel(&init_mm, pmdp, ptep); pmd_populate_kernel(&init_mm, pmdp, ptep);
} }
ptep = pte_offset_kernel(pmdp, dst_addr); ptep = pte_offset_kernel(pmdp, dst_addr);
set_pte(ptep, pfn_pte(virt_to_pfn(dst), PAGE_KERNEL_EXEC)); set_pte(ptep, pfn_pte(virt_to_pfn(page), PAGE_KERNEL_EXEC));
return 0;
}
/*
* Copies length bytes, starting at src_start into an new page,
* perform cache maintenance, then maps it at the specified address low
* address as executable.
*
* This is used by hibernate to copy the code it needs to execute when
* overwriting the kernel text. This function generates a new set of page
* tables, which it loads into ttbr0.
*
* Length is provided as we probably only want 4K of data, even on a 64K
* page system.
*/
static int create_safe_exec_page(void *src_start, size_t length,
unsigned long dst_addr,
phys_addr_t *phys_dst_addr)
{
void *page = (void *)get_safe_page(GFP_ATOMIC);
pgd_t *trans_pgd;
int rc;
if (!page)
return -ENOMEM;
memcpy(page, src_start, length);
__flush_icache_range((unsigned long)page, (unsigned long)page + length);
trans_pgd = (void *)get_safe_page(GFP_ATOMIC);
if (!trans_pgd)
return -ENOMEM;
rc = trans_pgd_map_page(trans_pgd, page, dst_addr,
PAGE_KERNEL_EXEC);
if (rc)
return rc;
/* /*
* Load our new page tables. A strict BBM approach requires that we * Load our new page tables. A strict BBM approach requires that we
...@@ -269,13 +270,12 @@ static int create_safe_exec_page(void *src_start, size_t length, ...@@ -269,13 +270,12 @@ static int create_safe_exec_page(void *src_start, size_t length,
*/ */
cpu_set_reserved_ttbr0(); cpu_set_reserved_ttbr0();
local_flush_tlb_all(); local_flush_tlb_all();
write_sysreg(phys_to_ttbr(virt_to_phys(pgdp)), ttbr0_el1); write_sysreg(phys_to_ttbr(virt_to_phys(trans_pgd)), ttbr0_el1);
isb(); isb();
*phys_dst_addr = virt_to_phys((void *)dst); *phys_dst_addr = virt_to_phys(page);
out: return 0;
return rc;
} }
#define dcache_clean_range(start, end) __flush_dcache_area(start, (end - start)) #define dcache_clean_range(start, end) __flush_dcache_area(start, (end - start))
...@@ -450,7 +450,7 @@ static int copy_pud(pgd_t *dst_pgdp, pgd_t *src_pgdp, unsigned long start, ...@@ -450,7 +450,7 @@ static int copy_pud(pgd_t *dst_pgdp, pgd_t *src_pgdp, unsigned long start,
return -ENOMEM; return -ENOMEM;
} else { } else {
set_pud(dst_pudp, set_pud(dst_pudp,
__pud(pud_val(pud) & ~PMD_SECT_RDONLY)); __pud(pud_val(pud) & ~PUD_SECT_RDONLY));
} }
} while (dst_pudp++, src_pudp++, addr = next, addr != end); } while (dst_pudp++, src_pudp++, addr = next, addr != end);
...@@ -476,6 +476,24 @@ static int copy_page_tables(pgd_t *dst_pgdp, unsigned long start, ...@@ -476,6 +476,24 @@ static int copy_page_tables(pgd_t *dst_pgdp, unsigned long start,
return 0; return 0;
} }
static int trans_pgd_create_copy(pgd_t **dst_pgdp, unsigned long start,
unsigned long end)
{
int rc;
pgd_t *trans_pgd = (pgd_t *)get_safe_page(GFP_ATOMIC);
if (!trans_pgd) {
pr_err("Failed to allocate memory for temporary page tables.\n");
return -ENOMEM;
}
rc = copy_page_tables(trans_pgd, start, end);
if (!rc)
*dst_pgdp = trans_pgd;
return rc;
}
/* /*
* Setup then Resume from the hibernate image using swsusp_arch_suspend_exit(). * Setup then Resume from the hibernate image using swsusp_arch_suspend_exit().
* *
...@@ -484,7 +502,7 @@ static int copy_page_tables(pgd_t *dst_pgdp, unsigned long start, ...@@ -484,7 +502,7 @@ static int copy_page_tables(pgd_t *dst_pgdp, unsigned long start,
*/ */
int swsusp_arch_resume(void) int swsusp_arch_resume(void)
{ {
int rc = 0; int rc;
void *zero_page; void *zero_page;
size_t exit_size; size_t exit_size;
pgd_t *tmp_pg_dir; pgd_t *tmp_pg_dir;
...@@ -497,15 +515,9 @@ int swsusp_arch_resume(void) ...@@ -497,15 +515,9 @@ int swsusp_arch_resume(void)
* Create a second copy of just the linear map, and use this when * Create a second copy of just the linear map, and use this when
* restoring. * restoring.
*/ */
tmp_pg_dir = (pgd_t *)get_safe_page(GFP_ATOMIC); rc = trans_pgd_create_copy(&tmp_pg_dir, PAGE_OFFSET, PAGE_END);
if (!tmp_pg_dir) {
pr_err("Failed to allocate memory for temporary page tables.\n");
rc = -ENOMEM;
goto out;
}
rc = copy_page_tables(tmp_pg_dir, PAGE_OFFSET, PAGE_END);
if (rc) if (rc)
goto out; return rc;
/* /*
* We need a zero page that is zero before & after resume in order to * We need a zero page that is zero before & after resume in order to
...@@ -514,8 +526,7 @@ int swsusp_arch_resume(void) ...@@ -514,8 +526,7 @@ int swsusp_arch_resume(void)
zero_page = (void *)get_safe_page(GFP_ATOMIC); zero_page = (void *)get_safe_page(GFP_ATOMIC);
if (!zero_page) { if (!zero_page) {
pr_err("Failed to allocate zero page.\n"); pr_err("Failed to allocate zero page.\n");
rc = -ENOMEM; return -ENOMEM;
goto out;
} }
/* /*
...@@ -530,11 +541,10 @@ int swsusp_arch_resume(void) ...@@ -530,11 +541,10 @@ int swsusp_arch_resume(void)
*/ */
rc = create_safe_exec_page(__hibernate_exit_text_start, exit_size, rc = create_safe_exec_page(__hibernate_exit_text_start, exit_size,
(unsigned long)hibernate_exit, (unsigned long)hibernate_exit,
&phys_hibernate_exit, &phys_hibernate_exit);
(void *)get_safe_page, GFP_ATOMIC);
if (rc) { if (rc) {
pr_err("Failed to create safe executable page for hibernate_exit code.\n"); pr_err("Failed to create safe executable page for hibernate_exit code.\n");
goto out; return rc;
} }
/* /*
...@@ -561,8 +571,7 @@ int swsusp_arch_resume(void) ...@@ -561,8 +571,7 @@ int swsusp_arch_resume(void)
resume_hdr.reenter_kernel, restore_pblist, resume_hdr.reenter_kernel, restore_pblist,
resume_hdr.__hyp_stub_vectors, virt_to_phys(zero_page)); resume_hdr.__hyp_stub_vectors, virt_to_phys(zero_page));
out: return 0;
return rc;
} }
int hibernate_resume_nonboot_cpu_disable(void) int hibernate_resume_nonboot_cpu_disable(void)
......
...@@ -120,6 +120,17 @@ u64 __init kaslr_early_init(u64 dt_phys) ...@@ -120,6 +120,17 @@ u64 __init kaslr_early_init(u64 dt_phys)
return 0; return 0;
} }
/*
* Mix in any entropy obtainable architecturally, open coded
* since this runs extremely early.
*/
if (__early_cpu_has_rndr()) {
unsigned long raw;
if (__arm64_rndr(&raw))
seed ^= raw;
}
if (!seed) { if (!seed) {
kaslr_status = KASLR_DISABLED_NO_SEED; kaslr_status = KASLR_DISABLED_NO_SEED;
return 0; return 0;
......
...@@ -47,10 +47,6 @@ static void *image_load(struct kimage *image, ...@@ -47,10 +47,6 @@ static void *image_load(struct kimage *image,
struct kexec_segment *kernel_segment; struct kexec_segment *kernel_segment;
int ret; int ret;
/* We don't support crash kernels yet. */
if (image->type == KEXEC_TYPE_CRASH)
return ERR_PTR(-EOPNOTSUPP);
/* /*
* We require a kernel with an unambiguous Image header. Per * We require a kernel with an unambiguous Image header. Per
* Documentation/arm64/booting.rst, this is the case when image_size * Documentation/arm64/booting.rst, this is the case when image_size
......
...@@ -160,18 +160,6 @@ void machine_kexec(struct kimage *kimage) ...@@ -160,18 +160,6 @@ void machine_kexec(struct kimage *kimage)
kexec_image_info(kimage); kexec_image_info(kimage);
pr_debug("%s:%d: control_code_page: %p\n", __func__, __LINE__,
kimage->control_code_page);
pr_debug("%s:%d: reboot_code_buffer_phys: %pa\n", __func__, __LINE__,
&reboot_code_buffer_phys);
pr_debug("%s:%d: reboot_code_buffer: %p\n", __func__, __LINE__,
reboot_code_buffer);
pr_debug("%s:%d: relocate_new_kernel: %p\n", __func__, __LINE__,
arm64_relocate_new_kernel);
pr_debug("%s:%d: relocate_new_kernel_size: 0x%lx(%lu) bytes\n",
__func__, __LINE__, arm64_relocate_new_kernel_size,
arm64_relocate_new_kernel_size);
/* /*
* Copy arm64_relocate_new_kernel to the reboot_code_buffer for use * Copy arm64_relocate_new_kernel to the reboot_code_buffer for use
* after the kernel is shut down. * after the kernel is shut down.
......
...@@ -17,12 +17,15 @@ ...@@ -17,12 +17,15 @@
#include <linux/memblock.h> #include <linux/memblock.h>
#include <linux/of_fdt.h> #include <linux/of_fdt.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
/* relevant device tree properties */ /* relevant device tree properties */
#define FDT_PROP_KEXEC_ELFHDR "linux,elfcorehdr"
#define FDT_PROP_MEM_RANGE "linux,usable-memory-range"
#define FDT_PROP_INITRD_START "linux,initrd-start" #define FDT_PROP_INITRD_START "linux,initrd-start"
#define FDT_PROP_INITRD_END "linux,initrd-end" #define FDT_PROP_INITRD_END "linux,initrd-end"
#define FDT_PROP_BOOTARGS "bootargs" #define FDT_PROP_BOOTARGS "bootargs"
...@@ -40,6 +43,10 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image) ...@@ -40,6 +43,10 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
vfree(image->arch.dtb); vfree(image->arch.dtb);
image->arch.dtb = NULL; image->arch.dtb = NULL;
vfree(image->arch.elf_headers);
image->arch.elf_headers = NULL;
image->arch.elf_headers_sz = 0;
return kexec_image_post_load_cleanup_default(image); return kexec_image_post_load_cleanup_default(image);
} }
...@@ -55,6 +62,31 @@ static int setup_dtb(struct kimage *image, ...@@ -55,6 +62,31 @@ static int setup_dtb(struct kimage *image,
off = ret; off = ret;
ret = fdt_delprop(dtb, off, FDT_PROP_KEXEC_ELFHDR);
if (ret && ret != -FDT_ERR_NOTFOUND)
goto out;
ret = fdt_delprop(dtb, off, FDT_PROP_MEM_RANGE);
if (ret && ret != -FDT_ERR_NOTFOUND)
goto out;
if (image->type == KEXEC_TYPE_CRASH) {
/* add linux,elfcorehdr */
ret = fdt_appendprop_addrrange(dtb, 0, off,
FDT_PROP_KEXEC_ELFHDR,
image->arch.elf_headers_mem,
image->arch.elf_headers_sz);
if (ret)
return (ret == -FDT_ERR_NOSPACE ? -ENOMEM : -EINVAL);
/* add linux,usable-memory-range */
ret = fdt_appendprop_addrrange(dtb, 0, off,
FDT_PROP_MEM_RANGE,
crashk_res.start,
crashk_res.end - crashk_res.start + 1);
if (ret)
return (ret == -FDT_ERR_NOSPACE ? -ENOMEM : -EINVAL);
}
/* add bootargs */ /* add bootargs */
if (cmdline) { if (cmdline) {
ret = fdt_setprop_string(dtb, off, FDT_PROP_BOOTARGS, cmdline); ret = fdt_setprop_string(dtb, off, FDT_PROP_BOOTARGS, cmdline);
...@@ -125,8 +157,8 @@ static int setup_dtb(struct kimage *image, ...@@ -125,8 +157,8 @@ static int setup_dtb(struct kimage *image,
} }
/* /*
* More space needed so that we can add initrd, bootargs, kaslr-seed, and * More space needed so that we can add initrd, bootargs, kaslr-seed,
* rng-seed. * rng-seed, userable-memory-range and elfcorehdr.
*/ */
#define DTB_EXTRA_SPACE 0x1000 #define DTB_EXTRA_SPACE 0x1000
...@@ -174,6 +206,43 @@ static int create_dtb(struct kimage *image, ...@@ -174,6 +206,43 @@ static int create_dtb(struct kimage *image,
} }
} }
static int prepare_elf_headers(void **addr, unsigned long *sz)
{
struct crash_mem *cmem;
unsigned int nr_ranges;
int ret;
u64 i;
phys_addr_t start, end;
nr_ranges = 1; /* for exclusion of crashkernel region */
for_each_mem_range(i, &memblock.memory, NULL, NUMA_NO_NODE,
MEMBLOCK_NONE, &start, &end, NULL)
nr_ranges++;
cmem = kmalloc(sizeof(struct crash_mem) +
sizeof(struct crash_mem_range) * nr_ranges, GFP_KERNEL);
if (!cmem)
return -ENOMEM;
cmem->max_nr_ranges = nr_ranges;
cmem->nr_ranges = 0;
for_each_mem_range(i, &memblock.memory, NULL, NUMA_NO_NODE,
MEMBLOCK_NONE, &start, &end, NULL) {
cmem->ranges[cmem->nr_ranges].start = start;
cmem->ranges[cmem->nr_ranges].end = end - 1;
cmem->nr_ranges++;
}
/* Exclude crashkernel region */
ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
if (!ret)
ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
kfree(cmem);
return ret;
}
int load_other_segments(struct kimage *image, int load_other_segments(struct kimage *image,
unsigned long kernel_load_addr, unsigned long kernel_load_addr,
unsigned long kernel_size, unsigned long kernel_size,
...@@ -181,14 +250,43 @@ int load_other_segments(struct kimage *image, ...@@ -181,14 +250,43 @@ int load_other_segments(struct kimage *image,
char *cmdline) char *cmdline)
{ {
struct kexec_buf kbuf; struct kexec_buf kbuf;
void *dtb = NULL; void *headers, *dtb = NULL;
unsigned long initrd_load_addr = 0, dtb_len; unsigned long headers_sz, initrd_load_addr = 0, dtb_len;
int ret = 0; int ret = 0;
kbuf.image = image; kbuf.image = image;
/* not allocate anything below the kernel */ /* not allocate anything below the kernel */
kbuf.buf_min = kernel_load_addr + kernel_size; kbuf.buf_min = kernel_load_addr + kernel_size;
/* load elf core header */
if (image->type == KEXEC_TYPE_CRASH) {
ret = prepare_elf_headers(&headers, &headers_sz);
if (ret) {
pr_err("Preparing elf core header failed\n");
goto out_err;
}
kbuf.buffer = headers;
kbuf.bufsz = headers_sz;
kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
kbuf.memsz = headers_sz;
kbuf.buf_align = SZ_64K; /* largest supported page size */
kbuf.buf_max = ULONG_MAX;
kbuf.top_down = true;
ret = kexec_add_buffer(&kbuf);
if (ret) {
vfree(headers);
goto out_err;
}
image->arch.elf_headers = headers;
image->arch.elf_headers_mem = kbuf.mem;
image->arch.elf_headers_sz = headers_sz;
pr_debug("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
image->arch.elf_headers_mem, headers_sz, headers_sz);
}
/* load initrd */ /* load initrd */
if (initrd) { if (initrd) {
kbuf.buffer = initrd; kbuf.buffer = initrd;
......
...@@ -646,6 +646,6 @@ asmlinkage void __sched arm64_preempt_schedule_irq(void) ...@@ -646,6 +646,6 @@ asmlinkage void __sched arm64_preempt_schedule_irq(void)
* Only allow a task to be preempted once cpufeatures have been * Only allow a task to be preempted once cpufeatures have been
* enabled. * enabled.
*/ */
if (static_branch_likely(&arm64_const_caps_ready)) if (system_capabilities_finalized())
preempt_schedule_irq(); preempt_schedule_irq();
} }
...@@ -615,6 +615,13 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset, ...@@ -615,6 +615,13 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
return 0; return 0;
} }
static int fpr_active(struct task_struct *target, const struct user_regset *regset)
{
if (!system_supports_fpsimd())
return -ENODEV;
return regset->n;
}
/* /*
* TODO: update fp accessors for lazy context switching (sync/flush hwstate) * TODO: update fp accessors for lazy context switching (sync/flush hwstate)
*/ */
...@@ -637,6 +644,9 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset, ...@@ -637,6 +644,9 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf) void *kbuf, void __user *ubuf)
{ {
if (!system_supports_fpsimd())
return -EINVAL;
if (target == current) if (target == current)
fpsimd_preserve_current_state(); fpsimd_preserve_current_state();
...@@ -676,6 +686,9 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset, ...@@ -676,6 +686,9 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
{ {
int ret; int ret;
if (!system_supports_fpsimd())
return -EINVAL;
ret = __fpr_set(target, regset, pos, count, kbuf, ubuf, 0); ret = __fpr_set(target, regset, pos, count, kbuf, ubuf, 0);
if (ret) if (ret)
return ret; return ret;
...@@ -1134,6 +1147,7 @@ static const struct user_regset aarch64_regsets[] = { ...@@ -1134,6 +1147,7 @@ static const struct user_regset aarch64_regsets[] = {
*/ */
.size = sizeof(u32), .size = sizeof(u32),
.align = sizeof(u32), .align = sizeof(u32),
.active = fpr_active,
.get = fpr_get, .get = fpr_get,
.set = fpr_set .set = fpr_set
}, },
...@@ -1348,6 +1362,9 @@ static int compat_vfp_get(struct task_struct *target, ...@@ -1348,6 +1362,9 @@ static int compat_vfp_get(struct task_struct *target,
compat_ulong_t fpscr; compat_ulong_t fpscr;
int ret, vregs_end_pos; int ret, vregs_end_pos;
if (!system_supports_fpsimd())
return -EINVAL;
uregs = &target->thread.uw.fpsimd_state; uregs = &target->thread.uw.fpsimd_state;
if (target == current) if (target == current)
...@@ -1381,6 +1398,9 @@ static int compat_vfp_set(struct task_struct *target, ...@@ -1381,6 +1398,9 @@ static int compat_vfp_set(struct task_struct *target,
compat_ulong_t fpscr; compat_ulong_t fpscr;
int ret, vregs_end_pos; int ret, vregs_end_pos;
if (!system_supports_fpsimd())
return -EINVAL;
uregs = &target->thread.uw.fpsimd_state; uregs = &target->thread.uw.fpsimd_state;
vregs_end_pos = VFP_STATE_SIZE - sizeof(compat_ulong_t); vregs_end_pos = VFP_STATE_SIZE - sizeof(compat_ulong_t);
...@@ -1438,6 +1458,7 @@ static const struct user_regset aarch32_regsets[] = { ...@@ -1438,6 +1458,7 @@ static const struct user_regset aarch32_regsets[] = {
.n = VFP_STATE_SIZE / sizeof(compat_ulong_t), .n = VFP_STATE_SIZE / sizeof(compat_ulong_t),
.size = sizeof(compat_ulong_t), .size = sizeof(compat_ulong_t),
.align = sizeof(compat_ulong_t), .align = sizeof(compat_ulong_t),
.active = fpr_active,
.get = compat_vfp_get, .get = compat_vfp_get,
.set = compat_vfp_set .set = compat_vfp_set
}, },
......
...@@ -285,6 +285,13 @@ void __init setup_arch(char **cmdline_p) ...@@ -285,6 +285,13 @@ void __init setup_arch(char **cmdline_p)
*cmdline_p = boot_command_line; *cmdline_p = boot_command_line;
/*
* If know now we are going to need KPTI then use non-global
* mappings from the start, avoiding the cost of rewriting
* everything later.
*/
arm64_use_ng_mappings = kaslr_requires_kpti();
early_fixmap_init(); early_fixmap_init();
early_ioremap_init(); early_ioremap_init();
......
...@@ -371,6 +371,8 @@ static int parse_user_sigframe(struct user_ctxs *user, ...@@ -371,6 +371,8 @@ static int parse_user_sigframe(struct user_ctxs *user,
goto done; goto done;
case FPSIMD_MAGIC: case FPSIMD_MAGIC:
if (!system_supports_fpsimd())
goto invalid;
if (user->fpsimd) if (user->fpsimd)
goto invalid; goto invalid;
...@@ -506,7 +508,7 @@ static int restore_sigframe(struct pt_regs *regs, ...@@ -506,7 +508,7 @@ static int restore_sigframe(struct pt_regs *regs,
if (err == 0) if (err == 0)
err = parse_user_sigframe(&user, sf); err = parse_user_sigframe(&user, sf);
if (err == 0) { if (err == 0 && system_supports_fpsimd()) {
if (!user.fpsimd) if (!user.fpsimd)
return -EINVAL; return -EINVAL;
...@@ -623,7 +625,7 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user, ...@@ -623,7 +625,7 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user,
err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set)); err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
if (err == 0) { if (err == 0 && system_supports_fpsimd()) {
struct fpsimd_context __user *fpsimd_ctx = struct fpsimd_context __user *fpsimd_ctx =
apply_user_offset(user, user->fpsimd_offset); apply_user_offset(user, user->fpsimd_offset);
err |= preserve_fpsimd_context(fpsimd_ctx); err |= preserve_fpsimd_context(fpsimd_ctx);
......
...@@ -223,7 +223,7 @@ static int compat_restore_sigframe(struct pt_regs *regs, ...@@ -223,7 +223,7 @@ static int compat_restore_sigframe(struct pt_regs *regs,
err |= !valid_user_regs(&regs->user_regs, current); err |= !valid_user_regs(&regs->user_regs, current);
aux = (struct compat_aux_sigframe __user *) sf->uc.uc_regspace; aux = (struct compat_aux_sigframe __user *) sf->uc.uc_regspace;
if (err == 0) if (err == 0 && system_supports_fpsimd())
err |= compat_restore_vfp_context(&aux->vfp); err |= compat_restore_vfp_context(&aux->vfp);
return err; return err;
...@@ -419,7 +419,7 @@ static int compat_setup_sigframe(struct compat_sigframe __user *sf, ...@@ -419,7 +419,7 @@ static int compat_setup_sigframe(struct compat_sigframe __user *sf,
aux = (struct compat_aux_sigframe __user *) sf->uc.uc_regspace; aux = (struct compat_aux_sigframe __user *) sf->uc.uc_regspace;
if (err == 0) if (err == 0 && system_supports_fpsimd())
err |= compat_preserve_vfp_context(&aux->vfp); err |= compat_preserve_vfp_context(&aux->vfp);
__put_user_error(0, &aux->end_magic, err); __put_user_error(0, &aux->end_magic, err);
......
...@@ -37,7 +37,7 @@ static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl) ...@@ -37,7 +37,7 @@ static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl)
/* Unsupported */ /* Unsupported */
if (state == ARM64_SSBD_UNKNOWN) if (state == ARM64_SSBD_UNKNOWN)
return -EINVAL; return -ENODEV;
/* Treat the unaffected/mitigated state separately */ /* Treat the unaffected/mitigated state separately */
if (state == ARM64_SSBD_MITIGATED) { if (state == ARM64_SSBD_MITIGATED) {
...@@ -102,7 +102,7 @@ static int ssbd_prctl_get(struct task_struct *task) ...@@ -102,7 +102,7 @@ static int ssbd_prctl_get(struct task_struct *task)
{ {
switch (arm64_get_ssbd_state()) { switch (arm64_get_ssbd_state()) {
case ARM64_SSBD_UNKNOWN: case ARM64_SSBD_UNKNOWN:
return -EINVAL; return -ENODEV;
case ARM64_SSBD_FORCE_ENABLE: case ARM64_SSBD_FORCE_ENABLE:
return PR_SPEC_DISABLE; return PR_SPEC_DISABLE;
case ARM64_SSBD_KERNEL: case ARM64_SSBD_KERNEL:
......
...@@ -154,14 +154,14 @@ static inline void sve_user_discard(void) ...@@ -154,14 +154,14 @@ static inline void sve_user_discard(void)
sve_user_disable(); sve_user_disable();
} }
void el0_svc_handler(struct pt_regs *regs) void do_el0_svc(struct pt_regs *regs)
{ {
sve_user_discard(); sve_user_discard();
el0_svc_common(regs, regs->regs[8], __NR_syscalls, sys_call_table); el0_svc_common(regs, regs->regs[8], __NR_syscalls, sys_call_table);
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
void el0_svc_compat_handler(struct pt_regs *regs) void do_el0_svc_compat(struct pt_regs *regs)
{ {
el0_svc_common(regs, regs->regs[7], __NR_compat_syscalls, el0_svc_common(regs, regs->regs[7], __NR_compat_syscalls,
compat_sys_call_table); compat_sys_call_table);
......
...@@ -22,7 +22,12 @@ ...@@ -22,7 +22,12 @@
.text .text
.pushsection .hyp.text, "ax" .pushsection .hyp.text, "ax"
/*
* We treat x18 as callee-saved as the host may use it as a platform
* register (e.g. for shadow call stack).
*/
.macro save_callee_saved_regs ctxt .macro save_callee_saved_regs ctxt
str x18, [\ctxt, #CPU_XREG_OFFSET(18)]
stp x19, x20, [\ctxt, #CPU_XREG_OFFSET(19)] stp x19, x20, [\ctxt, #CPU_XREG_OFFSET(19)]
stp x21, x22, [\ctxt, #CPU_XREG_OFFSET(21)] stp x21, x22, [\ctxt, #CPU_XREG_OFFSET(21)]
stp x23, x24, [\ctxt, #CPU_XREG_OFFSET(23)] stp x23, x24, [\ctxt, #CPU_XREG_OFFSET(23)]
...@@ -32,6 +37,8 @@ ...@@ -32,6 +37,8 @@
.endm .endm
.macro restore_callee_saved_regs ctxt .macro restore_callee_saved_regs ctxt
// We require \ctxt is not x18-x28
ldr x18, [\ctxt, #CPU_XREG_OFFSET(18)]
ldp x19, x20, [\ctxt, #CPU_XREG_OFFSET(19)] ldp x19, x20, [\ctxt, #CPU_XREG_OFFSET(19)]
ldp x21, x22, [\ctxt, #CPU_XREG_OFFSET(21)] ldp x21, x22, [\ctxt, #CPU_XREG_OFFSET(21)]
ldp x23, x24, [\ctxt, #CPU_XREG_OFFSET(23)] ldp x23, x24, [\ctxt, #CPU_XREG_OFFSET(23)]
...@@ -48,7 +55,7 @@ ENTRY(__guest_enter) ...@@ -48,7 +55,7 @@ ENTRY(__guest_enter)
// x0: vcpu // x0: vcpu
// x1: host context // x1: host context
// x2-x17: clobbered by macros // x2-x17: clobbered by macros
// x18: guest context // x29: guest context
// Store the host regs // Store the host regs
save_callee_saved_regs x1 save_callee_saved_regs x1
...@@ -67,31 +74,28 @@ alternative_else_nop_endif ...@@ -67,31 +74,28 @@ alternative_else_nop_endif
ret ret
1: 1:
add x18, x0, #VCPU_CONTEXT add x29, x0, #VCPU_CONTEXT
// Macro ptrauth_switch_to_guest format: // Macro ptrauth_switch_to_guest format:
// ptrauth_switch_to_guest(guest cxt, tmp1, tmp2, tmp3) // ptrauth_switch_to_guest(guest cxt, tmp1, tmp2, tmp3)
// The below macro to restore guest keys is not implemented in C code // The below macro to restore guest keys is not implemented in C code
// as it may cause Pointer Authentication key signing mismatch errors // as it may cause Pointer Authentication key signing mismatch errors
// when this feature is enabled for kernel code. // when this feature is enabled for kernel code.
ptrauth_switch_to_guest x18, x0, x1, x2 ptrauth_switch_to_guest x29, x0, x1, x2
// Restore guest regs x0-x17 // Restore guest regs x0-x17
ldp x0, x1, [x18, #CPU_XREG_OFFSET(0)] ldp x0, x1, [x29, #CPU_XREG_OFFSET(0)]
ldp x2, x3, [x18, #CPU_XREG_OFFSET(2)] ldp x2, x3, [x29, #CPU_XREG_OFFSET(2)]
ldp x4, x5, [x18, #CPU_XREG_OFFSET(4)] ldp x4, x5, [x29, #CPU_XREG_OFFSET(4)]
ldp x6, x7, [x18, #CPU_XREG_OFFSET(6)] ldp x6, x7, [x29, #CPU_XREG_OFFSET(6)]
ldp x8, x9, [x18, #CPU_XREG_OFFSET(8)] ldp x8, x9, [x29, #CPU_XREG_OFFSET(8)]
ldp x10, x11, [x18, #CPU_XREG_OFFSET(10)] ldp x10, x11, [x29, #CPU_XREG_OFFSET(10)]
ldp x12, x13, [x18, #CPU_XREG_OFFSET(12)] ldp x12, x13, [x29, #CPU_XREG_OFFSET(12)]
ldp x14, x15, [x18, #CPU_XREG_OFFSET(14)] ldp x14, x15, [x29, #CPU_XREG_OFFSET(14)]
ldp x16, x17, [x18, #CPU_XREG_OFFSET(16)] ldp x16, x17, [x29, #CPU_XREG_OFFSET(16)]
// Restore guest regs x19-x29, lr // Restore guest regs x18-x29, lr
restore_callee_saved_regs x18 restore_callee_saved_regs x29
// Restore guest reg x18
ldr x18, [x18, #CPU_XREG_OFFSET(18)]
// Do not touch any register after this! // Do not touch any register after this!
eret eret
...@@ -114,7 +118,7 @@ ENTRY(__guest_exit) ...@@ -114,7 +118,7 @@ ENTRY(__guest_exit)
// Retrieve the guest regs x0-x1 from the stack // Retrieve the guest regs x0-x1 from the stack
ldp x2, x3, [sp], #16 // x0, x1 ldp x2, x3, [sp], #16 // x0, x1
// Store the guest regs x0-x1 and x4-x18 // Store the guest regs x0-x1 and x4-x17
stp x2, x3, [x1, #CPU_XREG_OFFSET(0)] stp x2, x3, [x1, #CPU_XREG_OFFSET(0)]
stp x4, x5, [x1, #CPU_XREG_OFFSET(4)] stp x4, x5, [x1, #CPU_XREG_OFFSET(4)]
stp x6, x7, [x1, #CPU_XREG_OFFSET(6)] stp x6, x7, [x1, #CPU_XREG_OFFSET(6)]
...@@ -123,9 +127,8 @@ ENTRY(__guest_exit) ...@@ -123,9 +127,8 @@ ENTRY(__guest_exit)
stp x12, x13, [x1, #CPU_XREG_OFFSET(12)] stp x12, x13, [x1, #CPU_XREG_OFFSET(12)]
stp x14, x15, [x1, #CPU_XREG_OFFSET(14)] stp x14, x15, [x1, #CPU_XREG_OFFSET(14)]
stp x16, x17, [x1, #CPU_XREG_OFFSET(16)] stp x16, x17, [x1, #CPU_XREG_OFFSET(16)]
str x18, [x1, #CPU_XREG_OFFSET(18)]
// Store the guest regs x19-x29, lr // Store the guest regs x18-x29, lr
save_callee_saved_regs x1 save_callee_saved_regs x1
get_host_ctxt x2, x3 get_host_ctxt x2, x3
......
...@@ -28,7 +28,15 @@ ...@@ -28,7 +28,15 @@
/* Check whether the FP regs were dirtied while in the host-side run loop: */ /* Check whether the FP regs were dirtied while in the host-side run loop: */
static bool __hyp_text update_fp_enabled(struct kvm_vcpu *vcpu) static bool __hyp_text update_fp_enabled(struct kvm_vcpu *vcpu)
{ {
if (vcpu->arch.host_thread_info->flags & _TIF_FOREIGN_FPSTATE) /*
* When the system doesn't support FP/SIMD, we cannot rely on
* the _TIF_FOREIGN_FPSTATE flag. However, we always inject an
* abort on the very first access to FP and thus we should never
* see KVM_ARM64_FP_ENABLED. For added safety, make sure we always
* trap the accesses.
*/
if (!system_supports_fpsimd() ||
vcpu->arch.host_thread_info->flags & _TIF_FOREIGN_FPSTATE)
vcpu->arch.flags &= ~(KVM_ARM64_FP_ENABLED | vcpu->arch.flags &= ~(KVM_ARM64_FP_ENABLED |
KVM_ARM64_FP_HOST); KVM_ARM64_FP_HOST);
...@@ -119,7 +127,7 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu) ...@@ -119,7 +127,7 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
write_sysreg(val, cptr_el2); write_sysreg(val, cptr_el2);
if (cpus_have_const_cap(ARM64_WORKAROUND_1319367)) { if (cpus_have_const_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE)) {
struct kvm_cpu_context *ctxt = &vcpu->arch.ctxt; struct kvm_cpu_context *ctxt = &vcpu->arch.ctxt;
isb(); isb();
...@@ -158,11 +166,11 @@ static void deactivate_traps_vhe(void) ...@@ -158,11 +166,11 @@ static void deactivate_traps_vhe(void)
write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2); write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
/* /*
* ARM erratum 1165522 requires the actual execution of the above * ARM errata 1165522 and 1530923 require the actual execution of the
* before we can switch to the EL2/EL0 translation regime used by * above before we can switch to the EL2/EL0 translation regime used by
* the host. * the host.
*/ */
asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_1165522)); asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_SPECULATIVE_AT_VHE));
write_sysreg(CPACR_EL1_DEFAULT, cpacr_el1); write_sysreg(CPACR_EL1_DEFAULT, cpacr_el1);
write_sysreg(vectors, vbar_el1); write_sysreg(vectors, vbar_el1);
...@@ -173,7 +181,7 @@ static void __hyp_text __deactivate_traps_nvhe(void) ...@@ -173,7 +181,7 @@ static void __hyp_text __deactivate_traps_nvhe(void)
{ {
u64 mdcr_el2 = read_sysreg(mdcr_el2); u64 mdcr_el2 = read_sysreg(mdcr_el2);
if (cpus_have_const_cap(ARM64_WORKAROUND_1319367)) { if (cpus_have_const_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE)) {
u64 val; u64 val;
/* /*
......
...@@ -118,7 +118,7 @@ static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt) ...@@ -118,7 +118,7 @@ static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
write_sysreg(ctxt->sys_regs[MPIDR_EL1], vmpidr_el2); write_sysreg(ctxt->sys_regs[MPIDR_EL1], vmpidr_el2);
write_sysreg(ctxt->sys_regs[CSSELR_EL1], csselr_el1); write_sysreg(ctxt->sys_regs[CSSELR_EL1], csselr_el1);
if (!cpus_have_const_cap(ARM64_WORKAROUND_1319367)) { if (!cpus_have_const_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE)) {
write_sysreg_el1(ctxt->sys_regs[SCTLR_EL1], SYS_SCTLR); write_sysreg_el1(ctxt->sys_regs[SCTLR_EL1], SYS_SCTLR);
write_sysreg_el1(ctxt->sys_regs[TCR_EL1], SYS_TCR); write_sysreg_el1(ctxt->sys_regs[TCR_EL1], SYS_TCR);
} else if (!ctxt->__hyp_running_vcpu) { } else if (!ctxt->__hyp_running_vcpu) {
...@@ -149,7 +149,7 @@ static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt) ...@@ -149,7 +149,7 @@ static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
write_sysreg(ctxt->sys_regs[PAR_EL1], par_el1); write_sysreg(ctxt->sys_regs[PAR_EL1], par_el1);
write_sysreg(ctxt->sys_regs[TPIDR_EL1], tpidr_el1); write_sysreg(ctxt->sys_regs[TPIDR_EL1], tpidr_el1);
if (cpus_have_const_cap(ARM64_WORKAROUND_1319367) && if (cpus_have_const_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE) &&
ctxt->__hyp_running_vcpu) { ctxt->__hyp_running_vcpu) {
/* /*
* Must only be done for host registers, hence the context * Must only be done for host registers, hence the context
......
...@@ -23,10 +23,10 @@ static void __hyp_text __tlb_switch_to_guest_vhe(struct kvm *kvm, ...@@ -23,10 +23,10 @@ static void __hyp_text __tlb_switch_to_guest_vhe(struct kvm *kvm,
local_irq_save(cxt->flags); local_irq_save(cxt->flags);
if (cpus_have_const_cap(ARM64_WORKAROUND_1165522)) { if (cpus_have_const_cap(ARM64_WORKAROUND_SPECULATIVE_AT_VHE)) {
/* /*
* For CPUs that are affected by ARM erratum 1165522, we * For CPUs that are affected by ARM errata 1165522 or 1530923,
* cannot trust stage-1 to be in a correct state at that * we cannot trust stage-1 to be in a correct state at that
* point. Since we do not want to force a full load of the * point. Since we do not want to force a full load of the
* vcpu state, we prevent the EL1 page-table walker to * vcpu state, we prevent the EL1 page-table walker to
* allocate new TLBs. This is done by setting the EPD bits * allocate new TLBs. This is done by setting the EPD bits
...@@ -63,7 +63,7 @@ static void __hyp_text __tlb_switch_to_guest_vhe(struct kvm *kvm, ...@@ -63,7 +63,7 @@ static void __hyp_text __tlb_switch_to_guest_vhe(struct kvm *kvm,
static void __hyp_text __tlb_switch_to_guest_nvhe(struct kvm *kvm, static void __hyp_text __tlb_switch_to_guest_nvhe(struct kvm *kvm,
struct tlb_inv_context *cxt) struct tlb_inv_context *cxt)
{ {
if (cpus_have_const_cap(ARM64_WORKAROUND_1319367)) { if (cpus_have_const_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE)) {
u64 val; u64 val;
/* /*
...@@ -103,7 +103,7 @@ static void __hyp_text __tlb_switch_to_host_vhe(struct kvm *kvm, ...@@ -103,7 +103,7 @@ static void __hyp_text __tlb_switch_to_host_vhe(struct kvm *kvm,
write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2); write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
isb(); isb();
if (cpus_have_const_cap(ARM64_WORKAROUND_1165522)) { if (cpus_have_const_cap(ARM64_WORKAROUND_SPECULATIVE_AT_VHE)) {
/* Restore the registers to what they were */ /* Restore the registers to what they were */
write_sysreg_el1(cxt->tcr, SYS_TCR); write_sysreg_el1(cxt->tcr, SYS_TCR);
write_sysreg_el1(cxt->sctlr, SYS_SCTLR); write_sysreg_el1(cxt->sctlr, SYS_SCTLR);
...@@ -117,7 +117,7 @@ static void __hyp_text __tlb_switch_to_host_nvhe(struct kvm *kvm, ...@@ -117,7 +117,7 @@ static void __hyp_text __tlb_switch_to_host_nvhe(struct kvm *kvm,
{ {
write_sysreg(0, vttbr_el2); write_sysreg(0, vttbr_el2);
if (cpus_have_const_cap(ARM64_WORKAROUND_1319367)) { if (cpus_have_const_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE)) {
/* Ensure write of the host VMID */ /* Ensure write of the host VMID */
isb(); isb();
/* Restore the host's TCR_EL1 */ /* Restore the host's TCR_EL1 */
......
...@@ -1424,7 +1424,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { ...@@ -1424,7 +1424,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
ID_SANITISED(ID_ISAR4_EL1), ID_SANITISED(ID_ISAR4_EL1),
ID_SANITISED(ID_ISAR5_EL1), ID_SANITISED(ID_ISAR5_EL1),
ID_SANITISED(ID_MMFR4_EL1), ID_SANITISED(ID_MMFR4_EL1),
ID_UNALLOCATED(2,7), ID_SANITISED(ID_ISAR6_EL1),
/* CRm=3 */ /* CRm=3 */
ID_SANITISED(MVFR0_EL1), ID_SANITISED(MVFR0_EL1),
......
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
lib-y := clear_user.o delay.o copy_from_user.o \ lib-y := clear_user.o delay.o copy_from_user.o \
copy_to_user.o copy_in_user.o copy_page.o \ copy_to_user.o copy_in_user.o copy_page.o \
clear_page.o memchr.o memcpy.o memmove.o memset.o \ clear_page.o csum.o memchr.o memcpy.o memmove.o \
memcmp.o strcmp.o strncmp.o strlen.o strnlen.o \ memset.o memcmp.o strcmp.o strncmp.o strlen.o \
strchr.o strrchr.o tishift.o strnlen.o strchr.o strrchr.o tishift.o
ifeq ($(CONFIG_KERNEL_MODE_NEON), y) ifeq ($(CONFIG_KERNEL_MODE_NEON), y)
obj-$(CONFIG_XOR_BLOCKS) += xor-neon.o obj-$(CONFIG_XOR_BLOCKS) += xor-neon.o
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* Parameters: * Parameters:
* x0 - dest * x0 - dest
*/ */
ENTRY(clear_page) SYM_FUNC_START(clear_page)
mrs x1, dczid_el0 mrs x1, dczid_el0
and w1, w1, #0xf and w1, w1, #0xf
mov x2, #4 mov x2, #4
...@@ -25,5 +25,5 @@ ENTRY(clear_page) ...@@ -25,5 +25,5 @@ ENTRY(clear_page)
tst x0, #(PAGE_SIZE - 1) tst x0, #(PAGE_SIZE - 1)
b.ne 1b b.ne 1b
ret ret
ENDPROC(clear_page) SYM_FUNC_END(clear_page)
EXPORT_SYMBOL(clear_page) EXPORT_SYMBOL(clear_page)
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
* *
* Alignment fixed up by hardware. * Alignment fixed up by hardware.
*/ */
ENTRY(__arch_clear_user) SYM_FUNC_START(__arch_clear_user)
mov x2, x1 // save the size for fixup return mov x2, x1 // save the size for fixup return
subs x1, x1, #8 subs x1, x1, #8
b.mi 2f b.mi 2f
...@@ -40,7 +40,7 @@ uao_user_alternative 9f, strh, sttrh, wzr, x0, 2 ...@@ -40,7 +40,7 @@ uao_user_alternative 9f, strh, sttrh, wzr, x0, 2
uao_user_alternative 9f, strb, sttrb, wzr, x0, 0 uao_user_alternative 9f, strb, sttrb, wzr, x0, 0
5: mov x0, #0 5: mov x0, #0
ret ret
ENDPROC(__arch_clear_user) SYM_FUNC_END(__arch_clear_user)
EXPORT_SYMBOL(__arch_clear_user) EXPORT_SYMBOL(__arch_clear_user)
.section .fixup,"ax" .section .fixup,"ax"
......
...@@ -53,12 +53,12 @@ ...@@ -53,12 +53,12 @@
.endm .endm
end .req x5 end .req x5
ENTRY(__arch_copy_from_user) SYM_FUNC_START(__arch_copy_from_user)
add end, x0, x2 add end, x0, x2
#include "copy_template.S" #include "copy_template.S"
mov x0, #0 // Nothing to copy mov x0, #0 // Nothing to copy
ret ret
ENDPROC(__arch_copy_from_user) SYM_FUNC_END(__arch_copy_from_user)
EXPORT_SYMBOL(__arch_copy_from_user) EXPORT_SYMBOL(__arch_copy_from_user)
.section .fixup,"ax" .section .fixup,"ax"
......
...@@ -55,12 +55,12 @@ ...@@ -55,12 +55,12 @@
end .req x5 end .req x5
ENTRY(__arch_copy_in_user) SYM_FUNC_START(__arch_copy_in_user)
add end, x0, x2 add end, x0, x2
#include "copy_template.S" #include "copy_template.S"
mov x0, #0 mov x0, #0
ret ret
ENDPROC(__arch_copy_in_user) SYM_FUNC_END(__arch_copy_in_user)
EXPORT_SYMBOL(__arch_copy_in_user) EXPORT_SYMBOL(__arch_copy_in_user)
.section .fixup,"ax" .section .fixup,"ax"
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
* x0 - dest * x0 - dest
* x1 - src * x1 - src
*/ */
ENTRY(copy_page) SYM_FUNC_START(copy_page)
alternative_if ARM64_HAS_NO_HW_PREFETCH alternative_if ARM64_HAS_NO_HW_PREFETCH
// Prefetch three cache lines ahead. // Prefetch three cache lines ahead.
prfm pldl1strm, [x1, #128] prfm pldl1strm, [x1, #128]
...@@ -34,46 +34,46 @@ alternative_else_nop_endif ...@@ -34,46 +34,46 @@ alternative_else_nop_endif
ldp x14, x15, [x1, #96] ldp x14, x15, [x1, #96]
ldp x16, x17, [x1, #112] ldp x16, x17, [x1, #112]
mov x18, #(PAGE_SIZE - 128) add x0, x0, #256
add x1, x1, #128 add x1, x1, #128
1: 1:
subs x18, x18, #128 tst x0, #(PAGE_SIZE - 1)
alternative_if ARM64_HAS_NO_HW_PREFETCH alternative_if ARM64_HAS_NO_HW_PREFETCH
prfm pldl1strm, [x1, #384] prfm pldl1strm, [x1, #384]
alternative_else_nop_endif alternative_else_nop_endif
stnp x2, x3, [x0] stnp x2, x3, [x0, #-256]
ldp x2, x3, [x1] ldp x2, x3, [x1]
stnp x4, x5, [x0, #16] stnp x4, x5, [x0, #16 - 256]
ldp x4, x5, [x1, #16] ldp x4, x5, [x1, #16]
stnp x6, x7, [x0, #32] stnp x6, x7, [x0, #32 - 256]
ldp x6, x7, [x1, #32] ldp x6, x7, [x1, #32]
stnp x8, x9, [x0, #48] stnp x8, x9, [x0, #48 - 256]
ldp x8, x9, [x1, #48] ldp x8, x9, [x1, #48]
stnp x10, x11, [x0, #64] stnp x10, x11, [x0, #64 - 256]
ldp x10, x11, [x1, #64] ldp x10, x11, [x1, #64]
stnp x12, x13, [x0, #80] stnp x12, x13, [x0, #80 - 256]
ldp x12, x13, [x1, #80] ldp x12, x13, [x1, #80]
stnp x14, x15, [x0, #96] stnp x14, x15, [x0, #96 - 256]
ldp x14, x15, [x1, #96] ldp x14, x15, [x1, #96]
stnp x16, x17, [x0, #112] stnp x16, x17, [x0, #112 - 256]
ldp x16, x17, [x1, #112] ldp x16, x17, [x1, #112]
add x0, x0, #128 add x0, x0, #128
add x1, x1, #128 add x1, x1, #128
b.gt 1b b.ne 1b
stnp x2, x3, [x0] stnp x2, x3, [x0, #-256]
stnp x4, x5, [x0, #16] stnp x4, x5, [x0, #16 - 256]
stnp x6, x7, [x0, #32] stnp x6, x7, [x0, #32 - 256]
stnp x8, x9, [x0, #48] stnp x8, x9, [x0, #48 - 256]
stnp x10, x11, [x0, #64] stnp x10, x11, [x0, #64 - 256]
stnp x12, x13, [x0, #80] stnp x12, x13, [x0, #80 - 256]
stnp x14, x15, [x0, #96] stnp x14, x15, [x0, #96 - 256]
stnp x16, x17, [x0, #112] stnp x16, x17, [x0, #112 - 256]
ret ret
ENDPROC(copy_page) SYM_FUNC_END(copy_page)
EXPORT_SYMBOL(copy_page) EXPORT_SYMBOL(copy_page)
...@@ -52,12 +52,12 @@ ...@@ -52,12 +52,12 @@
.endm .endm
end .req x5 end .req x5
ENTRY(__arch_copy_to_user) SYM_FUNC_START(__arch_copy_to_user)
add end, x0, x2 add end, x0, x2
#include "copy_template.S" #include "copy_template.S"
mov x0, #0 mov x0, #0
ret ret
ENDPROC(__arch_copy_to_user) SYM_FUNC_END(__arch_copy_to_user)
EXPORT_SYMBOL(__arch_copy_to_user) EXPORT_SYMBOL(__arch_copy_to_user)
.section .fixup,"ax" .section .fixup,"ax"
......
...@@ -85,17 +85,17 @@ CPU_BE( rev16 w3, w3 ) ...@@ -85,17 +85,17 @@ CPU_BE( rev16 w3, w3 )
.endm .endm
.align 5 .align 5
ENTRY(crc32_le) SYM_FUNC_START(crc32_le)
alternative_if_not ARM64_HAS_CRC32 alternative_if_not ARM64_HAS_CRC32
b crc32_le_base b crc32_le_base
alternative_else_nop_endif alternative_else_nop_endif
__crc32 __crc32
ENDPROC(crc32_le) SYM_FUNC_END(crc32_le)
.align 5 .align 5
ENTRY(__crc32c_le) SYM_FUNC_START(__crc32c_le)
alternative_if_not ARM64_HAS_CRC32 alternative_if_not ARM64_HAS_CRC32
b __crc32c_le_base b __crc32c_le_base
alternative_else_nop_endif alternative_else_nop_endif
__crc32 c __crc32 c
ENDPROC(__crc32c_le) SYM_FUNC_END(__crc32c_le)
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2019-2020 Arm Ltd.
#include <linux/compiler.h>
#include <linux/kasan-checks.h>
#include <linux/kernel.h>
#include <net/checksum.h>
/* Looks dumb, but generates nice-ish code */
static u64 accumulate(u64 sum, u64 data)
{
__uint128_t tmp = (__uint128_t)sum + data;
return tmp + (tmp >> 64);
}
unsigned int do_csum(const unsigned char *buff, int len)
{
unsigned int offset, shift, sum;
const u64 *ptr;
u64 data, sum64 = 0;
if (unlikely(len == 0))
return 0;
offset = (unsigned long)buff & 7;
/*
* This is to all intents and purposes safe, since rounding down cannot
* result in a different page or cache line being accessed, and @buff
* should absolutely not be pointing to anything read-sensitive. We do,
* however, have to be careful not to piss off KASAN, which means using
* unchecked reads to accommodate the head and tail, for which we'll
* compensate with an explicit check up-front.
*/
kasan_check_read(buff, len);
ptr = (u64 *)(buff - offset);
len = len + offset - 8;
/*
* Head: zero out any excess leading bytes. Shifting back by the same
* amount should be at least as fast as any other way of handling the
* odd/even alignment, and means we can ignore it until the very end.
*/
shift = offset * 8;
data = READ_ONCE_NOCHECK(*ptr++);
#ifdef __LITTLE_ENDIAN
data = (data >> shift) << shift;
#else
data = (data << shift) >> shift;
#endif
/*
* Body: straightforward aligned loads from here on (the paired loads
* underlying the quadword type still only need dword alignment). The
* main loop strictly excludes the tail, so the second loop will always
* run at least once.
*/
while (unlikely(len > 64)) {
__uint128_t tmp1, tmp2, tmp3, tmp4;
tmp1 = READ_ONCE_NOCHECK(*(__uint128_t *)ptr);
tmp2 = READ_ONCE_NOCHECK(*(__uint128_t *)(ptr + 2));
tmp3 = READ_ONCE_NOCHECK(*(__uint128_t *)(ptr + 4));
tmp4 = READ_ONCE_NOCHECK(*(__uint128_t *)(ptr + 6));
len -= 64;
ptr += 8;
/* This is the "don't dump the carry flag into a GPR" idiom */
tmp1 += (tmp1 >> 64) | (tmp1 << 64);
tmp2 += (tmp2 >> 64) | (tmp2 << 64);
tmp3 += (tmp3 >> 64) | (tmp3 << 64);
tmp4 += (tmp4 >> 64) | (tmp4 << 64);
tmp1 = ((tmp1 >> 64) << 64) | (tmp2 >> 64);
tmp1 += (tmp1 >> 64) | (tmp1 << 64);
tmp3 = ((tmp3 >> 64) << 64) | (tmp4 >> 64);
tmp3 += (tmp3 >> 64) | (tmp3 << 64);
tmp1 = ((tmp1 >> 64) << 64) | (tmp3 >> 64);
tmp1 += (tmp1 >> 64) | (tmp1 << 64);
tmp1 = ((tmp1 >> 64) << 64) | sum64;
tmp1 += (tmp1 >> 64) | (tmp1 << 64);
sum64 = tmp1 >> 64;
}
while (len > 8) {
__uint128_t tmp;
sum64 = accumulate(sum64, data);
tmp = READ_ONCE_NOCHECK(*(__uint128_t *)ptr);
len -= 16;
ptr += 2;
#ifdef __LITTLE_ENDIAN
data = tmp >> 64;
sum64 = accumulate(sum64, tmp);
#else
data = tmp;
sum64 = accumulate(sum64, tmp >> 64);
#endif
}
if (len > 0) {
sum64 = accumulate(sum64, data);
data = READ_ONCE_NOCHECK(*ptr);
len -= 8;
}
/*
* Tail: zero any over-read bytes similarly to the head, again
* preserving odd/even alignment.
*/
shift = len * -8;
#ifdef __LITTLE_ENDIAN
data = (data << shift) >> shift;
#else
data = (data >> shift) << shift;
#endif
sum64 = accumulate(sum64, data);
/* Finally, folding */
sum64 += (sum64 >> 32) | (sum64 << 32);
sum = sum64 >> 32;
sum += (sum >> 16) | (sum << 16);
if (offset & 1)
return (u16)swab32(sum);
return sum >> 16;
}
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
* Returns: * Returns:
* x0 - address of first occurrence of 'c' or 0 * x0 - address of first occurrence of 'c' or 0
*/ */
WEAK(memchr) SYM_FUNC_START_WEAK_PI(memchr)
and w1, w1, #0xff and w1, w1, #0xff
1: subs x2, x2, #1 1: subs x2, x2, #1
b.mi 2f b.mi 2f
...@@ -30,5 +30,5 @@ WEAK(memchr) ...@@ -30,5 +30,5 @@ WEAK(memchr)
ret ret
2: mov x0, #0 2: mov x0, #0
ret ret
ENDPIPROC(memchr) SYM_FUNC_END_PI(memchr)
EXPORT_SYMBOL_NOKASAN(memchr) EXPORT_SYMBOL_NOKASAN(memchr)
...@@ -46,7 +46,7 @@ pos .req x11 ...@@ -46,7 +46,7 @@ pos .req x11
limit_wd .req x12 limit_wd .req x12
mask .req x13 mask .req x13
WEAK(memcmp) SYM_FUNC_START_WEAK_PI(memcmp)
cbz limit, .Lret0 cbz limit, .Lret0
eor tmp1, src1, src2 eor tmp1, src1, src2
tst tmp1, #7 tst tmp1, #7
...@@ -243,5 +243,5 @@ CPU_LE( rev data2, data2 ) ...@@ -243,5 +243,5 @@ CPU_LE( rev data2, data2 )
.Lret0: .Lret0:
mov result, #0 mov result, #0
ret ret
ENDPIPROC(memcmp) SYM_FUNC_END_PI(memcmp)
EXPORT_SYMBOL_NOKASAN(memcmp) EXPORT_SYMBOL_NOKASAN(memcmp)
...@@ -57,11 +57,11 @@ ...@@ -57,11 +57,11 @@
.endm .endm
.weak memcpy .weak memcpy
ENTRY(__memcpy) SYM_FUNC_START_ALIAS(__memcpy)
ENTRY(memcpy) SYM_FUNC_START_PI(memcpy)
#include "copy_template.S" #include "copy_template.S"
ret ret
ENDPIPROC(memcpy) SYM_FUNC_END_PI(memcpy)
EXPORT_SYMBOL(memcpy) EXPORT_SYMBOL(memcpy)
ENDPROC(__memcpy) SYM_FUNC_END_ALIAS(__memcpy)
EXPORT_SYMBOL(__memcpy) EXPORT_SYMBOL(__memcpy)
...@@ -46,8 +46,8 @@ D_l .req x13 ...@@ -46,8 +46,8 @@ D_l .req x13
D_h .req x14 D_h .req x14
.weak memmove .weak memmove
ENTRY(__memmove) SYM_FUNC_START_ALIAS(__memmove)
ENTRY(memmove) SYM_FUNC_START_PI(memmove)
cmp dstin, src cmp dstin, src
b.lo __memcpy b.lo __memcpy
add tmp1, src, count add tmp1, src, count
...@@ -184,7 +184,7 @@ ENTRY(memmove) ...@@ -184,7 +184,7 @@ ENTRY(memmove)
tst count, #0x3f tst count, #0x3f
b.ne .Ltail63 b.ne .Ltail63
ret ret
ENDPIPROC(memmove) SYM_FUNC_END_PI(memmove)
EXPORT_SYMBOL(memmove) EXPORT_SYMBOL(memmove)
ENDPROC(__memmove) SYM_FUNC_END_ALIAS(__memmove)
EXPORT_SYMBOL(__memmove) EXPORT_SYMBOL(__memmove)
...@@ -43,8 +43,8 @@ tmp3w .req w9 ...@@ -43,8 +43,8 @@ tmp3w .req w9
tmp3 .req x9 tmp3 .req x9
.weak memset .weak memset
ENTRY(__memset) SYM_FUNC_START_ALIAS(__memset)
ENTRY(memset) SYM_FUNC_START_PI(memset)
mov dst, dstin /* Preserve return value. */ mov dst, dstin /* Preserve return value. */
and A_lw, val, #255 and A_lw, val, #255
orr A_lw, A_lw, A_lw, lsl #8 orr A_lw, A_lw, A_lw, lsl #8
...@@ -203,7 +203,7 @@ ENTRY(memset) ...@@ -203,7 +203,7 @@ ENTRY(memset)
ands count, count, zva_bits_x ands count, count, zva_bits_x
b.ne .Ltail_maybe_long b.ne .Ltail_maybe_long
ret ret
ENDPIPROC(memset) SYM_FUNC_END_PI(memset)
EXPORT_SYMBOL(memset) EXPORT_SYMBOL(memset)
ENDPROC(__memset) SYM_FUNC_END_ALIAS(__memset)
EXPORT_SYMBOL(__memset) EXPORT_SYMBOL(__memset)
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* Returns: * Returns:
* x0 - address of first occurrence of 'c' or 0 * x0 - address of first occurrence of 'c' or 0
*/ */
WEAK(strchr) SYM_FUNC_START_WEAK(strchr)
and w1, w1, #0xff and w1, w1, #0xff
1: ldrb w2, [x0], #1 1: ldrb w2, [x0], #1
cmp w2, w1 cmp w2, w1
...@@ -28,5 +28,5 @@ WEAK(strchr) ...@@ -28,5 +28,5 @@ WEAK(strchr)
cmp w2, w1 cmp w2, w1
csel x0, x0, xzr, eq csel x0, x0, xzr, eq
ret ret
ENDPROC(strchr) SYM_FUNC_END(strchr)
EXPORT_SYMBOL_NOKASAN(strchr) EXPORT_SYMBOL_NOKASAN(strchr)
...@@ -48,7 +48,7 @@ tmp3 .req x9 ...@@ -48,7 +48,7 @@ tmp3 .req x9
zeroones .req x10 zeroones .req x10
pos .req x11 pos .req x11
WEAK(strcmp) SYM_FUNC_START_WEAK_PI(strcmp)
eor tmp1, src1, src2 eor tmp1, src1, src2
mov zeroones, #REP8_01 mov zeroones, #REP8_01
tst tmp1, #7 tst tmp1, #7
...@@ -219,5 +219,5 @@ CPU_BE( orr syndrome, diff, has_nul ) ...@@ -219,5 +219,5 @@ CPU_BE( orr syndrome, diff, has_nul )
lsr data1, data1, #56 lsr data1, data1, #56
sub result, data1, data2, lsr #56 sub result, data1, data2, lsr #56
ret ret
ENDPIPROC(strcmp) SYM_FUNC_END_PI(strcmp)
EXPORT_SYMBOL_NOKASAN(strcmp) EXPORT_SYMBOL_NOKASAN(strcmp)
...@@ -44,7 +44,7 @@ pos .req x12 ...@@ -44,7 +44,7 @@ pos .req x12
#define REP8_7f 0x7f7f7f7f7f7f7f7f #define REP8_7f 0x7f7f7f7f7f7f7f7f
#define REP8_80 0x8080808080808080 #define REP8_80 0x8080808080808080
WEAK(strlen) SYM_FUNC_START_WEAK_PI(strlen)
mov zeroones, #REP8_01 mov zeroones, #REP8_01
bic src, srcin, #15 bic src, srcin, #15
ands tmp1, srcin, #15 ands tmp1, srcin, #15
...@@ -111,5 +111,5 @@ CPU_LE( lsr tmp2, tmp2, tmp1 ) /* Shift (tmp1 & 63). */ ...@@ -111,5 +111,5 @@ CPU_LE( lsr tmp2, tmp2, tmp1 ) /* Shift (tmp1 & 63). */
csinv data1, data1, xzr, le csinv data1, data1, xzr, le
csel data2, data2, data2a, le csel data2, data2, data2a, le
b .Lrealigned b .Lrealigned
ENDPIPROC(strlen) SYM_FUNC_END_PI(strlen)
EXPORT_SYMBOL_NOKASAN(strlen) EXPORT_SYMBOL_NOKASAN(strlen)
...@@ -52,7 +52,7 @@ limit_wd .req x13 ...@@ -52,7 +52,7 @@ limit_wd .req x13
mask .req x14 mask .req x14
endloop .req x15 endloop .req x15
WEAK(strncmp) SYM_FUNC_START_WEAK_PI(strncmp)
cbz limit, .Lret0 cbz limit, .Lret0
eor tmp1, src1, src2 eor tmp1, src1, src2
mov zeroones, #REP8_01 mov zeroones, #REP8_01
...@@ -295,5 +295,5 @@ CPU_BE( orr syndrome, diff, has_nul ) ...@@ -295,5 +295,5 @@ CPU_BE( orr syndrome, diff, has_nul )
.Lret0: .Lret0:
mov result, #0 mov result, #0
ret ret
ENDPIPROC(strncmp) SYM_FUNC_END_PI(strncmp)
EXPORT_SYMBOL_NOKASAN(strncmp) EXPORT_SYMBOL_NOKASAN(strncmp)
...@@ -47,7 +47,7 @@ limit_wd .req x14 ...@@ -47,7 +47,7 @@ limit_wd .req x14
#define REP8_7f 0x7f7f7f7f7f7f7f7f #define REP8_7f 0x7f7f7f7f7f7f7f7f
#define REP8_80 0x8080808080808080 #define REP8_80 0x8080808080808080
WEAK(strnlen) SYM_FUNC_START_WEAK_PI(strnlen)
cbz limit, .Lhit_limit cbz limit, .Lhit_limit
mov zeroones, #REP8_01 mov zeroones, #REP8_01
bic src, srcin, #15 bic src, srcin, #15
...@@ -156,5 +156,5 @@ CPU_LE( lsr tmp2, tmp2, tmp4 ) /* Shift (tmp1 & 63). */ ...@@ -156,5 +156,5 @@ CPU_LE( lsr tmp2, tmp2, tmp4 ) /* Shift (tmp1 & 63). */
.Lhit_limit: .Lhit_limit:
mov len, limit mov len, limit
ret ret
ENDPIPROC(strnlen) SYM_FUNC_END_PI(strnlen)
EXPORT_SYMBOL_NOKASAN(strnlen) EXPORT_SYMBOL_NOKASAN(strnlen)
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* Returns: * Returns:
* x0 - address of last occurrence of 'c' or 0 * x0 - address of last occurrence of 'c' or 0
*/ */
WEAK(strrchr) SYM_FUNC_START_WEAK_PI(strrchr)
mov x3, #0 mov x3, #0
and w1, w1, #0xff and w1, w1, #0xff
1: ldrb w2, [x0], #1 1: ldrb w2, [x0], #1
...@@ -29,5 +29,5 @@ WEAK(strrchr) ...@@ -29,5 +29,5 @@ WEAK(strrchr)
b 1b b 1b
2: mov x0, x3 2: mov x0, x3
ret ret
ENDPIPROC(strrchr) SYM_FUNC_END_PI(strrchr)
EXPORT_SYMBOL_NOKASAN(strrchr) EXPORT_SYMBOL_NOKASAN(strrchr)
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#include <asm/assembler.h> #include <asm/assembler.h>
ENTRY(__ashlti3) SYM_FUNC_START(__ashlti3)
cbz x2, 1f cbz x2, 1f
mov x3, #64 mov x3, #64
sub x3, x3, x2 sub x3, x3, x2
...@@ -26,10 +26,10 @@ ENTRY(__ashlti3) ...@@ -26,10 +26,10 @@ ENTRY(__ashlti3)
lsl x1, x0, x1 lsl x1, x0, x1
mov x0, x2 mov x0, x2
ret ret
ENDPROC(__ashlti3) SYM_FUNC_END(__ashlti3)
EXPORT_SYMBOL(__ashlti3) EXPORT_SYMBOL(__ashlti3)
ENTRY(__ashrti3) SYM_FUNC_START(__ashrti3)
cbz x2, 1f cbz x2, 1f
mov x3, #64 mov x3, #64
sub x3, x3, x2 sub x3, x3, x2
...@@ -48,10 +48,10 @@ ENTRY(__ashrti3) ...@@ -48,10 +48,10 @@ ENTRY(__ashrti3)
asr x0, x1, x0 asr x0, x1, x0
mov x1, x2 mov x1, x2
ret ret
ENDPROC(__ashrti3) SYM_FUNC_END(__ashrti3)
EXPORT_SYMBOL(__ashrti3) EXPORT_SYMBOL(__ashrti3)
ENTRY(__lshrti3) SYM_FUNC_START(__lshrti3)
cbz x2, 1f cbz x2, 1f
mov x3, #64 mov x3, #64
sub x3, x3, x2 sub x3, x3, x2
...@@ -70,5 +70,5 @@ ENTRY(__lshrti3) ...@@ -70,5 +70,5 @@ ENTRY(__lshrti3)
lsr x0, x1, x0 lsr x0, x1, x0
mov x1, x2 mov x1, x2
ret ret
ENDPROC(__lshrti3) SYM_FUNC_END(__lshrti3)
EXPORT_SYMBOL(__lshrti3) EXPORT_SYMBOL(__lshrti3)
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
* - start - virtual start address of region * - start - virtual start address of region
* - end - virtual end address of region * - end - virtual end address of region
*/ */
ENTRY(__flush_icache_range) SYM_FUNC_START(__flush_icache_range)
/* FALLTHROUGH */ /* FALLTHROUGH */
/* /*
...@@ -37,7 +37,7 @@ ENTRY(__flush_icache_range) ...@@ -37,7 +37,7 @@ ENTRY(__flush_icache_range)
* - start - virtual start address of region * - start - virtual start address of region
* - end - virtual end address of region * - end - virtual end address of region
*/ */
ENTRY(__flush_cache_user_range) SYM_FUNC_START(__flush_cache_user_range)
uaccess_ttbr0_enable x2, x3, x4 uaccess_ttbr0_enable x2, x3, x4
alternative_if ARM64_HAS_CACHE_IDC alternative_if ARM64_HAS_CACHE_IDC
dsb ishst dsb ishst
...@@ -66,8 +66,8 @@ alternative_else_nop_endif ...@@ -66,8 +66,8 @@ alternative_else_nop_endif
9: 9:
mov x0, #-EFAULT mov x0, #-EFAULT
b 1b b 1b
ENDPROC(__flush_icache_range) SYM_FUNC_END(__flush_icache_range)
ENDPROC(__flush_cache_user_range) SYM_FUNC_END(__flush_cache_user_range)
/* /*
* invalidate_icache_range(start,end) * invalidate_icache_range(start,end)
...@@ -77,7 +77,7 @@ ENDPROC(__flush_cache_user_range) ...@@ -77,7 +77,7 @@ ENDPROC(__flush_cache_user_range)
* - start - virtual start address of region * - start - virtual start address of region
* - end - virtual end address of region * - end - virtual end address of region
*/ */
ENTRY(invalidate_icache_range) SYM_FUNC_START(invalidate_icache_range)
alternative_if ARM64_HAS_CACHE_DIC alternative_if ARM64_HAS_CACHE_DIC
mov x0, xzr mov x0, xzr
isb isb
...@@ -94,7 +94,7 @@ alternative_else_nop_endif ...@@ -94,7 +94,7 @@ alternative_else_nop_endif
2: 2:
mov x0, #-EFAULT mov x0, #-EFAULT
b 1b b 1b
ENDPROC(invalidate_icache_range) SYM_FUNC_END(invalidate_icache_range)
/* /*
* __flush_dcache_area(kaddr, size) * __flush_dcache_area(kaddr, size)
...@@ -105,10 +105,10 @@ ENDPROC(invalidate_icache_range) ...@@ -105,10 +105,10 @@ ENDPROC(invalidate_icache_range)
* - kaddr - kernel address * - kaddr - kernel address
* - size - size in question * - size - size in question
*/ */
ENTRY(__flush_dcache_area) SYM_FUNC_START_PI(__flush_dcache_area)
dcache_by_line_op civac, sy, x0, x1, x2, x3 dcache_by_line_op civac, sy, x0, x1, x2, x3
ret ret
ENDPIPROC(__flush_dcache_area) SYM_FUNC_END_PI(__flush_dcache_area)
/* /*
* __clean_dcache_area_pou(kaddr, size) * __clean_dcache_area_pou(kaddr, size)
...@@ -119,14 +119,14 @@ ENDPIPROC(__flush_dcache_area) ...@@ -119,14 +119,14 @@ ENDPIPROC(__flush_dcache_area)
* - kaddr - kernel address * - kaddr - kernel address
* - size - size in question * - size - size in question
*/ */
ENTRY(__clean_dcache_area_pou) SYM_FUNC_START(__clean_dcache_area_pou)
alternative_if ARM64_HAS_CACHE_IDC alternative_if ARM64_HAS_CACHE_IDC
dsb ishst dsb ishst
ret ret
alternative_else_nop_endif alternative_else_nop_endif
dcache_by_line_op cvau, ish, x0, x1, x2, x3 dcache_by_line_op cvau, ish, x0, x1, x2, x3
ret ret
ENDPROC(__clean_dcache_area_pou) SYM_FUNC_END(__clean_dcache_area_pou)
/* /*
* __inval_dcache_area(kaddr, size) * __inval_dcache_area(kaddr, size)
...@@ -138,7 +138,8 @@ ENDPROC(__clean_dcache_area_pou) ...@@ -138,7 +138,8 @@ ENDPROC(__clean_dcache_area_pou)
* - kaddr - kernel address * - kaddr - kernel address
* - size - size in question * - size - size in question
*/ */
ENTRY(__inval_dcache_area) SYM_FUNC_START_LOCAL(__dma_inv_area)
SYM_FUNC_START_PI(__inval_dcache_area)
/* FALLTHROUGH */ /* FALLTHROUGH */
/* /*
...@@ -146,7 +147,6 @@ ENTRY(__inval_dcache_area) ...@@ -146,7 +147,6 @@ ENTRY(__inval_dcache_area)
* - start - virtual start address of region * - start - virtual start address of region
* - size - size in question * - size - size in question
*/ */
__dma_inv_area:
add x1, x1, x0 add x1, x1, x0
dcache_line_size x2, x3 dcache_line_size x2, x3
sub x3, x2, #1 sub x3, x2, #1
...@@ -165,8 +165,8 @@ __dma_inv_area: ...@@ -165,8 +165,8 @@ __dma_inv_area:
b.lo 2b b.lo 2b
dsb sy dsb sy
ret ret
ENDPIPROC(__inval_dcache_area) SYM_FUNC_END_PI(__inval_dcache_area)
ENDPROC(__dma_inv_area) SYM_FUNC_END(__dma_inv_area)
/* /*
* __clean_dcache_area_poc(kaddr, size) * __clean_dcache_area_poc(kaddr, size)
...@@ -177,7 +177,8 @@ ENDPROC(__dma_inv_area) ...@@ -177,7 +177,8 @@ ENDPROC(__dma_inv_area)
* - kaddr - kernel address * - kaddr - kernel address
* - size - size in question * - size - size in question
*/ */
ENTRY(__clean_dcache_area_poc) SYM_FUNC_START_LOCAL(__dma_clean_area)
SYM_FUNC_START_PI(__clean_dcache_area_poc)
/* FALLTHROUGH */ /* FALLTHROUGH */
/* /*
...@@ -185,11 +186,10 @@ ENTRY(__clean_dcache_area_poc) ...@@ -185,11 +186,10 @@ ENTRY(__clean_dcache_area_poc)
* - start - virtual start address of region * - start - virtual start address of region
* - size - size in question * - size - size in question
*/ */
__dma_clean_area:
dcache_by_line_op cvac, sy, x0, x1, x2, x3 dcache_by_line_op cvac, sy, x0, x1, x2, x3
ret ret
ENDPIPROC(__clean_dcache_area_poc) SYM_FUNC_END_PI(__clean_dcache_area_poc)
ENDPROC(__dma_clean_area) SYM_FUNC_END(__dma_clean_area)
/* /*
* __clean_dcache_area_pop(kaddr, size) * __clean_dcache_area_pop(kaddr, size)
...@@ -200,13 +200,13 @@ ENDPROC(__dma_clean_area) ...@@ -200,13 +200,13 @@ ENDPROC(__dma_clean_area)
* - kaddr - kernel address * - kaddr - kernel address
* - size - size in question * - size - size in question
*/ */
ENTRY(__clean_dcache_area_pop) SYM_FUNC_START_PI(__clean_dcache_area_pop)
alternative_if_not ARM64_HAS_DCPOP alternative_if_not ARM64_HAS_DCPOP
b __clean_dcache_area_poc b __clean_dcache_area_poc
alternative_else_nop_endif alternative_else_nop_endif
dcache_by_line_op cvap, sy, x0, x1, x2, x3 dcache_by_line_op cvap, sy, x0, x1, x2, x3
ret ret
ENDPIPROC(__clean_dcache_area_pop) SYM_FUNC_END_PI(__clean_dcache_area_pop)
/* /*
* __dma_flush_area(start, size) * __dma_flush_area(start, size)
...@@ -216,10 +216,10 @@ ENDPIPROC(__clean_dcache_area_pop) ...@@ -216,10 +216,10 @@ ENDPIPROC(__clean_dcache_area_pop)
* - start - virtual start address of region * - start - virtual start address of region
* - size - size in question * - size - size in question
*/ */
ENTRY(__dma_flush_area) SYM_FUNC_START_PI(__dma_flush_area)
dcache_by_line_op civac, sy, x0, x1, x2, x3 dcache_by_line_op civac, sy, x0, x1, x2, x3
ret ret
ENDPIPROC(__dma_flush_area) SYM_FUNC_END_PI(__dma_flush_area)
/* /*
* __dma_map_area(start, size, dir) * __dma_map_area(start, size, dir)
...@@ -227,11 +227,11 @@ ENDPIPROC(__dma_flush_area) ...@@ -227,11 +227,11 @@ ENDPIPROC(__dma_flush_area)
* - size - size of region * - size - size of region
* - dir - DMA direction * - dir - DMA direction
*/ */
ENTRY(__dma_map_area) SYM_FUNC_START_PI(__dma_map_area)
cmp w2, #DMA_FROM_DEVICE cmp w2, #DMA_FROM_DEVICE
b.eq __dma_inv_area b.eq __dma_inv_area
b __dma_clean_area b __dma_clean_area
ENDPIPROC(__dma_map_area) SYM_FUNC_END_PI(__dma_map_area)
/* /*
* __dma_unmap_area(start, size, dir) * __dma_unmap_area(start, size, dir)
...@@ -239,8 +239,8 @@ ENDPIPROC(__dma_map_area) ...@@ -239,8 +239,8 @@ ENDPIPROC(__dma_map_area)
* - size - size of region * - size - size of region
* - dir - DMA direction * - dir - DMA direction
*/ */
ENTRY(__dma_unmap_area) SYM_FUNC_START_PI(__dma_unmap_area)
cmp w2, #DMA_TO_DEVICE cmp w2, #DMA_TO_DEVICE
b.ne __dma_inv_area b.ne __dma_inv_area
ret ret
ENDPIPROC(__dma_unmap_area) SYM_FUNC_END_PI(__dma_unmap_area)
...@@ -29,15 +29,9 @@ static cpumask_t tlb_flush_pending; ...@@ -29,15 +29,9 @@ static cpumask_t tlb_flush_pending;
#define ASID_MASK (~GENMASK(asid_bits - 1, 0)) #define ASID_MASK (~GENMASK(asid_bits - 1, 0))
#define ASID_FIRST_VERSION (1UL << asid_bits) #define ASID_FIRST_VERSION (1UL << asid_bits)
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 #define NUM_USER_ASIDS ASID_FIRST_VERSION
#define NUM_USER_ASIDS (ASID_FIRST_VERSION >> 1)
#define asid2idx(asid) (((asid) & ~ASID_MASK) >> 1)
#define idx2asid(idx) (((idx) << 1) & ~ASID_MASK)
#else
#define NUM_USER_ASIDS (ASID_FIRST_VERSION)
#define asid2idx(asid) ((asid) & ~ASID_MASK) #define asid2idx(asid) ((asid) & ~ASID_MASK)
#define idx2asid(idx) asid2idx(idx) #define idx2asid(idx) asid2idx(idx)
#endif
/* Get the ASIDBits supported by the current CPU */ /* Get the ASIDBits supported by the current CPU */
static u32 get_cpu_asid_bits(void) static u32 get_cpu_asid_bits(void)
...@@ -77,13 +71,33 @@ void verify_cpu_asid_bits(void) ...@@ -77,13 +71,33 @@ void verify_cpu_asid_bits(void)
} }
} }
static void set_kpti_asid_bits(void)
{
unsigned int len = BITS_TO_LONGS(NUM_USER_ASIDS) * sizeof(unsigned long);
/*
* In case of KPTI kernel/user ASIDs are allocated in
* pairs, the bottom bit distinguishes the two: if it
* is set, then the ASID will map only userspace. Thus
* mark even as reserved for kernel.
*/
memset(asid_map, 0xaa, len);
}
static void set_reserved_asid_bits(void)
{
if (arm64_kernel_unmapped_at_el0())
set_kpti_asid_bits();
else
bitmap_clear(asid_map, 0, NUM_USER_ASIDS);
}
static void flush_context(void) static void flush_context(void)
{ {
int i; int i;
u64 asid; u64 asid;
/* Update the list of reserved ASIDs and the ASID bitmap. */ /* Update the list of reserved ASIDs and the ASID bitmap. */
bitmap_clear(asid_map, 0, NUM_USER_ASIDS); set_reserved_asid_bits();
for_each_possible_cpu(i) { for_each_possible_cpu(i) {
asid = atomic64_xchg_relaxed(&per_cpu(active_asids, i), 0); asid = atomic64_xchg_relaxed(&per_cpu(active_asids, i), 0);
...@@ -261,6 +275,14 @@ static int asids_init(void) ...@@ -261,6 +275,14 @@ static int asids_init(void)
panic("Failed to allocate bitmap for %lu ASIDs\n", panic("Failed to allocate bitmap for %lu ASIDs\n",
NUM_USER_ASIDS); NUM_USER_ASIDS);
/*
* We cannot call set_reserved_asid_bits() here because CPU
* caps are not finalized yet, so it is safer to assume KPTI
* and reserve kernel ASID's from beginning.
*/
if (IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0))
set_kpti_asid_bits();
pr_info("ASID allocator initialised with %lu entries\n", NUM_USER_ASIDS); pr_info("ASID allocator initialised with %lu entries\n", NUM_USER_ASIDS);
return 0; return 0;
} }
......
...@@ -54,7 +54,7 @@ static int change_memory_common(unsigned long addr, int numpages, ...@@ -54,7 +54,7 @@ static int change_memory_common(unsigned long addr, int numpages,
pgprot_t set_mask, pgprot_t clear_mask) pgprot_t set_mask, pgprot_t clear_mask)
{ {
unsigned long start = addr; unsigned long start = addr;
unsigned long size = PAGE_SIZE*numpages; unsigned long size = PAGE_SIZE * numpages;
unsigned long end = start + size; unsigned long end = start + size;
struct vm_struct *area; struct vm_struct *area;
int i; int i;
......
...@@ -42,7 +42,14 @@ ...@@ -42,7 +42,14 @@
#define TCR_KASAN_FLAGS 0 #define TCR_KASAN_FLAGS 0
#endif #endif
#define MAIR(attr, mt) ((attr) << ((mt) * 8)) /* Default MAIR_EL1 */
#define MAIR_EL1_SET \
(MAIR_ATTRIDX(MAIR_ATTR_DEVICE_nGnRnE, MT_DEVICE_nGnRnE) | \
MAIR_ATTRIDX(MAIR_ATTR_DEVICE_nGnRE, MT_DEVICE_nGnRE) | \
MAIR_ATTRIDX(MAIR_ATTR_DEVICE_GRE, MT_DEVICE_GRE) | \
MAIR_ATTRIDX(MAIR_ATTR_NORMAL_NC, MT_NORMAL_NC) | \
MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL) | \
MAIR_ATTRIDX(MAIR_ATTR_NORMAL_WT, MT_NORMAL_WT))
#ifdef CONFIG_CPU_PM #ifdef CONFIG_CPU_PM
/** /**
...@@ -50,7 +57,7 @@ ...@@ -50,7 +57,7 @@
* *
* x0: virtual address of context pointer * x0: virtual address of context pointer
*/ */
ENTRY(cpu_do_suspend) SYM_FUNC_START(cpu_do_suspend)
mrs x2, tpidr_el0 mrs x2, tpidr_el0
mrs x3, tpidrro_el0 mrs x3, tpidrro_el0
mrs x4, contextidr_el1 mrs x4, contextidr_el1
...@@ -74,7 +81,7 @@ alternative_endif ...@@ -74,7 +81,7 @@ alternative_endif
stp x10, x11, [x0, #64] stp x10, x11, [x0, #64]
stp x12, x13, [x0, #80] stp x12, x13, [x0, #80]
ret ret
ENDPROC(cpu_do_suspend) SYM_FUNC_END(cpu_do_suspend)
/** /**
* cpu_do_resume - restore CPU register context * cpu_do_resume - restore CPU register context
...@@ -82,7 +89,7 @@ ENDPROC(cpu_do_suspend) ...@@ -82,7 +89,7 @@ ENDPROC(cpu_do_suspend)
* x0: Address of context pointer * x0: Address of context pointer
*/ */
.pushsection ".idmap.text", "awx" .pushsection ".idmap.text", "awx"
ENTRY(cpu_do_resume) SYM_FUNC_START(cpu_do_resume)
ldp x2, x3, [x0] ldp x2, x3, [x0]
ldp x4, x5, [x0, #16] ldp x4, x5, [x0, #16]
ldp x6, x8, [x0, #32] ldp x6, x8, [x0, #32]
...@@ -131,7 +138,7 @@ alternative_else_nop_endif ...@@ -131,7 +138,7 @@ alternative_else_nop_endif
isb isb
ret ret
ENDPROC(cpu_do_resume) SYM_FUNC_END(cpu_do_resume)
.popsection .popsection
#endif #endif
...@@ -142,7 +149,7 @@ ENDPROC(cpu_do_resume) ...@@ -142,7 +149,7 @@ ENDPROC(cpu_do_resume)
* *
* - pgd_phys - physical address of new TTB * - pgd_phys - physical address of new TTB
*/ */
ENTRY(cpu_do_switch_mm) SYM_FUNC_START(cpu_do_switch_mm)
mrs x2, ttbr1_el1 mrs x2, ttbr1_el1
mmid x1, x1 // get mm->context.id mmid x1, x1 // get mm->context.id
phys_to_ttbr x3, x0 phys_to_ttbr x3, x0
...@@ -161,7 +168,7 @@ alternative_else_nop_endif ...@@ -161,7 +168,7 @@ alternative_else_nop_endif
msr ttbr0_el1, x3 // now update TTBR0 msr ttbr0_el1, x3 // now update TTBR0
isb isb
b post_ttbr_update_workaround // Back to C code... b post_ttbr_update_workaround // Back to C code...
ENDPROC(cpu_do_switch_mm) SYM_FUNC_END(cpu_do_switch_mm)
.pushsection ".idmap.text", "awx" .pushsection ".idmap.text", "awx"
...@@ -182,7 +189,7 @@ ENDPROC(cpu_do_switch_mm) ...@@ -182,7 +189,7 @@ ENDPROC(cpu_do_switch_mm)
* This is the low-level counterpart to cpu_replace_ttbr1, and should not be * This is the low-level counterpart to cpu_replace_ttbr1, and should not be
* called by anything else. It can only be executed from a TTBR0 mapping. * called by anything else. It can only be executed from a TTBR0 mapping.
*/ */
ENTRY(idmap_cpu_replace_ttbr1) SYM_FUNC_START(idmap_cpu_replace_ttbr1)
save_and_disable_daif flags=x2 save_and_disable_daif flags=x2
__idmap_cpu_set_reserved_ttbr1 x1, x3 __idmap_cpu_set_reserved_ttbr1 x1, x3
...@@ -194,7 +201,7 @@ ENTRY(idmap_cpu_replace_ttbr1) ...@@ -194,7 +201,7 @@ ENTRY(idmap_cpu_replace_ttbr1)
restore_daif x2 restore_daif x2
ret ret
ENDPROC(idmap_cpu_replace_ttbr1) SYM_FUNC_END(idmap_cpu_replace_ttbr1)
.popsection .popsection
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
...@@ -222,7 +229,7 @@ ENDPROC(idmap_cpu_replace_ttbr1) ...@@ -222,7 +229,7 @@ ENDPROC(idmap_cpu_replace_ttbr1)
*/ */
__idmap_kpti_flag: __idmap_kpti_flag:
.long 1 .long 1
ENTRY(idmap_kpti_install_ng_mappings) SYM_FUNC_START(idmap_kpti_install_ng_mappings)
cpu .req w0 cpu .req w0
num_cpus .req w1 num_cpus .req w1
swapper_pa .req x2 swapper_pa .req x2
...@@ -250,15 +257,15 @@ ENTRY(idmap_kpti_install_ng_mappings) ...@@ -250,15 +257,15 @@ ENTRY(idmap_kpti_install_ng_mappings)
/* We're the boot CPU. Wait for the others to catch up */ /* We're the boot CPU. Wait for the others to catch up */
sevl sevl
1: wfe 1: wfe
ldaxr w18, [flag_ptr] ldaxr w17, [flag_ptr]
eor w18, w18, num_cpus eor w17, w17, num_cpus
cbnz w18, 1b cbnz w17, 1b
/* We need to walk swapper, so turn off the MMU. */ /* We need to walk swapper, so turn off the MMU. */
pre_disable_mmu_workaround pre_disable_mmu_workaround
mrs x18, sctlr_el1 mrs x17, sctlr_el1
bic x18, x18, #SCTLR_ELx_M bic x17, x17, #SCTLR_ELx_M
msr sctlr_el1, x18 msr sctlr_el1, x17
isb isb
/* Everybody is enjoying the idmap, so we can rewrite swapper. */ /* Everybody is enjoying the idmap, so we can rewrite swapper. */
...@@ -281,9 +288,9 @@ skip_pgd: ...@@ -281,9 +288,9 @@ skip_pgd:
isb isb
/* We're done: fire up the MMU again */ /* We're done: fire up the MMU again */
mrs x18, sctlr_el1 mrs x17, sctlr_el1
orr x18, x18, #SCTLR_ELx_M orr x17, x17, #SCTLR_ELx_M
msr sctlr_el1, x18 msr sctlr_el1, x17
isb isb
/* /*
...@@ -353,47 +360,48 @@ skip_pte: ...@@ -353,47 +360,48 @@ skip_pte:
b.ne do_pte b.ne do_pte
b next_pmd b next_pmd
.unreq cpu
.unreq num_cpus
.unreq swapper_pa
.unreq cur_pgdp
.unreq end_pgdp
.unreq pgd
.unreq cur_pudp
.unreq end_pudp
.unreq pud
.unreq cur_pmdp
.unreq end_pmdp
.unreq pmd
.unreq cur_ptep
.unreq end_ptep
.unreq pte
/* Secondary CPUs end up here */ /* Secondary CPUs end up here */
__idmap_kpti_secondary: __idmap_kpti_secondary:
/* Uninstall swapper before surgery begins */ /* Uninstall swapper before surgery begins */
__idmap_cpu_set_reserved_ttbr1 x18, x17 __idmap_cpu_set_reserved_ttbr1 x16, x17
/* Increment the flag to let the boot CPU we're ready */ /* Increment the flag to let the boot CPU we're ready */
1: ldxr w18, [flag_ptr] 1: ldxr w16, [flag_ptr]
add w18, w18, #1 add w16, w16, #1
stxr w17, w18, [flag_ptr] stxr w17, w16, [flag_ptr]
cbnz w17, 1b cbnz w17, 1b
/* Wait for the boot CPU to finish messing around with swapper */ /* Wait for the boot CPU to finish messing around with swapper */
sevl sevl
1: wfe 1: wfe
ldxr w18, [flag_ptr] ldxr w16, [flag_ptr]
cbnz w18, 1b cbnz w16, 1b
/* All done, act like nothing happened */ /* All done, act like nothing happened */
offset_ttbr1 swapper_ttb, x18 offset_ttbr1 swapper_ttb, x16
msr ttbr1_el1, swapper_ttb msr ttbr1_el1, swapper_ttb
isb isb
ret ret
.unreq cpu
.unreq num_cpus
.unreq swapper_pa
.unreq swapper_ttb .unreq swapper_ttb
.unreq flag_ptr .unreq flag_ptr
.unreq cur_pgdp SYM_FUNC_END(idmap_kpti_install_ng_mappings)
.unreq end_pgdp
.unreq pgd
.unreq cur_pudp
.unreq end_pudp
.unreq pud
.unreq cur_pmdp
.unreq end_pmdp
.unreq pmd
.unreq cur_ptep
.unreq end_ptep
.unreq pte
ENDPROC(idmap_kpti_install_ng_mappings)
.popsection .popsection
#endif #endif
...@@ -404,7 +412,7 @@ ENDPROC(idmap_kpti_install_ng_mappings) ...@@ -404,7 +412,7 @@ ENDPROC(idmap_kpti_install_ng_mappings)
* value of the SCTLR_EL1 register. * value of the SCTLR_EL1 register.
*/ */
.pushsection ".idmap.text", "awx" .pushsection ".idmap.text", "awx"
ENTRY(__cpu_setup) SYM_FUNC_START(__cpu_setup)
tlbi vmalle1 // Invalidate local TLB tlbi vmalle1 // Invalidate local TLB
dsb nsh dsb nsh
...@@ -416,23 +424,9 @@ ENTRY(__cpu_setup) ...@@ -416,23 +424,9 @@ ENTRY(__cpu_setup)
enable_dbg // since this is per-cpu enable_dbg // since this is per-cpu
reset_pmuserenr_el0 x0 // Disable PMU access from EL0 reset_pmuserenr_el0 x0 // Disable PMU access from EL0
/* /*
* Memory region attributes for LPAE: * Memory region attributes
*
* n = AttrIndx[2:0]
* n MAIR
* DEVICE_nGnRnE 000 00000000
* DEVICE_nGnRE 001 00000100
* DEVICE_GRE 010 00001100
* NORMAL_NC 011 01000100
* NORMAL 100 11111111
* NORMAL_WT 101 10111011
*/ */
ldr x5, =MAIR(0x00, MT_DEVICE_nGnRnE) | \ mov_q x5, MAIR_EL1_SET
MAIR(0x04, MT_DEVICE_nGnRE) | \
MAIR(0x0c, MT_DEVICE_GRE) | \
MAIR(0x44, MT_NORMAL_NC) | \
MAIR(0xff, MT_NORMAL) | \
MAIR(0xbb, MT_NORMAL_WT)
msr mair_el1, x5 msr mair_el1, x5
/* /*
* Prepare SCTLR * Prepare SCTLR
...@@ -475,4 +469,4 @@ ENTRY(__cpu_setup) ...@@ -475,4 +469,4 @@ ENTRY(__cpu_setup)
#endif /* CONFIG_ARM64_HW_AFDBM */ #endif /* CONFIG_ARM64_HW_AFDBM */
msr tcr_el1, x10 msr tcr_el1, x10
ret // return to head.S ret // return to head.S
ENDPROC(__cpu_setup) SYM_FUNC_END(__cpu_setup)
...@@ -56,11 +56,11 @@ ...@@ -56,11 +56,11 @@
#define XEN_IMM 0xEA1 #define XEN_IMM 0xEA1
#define HYPERCALL_SIMPLE(hypercall) \ #define HYPERCALL_SIMPLE(hypercall) \
ENTRY(HYPERVISOR_##hypercall) \ SYM_FUNC_START(HYPERVISOR_##hypercall) \
mov x16, #__HYPERVISOR_##hypercall; \ mov x16, #__HYPERVISOR_##hypercall; \
hvc XEN_IMM; \ hvc XEN_IMM; \
ret; \ ret; \
ENDPROC(HYPERVISOR_##hypercall) SYM_FUNC_END(HYPERVISOR_##hypercall)
#define HYPERCALL0 HYPERCALL_SIMPLE #define HYPERCALL0 HYPERCALL_SIMPLE
#define HYPERCALL1 HYPERCALL_SIMPLE #define HYPERCALL1 HYPERCALL_SIMPLE
...@@ -86,7 +86,7 @@ HYPERCALL2(multicall); ...@@ -86,7 +86,7 @@ HYPERCALL2(multicall);
HYPERCALL2(vm_assist); HYPERCALL2(vm_assist);
HYPERCALL3(dm_op); HYPERCALL3(dm_op);
ENTRY(privcmd_call) SYM_FUNC_START(privcmd_call)
mov x16, x0 mov x16, x0
mov x0, x1 mov x0, x1
mov x1, x2 mov x1, x2
...@@ -109,4 +109,4 @@ ENTRY(privcmd_call) ...@@ -109,4 +109,4 @@ ENTRY(privcmd_call)
*/ */
uaccess_ttbr0_disable x6, x7 uaccess_ttbr0_disable x6, x7
ret ret
ENDPROC(privcmd_call); SYM_FUNC_END(privcmd_call);
...@@ -298,6 +298,59 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node, ...@@ -298,6 +298,59 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
return status; return status;
} }
struct iort_workaround_oem_info {
char oem_id[ACPI_OEM_ID_SIZE + 1];
char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1];
u32 oem_revision;
};
static bool apply_id_count_workaround;
static struct iort_workaround_oem_info wa_info[] __initdata = {
{
.oem_id = "HISI ",
.oem_table_id = "HIP07 ",
.oem_revision = 0,
}, {
.oem_id = "HISI ",
.oem_table_id = "HIP08 ",
.oem_revision = 0,
}
};
static void __init
iort_check_id_count_workaround(struct acpi_table_header *tbl)
{
int i;
for (i = 0; i < ARRAY_SIZE(wa_info); i++) {
if (!memcmp(wa_info[i].oem_id, tbl->oem_id, ACPI_OEM_ID_SIZE) &&
!memcmp(wa_info[i].oem_table_id, tbl->oem_table_id, ACPI_OEM_TABLE_ID_SIZE) &&
wa_info[i].oem_revision == tbl->oem_revision) {
apply_id_count_workaround = true;
pr_warn(FW_BUG "ID count for ID mapping entry is wrong, applying workaround\n");
break;
}
}
}
static inline u32 iort_get_map_max(struct acpi_iort_id_mapping *map)
{
u32 map_max = map->input_base + map->id_count;
/*
* The IORT specification revision D (Section 3, table 4, page 9) says
* Number of IDs = The number of IDs in the range minus one, but the
* IORT code ignored the "minus one", and some firmware did that too,
* so apply a workaround here to keep compatible with both the spec
* compliant and non-spec compliant firmwares.
*/
if (apply_id_count_workaround)
map_max--;
return map_max;
}
static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in, static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
u32 *rid_out) u32 *rid_out)
{ {
...@@ -314,8 +367,7 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in, ...@@ -314,8 +367,7 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
return -ENXIO; return -ENXIO;
} }
if (rid_in < map->input_base || if (rid_in < map->input_base || rid_in > iort_get_map_max(map))
(rid_in >= map->input_base + map->id_count))
return -ENXIO; return -ENXIO;
*rid_out = map->output_base + (rid_in - map->input_base); *rid_out = map->output_base + (rid_in - map->input_base);
...@@ -1631,5 +1683,6 @@ void __init acpi_iort_init(void) ...@@ -1631,5 +1683,6 @@ void __init acpi_iort_init(void)
return; return;
} }
iort_check_id_count_workaround(iort_table);
iort_init_platform_devices(); iort_init_platform_devices();
} }
...@@ -633,13 +633,17 @@ static int ddr_perf_probe(struct platform_device *pdev) ...@@ -633,13 +633,17 @@ static int ddr_perf_probe(struct platform_device *pdev)
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "cpuhp_setup_state_multi failed\n"); dev_err(&pdev->dev, "cpuhp_setup_state_multi failed\n");
goto ddr_perf_err; goto cpuhp_state_err;
} }
pmu->cpuhp_state = ret; pmu->cpuhp_state = ret;
/* Register the pmu instance for cpu hotplug */ /* Register the pmu instance for cpu hotplug */
cpuhp_state_add_instance_nocalls(pmu->cpuhp_state, &pmu->node); ret = cpuhp_state_add_instance_nocalls(pmu->cpuhp_state, &pmu->node);
if (ret) {
dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
goto cpuhp_instance_err;
}
/* Request irq */ /* Request irq */
irq = of_irq_get(np, 0); irq = of_irq_get(np, 0);
...@@ -673,9 +677,10 @@ static int ddr_perf_probe(struct platform_device *pdev) ...@@ -673,9 +677,10 @@ static int ddr_perf_probe(struct platform_device *pdev)
return 0; return 0;
ddr_perf_err: ddr_perf_err:
if (pmu->cpuhp_state)
cpuhp_state_remove_instance_nocalls(pmu->cpuhp_state, &pmu->node); cpuhp_state_remove_instance_nocalls(pmu->cpuhp_state, &pmu->node);
cpuhp_instance_err:
cpuhp_remove_multi_state(pmu->cpuhp_state);
cpuhp_state_err:
ida_simple_remove(&ddr_ida, pmu->id); ida_simple_remove(&ddr_ida, pmu->id);
dev_warn(&pdev->dev, "i.MX8 DDR Perf PMU failed (%d), disabled\n", ret); dev_warn(&pdev->dev, "i.MX8 DDR Perf PMU failed (%d), disabled\n", ret);
return ret; return ret;
...@@ -686,6 +691,7 @@ static int ddr_perf_remove(struct platform_device *pdev) ...@@ -686,6 +691,7 @@ static int ddr_perf_remove(struct platform_device *pdev)
struct ddr_pmu *pmu = platform_get_drvdata(pdev); struct ddr_pmu *pmu = platform_get_drvdata(pdev);
cpuhp_state_remove_instance_nocalls(pmu->cpuhp_state, &pmu->node); cpuhp_state_remove_instance_nocalls(pmu->cpuhp_state, &pmu->node);
cpuhp_remove_multi_state(pmu->cpuhp_state);
irq_set_affinity_hint(pmu->irq, NULL); irq_set_affinity_hint(pmu->irq, NULL);
perf_pmu_unregister(&pmu->pmu); perf_pmu_unregister(&pmu->pmu);
......
...@@ -337,38 +337,44 @@ void hisi_uncore_pmu_disable(struct pmu *pmu) ...@@ -337,38 +337,44 @@ void hisi_uncore_pmu_disable(struct pmu *pmu)
hisi_pmu->ops->stop_counters(hisi_pmu); hisi_pmu->ops->stop_counters(hisi_pmu);
} }
/* /*
* Read Super CPU cluster and CPU cluster ID from MPIDR_EL1. * The Super CPU Cluster (SCCL) and CPU Cluster (CCL) IDs can be
* If multi-threading is supported, On Huawei Kunpeng 920 SoC whose cpu * determined from the MPIDR_EL1, but the encoding varies by CPU:
* core is tsv110, CCL_ID is the low 3-bits in MPIDR[Aff2] and SCCL_ID *
* is the upper 5-bits of Aff2 field; while for other cpu types, SCCL_ID * - For MT variants of TSV110:
* is in MPIDR[Aff3] and CCL_ID is in MPIDR[Aff2], if not, SCCL_ID * SCCL is Aff2[7:3], CCL is Aff2[2:0]
* is in MPIDR[Aff2] and CCL_ID is in MPIDR[Aff1]. *
* - For other MT parts:
* SCCL is Aff3[7:0], CCL is Aff2[7:0]
*
* - For non-MT parts:
* SCCL is Aff2[7:0], CCL is Aff1[7:0]
*/ */
static void hisi_read_sccl_and_ccl_id(int *sccl_id, int *ccl_id) static void hisi_read_sccl_and_ccl_id(int *scclp, int *cclp)
{ {
u64 mpidr = read_cpuid_mpidr(); u64 mpidr = read_cpuid_mpidr();
int aff3 = MPIDR_AFFINITY_LEVEL(mpidr, 3);
if (mpidr & MPIDR_MT_BITMASK) {
if (read_cpuid_part_number() == HISI_CPU_PART_TSV110) {
int aff2 = MPIDR_AFFINITY_LEVEL(mpidr, 2); int aff2 = MPIDR_AFFINITY_LEVEL(mpidr, 2);
int aff1 = MPIDR_AFFINITY_LEVEL(mpidr, 1);
if (sccl_id) bool mt = mpidr & MPIDR_MT_BITMASK;
*sccl_id = aff2 >> 3; int sccl, ccl;
if (ccl_id)
*ccl_id = aff2 & 0x7; if (mt && read_cpuid_part_number() == HISI_CPU_PART_TSV110) {
} else { sccl = aff2 >> 3;
if (sccl_id) ccl = aff2 & 0x7;
*sccl_id = MPIDR_AFFINITY_LEVEL(mpidr, 3); } else if (mt) {
if (ccl_id) sccl = aff3;
*ccl_id = MPIDR_AFFINITY_LEVEL(mpidr, 2); ccl = aff2;
}
} else { } else {
if (sccl_id) sccl = aff2;
*sccl_id = MPIDR_AFFINITY_LEVEL(mpidr, 2); ccl = aff1;
if (ccl_id)
*ccl_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
} }
if (scclp)
*scclp = sccl;
if (cclp)
*cclp = ccl;
} }
/* /*
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#define PROT_WRITE 0x2 /* page can be written */ #define PROT_WRITE 0x2 /* page can be written */
#define PROT_EXEC 0x4 /* page can be executed */ #define PROT_EXEC 0x4 /* page can be executed */
#define PROT_SEM 0x8 /* page may be used for atomic ops */ #define PROT_SEM 0x8 /* page may be used for atomic ops */
/* 0x10 reserved for arch-specific use */
/* 0x20 reserved for arch-specific use */
#define PROT_NONE 0x0 /* page can not be accessed */ #define PROT_NONE 0x0 /* page can not be accessed */
#define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */ #define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */
#define PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */ #define PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */
......
...@@ -159,6 +159,10 @@ static int do_kexec_load(unsigned long entry, unsigned long nr_segments, ...@@ -159,6 +159,10 @@ static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
kimage_terminate(image); kimage_terminate(image);
ret = machine_kexec_post_load(image);
if (ret)
goto out;
/* Install the new kernel and uninstall the old */ /* Install the new kernel and uninstall the old */
image = xchg(dest_image, image); image = xchg(dest_image, image);
......
...@@ -589,6 +589,12 @@ static void kimage_free_extra_pages(struct kimage *image) ...@@ -589,6 +589,12 @@ static void kimage_free_extra_pages(struct kimage *image)
kimage_free_page_list(&image->unusable_pages); kimage_free_page_list(&image->unusable_pages);
} }
int __weak machine_kexec_post_load(struct kimage *image)
{
return 0;
}
void kimage_terminate(struct kimage *image) void kimage_terminate(struct kimage *image)
{ {
if (*image->entry != 0) if (*image->entry != 0)
...@@ -1171,7 +1177,7 @@ int kernel_kexec(void) ...@@ -1171,7 +1177,7 @@ int kernel_kexec(void)
* CPU hotplug again; so re-enable it here. * CPU hotplug again; so re-enable it here.
*/ */
cpu_hotplug_enable(); cpu_hotplug_enable();
pr_emerg("Starting new kernel\n"); pr_notice("Starting new kernel\n");
machine_shutdown(); machine_shutdown();
} }
......
...@@ -441,6 +441,10 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, ...@@ -441,6 +441,10 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd,
kimage_terminate(image); kimage_terminate(image);
ret = machine_kexec_post_load(image);
if (ret)
goto out;
/* /*
* Free up any temporary buffers allocated which are not needed * Free up any temporary buffers allocated which are not needed
* after image has been loaded * after image has been loaded
......
...@@ -13,6 +13,8 @@ void kimage_terminate(struct kimage *image); ...@@ -13,6 +13,8 @@ void kimage_terminate(struct kimage *image);
int kimage_is_destination_range(struct kimage *image, int kimage_is_destination_range(struct kimage *image,
unsigned long start, unsigned long end); unsigned long start, unsigned long end);
int machine_kexec_post_load(struct kimage *image);
extern struct mutex kexec_mutex; extern struct mutex kexec_mutex;
#ifdef CONFIG_KEXEC_FILE #ifdef CONFIG_KEXEC_FILE
......
...@@ -223,7 +223,7 @@ KASAN_SANITIZE_stackdepot.o := n ...@@ -223,7 +223,7 @@ KASAN_SANITIZE_stackdepot.o := n
KCOV_INSTRUMENT_stackdepot.o := n KCOV_INSTRUMENT_stackdepot.o := n
libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o \ libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o \
fdt_empty_tree.o fdt_empty_tree.o fdt_addresses.o
$(foreach file, $(libfdt_files), \ $(foreach file, $(libfdt_files), \
$(eval CFLAGS_$(file) = -I $(srctree)/scripts/dtc/libfdt)) $(eval CFLAGS_$(file) = -I $(srctree)/scripts/dtc/libfdt))
lib-$(CONFIG_LIBFDT) += $(libfdt_files) lib-$(CONFIG_LIBFDT) += $(libfdt_files)
......
#include <linux/libfdt_env.h>
#include "../scripts/dtc/libfdt/fdt_addresses.c"
...@@ -31,6 +31,10 @@ cc-option = $(success,$(CC) -Werror $(CLANG_FLAGS) $(1) -E -x c /dev/null -o /de ...@@ -31,6 +31,10 @@ cc-option = $(success,$(CC) -Werror $(CLANG_FLAGS) $(1) -E -x c /dev/null -o /de
# Return y if the linker supports <flag>, n otherwise # Return y if the linker supports <flag>, n otherwise
ld-option = $(success,$(LD) -v $(1)) ld-option = $(success,$(LD) -v $(1))
# $(as-instr,<instr>)
# Return y if the assembler supports <instr>, n otherwise
as-instr = $(success,printf "%b\n" "$(1)" | $(CC) $(CLANG_FLAGS) -c -x assembler -o /dev/null -)
# check if $(CC) and $(LD) exist # check if $(CC) and $(LD) exist
$(error-if,$(failure,command -v $(CC)),compiler '$(CC)' not found) $(error-if,$(failure,command -v $(CC)),compiler '$(CC)' not found)
$(error-if,$(failure,command -v $(LD)),linker '$(LD)' not found) $(error-if,$(failure,command -v $(LD)),linker '$(LD)' not found)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment