linux/arch/arm/mm/tlb.c
Ard Biesheuvel 6b0ef2792c ARM: 9384/2: mm: Make tlbflush routines CFI safe
Instead of avoiding CFI entirely on the TLB flush helpers, reorganize
the code so that the CFI machinery can deal with it. The important
things to take into account are:
- functions in asm called indirectly from C need to be defined using
  SYM_TYPED_FUNC_START()
- a reference to the asm function needs to be visible to the compiler,
  in order to get it to emit the typeid symbol.

The latter means that defining the cpu_tlb_fns structs is best done from
C code, so that the references in the static initializers will be
visible to the compiler.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Tested-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Sami Tolvanen <samitolvanen@google.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
2024-04-29 14:14:15 +01:00

85 lines
2.7 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
// Copyright 2024 Google LLC
// Author: Ard Biesheuvel <ardb@google.com>
#include <linux/types.h>
#include <asm/tlbflush.h>
#ifdef CONFIG_CPU_TLB_V4WT
void v4_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
void v4_flush_kern_tlb_range(unsigned long, unsigned long);
struct cpu_tlb_fns v4_tlb_fns __initconst = {
.flush_user_range = v4_flush_user_tlb_range,
.flush_kern_range = v4_flush_kern_tlb_range,
.tlb_flags = v4_tlb_flags,
};
#endif
#ifdef CONFIG_CPU_TLB_V4WB
void v4wb_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
void v4wb_flush_kern_tlb_range(unsigned long, unsigned long);
struct cpu_tlb_fns v4wb_tlb_fns __initconst = {
.flush_user_range = v4wb_flush_user_tlb_range,
.flush_kern_range = v4wb_flush_kern_tlb_range,
.tlb_flags = v4wb_tlb_flags,
};
#endif
#if defined(CONFIG_CPU_TLB_V4WBI) || defined(CONFIG_CPU_TLB_FEROCEON)
void v4wbi_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
void v4wbi_flush_kern_tlb_range(unsigned long, unsigned long);
struct cpu_tlb_fns v4wbi_tlb_fns __initconst = {
.flush_user_range = v4wbi_flush_user_tlb_range,
.flush_kern_range = v4wbi_flush_kern_tlb_range,
.tlb_flags = v4wbi_tlb_flags,
};
#endif
#ifdef CONFIG_CPU_TLB_V6
void v6wbi_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
void v6wbi_flush_kern_tlb_range(unsigned long, unsigned long);
struct cpu_tlb_fns v6wbi_tlb_fns __initconst = {
.flush_user_range = v6wbi_flush_user_tlb_range,
.flush_kern_range = v6wbi_flush_kern_tlb_range,
.tlb_flags = v6wbi_tlb_flags,
};
#endif
#ifdef CONFIG_CPU_TLB_V7
void v7wbi_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
void v7wbi_flush_kern_tlb_range(unsigned long, unsigned long);
struct cpu_tlb_fns v7wbi_tlb_fns __initconst = {
.flush_user_range = v7wbi_flush_user_tlb_range,
.flush_kern_range = v7wbi_flush_kern_tlb_range,
.tlb_flags = IS_ENABLED(CONFIG_SMP) ? v7wbi_tlb_flags_smp
: v7wbi_tlb_flags_up,
};
#ifdef CONFIG_SMP_ON_UP
/* This will be run-time patched so the offset better be right */
static_assert(offsetof(struct cpu_tlb_fns, tlb_flags) == 8);
asm(" .pushsection \".alt.smp.init\", \"a\" \n" \
" .align 2 \n" \
" .long v7wbi_tlb_fns + 8 - . \n" \
" .long " __stringify(v7wbi_tlb_flags_up) " \n" \
" .popsection \n");
#endif
#endif
#ifdef CONFIG_CPU_TLB_FA
void fa_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
void fa_flush_kern_tlb_range(unsigned long, unsigned long);
struct cpu_tlb_fns fa_tlb_fns __initconst = {
.flush_user_range = fa_flush_user_tlb_range,
.flush_kern_range = fa_flush_kern_tlb_range,
.tlb_flags = fa_tlb_flags,
};
#endif