powerpc/features: Add capability to update mmu features later

On powerpc32, features fixup is performed very early and that's too
early to read the cmdline and take into account 'nosmap' parameter.

On the other hand, no userspace access is performed that early and
KUAP feature fixup can be performed later.

Add a function to update mmu features. The function is passed a
mask with the features that can be updated.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/31b27ee2c9d338f4f82cd8cd69d6bff979495290.1689091022.git.christophe.leroy@csgroup.eu
This commit is contained in:
Christophe Leroy 2023-07-11 17:59:16 +02:00 committed by Michael Ellerman
parent 38bb171b95
commit 6b289911c8
2 changed files with 28 additions and 4 deletions

View File

@ -292,6 +292,7 @@ extern long __start___barrier_nospec_fixup, __stop___barrier_nospec_fixup;
extern long __start__btb_flush_fixup, __stop__btb_flush_fixup;
void apply_feature_fixups(void);
void update_mmu_feature_fixups(unsigned long mask);
void setup_feature_keys(void);
#endif

View File

@ -67,7 +67,8 @@ static int patch_alt_instruction(u32 *src, u32 *dest, u32 *alt_start, u32 *alt_e
return 0;
}
static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
static int patch_feature_section_mask(unsigned long value, unsigned long mask,
struct fixup_entry *fcur)
{
u32 *start, *end, *alt_start, *alt_end, *src, *dest;
@ -79,7 +80,7 @@ static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
if ((alt_end - alt_start) > (end - start))
return 1;
if ((value & fcur->mask) == fcur->value)
if ((value & fcur->mask & mask) == (fcur->value & mask))
return 0;
src = alt_start;
@ -97,7 +98,8 @@ static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
return 0;
}
void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
static void do_feature_fixups_mask(unsigned long value, unsigned long mask,
void *fixup_start, void *fixup_end)
{
struct fixup_entry *fcur, *fend;
@ -105,7 +107,7 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
fend = fixup_end;
for (; fcur < fend; fcur++) {
if (patch_feature_section(value, fcur)) {
if (patch_feature_section_mask(value, mask, fcur)) {
WARN_ON(1);
printk("Unable to patch feature section at %p - %p" \
" with %p - %p\n",
@ -117,6 +119,11 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
}
}
void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
{
do_feature_fixups_mask(value, ~0, fixup_start, fixup_end);
}
#ifdef CONFIG_PPC_BARRIER_NOSPEC
static bool is_fixup_addr_valid(void *dest, size_t size)
{
@ -651,6 +658,17 @@ void __init apply_feature_fixups(void)
do_final_fixups();
}
void __init update_mmu_feature_fixups(unsigned long mask)
{
saved_mmu_features &= ~mask;
saved_mmu_features |= cur_cpu_spec->mmu_features & mask;
do_feature_fixups_mask(cur_cpu_spec->mmu_features, mask,
PTRRELOC(&__start___mmu_ftr_fixup),
PTRRELOC(&__stop___mmu_ftr_fixup));
mmu_feature_keys_init();
}
void __init setup_feature_keys(void)
{
/*
@ -683,6 +701,11 @@ late_initcall(check_features);
#define check(x) \
if (!(x)) printk("feature-fixups: test failed at line %d\n", __LINE__);
static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
{
return patch_feature_section_mask(value, ~0, fcur);
}
/* This must be after the text it fixes up, vmlinux.lds.S enforces that atm */
static struct fixup_entry fixup;