summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-09-04 13:32:46 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-09-04 13:32:46 -0700
commit3f17a52d47ed39c89cc8429307cf246e781ec979 (patch)
tree33cc4eea950d24d910d6fecc225de28e6526a1c2
parent408802f1e61dad400ed5d2504165579189cc183f (diff)
parent5445d64199626974269fcdf347769ad44b0bb53b (diff)
downloadlinux-3f17a52d47ed39c89cc8429307cf246e781ec979.tar.gz
linux-3f17a52d47ed39c89cc8429307cf246e781ec979.zip
Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull arm64 fixes from Will Deacon: "Nothing Earth-shattering, but worthwhile fixes nonetheless: - Disable interrupts during page-table walk in show_pte() - Fix kexec_file_load() with 52-bit capable kernels on machines without 52-bit addressing - Fix MIDR matching in CPU errata handling for KVM guests - Avoid reading MTE-specific ID registers when MTE support is disabled" * tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: arm64: Don't read GMID_EL1 when MTE is disabled arm64: errata: pass REVIDR when matching target implementation CPUs arm64: trans_pgd: clone only the linear map that exists at runtime arm64: mm: Fix the lockless page-table walk in show_pte()
-rw-r--r--arch/arm64/include/asm/cpu.h1
-rw-r--r--arch/arm64/include/asm/cpufeature.h7
-rw-r--r--arch/arm64/kernel/cpu_errata.c2
-rw-r--r--arch/arm64/kernel/cpufeature.c33
-rw-r--r--arch/arm64/kernel/cpuinfo.c2
-rw-r--r--arch/arm64/kernel/machine_kexec.c3
-rw-r--r--arch/arm64/mm/fault.c12
7 files changed, 42 insertions, 18 deletions
diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h
index 71493b760b83..3c008821219c 100644
--- a/arch/arm64/include/asm/cpu.h
+++ b/arch/arm64/include/asm/cpu.h
@@ -78,5 +78,6 @@ void __init cpuinfo_store_boot_cpu(void);
void __init init_cpu_features(struct cpuinfo_arm64 *info);
void update_cpu_features(int cpu, struct cpuinfo_arm64 *info,
struct cpuinfo_arm64 *boot);
+bool gmid_el1_accessible(const struct cpuinfo_arm64 *info);
#endif /* __ASM_CPU_H */
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 7404a6e83a93..4f04ad82ea34 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -627,13 +627,6 @@ static inline bool id_aa64pfr1_mpamfrac(u64 pfr1)
return val > 0;
}
-static inline bool id_aa64pfr1_mte(u64 pfr1)
-{
- u32 val = cpuid_feature_extract_unsigned_field(pfr1, ID_AA64PFR1_EL1_MTE_SHIFT);
-
- return val >= ID_AA64PFR1_EL1_MTE_MTE2;
-}
-
void __init setup_boot_cpu_features(void);
void __init setup_system_features(void);
void __init setup_user_features(void);
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 5db8f0619e4b..b33dccfafaf8 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -82,7 +82,7 @@ is_affected_midr_range(const struct arm64_cpu_capabilities *entry, int scope)
for (i = 0; i < target_impl_cpu_num; i++) {
if (__is_affected_midr_range(entry, target_impl_cpus[i].midr,
- target_impl_cpus[i].midr))
+ target_impl_cpus[i].revidr))
return true;
}
return false;
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 17b83a2518a8..32102c3912fa 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -1178,6 +1178,33 @@ static bool detect_ftr_has_mpam(void)
return id_aa64pfr0_mpam(pfr0) || id_aa64pfr1_mpamfrac(pfr1);
}
+bool gmid_el1_accessible(const struct cpuinfo_arm64 *info)
+{
+ const struct arm64_ftr_bits *ftrp;
+ s64 mte, ovr;
+ u64 ftr_mask;
+
+ /* No ID register reflects CONFIG_ARM64_MTE. */
+ if (!IS_ENABLED(CONFIG_ARM64_MTE))
+ return false;
+
+ for (ftrp = ftr_id_aa64pfr1; ftrp->width; ftrp++) {
+ if (ftrp->shift == ID_AA64PFR1_EL1_MTE_SHIFT)
+ break;
+ }
+
+ ftr_mask = arm64_ftr_mask(ftrp);
+ mte = arm64_ftr_value(ftrp, info->reg_id_aa64pfr1);
+
+ /* The boot CPU runs before init_cpu_ftr_reg() strips unsafe overrides. */
+ if ((id_aa64pfr1_override.mask & ftr_mask) == ftr_mask) {
+ ovr = arm64_ftr_value(ftrp, id_aa64pfr1_override.val);
+ mte = arm64_ftr_safe_value(ftrp, ovr, mte);
+ }
+
+ return mte >= ID_AA64PFR1_EL1_MTE_MTE2;
+}
+
void __init init_cpu_features(struct cpuinfo_arm64 *info)
{
/* Before we start using the tables, make sure it is sorted */
@@ -1230,7 +1257,7 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)
init_cpu_ftr_reg(SYS_MPAMIDR_EL1, info->reg_mpamidr);
}
- if (id_aa64pfr1_mte(info->reg_id_aa64pfr1))
+ if (gmid_el1_accessible(info))
init_cpu_ftr_reg(SYS_GMID_EL1, info->reg_gmid);
}
@@ -1492,11 +1519,9 @@ void update_cpu_features(int cpu,
* they read/write depends on the GMID_EL1.BS field. Check that the
* value is the same on all CPUs.
*/
- if (IS_ENABLED(CONFIG_ARM64_MTE) &&
- id_aa64pfr1_mte(info->reg_id_aa64pfr1)) {
+ if (gmid_el1_accessible(info))
taint |= check_update_ftr_reg(SYS_GMID_EL1, cpu,
info->reg_gmid, boot->reg_gmid);
- }
/*
* If we don't have AArch32 at all then skip the checks entirely
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index d50e2a9b066b..45c63f3d75c5 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -502,7 +502,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
info->reg_id_aa64smfr0 = read_cpuid(ID_AA64SMFR0_EL1);
info->reg_id_aa64fpfr0 = read_cpuid(ID_AA64FPFR0_EL1);
- if (id_aa64pfr1_mte(info->reg_id_aa64pfr1))
+ if (gmid_el1_accessible(info))
info->reg_gmid = read_cpuid(GMID_EL1);
if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0))
diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c
index c5693a32e49b..8f9bc2327dc8 100644
--- a/arch/arm64/kernel/machine_kexec.c
+++ b/arch/arm64/kernel/machine_kexec.c
@@ -129,7 +129,8 @@ int machine_kexec_post_load(struct kimage *kimage)
}
/* Create a copy of the linear map */
- rc = trans_pgd_create_copy(&info, &trans_pgd, PAGE_OFFSET, PAGE_END);
+ rc = trans_pgd_create_copy(&info, &trans_pgd,
+ _PAGE_OFFSET(vabits_actual), PAGE_END);
if (rc)
return rc;
kimage->arch.ttbr1 = __pa(trans_pgd);
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 0b52557652be..75c3e463df2e 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -16,6 +16,7 @@
#include <linux/mm.h>
#include <linux/hardirq.h>
#include <linux/init.h>
+#include <linux/irqflags.h>
#include <linux/kasan.h>
#include <linux/kprobes.h>
#include <linux/uaccess.h>
@@ -154,6 +155,9 @@ static void show_pte(unsigned long addr)
pr_alert("%s pgtable: %luk pages, %llu-bit VAs, pgdp=%016lx\n",
mm == &init_mm ? "swapper" : "user", PAGE_SIZE / SZ_1K,
vabits_actual, mm_to_pgd_phys(mm));
+
+ guard(irqsave)();
+
pgdp = pgd_offset(mm, addr);
pgd = READ_ONCE(*pgdp);
pr_alert("[%016lx] pgd=%016llx", addr, pgd_val(pgd));
@@ -167,25 +171,25 @@ static void show_pte(unsigned long addr)
if (pgd_none(pgd) || pgd_bad(pgd))
break;
- p4dp = p4d_offset(pgdp, addr);
+ p4dp = p4d_offset_lockless(pgdp, pgd, addr);
p4d = READ_ONCE(*p4dp);
pr_cont(", p4d=%016llx", p4d_val(p4d));
if (p4d_none(p4d) || p4d_bad(p4d))
break;
- pudp = pud_offset(p4dp, addr);
+ pudp = pud_offset_lockless(p4dp, p4d, addr);
pud = READ_ONCE(*pudp);
pr_cont(", pud=%016llx", pud_val(pud));
if (pud_none(pud) || pud_bad(pud))
break;
- pmdp = pmd_offset(pudp, addr);
+ pmdp = pmd_offset_lockless(pudp, pud, addr);
pmd = READ_ONCE(*pmdp);
pr_cont(", pmd=%016llx", pmd_val(pmd));
if (pmd_none(pmd) || pmd_bad(pmd))
break;
- ptep = pte_offset_map(pmdp, addr);
+ ptep = pte_offset_map(&pmd, addr);
if (!ptep)
break;