diff options
author | Christoph Muellner <christoph.muellner@theobroma-systems.com> | 2019-02-22 18:01:59 +0100 |
---|---|---|
committer | Christoph Muellner <christoph.muellner@theobroma-systems.com> | 2019-02-25 19:05:50 +0100 |
commit | cd70cc560c99d814e0d10e1198cac7a91c124821 (patch) | |
tree | 73692cb615866343185631c1b73910d80eb2a442 | |
parent | 62a90a2a28fe84b662ccbc26da110cfc09c82659 (diff) |
arm64: Allow reference symbols in alt-seqs to be in kernel-data.linux-4.16.12-amp
When patching-in alternative sequences during bootup, we copy
the alt-seq instructions to one or more target locations.
This relocation requires a fixup of references to symbols,
if they are outside of the alt-seq.
The decision if a fixup is required is implemented in the function
branch_insn_requires_update(), which checks if the given address
is in kernel-text (e.g. functions).
This patch renames the function to address_needs_relocation_fixup()
and also supports symbols in kernel-data (e.g. global variables).
This allows adrp to address such symbols, which is required for
e.g. ARM64_MISMATCHED_CACHE_LINE_SIZE.
Signed-off-by: Christoph Muellner <christoph.muellner@theobroma-systems.com>
-rw-r--r-- | arch/arm64/kernel/alternative.c | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c index fdcdb15251a3..c78d16e7bf7b 100644 --- a/arch/arm64/kernel/alternative.c +++ b/arch/arm64/kernel/alternative.c @@ -40,17 +40,21 @@ struct alt_region { }; /* - * Check if the target PC is within an alternative block. + * Check if the given address needs a relocation fixup + * in case the given alt-seq is moved. + * This is required if the address is e.g. in kernel-text, + * but not if it is within the given alt-seq itself. + * We call BUG() in cases where we cannot safely decide. */ -static bool branch_insn_requires_update(struct alt_instr *alt, unsigned long pc) +static bool address_needs_relocation_fixup(struct alt_instr *alt, unsigned long addr) { unsigned long replptr; - if (kernel_text_address(pc)) + if (kernel_text_address(addr) || core_kernel_data(addr)) return 1; replptr = (unsigned long)ALT_REPL_PTR(alt); - if (pc >= replptr && pc <= (replptr + alt->alt_len)) + if (addr >= replptr && addr <= (replptr + alt->alt_len)) return 0; /* @@ -79,7 +83,7 @@ static u32 get_alt_insn(struct alt_instr *alt, __le32 *insnptr, __le32 *altinsnp * do not rewrite the instruction, as it is already * correct. Otherwise, generate the new instruction. */ - if (branch_insn_requires_update(alt, target)) { + if (address_needs_relocation_fixup(alt, target)) { offset = target - (unsigned long)insnptr; insn = aarch64_set_branch_offset(insn, offset); } @@ -90,7 +94,7 @@ static u32 get_alt_insn(struct alt_instr *alt, __le32 *insnptr, __le32 *altinsnp orig_offset = aarch64_insn_adrp_get_offset(insn); target = align_down(altinsnptr, SZ_4K) + orig_offset; - if (branch_insn_requires_update(alt, target)) { + if (address_needs_relocation_fixup(alt, target)) { /* * If we're replacing an adrp instruction, which uses * PC-relative immediate addressing, adjust the offset @@ -106,7 +110,7 @@ static u32 get_alt_insn(struct alt_instr *alt, __le32 *insnptr, __le32 *altinsnp target = (unsigned long)altinsnptr + offset; - if (branch_insn_requires_update(alt, target)) { + if (address_needs_relocation_fixup(alt, target)) { /* * Disallow adr instructions for targets outside * of our alt block. |