[PATCH RFC 5/8] powerpc/64: Patch barrier_nospec in modules
From: Michal Suchanek
Date: Tue Mar 13 2018 - 14:35:31 EST
Copypasta from lwsync patching.
Note that unlike RFI which is patched only in kernel the nospec state
reflects settings at the time the module was loaded.
Iterating all modules and re-patching every time the settings change is
not implemented.
Signed-off-by: Michal Suchanek <msuchanek@xxxxxxx>
---
arch/powerpc/include/asm/setup.h | 5 ++++-
arch/powerpc/kernel/module.c | 6 ++++++
arch/powerpc/kernel/setup_64.c | 4 ++--
arch/powerpc/lib/feature-fixups.c | 17 ++++++++++++++---
4 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h
index 486d02e4a310..7e3a41248810 100644
--- a/arch/powerpc/include/asm/setup.h
+++ b/arch/powerpc/include/asm/setup.h
@@ -58,7 +58,10 @@ enum spec_barrier_type {
void __init setup_rfi_flush(enum l1d_flush_type, bool enable);
void do_rfi_flush_fixups(enum l1d_flush_type types);
void __init setup_barrier_nospec(enum spec_barrier_type, bool enable);
-void do_barrier_nospec_fixups(enum spec_barrier_type type);
+void do_barrier_nospec_fixups_kernel(enum spec_barrier_type type);
+void do_barrier_nospec_fixups(enum spec_barrier_type type,
+ void *start, void *end);
+extern enum spec_barrier_type powerpc_barrier_nospec;
#endif /* !__ASSEMBLY__ */
diff --git a/arch/powerpc/kernel/module.c b/arch/powerpc/kernel/module.c
index 3f7ba0f5bf29..7b6d0ec06a21 100644
--- a/arch/powerpc/kernel/module.c
+++ b/arch/powerpc/kernel/module.c
@@ -72,6 +72,12 @@ int module_finalize(const Elf_Ehdr *hdr,
do_feature_fixups(powerpc_firmware_features,
(void *)sect->sh_addr,
(void *)sect->sh_addr + sect->sh_size);
+
+ sect = find_section(hdr, sechdrs, "__spec_barrier_fixup");
+ if (sect != NULL)
+ do_barrier_nospec_fixups(powerpc_barrier_nospec,
+ (void *)sect->sh_addr,
+ (void *)sect->sh_addr + sect->sh_size);
#endif
sect = find_section(hdr, sechdrs, "__lwsync_fixup");
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 09f21a954bfc..d1d9f047161e 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -909,11 +909,11 @@ void barrier_nospec_enable(bool enable)
if (enable) {
powerpc_barrier_nospec = barrier_nospec_type;
- do_barrier_nospec_fixups(powerpc_barrier_nospec);
+ do_barrier_nospec_fixups_kernel(powerpc_barrier_nospec);
on_each_cpu(do_nothing, NULL, 1);
} else {
powerpc_barrier_nospec = SPEC_BARRIER_NONE;
- do_barrier_nospec_fixups(powerpc_barrier_nospec);
+ do_barrier_nospec_fixups_kernel(powerpc_barrier_nospec);
}
}
diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
index 000e153184ad..b59ebc2215e8 100644
--- a/arch/powerpc/lib/feature-fixups.c
+++ b/arch/powerpc/lib/feature-fixups.c
@@ -156,14 +156,15 @@ void do_rfi_flush_fixups(enum l1d_flush_type types)
printk(KERN_DEBUG "rfi-flush: patched %d locations\n", i);
}
-void do_barrier_nospec_fixups(enum spec_barrier_type type)
+void do_barrier_nospec_fixups(enum spec_barrier_type type,
+ void *fixup_start, void *fixup_end)
{
unsigned int instr, *dest;
long *start, *end;
int i;
- start = PTRRELOC(&__start___spec_barrier_fixup),
- end = PTRRELOC(&__stop___spec_barrier_fixup);
+ start = fixup_start;
+ end = fixup_end;
instr = 0x60000000; /* nop */
@@ -182,6 +183,16 @@ void do_barrier_nospec_fixups(enum spec_barrier_type type)
printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
}
+void do_barrier_nospec_fixups_kernel(enum spec_barrier_type type)
+{
+ void *start, *end;
+
+ start = PTRRELOC(&__start___spec_barrier_fixup),
+ end = PTRRELOC(&__stop___spec_barrier_fixup);
+
+ do_barrier_nospec_fixups(type, start, end);
+}
+
#endif /* CONFIG_PPC_BOOK3S_64 */
void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
--
2.13.6