2019-06-03 13:44:50 +08:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
2012-03-05 19:49:28 +08:00
|
|
|
/*
|
|
|
|
* Based on arch/arm/mm/proc.S
|
|
|
|
*
|
|
|
|
* Copyright (C) 2001 Deep Blue Solutions Ltd.
|
|
|
|
* Copyright (C) 2012 ARM Ltd.
|
|
|
|
* Author: Catalin Marinas <catalin.marinas@arm.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/linkage.h>
|
2020-06-09 12:32:42 +08:00
|
|
|
#include <linux/pgtable.h>
|
2022-09-09 05:54:51 +08:00
|
|
|
#include <linux/cfi_types.h>
|
2012-03-05 19:49:28 +08:00
|
|
|
#include <asm/assembler.h>
|
|
|
|
#include <asm/asm-offsets.h>
|
2020-03-13 17:05:01 +08:00
|
|
|
#include <asm/asm_pointer_auth.h>
|
2012-03-05 19:49:28 +08:00
|
|
|
#include <asm/hwcap.h>
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
#include <asm/kernel-pgtable.h>
|
2016-04-28 00:47:07 +08:00
|
|
|
#include <asm/pgtable-hwdef.h>
|
2016-02-25 09:44:57 +08:00
|
|
|
#include <asm/cpufeature.h>
|
|
|
|
#include <asm/alternative.h>
|
2020-03-13 17:04:55 +08:00
|
|
|
#include <asm/smp.h>
|
2019-09-06 17:58:01 +08:00
|
|
|
#include <asm/sysreg.h>
|
2012-03-05 19:49:28 +08:00
|
|
|
|
2014-04-03 00:55:40 +08:00
|
|
|
#ifdef CONFIG_ARM64_64K_PAGES
|
|
|
|
#define TCR_TG_FLAGS TCR_TG0_64K | TCR_TG1_64K
|
2015-10-19 21:19:37 +08:00
|
|
|
#elif defined(CONFIG_ARM64_16K_PAGES)
|
|
|
|
#define TCR_TG_FLAGS TCR_TG0_16K | TCR_TG1_16K
|
|
|
|
#else /* CONFIG_ARM64_4K_PAGES */
|
2014-04-03 00:55:40 +08:00
|
|
|
#define TCR_TG_FLAGS TCR_TG0_4K | TCR_TG1_4K
|
|
|
|
#endif
|
|
|
|
|
2018-02-27 22:15:49 +08:00
|
|
|
#ifdef CONFIG_RANDOMIZE_BASE
|
|
|
|
#define TCR_KASLR_FLAGS TCR_NFD1
|
|
|
|
#else
|
|
|
|
#define TCR_KASLR_FLAGS 0
|
|
|
|
#endif
|
|
|
|
|
2014-04-03 00:55:40 +08:00
|
|
|
#define TCR_SMP_FLAGS TCR_SHARED
|
2012-03-05 19:49:28 +08:00
|
|
|
|
2014-04-03 00:55:40 +08:00
|
|
|
/* PTWs cacheable, inner/outer WBWA */
|
|
|
|
#define TCR_CACHE_FLAGS TCR_IRGN_WBWA | TCR_ORGN_WBWA
|
|
|
|
|
2018-12-28 16:30:31 +08:00
|
|
|
#ifdef CONFIG_KASAN_SW_TAGS
|
2020-12-23 04:01:38 +08:00
|
|
|
#define TCR_KASAN_SW_FLAGS TCR_TBI1 | TCR_TBID1
|
2018-12-28 16:30:31 +08:00
|
|
|
#else
|
2020-12-23 04:01:38 +08:00
|
|
|
#define TCR_KASAN_SW_FLAGS 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_KASAN_HW_TAGS
|
2022-01-25 22:38:33 +08:00
|
|
|
#define TCR_MTE_FLAGS TCR_TCMA1 | TCR_TBI1 | TCR_TBID1
|
2022-09-16 06:20:53 +08:00
|
|
|
#elif defined(CONFIG_ARM64_MTE)
|
2021-06-03 07:52:29 +08:00
|
|
|
/*
|
|
|
|
* The mte_zero_clear_page_tags() implementation uses DC GZVA, which relies on
|
|
|
|
* TBI being enabled at EL1.
|
|
|
|
*/
|
|
|
|
#define TCR_MTE_FLAGS TCR_TBI1 | TCR_TBID1
|
2022-09-16 06:20:53 +08:00
|
|
|
#else
|
|
|
|
#define TCR_MTE_FLAGS 0
|
2018-12-28 16:30:31 +08:00
|
|
|
#endif
|
|
|
|
|
2019-11-27 17:51:13 +08:00
|
|
|
/*
|
|
|
|
* Default MAIR_EL1. MT_NORMAL_TAGGED is initially mapped as Normal memory and
|
2022-09-16 06:20:53 +08:00
|
|
|
* changed during mte_cpu_setup to Normal Tagged if the system supports MTE.
|
2019-11-27 17:51:13 +08:00
|
|
|
*/
|
2019-12-12 02:40:09 +08:00
|
|
|
#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_NORMAL_NC, MT_NORMAL_NC) | \
|
|
|
|
MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL) | \
|
2019-11-27 17:51:13 +08:00
|
|
|
MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL_TAGGED))
|
2012-03-05 19:49:28 +08:00
|
|
|
|
2015-01-27 02:33:44 +08:00
|
|
|
#ifdef CONFIG_CPU_PM
|
2013-07-17 17:14:45 +08:00
|
|
|
/**
|
|
|
|
* cpu_do_suspend - save CPU registers context
|
|
|
|
*
|
|
|
|
* x0: virtual address of context pointer
|
2020-04-28 00:00:12 +08:00
|
|
|
*
|
|
|
|
* This must be kept in sync with struct cpu_suspend_ctx in <asm/suspend.h>.
|
2013-07-17 17:14:45 +08:00
|
|
|
*/
|
2020-01-07 03:58:18 +08:00
|
|
|
SYM_FUNC_START(cpu_do_suspend)
|
2013-07-17 17:14:45 +08:00
|
|
|
mrs x2, tpidr_el0
|
|
|
|
mrs x3, tpidrro_el0
|
|
|
|
mrs x4, contextidr_el1
|
2019-04-09 01:17:19 +08:00
|
|
|
mrs x5, osdlr_el1
|
|
|
|
mrs x6, cpacr_el1
|
|
|
|
mrs x7, tcr_el1
|
|
|
|
mrs x8, vbar_el1
|
|
|
|
mrs x9, mdscr_el1
|
|
|
|
mrs x10, oslsr_el1
|
|
|
|
mrs x11, sctlr_el1
|
2021-05-20 19:50:27 +08:00
|
|
|
get_this_cpu_offset x12
|
2019-04-09 01:17:19 +08:00
|
|
|
mrs x13, sp_el0
|
2013-07-17 17:14:45 +08:00
|
|
|
stp x2, x3, [x0]
|
2019-04-09 01:17:19 +08:00
|
|
|
stp x4, x5, [x0, #16]
|
|
|
|
stp x6, x7, [x0, #32]
|
|
|
|
stp x8, x9, [x0, #48]
|
|
|
|
stp x10, x11, [x0, #64]
|
|
|
|
stp x12, x13, [x0, #80]
|
2020-04-28 00:00:12 +08:00
|
|
|
/*
|
|
|
|
* Save x18 as it may be used as a platform register, e.g. by shadow
|
|
|
|
* call stack.
|
|
|
|
*/
|
|
|
|
str x18, [x0, #96]
|
2013-07-17 17:14:45 +08:00
|
|
|
ret
|
2020-01-07 03:58:18 +08:00
|
|
|
SYM_FUNC_END(cpu_do_suspend)
|
2013-07-17 17:14:45 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* cpu_do_resume - restore CPU register context
|
|
|
|
*
|
2016-04-28 00:47:07 +08:00
|
|
|
* x0: Address of context pointer
|
2013-07-17 17:14:45 +08:00
|
|
|
*/
|
2020-01-07 03:58:18 +08:00
|
|
|
SYM_FUNC_START(cpu_do_resume)
|
2013-07-17 17:14:45 +08:00
|
|
|
ldp x2, x3, [x0]
|
|
|
|
ldp x4, x5, [x0, #16]
|
2016-04-28 00:47:07 +08:00
|
|
|
ldp x6, x8, [x0, #32]
|
|
|
|
ldp x9, x10, [x0, #48]
|
|
|
|
ldp x11, x12, [x0, #64]
|
2016-11-04 04:23:09 +08:00
|
|
|
ldp x13, x14, [x0, #80]
|
2020-04-28 00:00:12 +08:00
|
|
|
/*
|
|
|
|
* Restore x18, as it may be used as a platform register, and clear
|
|
|
|
* the buffer to minimize the risk of exposure when used for shadow
|
|
|
|
* call stack.
|
|
|
|
*/
|
|
|
|
ldr x18, [x0, #96]
|
|
|
|
str xzr, [x0, #96]
|
2013-07-17 17:14:45 +08:00
|
|
|
msr tpidr_el0, x2
|
|
|
|
msr tpidrro_el0, x3
|
|
|
|
msr contextidr_el1, x4
|
|
|
|
msr cpacr_el1, x6
|
2016-04-28 00:47:07 +08:00
|
|
|
|
|
|
|
/* Don't change t0sz here, mask those bits when restoring */
|
2019-04-09 01:17:19 +08:00
|
|
|
mrs x7, tcr_el1
|
|
|
|
bfi x8, x7, TCR_T0SZ_OFFSET, TCR_TxSZ_WIDTH
|
2016-04-28 00:47:07 +08:00
|
|
|
|
2013-07-17 17:14:45 +08:00
|
|
|
msr tcr_el1, x8
|
|
|
|
msr vbar_el1, x9
|
2016-08-26 23:03:42 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* __cpu_setup() cleared MDSCR_EL1.MDE and friends, before unmasking
|
|
|
|
* debug exceptions. By restoring MDSCR_EL1 here, we may take a debug
|
2017-11-02 20:12:34 +08:00
|
|
|
* exception. Mask them until local_daif_restore() in cpu_suspend()
|
2016-08-26 23:03:42 +08:00
|
|
|
* resets them.
|
|
|
|
*/
|
2017-11-02 20:12:34 +08:00
|
|
|
disable_daif
|
2013-07-17 17:14:45 +08:00
|
|
|
msr mdscr_el1, x10
|
2016-08-26 23:03:42 +08:00
|
|
|
|
2016-04-28 00:47:07 +08:00
|
|
|
msr sctlr_el1, x12
|
2021-05-20 19:50:27 +08:00
|
|
|
set_this_cpu_offset x13
|
2016-11-04 04:23:09 +08:00
|
|
|
msr sp_el0, x14
|
2013-07-17 17:14:45 +08:00
|
|
|
/*
|
|
|
|
* Restore oslsr_el1 by writing oslar_el1
|
|
|
|
*/
|
2019-04-09 01:17:19 +08:00
|
|
|
msr osdlr_el1, x5
|
2013-07-17 17:14:45 +08:00
|
|
|
ubfx x11, x11, #1, #1
|
|
|
|
msr oslar_el1, x11
|
2016-01-13 22:50:03 +08:00
|
|
|
reset_pmuserenr_el0 x0 // Disable PMU access from EL0
|
2020-03-05 17:06:22 +08:00
|
|
|
reset_amuserenr_el0 x0 // Disable AMU access from EL0
|
2018-01-16 03:38:59 +08:00
|
|
|
|
|
|
|
alternative_if ARM64_HAS_RAS_EXTN
|
|
|
|
msr_s SYS_DISR_EL1, xzr
|
|
|
|
alternative_else_nop_endif
|
|
|
|
|
2020-04-23 18:16:05 +08:00
|
|
|
ptrauth_keys_install_kernel_nosync x14, x1, x2, x3
|
2013-07-17 17:14:45 +08:00
|
|
|
isb
|
|
|
|
ret
|
2020-01-07 03:58:18 +08:00
|
|
|
SYM_FUNC_END(cpu_do_resume)
|
2013-07-17 17:14:45 +08:00
|
|
|
#endif
|
|
|
|
|
2023-04-29 02:28:17 +08:00
|
|
|
.pushsection ".idmap.text", "a"
|
2018-02-07 06:22:50 +08:00
|
|
|
|
|
|
|
.macro __idmap_cpu_set_reserved_ttbr1, tmp1, tmp2
|
2020-11-03 18:22:29 +08:00
|
|
|
adrp \tmp1, reserved_pg_dir
|
2018-01-29 19:59:57 +08:00
|
|
|
phys_to_ttbr \tmp2, \tmp1
|
2019-08-07 23:55:19 +08:00
|
|
|
offset_ttbr1 \tmp2, \tmp1
|
2018-02-07 06:22:50 +08:00
|
|
|
msr ttbr1_el1, \tmp2
|
|
|
|
isb
|
|
|
|
tlbi vmalle1
|
|
|
|
dsb nsh
|
|
|
|
isb
|
|
|
|
.endm
|
|
|
|
|
arm64: mm: add code to safely replace TTBR1_EL1
If page tables are modified without suitable TLB maintenance, the ARM
architecture permits multiple TLB entries to be allocated for the same
VA. When this occurs, it is permitted that TLB conflict aborts are
raised in response to synchronous data/instruction accesses, and/or and
amalgamation of the TLB entries may be used as a result of a TLB lookup.
The presence of conflicting TLB entries may result in a variety of
behaviours detrimental to the system (e.g. erroneous physical addresses
may be used by I-cache fetches and/or page table walks). Some of these
cases may result in unexpected changes of hardware state, and/or result
in the (asynchronous) delivery of SError.
To avoid these issues, we must avoid situations where conflicting
entries may be allocated into TLBs. For user and module mappings we can
follow a strict break-before-make approach, but this cannot work for
modifications to the swapper page tables that cover the kernel text and
data.
Instead, this patch adds code which is intended to be executed from the
idmap, which can safely unmap the swapper page tables as it only
requires the idmap to be active. This enables us to uninstall the active
TTBR1_EL1 entry, invalidate TLBs, then install a new TTBR1_EL1 entry
without potentially unmapping code or data required for the sequence.
This avoids the risk of conflict, but requires that updates are staged
in a copy of the swapper page tables prior to being installed.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Tested-by: Jeremy Linton <jeremy.linton@arm.com>
Cc: Laura Abbott <labbott@fedoraproject.org>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2016-01-25 19:45:01 +08:00
|
|
|
/*
|
2018-07-31 21:08:56 +08:00
|
|
|
* void idmap_cpu_replace_ttbr1(phys_addr_t ttbr1)
|
arm64: mm: add code to safely replace TTBR1_EL1
If page tables are modified without suitable TLB maintenance, the ARM
architecture permits multiple TLB entries to be allocated for the same
VA. When this occurs, it is permitted that TLB conflict aborts are
raised in response to synchronous data/instruction accesses, and/or and
amalgamation of the TLB entries may be used as a result of a TLB lookup.
The presence of conflicting TLB entries may result in a variety of
behaviours detrimental to the system (e.g. erroneous physical addresses
may be used by I-cache fetches and/or page table walks). Some of these
cases may result in unexpected changes of hardware state, and/or result
in the (asynchronous) delivery of SError.
To avoid these issues, we must avoid situations where conflicting
entries may be allocated into TLBs. For user and module mappings we can
follow a strict break-before-make approach, but this cannot work for
modifications to the swapper page tables that cover the kernel text and
data.
Instead, this patch adds code which is intended to be executed from the
idmap, which can safely unmap the swapper page tables as it only
requires the idmap to be active. This enables us to uninstall the active
TTBR1_EL1 entry, invalidate TLBs, then install a new TTBR1_EL1 entry
without potentially unmapping code or data required for the sequence.
This avoids the risk of conflict, but requires that updates are staged
in a copy of the swapper page tables prior to being installed.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Tested-by: Jeremy Linton <jeremy.linton@arm.com>
Cc: Laura Abbott <labbott@fedoraproject.org>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2016-01-25 19:45:01 +08:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2022-09-09 05:54:51 +08:00
|
|
|
SYM_TYPED_FUNC_START(idmap_cpu_replace_ttbr1)
|
2018-02-07 06:22:50 +08:00
|
|
|
__idmap_cpu_set_reserved_ttbr1 x1, x3
|
arm64: mm: add code to safely replace TTBR1_EL1
If page tables are modified without suitable TLB maintenance, the ARM
architecture permits multiple TLB entries to be allocated for the same
VA. When this occurs, it is permitted that TLB conflict aborts are
raised in response to synchronous data/instruction accesses, and/or and
amalgamation of the TLB entries may be used as a result of a TLB lookup.
The presence of conflicting TLB entries may result in a variety of
behaviours detrimental to the system (e.g. erroneous physical addresses
may be used by I-cache fetches and/or page table walks). Some of these
cases may result in unexpected changes of hardware state, and/or result
in the (asynchronous) delivery of SError.
To avoid these issues, we must avoid situations where conflicting
entries may be allocated into TLBs. For user and module mappings we can
follow a strict break-before-make approach, but this cannot work for
modifications to the swapper page tables that cover the kernel text and
data.
Instead, this patch adds code which is intended to be executed from the
idmap, which can safely unmap the swapper page tables as it only
requires the idmap to be active. This enables us to uninstall the active
TTBR1_EL1 entry, invalidate TLBs, then install a new TTBR1_EL1 entry
without potentially unmapping code or data required for the sequence.
This avoids the risk of conflict, but requires that updates are staged
in a copy of the swapper page tables prior to being installed.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Tested-by: Jeremy Linton <jeremy.linton@arm.com>
Cc: Laura Abbott <labbott@fedoraproject.org>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2016-01-25 19:45:01 +08:00
|
|
|
|
2019-08-07 23:55:19 +08:00
|
|
|
offset_ttbr1 x0, x3
|
2018-07-31 21:08:56 +08:00
|
|
|
msr ttbr1_el1, x0
|
arm64: mm: add code to safely replace TTBR1_EL1
If page tables are modified without suitable TLB maintenance, the ARM
architecture permits multiple TLB entries to be allocated for the same
VA. When this occurs, it is permitted that TLB conflict aborts are
raised in response to synchronous data/instruction accesses, and/or and
amalgamation of the TLB entries may be used as a result of a TLB lookup.
The presence of conflicting TLB entries may result in a variety of
behaviours detrimental to the system (e.g. erroneous physical addresses
may be used by I-cache fetches and/or page table walks). Some of these
cases may result in unexpected changes of hardware state, and/or result
in the (asynchronous) delivery of SError.
To avoid these issues, we must avoid situations where conflicting
entries may be allocated into TLBs. For user and module mappings we can
follow a strict break-before-make approach, but this cannot work for
modifications to the swapper page tables that cover the kernel text and
data.
Instead, this patch adds code which is intended to be executed from the
idmap, which can safely unmap the swapper page tables as it only
requires the idmap to be active. This enables us to uninstall the active
TTBR1_EL1 entry, invalidate TLBs, then install a new TTBR1_EL1 entry
without potentially unmapping code or data required for the sequence.
This avoids the risk of conflict, but requires that updates are staged
in a copy of the swapper page tables prior to being installed.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Tested-by: Jeremy Linton <jeremy.linton@arm.com>
Cc: Laura Abbott <labbott@fedoraproject.org>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2016-01-25 19:45:01 +08:00
|
|
|
isb
|
|
|
|
|
|
|
|
ret
|
2020-01-07 03:58:18 +08:00
|
|
|
SYM_FUNC_END(idmap_cpu_replace_ttbr1)
|
2024-02-14 20:29:04 +08:00
|
|
|
SYM_FUNC_ALIAS(__pi_idmap_cpu_replace_ttbr1, idmap_cpu_replace_ttbr1)
|
arm64: mm: add code to safely replace TTBR1_EL1
If page tables are modified without suitable TLB maintenance, the ARM
architecture permits multiple TLB entries to be allocated for the same
VA. When this occurs, it is permitted that TLB conflict aborts are
raised in response to synchronous data/instruction accesses, and/or and
amalgamation of the TLB entries may be used as a result of a TLB lookup.
The presence of conflicting TLB entries may result in a variety of
behaviours detrimental to the system (e.g. erroneous physical addresses
may be used by I-cache fetches and/or page table walks). Some of these
cases may result in unexpected changes of hardware state, and/or result
in the (asynchronous) delivery of SError.
To avoid these issues, we must avoid situations where conflicting
entries may be allocated into TLBs. For user and module mappings we can
follow a strict break-before-make approach, but this cannot work for
modifications to the swapper page tables that cover the kernel text and
data.
Instead, this patch adds code which is intended to be executed from the
idmap, which can safely unmap the swapper page tables as it only
requires the idmap to be active. This enables us to uninstall the active
TTBR1_EL1 entry, invalidate TLBs, then install a new TTBR1_EL1 entry
without potentially unmapping code or data required for the sequence.
This avoids the risk of conflict, but requires that updates are staged
in a copy of the swapper page tables prior to being installed.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Tested-by: Jeremy Linton <jeremy.linton@arm.com>
Cc: Laura Abbott <labbott@fedoraproject.org>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2016-01-25 19:45:01 +08:00
|
|
|
.popsection
|
|
|
|
|
2018-02-07 06:22:50 +08:00
|
|
|
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
|
arm64: kernel: Create initial ID map from C code
The asm code that creates the initial ID map is rather intricate and
hard to follow. This is problematic because it makes adding support for
things like LPA2 or WXN more difficult than necessary. Also, it is
parameterized like the rest of the MM code to run with a configurable
number of levels, which is rather pointless, given that all AArch64 CPUs
implement support for 48-bit virtual addressing, and that many systems
exist with DRAM located outside of the 39-bit addressable range, which
is the only smaller VA size that is widely used, and we need additional
tricks to make things work in that combination.
So let's bite the bullet, and rip out all the asm macros, and fiddly
code, and replace it with a C implementation based on the newly added
routines for creating the early kernel VA mappings. And while at it,
create the initial ID map based on 48-bit virtual addressing as well,
regardless of the number of configured levels for the kernel proper.
Note that this code may execute with the MMU and caches disabled, and is
therefore not permitted to make unaligned accesses. This shouldn't
generally happen in any case for the algorithm as implemented, but to be
sure, let's pass -mstrict-align to the compiler just in case.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20240214122845.2033971-66-ardb+git@google.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2024-02-14 20:29:07 +08:00
|
|
|
#define KPTI_NG_PTE_FLAGS (PTE_ATTRINDX(MT_NORMAL) | PTE_TYPE_PAGE | \
|
|
|
|
PTE_AF | PTE_SHARED | PTE_UXN | PTE_WRITE)
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
|
2023-04-29 02:28:17 +08:00
|
|
|
.pushsection ".idmap.text", "a"
|
2018-02-07 06:22:50 +08:00
|
|
|
|
2024-02-14 20:29:16 +08:00
|
|
|
.macro pte_to_phys, phys, pte
|
|
|
|
and \phys, \pte, #PTE_ADDR_LOW
|
|
|
|
#ifdef CONFIG_ARM64_PA_BITS_52
|
|
|
|
and \pte, \pte, #PTE_ADDR_HIGH
|
|
|
|
orr \phys, \phys, \pte, lsl #PTE_ADDR_HIGH_SHIFT
|
|
|
|
#endif
|
|
|
|
.endm
|
|
|
|
|
2022-06-10 01:43:19 +08:00
|
|
|
.macro kpti_mk_tbl_ng, type, num_entries
|
|
|
|
add end_\type\()p, cur_\type\()p, #\num_entries * 8
|
|
|
|
.Ldo_\type:
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
ldr \type, [cur_\type\()p] // Load the entry
|
2022-06-10 01:43:19 +08:00
|
|
|
tbz \type, #0, .Lnext_\type // Skip invalid and
|
|
|
|
tbnz \type, #11, .Lnext_\type // non-global entries
|
2018-02-07 06:22:50 +08:00
|
|
|
orr \type, \type, #PTE_NG // Same bit for blocks and pages
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
str \type, [cur_\type\()p] // Update the entry
|
2022-06-10 01:43:19 +08:00
|
|
|
.ifnc \type, pte
|
|
|
|
tbnz \type, #1, .Lderef_\type
|
|
|
|
.endif
|
|
|
|
.Lnext_\type:
|
|
|
|
add cur_\type\()p, cur_\type\()p, #8
|
|
|
|
cmp cur_\type\()p, end_\type\()p
|
|
|
|
b.ne .Ldo_\type
|
2018-02-07 06:22:50 +08:00
|
|
|
.endm
|
|
|
|
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
/*
|
|
|
|
* Dereference the current table entry and map it into the temporary
|
|
|
|
* fixmap slot associated with the current level.
|
|
|
|
*/
|
|
|
|
.macro kpti_map_pgtbl, type, level
|
|
|
|
str xzr, [temp_pte, #8 * (\level + 1)] // break before make
|
|
|
|
dsb nshst
|
|
|
|
add pte, temp_pte, #PAGE_SIZE * (\level + 1)
|
|
|
|
lsr pte, pte, #12
|
|
|
|
tlbi vaae1, pte
|
|
|
|
dsb nsh
|
|
|
|
isb
|
|
|
|
|
|
|
|
phys_to_pte pte, cur_\type\()p
|
|
|
|
add cur_\type\()p, temp_pte, #PAGE_SIZE * (\level + 1)
|
|
|
|
orr pte, pte, pte_flags
|
|
|
|
str pte, [temp_pte, #8 * (\level + 1)]
|
|
|
|
dsb nshst
|
|
|
|
.endm
|
|
|
|
|
2018-02-07 06:22:50 +08:00
|
|
|
/*
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
* void __kpti_install_ng_mappings(int cpu, int num_secondaries, phys_addr_t temp_pgd,
|
|
|
|
* unsigned long temp_pte_va)
|
2018-02-07 06:22:50 +08:00
|
|
|
*
|
|
|
|
* Called exactly once from stop_machine context by each CPU found during boot.
|
|
|
|
*/
|
2022-06-24 23:06:42 +08:00
|
|
|
.pushsection ".data", "aw", %progbits
|
|
|
|
SYM_DATA(__idmap_kpti_flag, .long 1)
|
|
|
|
.popsection
|
|
|
|
|
2022-09-09 05:54:51 +08:00
|
|
|
SYM_TYPED_FUNC_START(idmap_kpti_install_ng_mappings)
|
2018-02-07 06:22:50 +08:00
|
|
|
cpu .req w0
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
temp_pte .req x0
|
2018-02-07 06:22:50 +08:00
|
|
|
num_cpus .req w1
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
pte_flags .req x1
|
|
|
|
temp_pgd_phys .req x2
|
2018-02-07 06:22:50 +08:00
|
|
|
swapper_ttb .req x3
|
|
|
|
flag_ptr .req x4
|
|
|
|
cur_pgdp .req x5
|
|
|
|
end_pgdp .req x6
|
|
|
|
pgd .req x7
|
|
|
|
cur_pudp .req x8
|
|
|
|
end_pudp .req x9
|
|
|
|
cur_pmdp .req x11
|
|
|
|
end_pmdp .req x12
|
|
|
|
cur_ptep .req x14
|
|
|
|
end_ptep .req x15
|
|
|
|
pte .req x16
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
valid .req x17
|
2018-02-07 06:22:50 +08:00
|
|
|
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
mov x5, x3 // preserve temp_pte arg
|
2018-02-07 06:22:50 +08:00
|
|
|
mrs swapper_ttb, ttbr1_el1
|
2022-06-24 23:06:42 +08:00
|
|
|
adr_l flag_ptr, __idmap_kpti_flag
|
2018-02-07 06:22:50 +08:00
|
|
|
|
|
|
|
cbnz cpu, __idmap_kpti_secondary
|
|
|
|
|
|
|
|
/* We're the boot CPU. Wait for the others to catch up */
|
|
|
|
sevl
|
|
|
|
1: wfe
|
2019-12-07 06:13:37 +08:00
|
|
|
ldaxr w17, [flag_ptr]
|
|
|
|
eor w17, w17, num_cpus
|
|
|
|
cbnz w17, 1b
|
2018-02-07 06:22:50 +08:00
|
|
|
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
/* Switch to the temporary page tables on this CPU only */
|
|
|
|
__idmap_cpu_set_reserved_ttbr1 x8, x9
|
|
|
|
offset_ttbr1 temp_pgd_phys, x8
|
|
|
|
msr ttbr1_el1, temp_pgd_phys
|
2018-02-07 06:22:50 +08:00
|
|
|
isb
|
|
|
|
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
mov temp_pte, x5
|
2023-06-06 22:58:50 +08:00
|
|
|
mov_q pte_flags, KPTI_NG_PTE_FLAGS
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
|
2018-02-07 06:22:50 +08:00
|
|
|
/* Everybody is enjoying the idmap, so we can rewrite swapper. */
|
|
|
|
/* PGD */
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
adrp cur_pgdp, swapper_pg_dir
|
|
|
|
kpti_map_pgtbl pgd, 0
|
2022-06-10 01:43:19 +08:00
|
|
|
kpti_mk_tbl_ng pgd, PTRS_PER_PGD
|
2018-02-07 06:22:50 +08:00
|
|
|
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
/* Ensure all the updated entries are visible to secondary CPUs */
|
|
|
|
dsb ishst
|
2018-02-07 06:22:50 +08:00
|
|
|
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
/* We're done: fire up swapper_pg_dir again */
|
|
|
|
__idmap_cpu_set_reserved_ttbr1 x8, x9
|
|
|
|
msr ttbr1_el1, swapper_ttb
|
|
|
|
isb
|
2019-08-28 01:12:57 +08:00
|
|
|
|
2018-02-07 06:22:50 +08:00
|
|
|
/* Set the flag to zero to indicate that we're all done */
|
|
|
|
str wzr, [flag_ptr]
|
|
|
|
ret
|
|
|
|
|
2022-06-10 01:43:19 +08:00
|
|
|
.Lderef_pgd:
|
2018-02-07 06:22:50 +08:00
|
|
|
/* PUD */
|
2022-06-10 01:43:19 +08:00
|
|
|
.if CONFIG_PGTABLE_LEVELS > 3
|
|
|
|
pud .req x10
|
2018-02-07 06:22:50 +08:00
|
|
|
pte_to_phys cur_pudp, pgd
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
kpti_map_pgtbl pud, 1
|
2022-06-10 01:43:19 +08:00
|
|
|
kpti_mk_tbl_ng pud, PTRS_PER_PUD
|
|
|
|
b .Lnext_pgd
|
|
|
|
.else /* CONFIG_PGTABLE_LEVELS <= 3 */
|
|
|
|
pud .req pgd
|
|
|
|
.set .Lnext_pud, .Lnext_pgd
|
2018-02-07 06:22:50 +08:00
|
|
|
.endif
|
|
|
|
|
2022-06-10 01:43:19 +08:00
|
|
|
.Lderef_pud:
|
2018-02-07 06:22:50 +08:00
|
|
|
/* PMD */
|
2022-06-10 01:43:19 +08:00
|
|
|
.if CONFIG_PGTABLE_LEVELS > 2
|
|
|
|
pmd .req x13
|
2018-02-07 06:22:50 +08:00
|
|
|
pte_to_phys cur_pmdp, pud
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
kpti_map_pgtbl pmd, 2
|
2022-06-10 01:43:19 +08:00
|
|
|
kpti_mk_tbl_ng pmd, PTRS_PER_PMD
|
|
|
|
b .Lnext_pud
|
|
|
|
.else /* CONFIG_PGTABLE_LEVELS <= 2 */
|
|
|
|
pmd .req pgd
|
|
|
|
.set .Lnext_pmd, .Lnext_pgd
|
2018-02-07 06:22:50 +08:00
|
|
|
.endif
|
|
|
|
|
2022-06-10 01:43:19 +08:00
|
|
|
.Lderef_pmd:
|
2018-02-07 06:22:50 +08:00
|
|
|
/* PTE */
|
|
|
|
pte_to_phys cur_ptep, pmd
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
kpti_map_pgtbl pte, 3
|
2022-06-10 01:43:19 +08:00
|
|
|
kpti_mk_tbl_ng pte, PTRS_PER_PTE
|
|
|
|
b .Lnext_pmd
|
2018-02-07 06:22:50 +08:00
|
|
|
|
2019-12-07 06:13:37 +08:00
|
|
|
.unreq cpu
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
.unreq temp_pte
|
2019-12-07 06:13:37 +08:00
|
|
|
.unreq num_cpus
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
.unreq pte_flags
|
|
|
|
.unreq temp_pgd_phys
|
2019-12-07 06:13:37 +08:00
|
|
|
.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
|
arm64: mm: install KPTI nG mappings with MMU enabled
In cases where we unmap the kernel while running in user space, we rely
on ASIDs to distinguish the minimal trampoline from the full kernel
mapping, and this means we must use non-global attributes for those
mappings, to ensure they are scoped by ASID and will not hit in the TLB
inadvertently.
We only do this when needed, as this is generally more costly in terms
of TLB pressure, and so we boot without these non-global attributes, and
apply them to all existing kernel mappings once all CPUs are up and we
know whether or not the non-global attributes are needed. At this point,
we cannot simply unmap and remap the entire address space, so we have to
update all existing block and page descriptors in place.
Currently, we go through a lot of trouble to perform these updates with
the MMU and caches off, to avoid violating break before make (BBM) rules
imposed by the architecture. Since we make changes to page tables that
are not covered by the ID map, we gain access to those descriptors by
disabling translations altogether. This means that the stores to memory
are issued with device attributes, and require extra care in terms of
coherency, which is costly. We also rely on the ID map to access a
shared flag, which requires the ID map to be executable and writable at
the same time, which is another thing we'd prefer to avoid.
So let's switch to an approach where we replace the kernel mapping with
a minimal mapping of a few pages that can be used for a minimal, ad-hoc
fixmap that we can use to map each page table in turn as we traverse the
hierarchy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220609174320.4035379-3-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
2022-06-10 01:43:20 +08:00
|
|
|
.unreq valid
|
2019-12-07 06:13:37 +08:00
|
|
|
|
2018-02-07 06:22:50 +08:00
|
|
|
/* Secondary CPUs end up here */
|
|
|
|
__idmap_kpti_secondary:
|
|
|
|
/* Uninstall swapper before surgery begins */
|
2019-12-07 06:13:37 +08:00
|
|
|
__idmap_cpu_set_reserved_ttbr1 x16, x17
|
2018-02-07 06:22:50 +08:00
|
|
|
|
|
|
|
/* Increment the flag to let the boot CPU we're ready */
|
2019-12-07 06:13:37 +08:00
|
|
|
1: ldxr w16, [flag_ptr]
|
|
|
|
add w16, w16, #1
|
|
|
|
stxr w17, w16, [flag_ptr]
|
2018-02-07 06:22:50 +08:00
|
|
|
cbnz w17, 1b
|
|
|
|
|
|
|
|
/* Wait for the boot CPU to finish messing around with swapper */
|
|
|
|
sevl
|
|
|
|
1: wfe
|
2019-12-07 06:13:37 +08:00
|
|
|
ldxr w16, [flag_ptr]
|
|
|
|
cbnz w16, 1b
|
2018-02-07 06:22:50 +08:00
|
|
|
|
|
|
|
/* All done, act like nothing happened */
|
|
|
|
msr ttbr1_el1, swapper_ttb
|
|
|
|
isb
|
|
|
|
ret
|
|
|
|
|
|
|
|
.unreq swapper_ttb
|
|
|
|
.unreq flag_ptr
|
2020-01-07 03:58:18 +08:00
|
|
|
SYM_FUNC_END(idmap_kpti_install_ng_mappings)
|
2018-02-07 06:22:50 +08:00
|
|
|
.popsection
|
|
|
|
#endif
|
|
|
|
|
2012-03-05 19:49:28 +08:00
|
|
|
/*
|
|
|
|
* __cpu_setup
|
|
|
|
*
|
2020-03-13 17:04:52 +08:00
|
|
|
* Initialise the processor for turning the MMU on.
|
|
|
|
*
|
|
|
|
* Output:
|
|
|
|
* Return in x0 the value of the SCTLR_EL1 register.
|
2012-03-05 19:49:28 +08:00
|
|
|
*/
|
2023-04-29 02:28:17 +08:00
|
|
|
.pushsection ".idmap.text", "a"
|
2020-01-07 03:58:18 +08:00
|
|
|
SYM_FUNC_START(__cpu_setup)
|
2015-10-07 01:46:22 +08:00
|
|
|
tlbi vmalle1 // Invalidate local TLB
|
|
|
|
dsb nsh
|
2012-03-05 19:49:28 +08:00
|
|
|
|
arm64: Use a positive cpucap for FP/SIMD
Currently we have a negative cpucap which describes the *absence* of
FP/SIMD rather than *presence* of FP/SIMD. This largely works, but is
somewhat awkward relative to other cpucaps that describe the presence of
a feature, and it would be nicer to have a cpucap which describes the
presence of FP/SIMD:
* This will allow the cpucap to be treated as a standard
ARM64_CPUCAP_SYSTEM_FEATURE, which can be detected with the standard
has_cpuid_feature() function and ARM64_CPUID_FIELDS() description.
* This ensures that the cpucap will only transition from not-present to
present, reducing the risk of unintentional and/or unsafe usage of
FP/SIMD before cpucaps are finalized.
* This will allow using arm64_cpu_capabilities::cpu_enable() to enable
the use of FP/SIMD later, with FP/SIMD being disabled at boot time
otherwise. This will ensure that any unintentional and/or unsafe usage
of FP/SIMD prior to this is trapped, and will ensure that FP/SIMD is
never unintentionally enabled for userspace in mismatched big.LITTLE
systems.
This patch replaces the negative ARM64_HAS_NO_FPSIMD cpucap with a
positive ARM64_HAS_FPSIMD cpucap, making changes as described above.
Note that as FP/SIMD will now be trapped when not supported system-wide,
do_fpsimd_acc() must handle these traps in the same way as for SVE and
SME. The commentary in fpsimd_restore_current_state() is updated to
describe the new scheme.
No users of system_supports_fpsimd() need to know that FP/SIMD is
available prior to alternatives being patched, so this is updated to
use alternative_has_cap_likely() to check for the ARM64_HAS_FPSIMD
cpucap, without generating code to test the system_cpucaps bitmap.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Mark Brown <broonie@kernel.org>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2023-10-16 18:24:36 +08:00
|
|
|
msr cpacr_el1, xzr // Reset cpacr_el1
|
2020-03-13 17:04:52 +08:00
|
|
|
mov x1, #1 << 12 // Reset mdscr_el1 and disable
|
|
|
|
msr mdscr_el1, x1 // access to the DCC from EL0
|
arm64: debug: unmask PSTATE.D earlier
Clearing PSTATE.D is one of the requirements for generating a debug
exception. The arm64 booting protocol requires that PSTATE.D is set,
since many of the debug registers (for example, the hw_breakpoint
registers) are UNKNOWN out of reset and could potentially generate
spurious, fatal debug exceptions in early boot code if PSTATE.D was
clear. Once the debug registers have been safely initialised, PSTATE.D
is cleared, however this is currently broken for two reasons:
(1) The boot CPU clears PSTATE.D in a postcore_initcall and secondary
CPUs clear PSTATE.D in secondary_start_kernel. Since the initcall
runs after SMP (and the scheduler) have been initialised, there is
no guarantee that it is actually running on the boot CPU. In this
case, the boot CPU is left with PSTATE.D set and is not capable of
generating debug exceptions.
(2) In a preemptible kernel, we may explicitly schedule on the IRQ
return path to EL1. If an IRQ occurs with PSTATE.D set in the idle
thread, then we may schedule the kthread_init thread, run the
postcore_initcall to clear PSTATE.D and then context switch back
to the idle thread before returning from the IRQ. The exception
return path will then restore PSTATE.D from the stack, and set it
again.
This patch fixes the problem by moving the clearing of PSTATE.D earlier
to proc.S. This has the desirable effect of clearing it in one place for
all CPUs, long before we have to worry about the scheduler or any
exception handling. We ensure that the previous reset of MDSCR_EL1 has
completed before unmasking the exception, so that any spurious
exceptions resulting from UNKNOWN debug registers are not generated.
Without this patch applied, the kprobes selftests have been seen to fail
under KVM, where we end up attempting to step the OOL instruction buffer
with PSTATE.D set and therefore fail to complete the step.
Cc: <stable@vger.kernel.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Reported-by: Catalin Marinas <catalin.marinas@arm.com>
Tested-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Tested-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2016-07-19 22:07:37 +08:00
|
|
|
isb // Unmask debug exceptions now,
|
|
|
|
enable_dbg // since this is per-cpu
|
2020-03-13 17:04:52 +08:00
|
|
|
reset_pmuserenr_el0 x1 // Disable PMU access from EL0
|
2020-03-25 19:11:08 +08:00
|
|
|
reset_amuserenr_el0 x1 // Disable AMU access from EL0
|
2020-03-05 17:06:22 +08:00
|
|
|
|
2012-03-05 19:49:28 +08:00
|
|
|
/*
|
arm64: setup: name `tcr` register
In __cpu_setup we conditionally manipulate the TCR_EL1 value in x10
after previously using x10 as a scratch register for unrelated temporary
variables.
To make this a bit clearer, let's move the TCR_EL1 value into a named
register `tcr`. To simplify the register allocation, this is placed in
the highest available caller-saved scratch register, tcr.
Following the example of `mair`, we initialise the register with the
default value prior to any feature discovery, and write it to MAIR_EL1
after all feature discovery is complete, which allows us to simplify the
featuere discovery code.
The existing `mte_tcr` register is no longer needed, and is replaced by
the use of x10 as a temporary, matching the rest of the MTE feature
discovery assembly in __cpu_setup. As x20 is no longer used, the
function is now AAPCS compliant, as we've generally aimed for in our
assembly functions.
There should be no functional change as as a result of this patch.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20210326180137.43119-3-mark.rutland@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2021-03-27 02:01:37 +08:00
|
|
|
* Default values for VMSA control registers. These will be adjusted
|
|
|
|
* below depending on detected CPU features.
|
2012-03-05 19:49:28 +08:00
|
|
|
*/
|
2021-03-27 02:01:36 +08:00
|
|
|
mair .req x17
|
arm64: setup: name `tcr` register
In __cpu_setup we conditionally manipulate the TCR_EL1 value in x10
after previously using x10 as a scratch register for unrelated temporary
variables.
To make this a bit clearer, let's move the TCR_EL1 value into a named
register `tcr`. To simplify the register allocation, this is placed in
the highest available caller-saved scratch register, tcr.
Following the example of `mair`, we initialise the register with the
default value prior to any feature discovery, and write it to MAIR_EL1
after all feature discovery is complete, which allows us to simplify the
featuere discovery code.
The existing `mte_tcr` register is no longer needed, and is replaced by
the use of x10 as a temporary, matching the rest of the MTE feature
discovery assembly in __cpu_setup. As x20 is no longer used, the
function is now AAPCS compliant, as we've generally aimed for in our
assembly functions.
There should be no functional change as as a result of this patch.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20210326180137.43119-3-mark.rutland@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2021-03-27 02:01:37 +08:00
|
|
|
tcr .req x16
|
2021-03-27 02:01:36 +08:00
|
|
|
mov_q mair, MAIR_EL1_SET
|
arm64: mm: Handle LVA support as a CPU feature
Currently, we detect CPU support for 52-bit virtual addressing (LVA)
extremely early, before creating the kernel page tables or enabling the
MMU. We cannot override the feature this early, and so large virtual
addressing is always enabled on CPUs that implement support for it if
the software support for it was enabled at build time. It also means we
rely on non-trivial code in asm to deal with this feature.
Given that both the ID map and the TTBR1 mapping of the kernel image are
guaranteed to be 48-bit addressable, it is not actually necessary to
enable support this early, and instead, we can model it as a CPU
feature. That way, we can rely on code patching to get the correct
TCR.T1SZ values programmed on secondary boot and resume from suspend.
On the primary boot path, we simply enable the MMU with 48-bit virtual
addressing initially, and update TCR.T1SZ if LVA is supported from C
code, right before creating the kernel mapping. Given that TTBR1 still
points to reserved_pg_dir at this point, updating TCR.T1SZ should be
safe without the need for explicit TLB maintenance.
Since this gets rid of all accesses to the vabits_actual variable from
asm code that occurred before TCR.T1SZ had been programmed, we no longer
have a need for this variable, and we can replace it with a C expression
that produces the correct value directly, based on the value of TCR.T1SZ.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20240214122845.2033971-70-ardb+git@google.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2024-02-14 20:29:11 +08:00
|
|
|
mov_q tcr, TCR_T0SZ(IDMAP_VA_BITS) | TCR_T1SZ(VA_BITS_MIN) | TCR_CACHE_FLAGS | \
|
2024-02-14 20:29:05 +08:00
|
|
|
TCR_SMP_FLAGS | TCR_TG_FLAGS | TCR_KASLR_FLAGS | TCR_ASID16 | \
|
|
|
|
TCR_TBI0 | TCR_A1 | TCR_KASAN_SW_FLAGS | TCR_MTE_FLAGS
|
2019-09-06 17:58:01 +08:00
|
|
|
|
arm64: setup: name `tcr` register
In __cpu_setup we conditionally manipulate the TCR_EL1 value in x10
after previously using x10 as a scratch register for unrelated temporary
variables.
To make this a bit clearer, let's move the TCR_EL1 value into a named
register `tcr`. To simplify the register allocation, this is placed in
the highest available caller-saved scratch register, tcr.
Following the example of `mair`, we initialise the register with the
default value prior to any feature discovery, and write it to MAIR_EL1
after all feature discovery is complete, which allows us to simplify the
featuere discovery code.
The existing `mte_tcr` register is no longer needed, and is replaced by
the use of x10 as a temporary, matching the rest of the MTE feature
discovery assembly in __cpu_setup. As x20 is no longer used, the
function is now AAPCS compliant, as we've generally aimed for in our
assembly functions.
There should be no functional change as as a result of this patch.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20210326180137.43119-3-mark.rutland@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2021-03-27 02:01:37 +08:00
|
|
|
tcr_clear_errata_bits tcr, x9, x5
|
2018-12-07 06:50:41 +08:00
|
|
|
|
2019-08-07 23:55:22 +08:00
|
|
|
#ifdef CONFIG_ARM64_VA_BITS_52
|
arm64: mm: Handle LVA support as a CPU feature
Currently, we detect CPU support for 52-bit virtual addressing (LVA)
extremely early, before creating the kernel page tables or enabling the
MMU. We cannot override the feature this early, and so large virtual
addressing is always enabled on CPUs that implement support for it if
the software support for it was enabled at build time. It also means we
rely on non-trivial code in asm to deal with this feature.
Given that both the ID map and the TTBR1 mapping of the kernel image are
guaranteed to be 48-bit addressable, it is not actually necessary to
enable support this early, and instead, we can model it as a CPU
feature. That way, we can rely on code patching to get the correct
TCR.T1SZ values programmed on secondary boot and resume from suspend.
On the primary boot path, we simply enable the MMU with 48-bit virtual
addressing initially, and update TCR.T1SZ if LVA is supported from C
code, right before creating the kernel mapping. Given that TTBR1 still
points to reserved_pg_dir at this point, updating TCR.T1SZ should be
safe without the need for explicit TLB maintenance.
Since this gets rid of all accesses to the vabits_actual variable from
asm code that occurred before TCR.T1SZ had been programmed, we no longer
have a need for this variable, and we can replace it with a C expression
that produces the correct value directly, based on the value of TCR.T1SZ.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20240214122845.2033971-70-ardb+git@google.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2024-02-14 20:29:11 +08:00
|
|
|
mov x9, #64 - VA_BITS
|
|
|
|
alternative_if ARM64_HAS_VA52
|
arm64: setup: name `tcr` register
In __cpu_setup we conditionally manipulate the TCR_EL1 value in x10
after previously using x10 as a scratch register for unrelated temporary
variables.
To make this a bit clearer, let's move the TCR_EL1 value into a named
register `tcr`. To simplify the register allocation, this is placed in
the highest available caller-saved scratch register, tcr.
Following the example of `mair`, we initialise the register with the
default value prior to any feature discovery, and write it to MAIR_EL1
after all feature discovery is complete, which allows us to simplify the
featuere discovery code.
The existing `mte_tcr` register is no longer needed, and is replaced by
the use of x10 as a temporary, matching the rest of the MTE feature
discovery assembly in __cpu_setup. As x20 is no longer used, the
function is now AAPCS compliant, as we've generally aimed for in our
assembly functions.
There should be no functional change as as a result of this patch.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20210326180137.43119-3-mark.rutland@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2021-03-27 02:01:37 +08:00
|
|
|
tcr_set_t1sz tcr, x9
|
arm64: mm: Handle LVA support as a CPU feature
Currently, we detect CPU support for 52-bit virtual addressing (LVA)
extremely early, before creating the kernel page tables or enabling the
MMU. We cannot override the feature this early, and so large virtual
addressing is always enabled on CPUs that implement support for it if
the software support for it was enabled at build time. It also means we
rely on non-trivial code in asm to deal with this feature.
Given that both the ID map and the TTBR1 mapping of the kernel image are
guaranteed to be 48-bit addressable, it is not actually necessary to
enable support this early, and instead, we can model it as a CPU
feature. That way, we can rely on code patching to get the correct
TCR.T1SZ values programmed on secondary boot and resume from suspend.
On the primary boot path, we simply enable the MMU with 48-bit virtual
addressing initially, and update TCR.T1SZ if LVA is supported from C
code, right before creating the kernel mapping. Given that TTBR1 still
points to reserved_pg_dir at this point, updating TCR.T1SZ should be
safe without the need for explicit TLB maintenance.
Since this gets rid of all accesses to the vabits_actual variable from
asm code that occurred before TCR.T1SZ had been programmed, we no longer
have a need for this variable, and we can replace it with a C expression
that produces the correct value directly, based on the value of TCR.T1SZ.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20240214122845.2033971-70-ardb+git@google.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2024-02-14 20:29:11 +08:00
|
|
|
alternative_else_nop_endif
|
2018-12-07 06:50:41 +08:00
|
|
|
#endif
|
arm64: mm: increase VA range of identity map
The page size and the number of translation levels, and hence the supported
virtual address range, are build-time configurables on arm64 whose optimal
values are use case dependent. However, in the current implementation, if
the system's RAM is located at a very high offset, the virtual address range
needs to reflect that merely because the identity mapping, which is only used
to enable or disable the MMU, requires the extended virtual range to map the
physical memory at an equal virtual offset.
This patch relaxes that requirement, by increasing the number of translation
levels for the identity mapping only, and only when actually needed, i.e.,
when system RAM's offset is found to be out of reach at runtime.
Tested-by: Laura Abbott <lauraa@codeaurora.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Tested-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
2015-03-20 00:42:27 +08:00
|
|
|
|
2014-03-07 16:49:25 +08:00
|
|
|
/*
|
2017-12-14 01:07:17 +08:00
|
|
|
* Set the IPS bits in TCR_EL1.
|
2014-03-07 16:49:25 +08:00
|
|
|
*/
|
arm64: setup: name `tcr` register
In __cpu_setup we conditionally manipulate the TCR_EL1 value in x10
after previously using x10 as a scratch register for unrelated temporary
variables.
To make this a bit clearer, let's move the TCR_EL1 value into a named
register `tcr`. To simplify the register allocation, this is placed in
the highest available caller-saved scratch register, tcr.
Following the example of `mair`, we initialise the register with the
default value prior to any feature discovery, and write it to MAIR_EL1
after all feature discovery is complete, which allows us to simplify the
featuere discovery code.
The existing `mte_tcr` register is no longer needed, and is replaced by
the use of x10 as a temporary, matching the rest of the MTE feature
discovery assembly in __cpu_setup. As x20 is no longer used, the
function is now AAPCS compliant, as we've generally aimed for in our
assembly functions.
There should be no functional change as as a result of this patch.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20210326180137.43119-3-mark.rutland@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2021-03-27 02:01:37 +08:00
|
|
|
tcr_compute_pa_size tcr, #TCR_IPS_SHIFT, x5, x6
|
2015-07-11 00:24:28 +08:00
|
|
|
#ifdef CONFIG_ARM64_HW_AFDBM
|
|
|
|
/*
|
2018-03-26 22:12:48 +08:00
|
|
|
* Enable hardware update of the Access Flags bit.
|
|
|
|
* Hardware dirty bit management is enabled later,
|
|
|
|
* via capabilities.
|
2015-07-11 00:24:28 +08:00
|
|
|
*/
|
|
|
|
mrs x9, ID_AA64MMFR1_EL1
|
2023-07-11 17:04:58 +08:00
|
|
|
and x9, x9, ID_AA64MMFR1_EL1_HAFDBS_MASK
|
2018-03-26 22:12:48 +08:00
|
|
|
cbz x9, 1f
|
arm64: setup: name `tcr` register
In __cpu_setup we conditionally manipulate the TCR_EL1 value in x10
after previously using x10 as a scratch register for unrelated temporary
variables.
To make this a bit clearer, let's move the TCR_EL1 value into a named
register `tcr`. To simplify the register allocation, this is placed in
the highest available caller-saved scratch register, tcr.
Following the example of `mair`, we initialise the register with the
default value prior to any feature discovery, and write it to MAIR_EL1
after all feature discovery is complete, which allows us to simplify the
featuere discovery code.
The existing `mte_tcr` register is no longer needed, and is replaced by
the use of x10 as a temporary, matching the rest of the MTE feature
discovery assembly in __cpu_setup. As x20 is no longer used, the
function is now AAPCS compliant, as we've generally aimed for in our
assembly functions.
There should be no functional change as as a result of this patch.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20210326180137.43119-3-mark.rutland@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2021-03-27 02:01:37 +08:00
|
|
|
orr tcr, tcr, #TCR_HA // hardware Access flag update
|
2018-03-26 22:12:48 +08:00
|
|
|
1:
|
2015-07-11 00:24:28 +08:00
|
|
|
#endif /* CONFIG_ARM64_HW_AFDBM */
|
2021-03-27 02:01:36 +08:00
|
|
|
msr mair_el1, mair
|
arm64: setup: name `tcr` register
In __cpu_setup we conditionally manipulate the TCR_EL1 value in x10
after previously using x10 as a scratch register for unrelated temporary
variables.
To make this a bit clearer, let's move the TCR_EL1 value into a named
register `tcr`. To simplify the register allocation, this is placed in
the highest available caller-saved scratch register, tcr.
Following the example of `mair`, we initialise the register with the
default value prior to any feature discovery, and write it to MAIR_EL1
after all feature discovery is complete, which allows us to simplify the
featuere discovery code.
The existing `mte_tcr` register is no longer needed, and is replaced by
the use of x10 as a temporary, matching the rest of the MTE feature
discovery assembly in __cpu_setup. As x20 is no longer used, the
function is now AAPCS compliant, as we've generally aimed for in our
assembly functions.
There should be no functional change as as a result of this patch.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20210326180137.43119-3-mark.rutland@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2021-03-27 02:01:37 +08:00
|
|
|
msr tcr_el1, tcr
|
2023-06-06 22:58:55 +08:00
|
|
|
|
|
|
|
mrs_s x1, SYS_ID_AA64MMFR3_EL1
|
|
|
|
ubfx x1, x1, #ID_AA64MMFR3_EL1_S1PIE_SHIFT, #4
|
|
|
|
cbz x1, .Lskip_indirection
|
|
|
|
|
2024-02-14 20:29:13 +08:00
|
|
|
/*
|
|
|
|
* The PROT_* macros describing the various memory types may resolve to
|
|
|
|
* C expressions if they include the PTE_MAYBE_* macros, and so they
|
|
|
|
* can only be used from C code. The PIE_E* constants below are also
|
|
|
|
* defined in terms of those macros, but will mask out those
|
|
|
|
* PTE_MAYBE_* constants, whether they are set or not. So #define them
|
|
|
|
* as 0x0 here so we can evaluate the PIE_E* constants in asm context.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define PTE_MAYBE_NG 0
|
2024-02-14 20:29:15 +08:00
|
|
|
#define PTE_MAYBE_SHARED 0
|
2024-02-14 20:29:13 +08:00
|
|
|
|
2023-06-06 22:58:55 +08:00
|
|
|
mov_q x0, PIE_E0
|
|
|
|
msr REG_PIRE0_EL1, x0
|
|
|
|
mov_q x0, PIE_E1
|
|
|
|
msr REG_PIR_EL1, x0
|
|
|
|
|
2024-02-14 20:29:13 +08:00
|
|
|
#undef PTE_MAYBE_NG
|
2024-02-14 20:29:15 +08:00
|
|
|
#undef PTE_MAYBE_SHARED
|
2024-02-14 20:29:13 +08:00
|
|
|
|
2023-06-06 22:58:55 +08:00
|
|
|
mov x0, TCR2_EL1x_PIE
|
|
|
|
msr REG_TCR2_EL1, x0
|
|
|
|
|
|
|
|
.Lskip_indirection:
|
|
|
|
|
2020-03-13 17:04:52 +08:00
|
|
|
/*
|
|
|
|
* Prepare SCTLR
|
|
|
|
*/
|
2020-11-13 20:49:24 +08:00
|
|
|
mov_q x0, INIT_SCTLR_EL1_MMU_ON
|
2012-03-05 19:49:28 +08:00
|
|
|
ret // return to head.S
|
2021-03-27 02:01:36 +08:00
|
|
|
|
|
|
|
.unreq mair
|
arm64: setup: name `tcr` register
In __cpu_setup we conditionally manipulate the TCR_EL1 value in x10
after previously using x10 as a scratch register for unrelated temporary
variables.
To make this a bit clearer, let's move the TCR_EL1 value into a named
register `tcr`. To simplify the register allocation, this is placed in
the highest available caller-saved scratch register, tcr.
Following the example of `mair`, we initialise the register with the
default value prior to any feature discovery, and write it to MAIR_EL1
after all feature discovery is complete, which allows us to simplify the
featuere discovery code.
The existing `mte_tcr` register is no longer needed, and is replaced by
the use of x10 as a temporary, matching the rest of the MTE feature
discovery assembly in __cpu_setup. As x20 is no longer used, the
function is now AAPCS compliant, as we've generally aimed for in our
assembly functions.
There should be no functional change as as a result of this patch.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20210326180137.43119-3-mark.rutland@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2021-03-27 02:01:37 +08:00
|
|
|
.unreq tcr
|
2020-01-07 03:58:18 +08:00
|
|
|
SYM_FUNC_END(__cpu_setup)
|