summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Muellner <christoph.muellner@theobroma-systems.com>2019-02-22 18:01:59 +0100
committerChristoph Muellner <christoph.muellner@theobroma-systems.com>2019-02-25 19:05:50 +0100
commitcd70cc560c99d814e0d10e1198cac7a91c124821 (patch)
tree73692cb615866343185631c1b73910d80eb2a442
parent62a90a2a28fe84b662ccbc26da110cfc09c82659 (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.c18
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.