Skip to content

Commit

Permalink
arm64: add module support for alternatives fixups
Browse files Browse the repository at this point in the history
Currently the kernel patches all necessary instructions once at boot
time, so modules are not covered by this.
Change the apply_alternatives() function to take a beginning and an
end pointer and introduce a new variant (apply_alternatives_all()) to
cover the existing use case for the static kernel image section.
Add a module_finalize() function to arm64 to check for an
alternatives section in a module and patch only the instructions from
that specific area.
Since that module code is not touched before the module
initialization has ended, we don't need to halt the machine before
doing the patching in the module's code.

Signed-off-by: Andre Przywara <[email protected]>
Signed-off-by: Will Deacon <[email protected]>
  • Loading branch information
Andre-ARM authored and wildea01 committed Dec 4, 2014
1 parent cbbf2e6 commit 932ded4
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 6 deletions.
3 changes: 2 additions & 1 deletion arch/arm64/include/asm/alternative.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ struct alt_instr {
u8 alt_len; /* size of new instruction(s), <= orig_len */
};

void apply_alternatives(void);
void apply_alternatives_all(void);
void apply_alternatives(void *start, size_t length);
void free_alternatives_memory(void);

#define ALTINSTR_ENTRY(feature) \
Expand Down
29 changes: 25 additions & 4 deletions arch/arm64/kernel/alternative.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,18 @@

extern struct alt_instr __alt_instructions[], __alt_instructions_end[];

static int __apply_alternatives(void *dummy)
struct alt_region {
struct alt_instr *begin;
struct alt_instr *end;
};

static int __apply_alternatives(void *alt_region)
{
struct alt_instr *alt;
struct alt_region *region = alt_region;
u8 *origptr, *replptr;

for (alt = __alt_instructions; alt < __alt_instructions_end; alt++) {
for (alt = region->begin; alt < region->end; alt++) {
if (!cpus_have_cap(alt->cpufeature))
continue;

Expand All @@ -51,10 +57,25 @@ static int __apply_alternatives(void *dummy)
return 0;
}

void apply_alternatives(void)
void apply_alternatives_all(void)
{
struct alt_region region = {
.begin = __alt_instructions,
.end = __alt_instructions_end,
};

/* better not try code patching on a live SMP system */
stop_machine(__apply_alternatives, NULL, NULL);
stop_machine(__apply_alternatives, &region, NULL);
}

void apply_alternatives(void *start, size_t length)
{
struct alt_region region = {
.begin = start,
.end = start + length,
};

__apply_alternatives(&region);
}

void free_alternatives_memory(void)
Expand Down
18 changes: 18 additions & 0 deletions arch/arm64/kernel/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <linux/moduleloader.h>
#include <linux/vmalloc.h>
#include <asm/insn.h>
#include <asm/sections.h>

#define AARCH64_INSN_IMM_MOVNZ AARCH64_INSN_IMM_MAX
#define AARCH64_INSN_IMM_MOVK AARCH64_INSN_IMM_16
Expand Down Expand Up @@ -394,3 +395,20 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
me->name, (int)ELF64_R_TYPE(rel[i].r_info), val);
return -ENOEXEC;
}

int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
struct module *me)
{
const Elf_Shdr *s, *se;
const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;

for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) {
if (strcmp(".altinstructions", secstrs + s->sh_name) == 0) {
apply_alternatives((void *)s->sh_addr, s->sh_size);
return 0;
}
}

return 0;
}
2 changes: 1 addition & 1 deletion arch/arm64/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ void cpu_die(void)
void __init smp_cpus_done(unsigned int max_cpus)
{
pr_info("SMP: Total of %d processors activated.\n", num_online_cpus());
apply_alternatives();
apply_alternatives_all();
}

void __init smp_prepare_boot_cpu(void)
Expand Down

0 comments on commit 932ded4

Please sign in to comment.