@@ -56,6 +56,8 @@ typedef struct {
*/
#define ASID(mm) (atomic64_read(&(mm)->context.id) & 0xffff)
+extern bool block_mapping;
+
static inline bool arm64_kernel_unmapped_at_el0(void)
{
return alternative_has_cap_unlikely(ARM64_UNMAP_KERNEL_AT_EL0);
@@ -72,6 +74,7 @@ extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
extern void *fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot);
extern void mark_linear_text_alias_ro(void);
extern int split_linear_mapping(unsigned long start, unsigned long end);
+extern int __repaint_linear_mappings(void *__unused);
/*
* This check is triggered during the early boot before the cpufeature
@@ -85,6 +85,7 @@
#include <asm/insn.h>
#include <asm/kvm_host.h>
#include <asm/mmu_context.h>
+#include <asm/mmu.h>
#include <asm/mte.h>
#include <asm/processor.h>
#include <asm/smp.h>
@@ -1972,6 +1973,28 @@ static int __init __kpti_install_ng_mappings(void *__unused)
return 0;
}
+static void __init repaint_linear_mappings(void)
+{
+ struct cpumask bbml2_cpus;
+
+ if (!block_mapping)
+ return;
+
+ if (!rodata_full)
+ return;
+
+ if (system_supports_bbml2_noabort())
+ return;
+
+ /*
+ * Need to guarantee repainting linear mapping is called on the
+ * boot CPU since boot CPU supports BBML2.
+ */
+ cpumask_clear(&bbml2_cpus);
+ cpumask_set_cpu(smp_processor_id(), &bbml2_cpus);
+ stop_machine(__repaint_linear_mappings, NULL, &bbml2_cpus);
+}
+
static void __init kpti_install_ng_mappings(void)
{
/* Check whether KPTI is going to be used */
@@ -3814,6 +3837,7 @@ void __init setup_system_features(void)
{
setup_system_capabilities();
+ repaint_linear_mappings();
kpti_install_ng_mappings();
sve_setup();
@@ -209,6 +209,8 @@ static int split_pmd(pmd_t *pmdp, pmd_t pmdval,
/* It must be naturally aligned if PMD is leaf */
if ((flags & NO_CONT_MAPPINGS) == 0)
prot = __pgprot(pgprot_val(prot) | PTE_CONT);
+ else
+ prot = __pgprot(pgprot_val(prot) & ~PTE_CONT);
for (i = 0; i < PTRS_PER_PTE; i++, ptep++)
__set_pte_nosync(ptep, pfn_pte(pfn + i, prot));
@@ -258,6 +260,8 @@ static int split_pud(pud_t *pudp, pud_t pudval,
/* It must be naturally aligned if PUD is leaf */
if ((flags & NO_CONT_MAPPINGS) == 0)
prot = __pgprot(pgprot_val(prot) | PTE_CONT);
+ else
+ prot = __pgprot(pgprot_val(prot) & ~PTE_CONT);
for (int i = 0; i < PTRS_PER_PMD; i++, pmdp++) {
__set_pmd_nosync(pmdp, pfn_pmd(pfn, prot));
@@ -806,6 +810,37 @@ void __init mark_linear_text_alias_ro(void)
PAGE_KERNEL_RO);
}
+int __init __repaint_linear_mappings(void *__unused)
+{
+ phys_addr_t kernel_start = __pa_symbol(_stext);
+ phys_addr_t kernel_end = __pa_symbol(__init_begin);
+ phys_addr_t start, end;
+ unsigned long vstart, vend;
+ u64 i;
+ int ret;
+
+ memblock_mark_nomap(kernel_start, kernel_end - kernel_start);
+ /* Split the whole linear mapping */
+ for_each_mem_range(i, &start, &end) {
+ if (start >= end)
+ return -EINVAL;
+
+ vstart = __phys_to_virt(start);
+ vend = __phys_to_virt(end);
+ ret = __create_pgd_mapping_locked(init_mm.pgd, start,
+ vstart, (end - start), __pgprot(0),
+ __pgd_pgtable_alloc,
+ NO_CONT_MAPPINGS | SPLIT_MAPPINGS);
+ if (ret)
+ panic("Failed to split linear mappings\n");
+
+ flush_tlb_kernel_range(vstart, vend);
+ }
+ memblock_clear_nomap(kernel_start, kernel_end - kernel_start);
+
+ return 0;
+}
+
#ifdef CONFIG_KFENCE
bool __ro_after_init kfence_early_init = !!CONFIG_KFENCE_SAMPLE_INTERVAL;
@@ -860,6 +895,8 @@ static inline void arm64_kfence_map_pool(phys_addr_t kfence_pool, pgd_t *pgdp) {
#endif /* CONFIG_KFENCE */
+bool block_mapping;
+
static inline bool force_pte_mapping(void)
{
/*
@@ -888,6 +925,8 @@ static void __init map_mem(pgd_t *pgdp)
int flags = NO_EXEC_MAPPINGS;
u64 i;
+ block_mapping = true;
+
/*
* Setting hierarchical PXNTable attributes on table entries covering
* the linear region is only possible if it is guaranteed that no table
@@ -903,8 +942,10 @@ static void __init map_mem(pgd_t *pgdp)
early_kfence_pool = arm64_kfence_alloc_pool();
- if (force_pte_mapping())
+ if (force_pte_mapping()) {
+ block_mapping = false;
flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
+ }
/*
* Take care not to create a writable alias for the
The kernel linear mapping is painted in very early stage of system boot. The cpufeature has not been finalized yet at this point. So the linear mapping is determined by the capability of boot CPU. If the boot CPU supports BBML2, large block mapping will be used for linear mapping. But the secondary CPUs may not support BBML2, so repaint the linear mapping if large block mapping is used and the secondary CPUs don't support BBML2 once cpufeature is finalized on all CPUs. If the boot CPU doesn't support BBML2 or the secondary CPUs have the same BBML2 capability with the boot CPU, repainting the linear mapping is not needed. Signed-off-by: Yang Shi <yang@os.amperecomputing.com> --- arch/arm64/include/asm/mmu.h | 3 +++ arch/arm64/kernel/cpufeature.c | 24 +++++++++++++++++++ arch/arm64/mm/mmu.c | 43 +++++++++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 1 deletion(-)