mirror of
https://github.com/torvalds/linux.git
synced 2025-04-11 04:53:02 +00:00

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>
85 lines
2.7 KiB
C
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
|