mirror of
https://github.com/torvalds/linux.git
synced 2026-06-04 04:23:35 +02:00
arm64 fixes for -rc1
- Disable problematic linker assertions for broken versions of LLD.
- Work around sporadic link failure with LLD and various randconfig
builds.
- Fix missing invalidation in the TLB batching code when reclaim races
with mprotect() and friends.
- Add a command-line override for MPAM to allow booting on systems with
broken firmware.
-----BEGIN PGP SIGNATURE-----
iQFEBAABCgAuFiEEPxTL6PPUbjXGY88ct6xw3ITBYzQFAmhBcycQHHdpbGxAa2Vy
bmVsLm9yZwAKCRC3rHDchMFjNDwWCACtc4Jw3wwkmaiiP9Ner1/7wKq8xRLC2WRU
tJjWLSkeoTthxf0DZILc61rNpOalfaRK774/Xo0OiYOBpKeAi5cSaUYMyabVJGcK
k1R0KXDUu8oS6xKXmXyeuBV2pK4v4aET3E6lzUQZfvamhzuZfCvvKKrF5K8vv5Ph
eowBMWKugMrwXMOBkRgVopppobdneFuVvnoMlNNYWOy70wDekoPV3qizoVJG/ulQ
BTFunXX8Otufrm48Ye2bYalfwoiGdUQaJz/gRuHko0o3SOhqR3qZp2DWxQgBwJ+g
VI6/dRLnVQpdg6toTvS9jzPczVfLt4/5VhLevbBcJuaUOER4SOZl
=cfnk
-----END PGP SIGNATURE-----
Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull arm64 fixes from Will Deacon:
"We've got a couple of build fixes when using LLD, a missing TLB
invalidation and a workaround for broken firmware on SoCs with CPUs
that implement MPAM:
- Disable problematic linker assertions for broken versions of LLD
- Work around sporadic link failure with LLD and various randconfig
builds
- Fix missing invalidation in the TLB batching code when reclaim
races with mprotect() and friends
- Add a command-line override for MPAM to allow booting on systems
with broken firmware"
* tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux:
arm64: Add override for MPAM
arm64/mm: Close theoretical race where stale TLB entry remains valid
arm64: Work around convergence issue with LLD linker
arm64: Disable LLD linker ASSERT()s for the time being
This commit is contained in:
commit
e9e668cd27
|
|
@ -458,6 +458,9 @@
|
|||
arm64.nomops [ARM64] Unconditionally disable Memory Copy and Memory
|
||||
Set instructions support
|
||||
|
||||
arm64.nompam [ARM64] Unconditionally disable Memory Partitioning And
|
||||
Monitoring support
|
||||
|
||||
arm64.nomte [ARM64] Unconditionally disable Memory Tagging Extension
|
||||
support
|
||||
|
||||
|
|
|
|||
|
|
@ -298,19 +298,6 @@
|
|||
.Lskip_gcs_\@:
|
||||
.endm
|
||||
|
||||
.macro __init_el2_mpam
|
||||
/* Memory Partitioning And Monitoring: disable EL2 traps */
|
||||
mrs x1, id_aa64pfr0_el1
|
||||
ubfx x0, x1, #ID_AA64PFR0_EL1_MPAM_SHIFT, #4
|
||||
cbz x0, .Lskip_mpam_\@ // skip if no MPAM
|
||||
msr_s SYS_MPAM2_EL2, xzr // use the default partition
|
||||
// and disable lower traps
|
||||
mrs_s x0, SYS_MPAMIDR_EL1
|
||||
tbz x0, #MPAMIDR_EL1_HAS_HCR_SHIFT, .Lskip_mpam_\@ // skip if no MPAMHCR reg
|
||||
msr_s SYS_MPAMHCR_EL2, xzr // clear TRAP_MPAMIDR_EL1 -> EL2
|
||||
.Lskip_mpam_\@:
|
||||
.endm
|
||||
|
||||
/**
|
||||
* Initialize EL2 registers to sane values. This should be called early on all
|
||||
* cores that were booted in EL2. Note that everything gets initialised as
|
||||
|
|
@ -328,7 +315,6 @@
|
|||
__init_el2_stage2
|
||||
__init_el2_gicv3
|
||||
__init_el2_hstr
|
||||
__init_el2_mpam
|
||||
__init_el2_nvhe_idregs
|
||||
__init_el2_cptr
|
||||
__init_el2_fgt
|
||||
|
|
@ -375,6 +361,16 @@
|
|||
#endif
|
||||
|
||||
.macro finalise_el2_state
|
||||
check_override id_aa64pfr0, ID_AA64PFR0_EL1_MPAM_SHIFT, .Linit_mpam_\@, .Lskip_mpam_\@, x1, x2
|
||||
|
||||
.Linit_mpam_\@:
|
||||
msr_s SYS_MPAM2_EL2, xzr // use the default partition
|
||||
// and disable lower traps
|
||||
mrs_s x0, SYS_MPAMIDR_EL1
|
||||
tbz x0, #MPAMIDR_EL1_HAS_HCR_SHIFT, .Lskip_mpam_\@ // skip if no MPAMHCR reg
|
||||
msr_s SYS_MPAMHCR_EL2, xzr // clear TRAP_MPAMIDR_EL1 -> EL2
|
||||
|
||||
.Lskip_mpam_\@:
|
||||
check_override id_aa64pfr0, ID_AA64PFR0_EL1_SVE_SHIFT, .Linit_sve_\@, .Lskip_sve_\@, x1, x2
|
||||
|
||||
.Linit_sve_\@: /* SVE register access */
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@
|
|||
#define INIT_DIR_SIZE (PAGE_SIZE * (EARLY_PAGES(SWAPPER_PGTABLE_LEVELS, KIMAGE_VADDR, _end, EXTRA_PAGE) \
|
||||
+ EARLY_SEGMENT_EXTRA_PAGES))
|
||||
|
||||
#define INIT_IDMAP_DIR_PAGES (EARLY_PAGES(INIT_IDMAP_PGTABLE_LEVELS, KIMAGE_VADDR, _end, 1))
|
||||
#define INIT_IDMAP_DIR_PAGES (EARLY_PAGES(INIT_IDMAP_PGTABLE_LEVELS, KIMAGE_VADDR, kimage_limit, 1))
|
||||
#define INIT_IDMAP_DIR_SIZE ((INIT_IDMAP_DIR_PAGES + EARLY_IDMAP_EXTRA_PAGES) * PAGE_SIZE)
|
||||
|
||||
#define INIT_IDMAP_FDT_PAGES (EARLY_PAGES(INIT_IDMAP_PGTABLE_LEVELS, 0UL, UL(MAX_FDT_SIZE), 1) - 1)
|
||||
|
|
|
|||
|
|
@ -323,13 +323,14 @@ static inline bool arch_tlbbatch_should_defer(struct mm_struct *mm)
|
|||
}
|
||||
|
||||
/*
|
||||
* If mprotect/munmap/etc occurs during TLB batched flushing, we need to
|
||||
* synchronise all the TLBI issued with a DSB to avoid the race mentioned in
|
||||
* flush_tlb_batched_pending().
|
||||
* If mprotect/munmap/etc occurs during TLB batched flushing, we need to ensure
|
||||
* all the previously issued TLBIs targeting mm have completed. But since we
|
||||
* can be executing on a remote CPU, a DSB cannot guarantee this like it can
|
||||
* for arch_tlbbatch_flush(). Our only option is to flush the entire mm.
|
||||
*/
|
||||
static inline void arch_flush_tlb_batched_pending(struct mm_struct *mm)
|
||||
{
|
||||
dsb(ish);
|
||||
flush_tlb_mm(mm);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1199,8 +1199,10 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)
|
|||
cpacr_restore(cpacr);
|
||||
}
|
||||
|
||||
if (id_aa64pfr0_mpam(info->reg_id_aa64pfr0))
|
||||
if (id_aa64pfr0_mpam(read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1))) {
|
||||
info->reg_mpamidr = read_cpuid(MPAMIDR_EL1);
|
||||
init_cpu_ftr_reg(SYS_MPAMIDR_EL1, info->reg_mpamidr);
|
||||
}
|
||||
|
||||
if (id_aa64pfr1_mte(info->reg_id_aa64pfr1))
|
||||
init_cpu_ftr_reg(SYS_GMID_EL1, info->reg_gmid);
|
||||
|
|
@ -1453,7 +1455,8 @@ void update_cpu_features(int cpu,
|
|||
cpacr_restore(cpacr);
|
||||
}
|
||||
|
||||
if (id_aa64pfr0_mpam(info->reg_id_aa64pfr0)) {
|
||||
if (id_aa64pfr0_mpam(read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1))) {
|
||||
info->reg_mpamidr = read_cpuid(MPAMIDR_EL1);
|
||||
taint |= check_update_ftr_reg(SYS_MPAMIDR_EL1, cpu,
|
||||
info->reg_mpamidr, boot->reg_mpamidr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -496,8 +496,11 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
|
|||
if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0))
|
||||
__cpuinfo_store_cpu_32bit(&info->aarch32);
|
||||
|
||||
if (id_aa64pfr0_mpam(info->reg_id_aa64pfr0))
|
||||
info->reg_mpamidr = read_cpuid(MPAMIDR_EL1);
|
||||
/*
|
||||
* info->reg_mpamidr deferred to {init,update}_cpu_features because we
|
||||
* don't want to read it (and trigger a trap on buggy firmware) if
|
||||
* using an aa64pfr0_el1 override to unconditionally disable MPAM.
|
||||
*/
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARM64_SME) &&
|
||||
id_aa64pfr1_sme(info->reg_id_aa64pfr1)) {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@
|
|||
#error This file should only be included in vmlinux.lds.S
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_LD_IS_LLD) && CONFIG_LLD_VERSION < 210000
|
||||
#define ASSERT(...)
|
||||
#endif
|
||||
|
||||
#define PI_EXPORT_SYM(sym) \
|
||||
__PI_EXPORT_SYM(sym, __pi_ ## sym, Cannot export BSS symbol sym to startup code)
|
||||
#define __PI_EXPORT_SYM(sym, pisym, msg)\
|
||||
|
|
@ -140,4 +144,17 @@ KVM_NVHE_ALIAS(kvm_protected_mode_initialized);
|
|||
_kernel_codesize = ABSOLUTE(__inittext_end - _text);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* LLD will occasionally error out with a '__init_end does not converge' error
|
||||
* if INIT_IDMAP_DIR_SIZE is defined in terms of _end, as this results in a
|
||||
* circular dependency. Counter this by dimensioning the initial IDMAP page
|
||||
* tables based on kimage_limit, which is defined such that its value should
|
||||
* not change as a result of the initdata segment being pushed over a 64k
|
||||
* segment boundary due to changes in INIT_IDMAP_DIR_SIZE, provided that its
|
||||
* value doesn't change by more than 2M between linker passes.
|
||||
*/
|
||||
kimage_limit = ALIGN(ABSOLUTE(_end + SZ_64K), SZ_2M);
|
||||
|
||||
#undef ASSERT
|
||||
|
||||
#endif /* __ARM64_KERNEL_IMAGE_VARS_H */
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ static const struct ftr_set_desc pfr0 __prel64_initconst = {
|
|||
.fields = {
|
||||
FIELD("sve", ID_AA64PFR0_EL1_SVE_SHIFT, pfr0_sve_filter),
|
||||
FIELD("el0", ID_AA64PFR0_EL1_EL0_SHIFT, NULL),
|
||||
FIELD("mpam", ID_AA64PFR0_EL1_MPAM_SHIFT, NULL),
|
||||
{}
|
||||
},
|
||||
};
|
||||
|
|
@ -154,6 +155,7 @@ static const struct ftr_set_desc pfr1 __prel64_initconst = {
|
|||
FIELD("gcs", ID_AA64PFR1_EL1_GCS_SHIFT, NULL),
|
||||
FIELD("mte", ID_AA64PFR1_EL1_MTE_SHIFT, NULL),
|
||||
FIELD("sme", ID_AA64PFR1_EL1_SME_SHIFT, pfr1_sme_filter),
|
||||
FIELD("mpam_frac", ID_AA64PFR1_EL1_MPAM_frac_SHIFT, NULL),
|
||||
{}
|
||||
},
|
||||
};
|
||||
|
|
@ -246,6 +248,7 @@ static const struct {
|
|||
{ "rodata=off", "arm64_sw.rodataoff=1" },
|
||||
{ "arm64.nolva", "id_aa64mmfr2.varange=0" },
|
||||
{ "arm64.no32bit_el0", "id_aa64pfr0.el0=1" },
|
||||
{ "arm64.nompam", "id_aa64pfr0.mpam=0 id_aa64pfr1.mpam_frac=0" },
|
||||
};
|
||||
|
||||
static int __init parse_hexdigit(const char *p, u64 *v)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user